Skip to content

Commit 85ddbcb

Browse files
committed
[build] Fix tests by using tsc for all builds and proper ESM module aliasing
- Convert test/bootstrap.js to test/bootstrap.ts for automatic tsc transpilation - Load bootstrap via NODE_OPTIONS before extension activation to register ESM-to-CJS module aliases - Use absolute paths in bootstrap to correctly resolve aliased modules from any context - Unset ELECTRON_RUN_AS_NODE in test environment to prevent workspace file execution errors - Remove manual bootstrap require() calls from test index files - Alphabetize package.json devDependencies This ensures tests run with tsc-built (unbundled) code rather than esbuild-bundled code, allowing Sinon stubs to work correctly. Signed-off-by: Victor Rubezhny <vrubezhny@redhat.com> Assisted-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 67c6850 commit 85ddbcb

4 files changed

Lines changed: 77 additions & 33 deletions

File tree

build/run-tests.cjs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ async function main() {
1616
const extensionRootPath = path.resolve(__dirname, '../');
1717
const extensionDevelopmentPath = path.resolve(extensionRootPath, extension);
1818
const extensionTestsPath = path.resolve(extensionRootPath, 'out', 'test', tests);
19-
const integrationWorkspacePath = path.resolve(extensionRootPath, 'test', 'fixtures', 'components', 'components.code-workspace');
20-
const unitTestWorkspacePath = path.resolve(extensionRootPath, 'test', 'fixtures', 'components', 'empty.code-workspace');
19+
const integrationWorkspacePath = path.resolve(extensionRootPath, 'out', 'test', 'fixtures', 'components', 'components.code-workspace');
20+
const unitTestWorkspacePath = path.resolve(extensionRootPath, 'out', 'test', 'fixtures', 'components', 'empty.code-workspace');
2121

2222
// On some environments, the Mocha reporters do not make amy output to the console when running tests locally if
2323
// tests are invoked without '--verbose' argument. Set the VERBOSE environment variable to any positive boolean value ('true', or 'yes')
@@ -34,18 +34,27 @@ async function main() {
3434
const boolPattern = /^(true|1|yes)$/i;
3535
const verbose = boolPattern.test(process.env.VERBOSE);
3636

37-
// Point to bootstrap loader
38-
process.env.NODE_OPTIONS = `--require ${path.resolve(__dirname, '../test/bootstrap.js')}`;
39-
4037
try {
38+
const workspacePath = tests === 'integration' ? integrationWorkspacePath : unitTestWorkspacePath;
39+
const launchArgs = [workspacePath, '--disable-workspace-trust'];
40+
41+
if (verbose) {
42+
launchArgs.push('--verbose');
43+
}
44+
45+
// Bootstrap is loaded via NODE_OPTIONS to register ESM-to-CJS module aliases
46+
// before the extension activates
47+
const bootstrapPath = path.resolve(extensionRootPath, 'out', 'test', 'bootstrap.js');
48+
4149
await etest.runTests({
4250
extensionDevelopmentPath,
4351
extensionTestsPath,
44-
launchArgs: [
45-
tests === 'integration' ? integrationWorkspacePath : unitTestWorkspacePath,
46-
'--disable-workspace-trust',
47-
verbose ? '--verbose' : ''
48-
],
52+
launchArgs,
53+
extensionTestsEnv: {
54+
...process.env,
55+
NODE_OPTIONS: `-r ${bootstrapPath}`,
56+
ELECTRON_RUN_AS_NODE: undefined // Unset to prevent workspace file execution
57+
}
4958
});
5059
} catch (err) {
5160
// eslint-disable-next-line no-console

package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,12 @@
120120
"@uiw/codemirror-theme-vscode": "^4.25.10",
121121
"@uiw/react-codemirror": "^4.25.10",
122122
"@vscode/test-electron": "^3.0.0",
123+
"@xterm/addon-fit": "^0.11.0",
124+
"@xterm/addon-serialize": "^0.14.0",
125+
"@xterm/addon-web-links": "^0.12.0",
126+
"@xterm/addon-webgl": "^0.19.0",
127+
"@xterm/headless": "^6.0.0",
128+
"@xterm/xterm": "^6.0.0",
123129
"chai": "^6.2.2",
124130
"chokidar": "^5.0.0",
125131
"clipboardy": "^5.3.1",
@@ -186,12 +192,6 @@
186192
"validator": "^13.15.35",
187193
"vscode-extension-tester": "^8.23.0",
188194
"vscode-kubernetes-tools-api": "^1.3.0",
189-
"@xterm/xterm": "^6.0.0",
190-
"@xterm/addon-fit": "^0.11.0",
191-
"@xterm/addon-serialize": "^0.14.0",
192-
"@xterm/addon-web-links": "^0.12.0",
193-
"@xterm/addon-webgl": "^0.19.0",
194-
"@xterm/headless": "^6.0.0",
195195
"yaml": "^2.9.0"
196196
},
197197
"overrides": {

test/bootstrap.js

Lines changed: 0 additions & 17 deletions
This file was deleted.

test/bootstrap.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*-----------------------------------------------------------------------------------------------
2+
* Copyright (c) Red Hat, Inc. All rights reserved.
3+
* Licensed under the MIT License. See LICENSE file in the project root for license information.
4+
*-----------------------------------------------------------------------------------------------*/
5+
6+
const path = require('path');
7+
const Module = require('module');
8+
9+
// Find project root by looking for package.json
10+
let projectRoot = __dirname;
11+
while (projectRoot !== path.dirname(projectRoot)) {
12+
if (require('fs').existsSync(path.join(projectRoot, 'package.json'))) {
13+
const pkg = JSON.parse(require('fs').readFileSync(path.join(projectRoot, 'package.json'), 'utf-8'));
14+
if (pkg.name === 'vscode-openshift-connector') {
15+
break;
16+
}
17+
}
18+
projectRoot = path.dirname(projectRoot);
19+
}
20+
21+
// --- ESM module aliases mapping
22+
// Use absolute paths based on project root
23+
const aliases = {
24+
'clipboardy': path.join(projectRoot, 'out/esm/clipboardy.cjs'),
25+
'got': path.join(projectRoot, 'out/esm/got.cjs'),
26+
'uuid': path.join(projectRoot, 'out/esm/uuid.cjs'),
27+
'@kubernetes/client-node': path.join(projectRoot, 'out/esm/k8s-client-node.cjs'),
28+
'@apidevtools/json-schema-ref-parser': path.join(projectRoot, 'out/esm/apidevtools-json-schema-ref-parser.cjs'),
29+
};
30+
31+
// Custom module resolver to handle both base imports and subpath imports
32+
// E.g., both '@kubernetes/client-node' and '@kubernetes/client-node/dist/config_types'
33+
// should resolve to the same bundled .cjs file
34+
const originalResolveFilename = Module._resolveFilename;
35+
36+
Module._resolveFilename = function(request, parent, isMain, options) {
37+
// Check for exact match first
38+
if (aliases[request]) {
39+
return aliases[request];
40+
}
41+
42+
// Check for subpath imports (e.g., '@kubernetes/client-node/dist/config_types')
43+
for (const [pkg, target] of Object.entries(aliases)) {
44+
if (request === pkg || request.startsWith(`${pkg}/`)) {
45+
// Both the base package and any subpaths resolve to the bundled file
46+
return target;
47+
}
48+
}
49+
50+
// Not an aliased module, use original resolution
51+
return originalResolveFilename.call(this, request, parent, isMain, options);
52+
};

0 commit comments

Comments
 (0)