From 4079e2b39f3950a974e6664d9bb90c7d46152b74 Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Fri, 24 Apr 2026 18:41:04 +0000 Subject: [PATCH 1/3] fix(genai): update virtual-try-on model to stable version 001 --- genai/image-generation/imggen_virtual-try-on-with-txt-img.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/genai/image-generation/imggen_virtual-try-on-with-txt-img.js b/genai/image-generation/imggen_virtual-try-on-with-txt-img.js index ff0686357a..2a4754b5ea 100644 --- a/genai/image-generation/imggen_virtual-try-on-with-txt-img.js +++ b/genai/image-generation/imggen_virtual-try-on-with-txt-img.js @@ -48,7 +48,7 @@ async function virtualTryOn( }; const image = await client.models.recontextImage({ - model: 'virtual-try-on-preview-08-04', + model: 'virtual-try-on-001', source: source, }); From c98c6da33464f1e422dc9bda18a7d2461ba7258a Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Mon, 27 Apr 2026 19:22:45 +0000 Subject: [PATCH 2/3] fix(test): use env var for GCS bucket to avoid local 403 errors --- genai/image-generation/test/imggen-util.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/genai/image-generation/test/imggen-util.js b/genai/image-generation/test/imggen-util.js index 36e77bb2d8..733266bb81 100644 --- a/genai/image-generation/test/imggen-util.js +++ b/genai/image-generation/test/imggen-util.js @@ -15,7 +15,8 @@ const {Storage} = require('@google-cloud/storage'); const {format} = require('date-fns'); -const gcsOutputBucket = 'nodejs-docs-samples-tests'; +const gcsOutputBucket = + process.env.GCLOUD_STORAGE_BUCKET || 'nodejs-docs-samples-tests'; module.exports.createOutputGcsUri = async function () { const prefix = `text_output/${format(new Date(), 'yyyy-MM-dd-HH-mm-ss')}`; From 542327d8976f8f655c1b1e82f1affe04594e216c Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Mon, 4 May 2026 21:50:21 +0000 Subject: [PATCH 3/3] test(imggen): replace live GenAI calls with local mocks --- genai/image-generation/package.json | 6 +- ...mggen-canny-ctrl-type-with-txt-img.test.js | 77 ++++++++++++---- .../imggen-raw-reference-with-txt-img.test.js | 63 +++++++++---- ...en-scribble-ctrl-type-with-txt-img.test.js | 72 +++++++++++---- ...mggen-style-reference-with-txt-img.test.js | 89 +++++++++++++----- ...ubj-refer-ctrl-refer-with-txt-imgs.test.js | 90 ++++++++++++++----- 6 files changed, 299 insertions(+), 98 deletions(-) diff --git a/genai/image-generation/package.json b/genai/image-generation/package.json index 50a1968737..e2d15a69d6 100644 --- a/genai/image-generation/package.json +++ b/genai/image-generation/package.json @@ -10,13 +10,15 @@ "test": "c8 mocha -p -j 2 --timeout 2400000 test/*.test.js" }, "dependencies": { - "@google/genai": "1.34.0", "@google-cloud/storage": "^7.17.3", + "@google/genai": "1.34.0", "date-fns": "^4.1.0" }, "devDependencies": { "c8": "^10.0.0", "chai": "^4.5.0", - "mocha": "^10.0.0" + "mocha": "^10.0.0", + "proxyquire": "^2.1.3", + "sinon": "^21.1.2" } } diff --git a/genai/image-generation/test/imggen-canny-ctrl-type-with-txt-img.test.js b/genai/image-generation/test/imggen-canny-ctrl-type-with-txt-img.test.js index 1325a933ed..542fb9853c 100644 --- a/genai/image-generation/test/imggen-canny-ctrl-type-with-txt-img.test.js +++ b/genai/image-generation/test/imggen-canny-ctrl-type-with-txt-img.test.js @@ -15,27 +15,66 @@ 'use strict'; const {assert} = require('chai'); -const {describe, it} = require('mocha'); +const {describe, it, beforeEach, afterEach} = require('mocha'); +const proxyquire = require('proxyquire'); +const sinon = require('sinon'); -const projectId = process.env.CAIP_PROJECT_ID; +describe('imggen-canny-ctrl-type-with-txt-img', () => { + const projectId = process.env.CAIP_PROJECT_ID || 'mock-project-id'; + const location = 'us-central1'; + const MOCK_IMAGE_URI = 'gs://mock-bucket/mock-image.png'; + let sample; + let editImageStub; -const sample = require('../imggen-canny-ctrl-type-with-txt-img'); -const location = 'us-central1'; -const {delay} = require('../../test/util'); -const {createOutputGcsUri} = require('./imggen-util'); + beforeEach(() => { + editImageStub = sinon.stub().resolves({ + generatedImages: [ + { + image: { + gcsUri: MOCK_IMAGE_URI, + }, + }, + ], + }); -describe('imggen-canny-ctrl-type-with-txt-img', () => { - it('should return an array of generated image URIs', async function () { - this.timeout(180000); - this.retries(4); - const output = await createOutputGcsUri(); - console.log(output.uri); - await delay(this.test); - const generatedFileNames = await sample.generateImage( - output.uri, - projectId, - location - ); - assert(generatedFileNames.length > 0); + sample = proxyquire('../imggen-canny-ctrl-type-with-txt-img', { + '@google/genai': { + GoogleGenAI: class MockGoogleGenAI { + constructor() { + this.models = { + editImage: editImageStub, + }; + } + }, + ControlReferenceImage: class MockControlReferenceImage {}, + }, + }); + }); + + afterEach(() => { + sinon.restore(); + }); + + it('should return a generated image URI', async () => { + const mockOutputUri = 'gs://test-bucket/test'; + try { + const generatedUri = await sample.generateImage( + mockOutputUri, + projectId, + location + ); + + assert.isTrue(editImageStub.calledOnce); + + const apiCallArgs = editImageStub.firstCall.args[0]; + assert.strictEqual(apiCallArgs.model, 'imagen-3.0-capability-001'); + assert.strictEqual(apiCallArgs.config.outputGcsUri, mockOutputUri); + + assert.isString(generatedUri); + assert.strictEqual(generatedUri, MOCK_IMAGE_URI); + } catch (err) { + console.error('Image generation failed:', err); + throw err; + } }); }); diff --git a/genai/image-generation/test/imggen-raw-reference-with-txt-img.test.js b/genai/image-generation/test/imggen-raw-reference-with-txt-img.test.js index 4d050a6822..e61b0ecd72 100644 --- a/genai/image-generation/test/imggen-raw-reference-with-txt-img.test.js +++ b/genai/image-generation/test/imggen-raw-reference-with-txt-img.test.js @@ -15,33 +15,60 @@ 'use strict'; const {assert} = require('chai'); -const {describe, it} = require('mocha'); +const {describe, it, beforeEach} = require('mocha'); +const proxyquire = require('proxyquire'); +const sinon = require('sinon'); -const projectId = process.env.CAIP_PROJECT_ID; +describe('imggen-raw-reference-with-txt-img', () => { + const projectId = process.env.CAIP_PROJECT_ID || 'mock-project-id'; + const location = 'us-central1'; + const MOCK_IMAGE_URI = 'gs://mock-bucket/mock-image.png'; -const sample = require('../imggen-raw-reference-with-txt-img'); -const {delay} = require('../../test/util'); -const {createOutputGcsUri} = require('./imggen-util'); -const location = 'us-central1'; + let sample; + let editImageStub; -describe('imggen-raw-reference-with-txt-img', () => { - it('should return an array of generated image URIs', async function () { - this.timeout(600000); - this.retries(3); + beforeEach(() => { + editImageStub = sinon.stub().resolves({ + generatedImages: [ + { + image: { + gcsUri: MOCK_IMAGE_URI, + }, + }, + ], + }); - const output = await createOutputGcsUri(); - console.log('Output GCS URI:', output.uri); + sample = proxyquire('../imggen-raw-reference-with-txt-img', { + '@google/genai': { + GoogleGenAI: class MockGoogleGenAI { + constructor() { + this.models = { + editImage: editImageStub, + }; + } + }, + RawReferenceImage: class MockRawReferenceImage {}, + }, + }); + }); + + afterEach(() => { + sinon.restore(); + }); + + it('should return a generated image URI', async () => { + const mockOutputUri = 'gs://test-bucket/test'; try { - await delay(this.test); - const generatedFileNames = await sample.generateImage( - output.uri, + const generatedUri = await sample.generateImage( + mockOutputUri, projectId, location ); - console.log('Generated files:', generatedFileNames); - - assert(generatedFileNames.length > 0); + const apiCallArgs = editImageStub.firstCall.args[0]; + assert.strictEqual(apiCallArgs.model, 'imagen-3.0-capability-001'); + assert.isString(generatedUri); + assert.strictEqual(generatedUri, MOCK_IMAGE_URI); } catch (err) { console.error('Image generation failed:', err); throw err; diff --git a/genai/image-generation/test/imggen-scribble-ctrl-type-with-txt-img.test.js b/genai/image-generation/test/imggen-scribble-ctrl-type-with-txt-img.test.js index 511c51a592..7e6463541f 100644 --- a/genai/image-generation/test/imggen-scribble-ctrl-type-with-txt-img.test.js +++ b/genai/image-generation/test/imggen-scribble-ctrl-type-with-txt-img.test.js @@ -15,32 +15,70 @@ 'use strict'; const {assert} = require('chai'); -const {describe, it} = require('mocha'); +const {describe, it, beforeEach, afterEach} = require('mocha'); +const proxyquire = require('proxyquire'); +const sinon = require('sinon'); -const projectId = process.env.CAIP_PROJECT_ID; -const sample = require('../imggen-scribble-ctrl-type-with-txt-img'); -const {delay} = require('../../test/util'); -const {createOutputGcsUri} = require('./imggen-util'); -const location = 'us-central1'; +describe('imggen-scribble-ctrl-type-with-txt-img', () => { + const projectId = process.env.CAIP_PROJECT_ID || 'mock-project-id'; + const location = 'us-central1'; + const MOCK_IMAGE_URI = 'gs://mock-bucket/mock-image.png'; -describe('imggen-scribble-ctrl-type-with-txt-img', async () => { - it('should generate images from a text prompt with control reference image', async function () { - this.timeout(600000); - this.retries(3); + let sample; + let editImageStub; - const output = await createOutputGcsUri(); - console.log('Output GCS URI:', output.uri); + beforeEach(() => { + editImageStub = sinon.stub().resolves({ + generatedImages: [ + { + image: { + gcsUri: MOCK_IMAGE_URI, + }, + }, + ], + }); + + sample = proxyquire('../imggen-scribble-ctrl-type-with-txt-img', { + '@google/genai': { + GoogleGenAI: class MockGoogleGenAI { + constructor() { + this.models = { + editImage: editImageStub, + }; + } + }, + ControlReferenceImage: class MockControlReferenceImage {}, + }, + }); + }); + + afterEach(() => { + sinon.restore(); + }); + + it('should generate images from a text prompt with control reference image', async () => { + const mockOutputUri = 'gs://test-bucket/test'; try { - await delay(this.test); - const generatedFileNames = await sample.generateImage( - output.uri, + const generatedImages = await sample.generateImage( + mockOutputUri, projectId, location ); - console.log('Generated files:', generatedFileNames); - assert(generatedFileNames.length > 0); + const apiCallArgs = editImageStub.firstCall.args[0]; + assert.strictEqual(apiCallArgs.model, 'imagen-3.0-capability-001'); + assert.isArray(generatedImages, 'The response should be an array'); + assert.lengthOf( + generatedImages, + 1, + 'The array should contain one image object' + ); + assert.strictEqual( + generatedImages[0].image.gcsUri, + MOCK_IMAGE_URI, + 'The generated URI should match the mock URI' + ); } catch (err) { console.error('Image generation failed:', err); throw err; diff --git a/genai/image-generation/test/imggen-style-reference-with-txt-img.test.js b/genai/image-generation/test/imggen-style-reference-with-txt-img.test.js index ac106c0001..9f79c2d52b 100644 --- a/genai/image-generation/test/imggen-style-reference-with-txt-img.test.js +++ b/genai/image-generation/test/imggen-style-reference-with-txt-img.test.js @@ -15,26 +15,73 @@ 'use strict'; const {assert} = require('chai'); -const {describe, it} = require('mocha'); - -const projectId = process.env.CAIP_PROJECT_ID; -const sample = require('../imggen-style-reference-with-txt-img'); -const {delay} = require('../../test/util'); -const {createOutputGcsUri} = require('./imggen-util'); -const location = 'us-central1'; - -describe('imggen-style-reference-with-txt-img', async () => { - it('should generate images from a text prompt with style reference', async function () { - this.timeout(180000); - this.retries(4); - const output = await createOutputGcsUri(); - console.log(output.uri); - await delay(this.test); - const generatedFileNames = await sample.generateImage( - output.uri, - projectId, - location - ); - assert(generatedFileNames.length > 0); +const {describe, it, beforeEach, afterEach} = require('mocha'); +const proxyquire = require('proxyquire'); +const sinon = require('sinon'); + +describe('imggen-style-reference-with-txt-img', () => { + const projectId = process.env.CAIP_PROJECT_ID || 'mock-project-id'; + const location = 'us-central1'; + const MOCK_IMAGE_URI = 'gs://mock-bucket/mock-image.png'; + + let sample; + let editImageStub; + + beforeEach(() => { + editImageStub = sinon.stub().resolves({ + generatedImages: [ + { + image: { + gcsUri: MOCK_IMAGE_URI, + }, + }, + ], + }); + + sample = proxyquire('../imggen-style-reference-with-txt-img', { + '@google/genai': { + GoogleGenAI: class MockGoogleGenAI { + constructor() { + this.models = { + editImage: editImageStub, + }; + } + }, + StyleReferenceImage: class MockStyleReferenceImage {}, + }, + }); + }); + + afterEach(() => { + sinon.restore(); + }); + + it('should generate images from a text prompt with style reference', async () => { + const mockOutputUri = 'gs://test-bucket/test-prefix'; + + try { + const generatedImages = await sample.generateImage( + mockOutputUri, + projectId, + location + ); + + const apiCallArgs = editImageStub.firstCall.args[0]; + assert.strictEqual(apiCallArgs.model, 'imagen-3.0-capability-001'); + assert.isArray(generatedImages, 'The response should be an array'); + assert.lengthOf( + generatedImages, + 1, + 'The array should contain one image object' + ); + assert.strictEqual( + generatedImages[0].image.gcsUri, + MOCK_IMAGE_URI, + 'The generated URI should match the mock URI' + ); + } catch (err) { + console.error('Image generation failed:', err); + throw err; + } }); }); diff --git a/genai/image-generation/test/imggen-subj-refer-ctrl-refer-with-txt-imgs.test.js b/genai/image-generation/test/imggen-subj-refer-ctrl-refer-with-txt-imgs.test.js index c94b7cf848..f817c8071d 100644 --- a/genai/image-generation/test/imggen-subj-refer-ctrl-refer-with-txt-imgs.test.js +++ b/genai/image-generation/test/imggen-subj-refer-ctrl-refer-with-txt-imgs.test.js @@ -15,26 +15,74 @@ 'use strict'; const {assert} = require('chai'); -const {describe, it} = require('mocha'); - -const projectId = process.env.CAIP_PROJECT_ID; -const sample = require('../imggen-subj-refer-ctrl-refer-with-txt-imgs'); -const {delay} = require('../../test/util'); -const {createOutputGcsUri} = require('./imggen-util'); -const location = 'us-central1'; - -describe('imggen-subj-refer-ctrl-refer-with-txt-imgs', async () => { - it('should generate images from a text prompt with subject reference image and control reference image', async function () { - this.timeout(180000); - this.retries(4); - const output = await createOutputGcsUri(); - console.log(output.uri); - await delay(this.test); - const generatedFileNames = await sample.generateImage( - output.uri, - projectId, - location - ); - assert(generatedFileNames.length > 0); +const {describe, it, beforeEach, afterEach} = require('mocha'); +const proxyquire = require('proxyquire'); +const sinon = require('sinon'); + +describe('imggen-subj-refer-ctrl-refer-with-txt-imgs', () => { + const projectId = process.env.CAIP_PROJECT_ID || 'mock-project-id'; + const location = 'us-central1'; + const MOCK_IMAGE_URI = 'gs://mock-bucket/mock-image.png'; + + let sample; + let editImageStub; + + beforeEach(() => { + editImageStub = sinon.stub().resolves({ + generatedImages: [ + { + image: { + gcsUri: MOCK_IMAGE_URI, + }, + }, + ], + }); + + sample = proxyquire('../imggen-subj-refer-ctrl-refer-with-txt-imgs', { + '@google/genai': { + GoogleGenAI: class MockGoogleGenAI { + constructor() { + this.models = { + editImage: editImageStub, + }; + } + }, + ControlReferenceImage: class MockControlReferenceImage {}, + SubjectReferenceImage: class MockSubjectReferenceImage {}, + }, + }); + }); + + afterEach(() => { + sinon.restore(); + }); + + it('should generate images from a text prompt with subject reference image and control reference image', async () => { + const mockOutputUri = 'gs://test-bucket/test-prefix'; + + try { + const generatedImages = await sample.generateImage( + mockOutputUri, + projectId, + location + ); + + const apiCallArgs = editImageStub.firstCall.args[0]; + assert.strictEqual(apiCallArgs.model, 'imagen-3.0-capability-001'); + assert.isArray(generatedImages, 'The response should be an array'); + assert.lengthOf( + generatedImages, + 1, + 'The array should contain one image object' + ); + assert.strictEqual( + generatedImages[0].image.gcsUri, + MOCK_IMAGE_URI, + 'The generated URI should match the mock URI' + ); + } catch (err) { + console.error('Image generation failed:', err); + throw err; + } }); });