Skip to content

Commit 95d1cc6

Browse files
fix(scripts): disable Rollup externalLiveBindings to fix Jest auto-mocking (#7767)
When the CJS inliner bundles a client, variant files (e.g. runtimeConfig with react-native counterparts) and their transitive dependencies are kept as Rollup externals. By default, Rollup re-exports these externals using lazy Object.defineProperty getters: Object.defineProperty(exports, k, { enumerable: true, get: function () { return external[k]; } }); Jest's auto-mock (jest.mock()) snapshots module exports at mock-creation time. Lazy getters haven't resolved yet at that point, so all re-exported symbols (models, enums, exceptions) become undefined in tests. Setting externalLiveBindings: false makes Rollup emit eager assignments: exports[k] = external[k]; This is semantically equivalent for CJS (live bindings only matter for ESM circular imports) and allows Jest to see all exports immediately.
1 parent 58b80de commit 95d1cc6

3 files changed

Lines changed: 56 additions & 0 deletions

File tree

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ test-schema: bundles
5353
test-integration: bundles
5454
rm -rf ./clients/client-sso/node_modules/\@smithy # todo(yarn) incompatible redundant nesting.
5555
node ./scripts/validation/no-generic-byte-arrays.js
56+
node ./scripts/compilation/Inliner.spec.js
5657
yarn g:vitest run -c vitest.config.integ.mts
5758
make test-protocols
5859
make test-types

scripts/compilation/Inliner.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ module.exports = class Inliner {
226226
format: "cjs",
227227
exports: "named",
228228
preserveModules: false,
229+
externalLiveBindings: false,
229230
};
230231

231232
const bundle = await rollup.rollup(inputOptions(variantExternalsForRollup));
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
const assert = require("assert");
2+
const path = require("path");
3+
const fs = require("fs");
4+
5+
/**
6+
* Verify that the Inliner's Rollup output uses eager bindings
7+
* for external re-exports (externalLiveBindings: false).
8+
*
9+
* When externalLiveBindings is true (the default), Rollup emits:
10+
* Object.defineProperty(exports, k, { enumerable: true, get: function () { return ext[k]; } });
11+
*
12+
* These lazy getters break Jest's auto-mocking because jest.mock()
13+
* snapshots exports at mock-creation time, before the getters resolve.
14+
*
15+
* With externalLiveBindings: false, Rollup emits:
16+
* exports[k] = ext[k];
17+
*
18+
* which Jest can auto-mock correctly.
19+
*
20+
* See: https://github.com/aws/aws-sdk-js-v3/issues/7748
21+
*/
22+
23+
// Test 1: Verify the Inliner source contains externalLiveBindings: false
24+
const inlinerSource = fs.readFileSync(path.join(__dirname, "Inliner.js"), "utf-8");
25+
assert.ok(
26+
inlinerSource.includes("externalLiveBindings: false"),
27+
"Inliner.js must set externalLiveBindings: false in Rollup outputOptions"
28+
);
29+
30+
// Test 2: If a built client-dynamodb dist-cjs/index.js exists, verify no lazy getter re-exports
31+
const dynamoIndexPath = path.join(__dirname, "..", "..", "clients", "client-dynamodb", "dist-cjs", "index.js");
32+
if (fs.existsSync(dynamoIndexPath)) {
33+
const indexContents = fs.readFileSync(dynamoIndexPath, "utf-8");
34+
35+
// Match the lazy getter pattern Rollup emits with externalLiveBindings: true
36+
const lazyGetterPattern = /Object\.defineProperty\(exports,\s*k,\s*\{[^}]*get:\s*function/g;
37+
const matches = indexContents.match(lazyGetterPattern);
38+
39+
assert.strictEqual(
40+
matches,
41+
null,
42+
"dist-cjs/index.js must not contain lazy Object.defineProperty getter re-exports. " +
43+
"Found " +
44+
(matches?.length ?? 0) +
45+
" occurrences. " +
46+
"Ensure externalLiveBindings: false is set in Rollup outputOptions."
47+
);
48+
49+
console.log("PASS: dist-cjs/index.js has no lazy getter re-exports.");
50+
} else {
51+
console.log("SKIP: client-dynamodb dist-cjs/index.js not found (not built).");
52+
}
53+
54+
console.log("PASS: Inliner.js has externalLiveBindings: false.");

0 commit comments

Comments
 (0)