Skip to content

Commit cc0fc05

Browse files
committed
AI SDK tests.
1 parent 9c5113b commit cc0fc05

File tree

9 files changed

+983
-4133
lines changed

9 files changed

+983
-4133
lines changed

js-sdk-framework-tests/nextjs/app/page.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ export default async function Page() {
2525
<p />
2626
<h2>Manually test:</h2>
2727
<ul>
28+
<li>AI</li>
29+
<ul>
30+
<li><Link href="/tests/ai/web_client">AI Web SDK client-side tests</Link></li>
31+
<li><Link href="/tests/ai/web_ssr">AI Web SDK server-side tests</Link></li>
32+
</ul>
33+
<p />
2834
<li>Analytics</li>
2935
<ul>
3036
<li><Link href="/tests/analytics/web_client">Analytics Web SDK client-side tests</Link></li>
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**
2+
* @license
3+
* Copyright 2025 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
import type { Metadata } from 'next'
18+
import ClientResults from '@/components/app_tests/ai/csr_test_runner';
19+
20+
export const metadata: Metadata = {
21+
title: 'AI Web SDK CSR test'
22+
}
23+
24+
export default function Page() {
25+
return (
26+
<>
27+
<h1>AI CSR Test results:</h1>
28+
<ClientResults />
29+
</>
30+
);
31+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* @license
3+
* Copyright 2025 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
import type { Metadata } from 'next'
18+
import { testAI, TestResults } from '@/lib/app_tests/ai/test';
19+
import ResultsDisplay from '@/components/app_tests/ai/results_display';
20+
21+
export const metadata: Metadata = {
22+
title: 'AI Web SDK SSR test'
23+
}
24+
25+
export default async function Page() {
26+
const testResults: TestResults = await testAI(/*isServer=*/true);
27+
return (
28+
<>
29+
<h1>AI SSR Test results:</h1>
30+
<ResultsDisplay statusString='Tests Complete!' testResults={testResults} />
31+
</>
32+
);
33+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* @license
3+
* Copyright 2025 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
'use client'
18+
19+
import { useState, useEffect } from 'react'
20+
import { testAI, initializeTestResults } from '@/lib/app_tests/ai/test';
21+
import ResultsDisplay from './results_display';
22+
23+
export default function ClientResults() {
24+
const [testStatus, setTestStatus] = useState<string>("running...");
25+
const [testResults, setTestResults] = useState(initializeTestResults());
26+
useEffect(() => {
27+
const asyncTest = async () => {
28+
setTestResults(await testAI());
29+
setTestStatus("Complete!");
30+
}
31+
asyncTest().catch((e) => {
32+
console.error("Error encountered during testing: ", e);
33+
setTestStatus("Errored!");
34+
});
35+
}, []);
36+
37+
return (
38+
<ResultsDisplay statusString={testStatus} testResults={testResults} />
39+
);
40+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/**
2+
* @license
3+
* Copyright 2025 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
import Link from 'next/link';
18+
export default function ResultsDisplay({ statusString, testResults }) {
19+
return (
20+
<>
21+
<h2 title="testStatus">{statusString}</h2>
22+
<h4 title="initializeAppResult">initializeAppResult: {testResults.initializeAppResult}</h4>
23+
<h4 title="initializeAuthResult">initializeAuthResult: {testResults.initializeAuthResult}</h4>
24+
<h4 title="signInAnonymouslyResult">signInAnonymouslyResult: {testResults.signInAnonymouslyResult}</h4>
25+
<h4 title="getAIResult">getAIResult: {testResults.getAIResult}</h4>
26+
<h4 title="getGenerativeModelResult">getGenerativeModelResult: {testResults.getGenerativeModelResult}</h4>
27+
<h4 title="startChatResult">startChatResult: {testResults.startChatResult}</h4>
28+
<h4 title="chatSendFirstMessageResult">chatSendFirstMessageResult: {testResults.chatSendFirstMessageResult}</h4>
29+
<h4 title="chatFirstResponseCheckResult">chatFirstResponseCheckResult: {testResults.chatFirstResponseCheckResult}</h4>
30+
<h4 title="chatSendSecondMessageResult">chatSendSecondMessageResult: {testResults.chatSendSecondMessageResult}</h4>
31+
<h4 title="chatSecondResponseCheckResult">chatSecondResponseCheckResult: {testResults.chatSecondResponseCheckResult}</h4>
32+
<h4 title="getHistoryResult">getHistoryResult: {testResults.getHistoryResult}</h4>
33+
<h4 title="deleteUserResult">deleteUserResult: {testResults.deleteUserResult}</h4>
34+
<p />
35+
<Link href="/">Back to test index</Link>
36+
</>
37+
);
38+
}
39+
40+
41+
42+
43+
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
/**
2+
* @license
3+
* Copyright 2025 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
import { initializeApp } from 'firebase/app';
18+
import {
19+
GenerationConfig,
20+
HarmBlockThreshold,
21+
HarmCategory,
22+
Content,
23+
SafetySetting,
24+
getAI,
25+
getGenerativeModel,
26+
GoogleAIBackend
27+
} from 'firebase/ai';
28+
import { getAuth, signInAnonymously } from 'firebase/auth';
29+
import { firebaseConfig } from '@/lib/app_tests/firebase';
30+
import { OK, FAILED } from '@/lib/app_tests/util';
31+
32+
export type TestResults = {
33+
initializeAppResult: string,
34+
initializeAuthResult: string,
35+
signInAnonymouslyResult: string,
36+
getAIResult: string,
37+
getGenerativeModelResult: string,
38+
startChatResult: string,
39+
chatSendFirstMessageResult: string,
40+
chatFirstResponseCheckResult: string,
41+
chatSendSecondMessageResult: string,
42+
chatSecondResponseCheckResult: string,
43+
getHistoryResult: string,
44+
deleteUserResult: string
45+
};
46+
47+
export function initializeTestResults(): TestResults {
48+
const testAnalyticsResult: TestResults = {
49+
initializeAppResult: FAILED,
50+
initializeAuthResult: FAILED,
51+
signInAnonymouslyResult: FAILED,
52+
getAIResult: FAILED,
53+
getGenerativeModelResult: FAILED,
54+
startChatResult: FAILED,
55+
chatSendFirstMessageResult: FAILED,
56+
chatFirstResponseCheckResult: FAILED,
57+
chatSendSecondMessageResult: FAILED,
58+
chatSecondResponseCheckResult: FAILED,
59+
getHistoryResult: FAILED,
60+
deleteUserResult: FAILED
61+
};
62+
return testAnalyticsResult;
63+
}
64+
65+
const commonGenerationConfig: GenerationConfig = {
66+
temperature: 0,
67+
topP: 0,
68+
responseMimeType: 'text/plain'
69+
};
70+
71+
const commonSafetySettings: SafetySetting[] = [
72+
{
73+
category: HarmCategory.HARM_CATEGORY_HARASSMENT,
74+
threshold: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE
75+
},
76+
{
77+
category: HarmCategory.HARM_CATEGORY_HATE_SPEECH,
78+
threshold: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE
79+
},
80+
{
81+
category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
82+
threshold: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE
83+
},
84+
{
85+
category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
86+
threshold: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE
87+
}
88+
];
89+
90+
const commonSystemInstruction: Content = {
91+
role: 'system',
92+
parts: [
93+
{
94+
text: 'You are a friendly and helpful assistant.'
95+
}
96+
]
97+
};
98+
99+
export async function testAI(isServer: boolean = false): Promise<TestResults> {
100+
if (isServer) {
101+
console.log("Server side");
102+
}
103+
const result: TestResults = initializeTestResults();
104+
const firebaseApp = initializeApp(firebaseConfig);
105+
result.initializeAppResult = OK;
106+
107+
const auth = getAuth(firebaseApp);
108+
result.initializeAuthResult = OK;
109+
await signInAnonymously(auth);
110+
if (auth.currentUser) {
111+
result.signInAnonymouslyResult = OK;
112+
113+
const ai = getAI(firebaseApp, { backend: new GoogleAIBackend() });
114+
result.getAIResult = OK;
115+
116+
const model = getGenerativeModel(ai, {
117+
model: "gemini-2.5-flash",
118+
generationConfig: commonGenerationConfig,
119+
safetySettings: commonSafetySettings,
120+
systemInstruction: commonSystemInstruction
121+
});
122+
result.getGenerativeModelResult = OK;
123+
124+
const chat = model.startChat();
125+
result.startChatResult = OK;
126+
127+
const result1 = await chat.sendMessage(
128+
'What is the capital of France?'
129+
);
130+
result.chatSendFirstMessageResult = OK;
131+
132+
const response1 = result1.response;
133+
if (response1.text().length !== 0) {
134+
result.chatFirstResponseCheckResult = OK;
135+
}
136+
137+
const result2 = await chat.sendMessage('And what about Italy?');
138+
result.chatSendSecondMessageResult = OK;
139+
140+
const response2 = result2.response;
141+
if (response2.text().length !== 0) {
142+
result.chatSecondResponseCheckResult = OK;
143+
}
144+
145+
const history = await chat.getHistory();
146+
if(history.length !== 0) {
147+
result.getHistoryResult = OK;
148+
}
149+
150+
if (auth.currentUser) {
151+
await auth.currentUser.delete();
152+
result.deleteUserResult = OK;
153+
}
154+
}
155+
return result;
156+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* @license
3+
* Copyright 2025 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
import { test, expect } from '@playwright/test';
18+
19+
async function commonExpectations(page) {
20+
await expect(page.getByTitle('initializeAppResult')).not.toContainText("FAILED");
21+
await expect(page.getByTitle('initializeAuthResult')).not.toContainText("FAILED");
22+
await expect(page.getByTitle('signInAnonymouslyResult')).not.toContainText("FAILED");
23+
await expect(page.getByTitle('getAIResult')).not.toContainText("FAILED");
24+
await expect(page.getByTitle('getGenerativeModelResult')).not.toContainText("FAILED");
25+
await expect(page.getByTitle('startChatResult')).not.toContainText("FAILED");
26+
await expect(page.getByTitle('chatSendFirstMessageResult')).not.toContainText("FAILED");
27+
await expect(page.getByTitle('chatFirstResponseCheckResult')).not.toContainText("FAILED");
28+
await expect(page.getByTitle('chatSendSecondMessageResult')).not.toContainText("FAILED");
29+
await expect(page.getByTitle('chatSecondResponseCheckResult')).not.toContainText("FAILED");
30+
await expect(page.getByTitle('getHistoryResult')).not.toContainText("FAILED");
31+
await expect(page.getByTitle('deleteUserResult')).not.toContainText("FAILED");
32+
33+
}
34+
35+
test('ai operations should pass - client', async ({ page, baseURL }) => {
36+
await page.goto(`${baseURL}/tests/ai/web_client`);
37+
await expect(page.getByTitle('testStatus')).toContainText('Complete', { timeout: 10000 });
38+
await expect(page.locator('h1')).toContainText('AI CSR Test');
39+
await commonExpectations(page);
40+
});
41+
42+
test('ai operations should pass - server', async ({ page, baseURL }) => {
43+
await page.goto(`${baseURL}/tests/ai/web_ssr`);
44+
await expect(page.getByTitle('testStatus')).toContainText('Complete', { timeout: 10000 });
45+
await expect(page.locator('h1')).toContainText('AI SSR Test');
46+
await commonExpectations(page);
47+
});

0 commit comments

Comments
 (0)