Skip to content

test(ai): add integration tests #8853

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 30 commits into from
Jun 5, 2025
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
98574c2
Skeleton
dlarocque Mar 18, 2025
ae05e53
Integration tests
dlarocque Mar 19, 2025
d83b22e
Import firebase config from secret file
dlarocque Mar 19, 2025
f78282a
Validate that config file exists.
dlarocque Mar 19, 2025
0d1fb41
Cleanup
dlarocque Mar 19, 2025
b083d00
Format
dlarocque Mar 19, 2025
4d6a5ce
Lint fix
dlarocque Mar 19, 2025
3fbb6d6
Extend preprocessor in vertex ai karma conf
dlarocque Mar 19, 2025
d446c77
format
dlarocque Mar 19, 2025
fe6528b
Add placeholder `integration/firebase-config.ts`
dlarocque Mar 19, 2025
7ad7833
Format
dlarocque Mar 20, 2025
11a8b05
Merge branch 'main' into dl/vertex-integration
dlarocque May 16, 2025
9f908d2
Add test configs to run against each test
dlarocque May 16, 2025
abe830c
Add test configs to run against each test
dlarocque May 16, 2025
472c452
count tokens tests
dlarocque May 16, 2025
681b4bd
Format and fix lint issues
dlarocque May 16, 2025
62dab2b
Merge branch 'main' into dl/vertex-integration
dlarocque May 20, 2025
8f65c98
Merge branch 'main' into dl/vertex-integration
dlarocque May 20, 2025
c769317
count tokens tests against both backends
dlarocque May 21, 2025
d78fc29
count tokens test cleanup
dlarocque May 21, 2025
676e90d
remaining integration tests
dlarocque May 22, 2025
ddfd7f5
revert changes to gitignore
dlarocque May 22, 2025
46e910d
Merge branch 'main' into dl/vertex-integration
dlarocque May 22, 2025
3bfcfa7
Merge branch 'dl/vertex-integration' of https://github.com/firebase/f…
dlarocque May 22, 2025
28f843c
use ci config file
dlarocque May 22, 2025
f851be4
import from minified @firebase/ai in integration tests
dlarocque May 23, 2025
f327b4b
exclude integration from rollup
dlarocque May 23, 2025
604a419
revert change to import from @firebase/ai
dlarocque May 23, 2025
9b97310
cleanup
dlarocque May 23, 2025
63f7215
format
dlarocque May 23, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,7 @@ vertexai-sdk-test-data
mocks-lookup.ts

# temp changeset output
changeset-temp.json
changeset-temp.json

# Vertex AI integration test Firebase project config
packages/vertexai/integration/firebase-config.ts
63 changes: 63 additions & 0 deletions packages/vertexai/integration/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* @license
* Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import {
Content,
GenerationConfig,
HarmBlockMethod,
HarmBlockThreshold,
HarmCategory,
SafetySetting
} from '../src';

export const MODEL_NAME = 'gemini-1.5-pro';

export const generationConfig: GenerationConfig = {
temperature: 0,
topP: 0,
responseMimeType: 'text/plain'
};

export const safetySettings: SafetySetting[] = [
{
category: HarmCategory.HARM_CATEGORY_HARASSMENT,
threshold: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE,
method: HarmBlockMethod.PROBABILITY
},
{
category: HarmCategory.HARM_CATEGORY_HATE_SPEECH,
threshold: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE,
method: HarmBlockMethod.SEVERITY
},
{
category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
threshold: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE
},
{
category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
threshold: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE
}
];

export const systemInstruction: Content = {
role: 'system',
parts: [
{
text: 'You are a friendly and helpful assistant.'
}
]
};
56 changes: 56 additions & 0 deletions packages/vertexai/integration/count-tokens.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* @license
* Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { expect } from 'chai';
import { Modality, getGenerativeModel, getVertexAI } from '../src';
import {
MODEL_NAME,
generationConfig,
systemInstruction,
safetySettings
} from './constants';
import { initializeApp } from '@firebase/app';
import { FIREBASE_CONFIG } from './firebase-config';

