Skip to content

test: replace proxyquire with sinon in gax, common, error-reporting, translate - #9638

Closed
danieljbruce wants to merge 1 commit into
googleapis:mainfrom
danieljbruce:fix/remove-proxyquire-shim-sinon
Closed

danieljbruce wants to merge 1 commit into
googleapis:mainfrom
danieljbruce:fix/remove-proxyquire-shim-sinon

Conversation

@danieljbruce

@danieljbruce danieljbruce commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Description

Replaces proxyquire with sinon and direct stubs across four packages.

Impact

Removes --proxyquire-shim from gax, googleapis-common, error-reporting, and translate unit tests.

Changes

Testing

  • Executed pnpm test under both Node.js and Bun (JS_RUNTIME=bun) in core/packages/gax, core/packages/nodejs-googleapis-common, handwritten/error-reporting, and packages/google-cloud-translate.
  • Verified strict lint and type checks pass via bin/linter.mjs --strict.

Alternatives

  • Not merging this pull request was considered, which would leave these four packages dependent on the global bin/proxyquire-bun-shim.cjs preload shim.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request removes the dependency on proxyquire across multiple packages, replacing it with standard sinon stubs and manual module caching techniques for mocking, which also allows removing the --proxyquire-shim flag from test scripts. The review feedback suggests two key improvements: first, avoid overriding Module.prototype.require in the Translate tests by directly mutating the cached module exports instead; second, stub the getClient method on the specific auth instance rather than on the GoogleAuth prototype to prevent global prototype pollution.

Comment on lines +77 to +100
const stubs: Record<string, unknown> = {
'@google-cloud/common': {
util: fakeUtil,
Service: FakeService,
},
'@google-cloud/promisify': fakePromisify,
}).Translate;
};
const mod = Module as unknown as {prototype: {require: NodeRequire}};
const origRequire = mod.prototype.require;
const v2Path = require.resolve('../src/v2');
const cached = require.cache[v2Path];
delete require.cache[v2Path];
mod.prototype.require = Object.assign(function (
this: NodeModule,
id: string,
) {
return id in stubs ? stubs[id] : origRequire.call(this, id);
}, origRequire);
try {
Translate = require('../src/v2').Translate;
} finally {
mod.prototype.require = origRequire;
if (cached) require.cache[v2Path] = cached;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Overriding Module.prototype.require is a fragile hack that relies on Node.js internal APIs and can easily break across different Node versions or alternative runtimes (like Bun or Deno). Since @google-cloud/common and @google-cloud/promisify are already loaded and cached in require.cache, you can simply mutate their exported properties on the cached module objects before requiring ../src/v2, and restore them in the finally block. This is much cleaner, safer, and standard.

    const common = require('@google-cloud/common');
    const origUtil = common.util;
    const origService = common.Service;
    const origPromisifyAll = pfy.promisifyAll;

    common.util = fakeUtil;
    common.Service = FakeService;
    pfy.promisifyAll = fakePromisify;

    const v2Path = require.resolve('../src/v2');
    const cached = require.cache[v2Path];
    delete require.cache[v2Path];
    try {
      Translate = require('../src/v2').Translate;
    } finally {
      common.util = origUtil;
      common.Service = origService;
      pfy.promisifyAll = origPromisifyAll;
      if (cached) require.cache[v2Path] = cached;
    }

Comment on lines +38 to +41
const getClientStub = sinon
.stub(auth.GoogleAuth.prototype, 'getClient')
// eslint-disable-next-line @typescript-eslint/no-explicit-any
.resolves({} as any);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Instead of stubbing the prototype of GoogleAuth (which mutates the class prototype globally for all instances), you can stub the getClient method directly on the auth instance. This is safer, avoids prototype pollution, and is more idiomatic.

Suggested change
const getClientStub = sinon
.stub(auth.GoogleAuth.prototype, 'getClient')
// eslint-disable-next-line @typescript-eslint/no-explicit-any
.resolves({} as any);
const getClientStub = sinon
.stub(auth, 'getClient')
// eslint-disable-next-line @typescript-eslint/no-explicit-any
.resolves({} as any);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant