Skip to content

Commit

Permalink
test_runner: support typescript module mocking
Browse files Browse the repository at this point in the history
PR-URL: nodejs#54878
Fixes: nodejs#54428
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
Reviewed-By: Erick Wendel <erick.workspace@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
  • Loading branch information
marco-ippolito authored and louwers committed Nov 2, 2024
1 parent a6915e9 commit 8b8a4b2
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 6 deletions.
4 changes: 2 additions & 2 deletions lib/internal/modules/esm/translators.js
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ translators.set('wasm', async function(url, source) {
// Strategy for loading a commonjs TypeScript module
translators.set('commonjs-typescript', function(url, source) {
emitExperimentalWarning('Type Stripping');
assertBufferSource(source, false, 'load');
assertBufferSource(source, true, 'load');
const code = stripTypeScriptTypes(stringify(source), url);
debug(`Translating TypeScript ${url}`);
return FunctionPrototypeCall(translators.get('commonjs'), this, url, code, false);
Expand All @@ -468,7 +468,7 @@ translators.set('commonjs-typescript', function(url, source) {
// Strategy for loading an esm TypeScript module
translators.set('module-typescript', function(url, source) {
emitExperimentalWarning('Type Stripping');
assertBufferSource(source, false, 'load');
assertBufferSource(source, true, 'load');
const code = stripTypeScriptTypes(stringify(source), url);
debug(`Translating TypeScript ${url}`);
return FunctionPrototypeCall(translators.get('module'), this, url, code, false);
Expand Down
2 changes: 1 addition & 1 deletion lib/internal/test_runner/mock/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ async function load(url, context, nextLoad) {
async function createSourceFromMock(mock, format) {
// Create mock implementation from provided exports.
const { exportNames, hasDefaultExport, url } = mock;
const useESM = format === 'module';
const useESM = format === 'module' || format === 'module-typescript';
const source = `${testImportSource(useESM)}
if (!$__test.mock._mockExports.has('${url}')) {
throw new Error(${JSONStringify(`mock exports not found for "${url}"`)});
Expand Down
7 changes: 5 additions & 2 deletions lib/internal/test_runner/mock/mock.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ const kMockUnknownMessage = 3;
const kWaitTimeout = 5_000;
const kBadExportsMessage = 'Cannot create mock because named exports ' +
'cannot be applied to the provided default export.';
const kSupportedFormats = ['builtin', 'commonjs', 'module'];
const kSupportedFormats = ['builtin', 'commonjs', 'module', 'module-typescript', 'commonjs-typescript'];
let sharedModuleState;

class MockFunctionContext {
Expand Down Expand Up @@ -517,7 +517,10 @@ class MockTracker {

// Get the file that called this function. We need four stack frames:
// vm context -> getStructuredStack() -> this function -> actual caller.
const caller = pathToFileURL(getStructuredStack()[3]?.getFileName()).href;
const filename = getStructuredStack()[3]?.getFileName();
// If the caller is already a file URL, use it as is. Otherwise, convert it.
const hasFileProtocol = StringPrototypeStartsWith(filename, 'file://');
const caller = hasFileProtocol ? filename : pathToFileURL(filename).href;
const { format, url } = sharedState.moduleLoader.resolveSync(
mockSpecifier, caller, null,
);
Expand Down
19 changes: 18 additions & 1 deletion test/es-module/test-typescript.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { skip, spawnPromisified } from '../common/index.mjs';
import { skip, spawnPromisified, isWindows } from '../common/index.mjs';
import * as fixtures from '../common/fixtures.mjs';
import { match, strictEqual } from 'node:assert';
import { test } from 'node:test';
Expand Down Expand Up @@ -336,3 +336,20 @@ test('execute a JavaScript file importing a cjs TypeScript file', async () => {
match(result.stdout, /Hello, TypeScript!/);
strictEqual(result.code, 0);
});

// TODO(marco-ippolito) Due to a bug in SWC, the TypeScript loader
// does not work on Windows arm64. This test should be re-enabled
// when https://github.com/nodejs/node/issues/54645 is fixed
test('execute a TypeScript test mocking module', { skip: isWindows && process.arch === 'arm64' }, async () => {
const result = await spawnPromisified(process.execPath, [
'--test',
'--experimental-test-module-mocks',
'--experimental-strip-types',
'--no-warnings',
fixtures.path('typescript/ts/test-mock-module.ts'),
]);
strictEqual(result.stderr, '');
match(result.stdout, /Hello, TypeScript-Module!/);
match(result.stdout, /Hello, TypeScript-CommonJS!/);
strictEqual(result.code, 0);
});
5 changes: 5 additions & 0 deletions test/fixtures/typescript/ts/commonjs-logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const logger = (): void => { };

module.exports = {
logger
}
1 change: 1 addition & 0 deletions test/fixtures/typescript/ts/module-logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const logger = (): void => { };
23 changes: 23 additions & 0 deletions test/fixtures/typescript/ts/test-mock-module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { before, mock, test } from 'node:test';
import { strictEqual } from 'node:assert';

const logger = mock.fn((s) => console.log(`Hello, ${s}!`));

before(async () => {
mock.module('./module-logger.ts', {
namedExports: { logger }
});
mock.module('./commonjs-logger.ts', {
namedExports: { logger }
});
});

test('logger', async () => {
const { logger: mockedModule } = await import('./module-logger.ts');
mockedModule('TypeScript-Module');
strictEqual(logger.mock.callCount(), 1);

const { logger: mockedCommonjs } = await import('./commonjs-logger.ts');
mockedCommonjs('TypeScript-CommonJS');
strictEqual(logger.mock.callCount(), 2);
});

0 comments on commit 8b8a4b2

Please sign in to comment.