describe('Count Tokens', () => {
before(() => initializeApp(FIREBASE_CONFIG));

it('CountTokens text', async () => {
const vertexAI = getVertexAI();
const model = getGenerativeModel(vertexAI, {
model: MODEL_NAME,
generationConfig,
systemInstruction,
safetySettings
});

const response = await model.countTokens('Why is the sky blue?');

expect(response.totalTokens).to.equal(6);
expect(response.totalBillableCharacters).to.equal(16);
expect(response.promptTokensDetails).to.not.be.null;
expect(response.promptTokensDetails!.length).to.equal(1);
expect(response.promptTokensDetails![0].modality).to.equal(Modality.TEXT);
expect(response.promptTokensDetails![0].tokenCount).to.equal(6);
});
// TODO (dlarocque): Test countTokens() with the following:
// - inline data
// - public storage reference
// - private storage reference (testing auth integration)
// - count tokens
// - JSON schema
});
19 changes: 19 additions & 0 deletions packages/vertexai/integration/firebase-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* @license
* Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// PLACEHOLDER: This should be replaced with a Firebase config for a project with access to Vertex AI.
export const FIREBASE_CONFIG = {};
84 changes: 84 additions & 0 deletions packages/vertexai/integration/generate-content.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* @license
* Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { expect } from 'chai';
import { Modality, getGenerativeModel, getVertexAI } from '../src';
import {
MODEL_NAME,
generationConfig,
systemInstruction,
safetySettings
} from './constants';
import { initializeApp } from '@firebase/app';
import { FIREBASE_CONFIG } from './firebase-config';

// Token counts are only expected to differ by at most this number of tokens.
// Set to 1 for whitespace that is not always present.
const TOKEN_COUNT_DELTA = 1;

describe('Generate Content', () => {
before(() => initializeApp(FIREBASE_CONFIG));

it('generateContent', async () => {
const vertexAI = getVertexAI();
const model = getGenerativeModel(vertexAI, {
model: MODEL_NAME,
generationConfig,
systemInstruction,
safetySettings
});

const result = await model.generateContent(
'Where is Google headquarters located? Answer with the city name only.'
);
const response = result.response;

const trimmedText = response.text().trim();
expect(trimmedText).to.equal('Mountain View');

expect(response.usageMetadata).to.not.be.null;
expect(response.usageMetadata!.promptTokenCount).to.be.closeTo(
21,
TOKEN_COUNT_DELTA
);
expect(response.usageMetadata!.candidatesTokenCount).to.be.closeTo(
4,
TOKEN_COUNT_DELTA
);
expect(response.usageMetadata!.totalTokenCount).to.be.closeTo(
25,
TOKEN_COUNT_DELTA * 2
);
expect(response.usageMetadata!.promptTokensDetails).to.not.be.null;
expect(response.usageMetadata!.promptTokensDetails!.length).to.equal(1);
expect(response.usageMetadata!.promptTokensDetails![0].modality).to.equal(
Modality.TEXT
);
expect(response.usageMetadata!.promptTokensDetails![0].tokenCount).to.equal(
21
);
expect(response.usageMetadata!.candidatesTokensDetails).to.not.be.null;
expect(response.usageMetadata!.candidatesTokensDetails!.length).to.equal(1);
expect(
response.usageMetadata!.candidatesTokensDetails![0].modality
).to.equal(Modality.TEXT);
expect(
response.usageMetadata!.candidatesTokensDetails![0].tokenCount
).to.equal(4);
});
// TODO (dlarocque): Test generateContentStream
});
26 changes: 25 additions & 1 deletion packages/vertexai/karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,38 @@
*/

const karmaBase = require('../../config/karma.base');
const { argv } = require('yargs');
const { existsSync } = require('fs');

const files = [`src/**/*.test.ts`];

// Validate that the file that defines the Firebase config to be used in the integration tests exists.
if (argv.integration) {
if (!existsSync('integration/firebase-config.ts')) {
throw new Error(
`integration/firebase-config.ts does not exist. This file must contain a Firebase config for a project with Vertex AI enabled.`
);
}
}

module.exports = function (config) {
const karmaConfig = {
...karmaBase,

preprocessors: {
...karmaBase.preprocessors,
'integration/**/*.ts': ['webpack', 'sourcemap']
},

// files to load into karma
files,
files: (() => {
if (argv.integration) {
return ['integration/**'];
} else {
return ['src/**/*.test.ts'];
}
})(),

// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['mocha']
Expand Down
1 change: 1 addition & 0 deletions packages/vertexai/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"test:ci": "yarn testsetup && node ../../scripts/run_tests_in_ci.js -s test",
"test:skip-clone": "karma start",
"test:browser": "yarn testsetup && karma start",
"test:integration": "karma start --integration",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll have to call this from "test" (line 38) if you want to run it on PRs or do you not want to do that yet?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer not to add this to test since then it'll be ran when someone runs test in the root directory- which is going to fail if someone hasn't defined the config that's used in these tests. Could be annoying for people working on other SDKs

"api-report": "api-extractor run --local --verbose",
"typings:public": "node ../../scripts/build/use_typings.js ./dist/vertexai-public.d.ts",
"trusted-type-check": "tsec -p tsconfig.json --noEmit"
Expand Down
Loading