| const { GoogleGenAI } = require('@google/genai');
|
| const { TestConfig } = require('./config');
|
|
|
|
|
| class TestHelper {
|
| constructor() {
|
| this.config = new TestConfig();
|
|
|
| try {
|
| this.config.validateConfig();
|
| this.client = new GoogleGenAI({
|
| apiKey: this.config.apiKey,
|
| httpOptions:{
|
| baseUrl: this.config.baseUrl,
|
| headers: this.config.getHeaders()
|
| }
|
| });
|
| } catch (error) {
|
| console.log(`Skipping tests due to configuration error: ${error.message}`);
|
| process.exit(0);
|
| }
|
| }
|
|
|
| printHeaders() {
|
| console.log(`Using headers: ${JSON.stringify(this.config.getHeaders())}`);
|
| }
|
|
|
| createTestContext() {
|
|
|
| return {
|
| headers: this.config.getHeaders()
|
| };
|
| }
|
|
|
| assertNoError(error, message) {
|
| if (error) {
|
| throw new Error(`${message}: ${error.message}`);
|
| }
|
| }
|
|
|
| validateChatResponse(response, description) {
|
| if (!response) {
|
| throw new Error(`Response is null for ${description}`);
|
| }
|
|
|
| if (!response.candidates || response.candidates.length === 0) {
|
| throw new Error(`No candidates in response for ${description}`);
|
| }
|
|
|
| const candidate = response.candidates[0];
|
| if (!candidate.content || !candidate.content.parts || candidate.content.parts.length === 0) {
|
| throw new Error(`Empty content in response for ${description}`);
|
| }
|
|
|
| console.log(`${description} - Response validated successfully: ${response.candidates.length} candidates`);
|
| }
|
|
|
| getModel() {
|
| return this.config.model;
|
| }
|
| }
|
|
|
|
|
| function containsCaseInsensitive(text, substring) {
|
| return text.toLowerCase().includes(substring.toLowerCase());
|
| }
|
|
|
| function containsAnyCaseInsensitive(text, ...substrings) {
|
| return substrings.some(substring => containsCaseInsensitive(text, substring));
|
| }
|
|
|
| function extractTextFromResponse(response) {
|
| if (!response || !response.candidates || response.candidates.length === 0) {
|
| return '';
|
| }
|
|
|
| const candidate = response.candidates[0];
|
| if (!candidate.content || !candidate.content.parts || candidate.content.parts.length === 0) {
|
| return '';
|
| }
|
|
|
| return candidate.content.parts
|
| .filter(part => part.text)
|
| .map(part => part.text)
|
| .join('');
|
| }
|
|
|
| function containsNumber(text) {
|
| const numbers = ['4', 'four', 'Four'];
|
| return numbers.some(num => containsCaseInsensitive(text, num));
|
| }
|
|
|
|
|
| async function testSimpleQA() {
|
| console.log('Running TestSimpleQA...');
|
|
|
| const helper = new TestHelper();
|
| helper.printHeaders();
|
|
|
| const context = helper.createTestContext();
|
| const question = 'What is 2 + 2?';
|
|
|
| console.log(`Sending question: ${question}`);
|
|
|
| const modelName = helper.getModel();
|
|
|
| try {
|
| const response = await helper.client.models.generateContent({
|
| model: modelName,
|
| contents: question,
|
| ...context
|
| });
|
|
|
| helper.validateChatResponse(response, 'Simple Q&A');
|
|
|
| const responseText = extractTextFromResponse(response);
|
| console.log(`Response: ${responseText}`);
|
|
|
| if (!containsNumber(responseText)) {
|
| throw new Error(`Expected response to contain a number, got: ${responseText}`);
|
| }
|
|
|
| console.log('✅ TestSimpleQA passed');
|
| } catch (error) {
|
| console.error('❌ TestSimpleQA failed:', error.message);
|
| throw error;
|
| }
|
| }
|
|
|
| async function testSimpleQAWithDifferentQuestion() {
|
| console.log('Running TestSimpleQAWithDifferentQuestion...');
|
|
|
| const helper = new TestHelper();
|
| const context = helper.createTestContext();
|
| const question = 'What is the capital of France?';
|
|
|
| console.log(`Sending question: ${question}`);
|
|
|
| const modelName = helper.getModel();
|
|
|
| try {
|
| const response = await helper.client.models.generateContent({
|
| model: modelName,
|
| contents: question,
|
| ...context
|
| });
|
|
|
| helper.validateChatResponse(response, 'Simple Q&A with capital question');
|
|
|
| const responseText = extractTextFromResponse(response);
|
| console.log(`Response: ${responseText}`);
|
|
|
| if (!containsCaseInsensitive(responseText, 'Paris')) {
|
| throw new Error(`Expected response to contain 'Paris', got: ${responseText}`);
|
| }
|
|
|
| console.log('✅ TestSimpleQAWithDifferentQuestion passed');
|
| } catch (error) {
|
| console.error('❌ TestSimpleQAWithDifferentQuestion failed:', error.message);
|
| throw error;
|
| }
|
| }
|
|
|
| async function testMultipleQuestions() {
|
| console.log('Running TestMultipleQuestions...');
|
|
|
| const helper = new TestHelper();
|
| const context = helper.createTestContext();
|
|
|
| const questions = [
|
| 'What is the largest planet in our solar system?',
|
| 'Who wrote Romeo and Juliet?',
|
| 'What is the chemical symbol for gold?'
|
| ];
|
|
|
| const modelName = helper.getModel();
|
|
|
| try {
|
| for (let i = 0; i < questions.length; i++) {
|
| const question = questions[i];
|
| console.log(`Question ${i + 1}: ${question}`);
|
|
|
| const response = await helper.client.models.generateContent({
|
| model: modelName,
|
| contents: question,
|
| ...context
|
| });
|
|
|
| helper.validateChatResponse(response, `Question ${i + 1}`);
|
|
|
| const responseText = extractTextFromResponse(response);
|
| console.log(`Answer ${i + 1}: ${responseText}`);
|
| }
|
|
|
| console.log('✅ TestMultipleQuestions passed');
|
| } catch (error) {
|
| console.error('❌ TestMultipleQuestions failed:', error.message);
|
| throw error;
|
| }
|
| }
|
|
|
| async function testConversationHistory() {
|
| console.log('Running TestConversationHistory...');
|
|
|
| const helper = new TestHelper();
|
| const context = helper.createTestContext();
|
| const modelName = helper.getModel();
|
|
|
| try {
|
|
|
| const chat = helper.client.chats.create({
|
| model: modelName,
|
| history: [],
|
| config: {
|
| temperature: 0.5
|
| }
|
| });
|
|
|
|
|
| const question1 = "My name is Alice. What's your name?";
|
| console.log(`Question 1: ${question1}`);
|
|
|
| const response1 = await chat.sendMessage(question1);
|
| helper.validateChatResponse(response1, 'First message');
|
|
|
| const responseText1 = extractTextFromResponse(response1);
|
| console.log(`Response 1: ${responseText1}`);
|
|
|
|
|
| const question2 = 'What did I just tell you my name is?';
|
| console.log(`Question 2: ${question2}`);
|
|
|
| const response2 = await chat.sendMessage(question2);
|
| helper.validateChatResponse(response2, 'Second message');
|
|
|
| const responseText2 = extractTextFromResponse(response2);
|
| console.log(`Response 2: ${responseText2}`);
|
|
|
|
|
| if (!containsAnyCaseInsensitive(responseText2, 'Alice', 'alice')) {
|
| throw new Error(`Expected response to contain 'Alice', got: ${responseText2}`);
|
| }
|
|
|
| console.log('✅ TestConversationHistory passed');
|
| } catch (error) {
|
| console.error('❌ TestConversationHistory failed:', error.message);
|
| throw error;
|
| }
|
| }
|
|
|
|
|
| async function runTests() {
|
| console.log('🚀 Starting Gemini Node.js Integration Tests\n');
|
|
|
| const tests = [
|
| testSimpleQA,
|
| testSimpleQAWithDifferentQuestion,
|
| testMultipleQuestions,
|
| testConversationHistory
|
| ];
|
|
|
| let passed = 0;
|
| let failed = 0;
|
|
|
| for (const test of tests) {
|
| try {
|
| await test();
|
| passed++;
|
| } catch (error) {
|
| failed++;
|
| console.error(`Test failed: ${error.message}`);
|
| }
|
| console.log('');
|
| }
|
|
|
| console.log(`\n📊 Test Results: ${passed} passed, ${failed} failed`);
|
|
|
| if (failed > 0) {
|
| process.exit(1);
|
| } else {
|
| console.log('🎉 All tests passed!');
|
| process.exit(0);
|
| }
|
| }
|
|
|
|
|
| if (require.main === module) {
|
| runTests().catch(error => {
|
| console.error('❌ Test runner failed:', error.message);
|
| process.exit(1);
|
| });
|
| }
|
|
|
| module.exports = {
|
| TestConfig,
|
| TestHelper,
|
| testSimpleQA,
|
| testSimpleQAWithDifferentQuestion,
|
| testMultipleQuestions,
|
| testConversationHistory,
|
| runTests
|
| }; |