Skip to content

Commit b9c6007

Browse files
committed
test(intercept): add tests
1 parent c6ac733 commit b9c6007

File tree

16 files changed

+254
-33
lines changed

16 files changed

+254
-33
lines changed

package-lock.json

Lines changed: 28 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/test-runner-intercept/browser/index.js renamed to packages/test-runner-intercept/browser/index.mjs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,15 @@
55
* If the module to be intercepted contains a default export, the export will be available in the `default` property. Only function expressions are supported when intercepting default exports.
66
*/
77
export async function interceptModule(moduleName) {
8+
if (moduleName.includes('./')) {
9+
throw new Error(
10+
`Parameter \`moduleName\` ('${moduleName}') contains a relative reference. This is not supported. Convert \`moduleName\` first to a server relative path. (eg. \`new URL(import.meta.resolve(moduleName)).pathname\`)`,
11+
);
12+
}
13+
814
let module;
915
try {
10-
module = await import(`/__intercept-module__/${moduleName}`);
16+
module = await import(`/__intercept-module__?${moduleName}`);
1117
} catch (e) {
1218
throw new Error(
1319
`Module interception is not active. Make sure the \`interceptModulePlugin\` of \`@web/test-runner-intercept\` is added to the Test Runner config.`,

packages/test-runner-intercept/package.json

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"exports": {
1818
".": {
1919
"types": "./browser/index.d.ts",
20-
"default": "./browser/index.js"
20+
"default": "./browser/index.mjs"
2121
},
2222
"./plugin": {
2323
"types": "./plugin.d.ts",
@@ -26,14 +26,12 @@
2626
}
2727
},
2828
"engines": {
29-
"node": ">=16.0.0"
29+
"node": ">=18.0.0"
3030
},
3131
"scripts": {
3232
"build": "tsc",
33-
"test": "mocha \"test/**/*.test.ts\" --require ts-node/register && npm run test:ci",
34-
"test:browser": "node ../test-runner/dist/bin.js test-browser/test/**/*.test.{js,html} --config test-browser/web-test-runner.config.mjs",
35-
"test:ci": "npm run test:browser",
36-
"test:watch": "mocha \"test/**/*.test.ts\" --require ts-node/register --watch --watch-files src,test"
33+
"test": "mocha test/**/*.test.ts --require ts-node/register",
34+
"test:watch": "mocha test/**/*.test.ts --require ts-node/register --watch --watch-files src,test"
3735
},
3836
"files": [
3937
"*.d.ts",
@@ -54,10 +52,13 @@
5452
"intercept"
5553
],
5654
"dependencies": {
57-
"@web/dev-server-core": "^0.6.2",
55+
"@web/dev-server-core": "^0.7.0",
5856
"es-module-lexer": "^1.3.1"
5957
},
6058
"devDependencies": {
61-
"@web/test-runner": "^0.17.0"
59+
"@web/test-runner": "^0.18.0",
60+
"@web/test-runner-chrome": "^0.15.0",
61+
"chai": "^4.2.0",
62+
"mocha": "^10.2.0"
6263
}
6364
}

packages/test-runner-intercept/src/interceptModulePlugin.ts

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { Plugin } from '@web/dev-server-core';
2-
import { readFile } from 'fs/promises';
32
import { parse } from 'es-module-lexer';
43
import { createResolveImport, ResolveImport } from './createResolveImport';
54
import { stripColor } from './stripColor';
@@ -8,7 +7,7 @@ import { stripColor } from './stripColor';
87
* Plugin that allows the interception of modules
98
*/
109
export function interceptModulePlugin(): Plugin {
11-
const paths: string[] = [];
10+
const absolutePaths: string[] = [];
1211

1312
let resolveImport: ResolveImport;
1413
return {
@@ -18,24 +17,28 @@ export function interceptModulePlugin(): Plugin {
1817
resolveImport = createResolveImport(params, this);
1918
},
2019
async serve(context) {
21-
if (context.path.startsWith('/__intercept-module__/')) {
22-
let body;
23-
try {
24-
const source = context.path.replace('/__intercept-module__/', '');
25-
paths.push(source);
26-
20+
let body;
21+
try {
22+
if (context.path.endsWith('/__intercept-module__')) {
23+
const source = (context.querystring[0] === '/' ? '.' : '') + context.querystring;
2724
const resolvedPath = await resolveImport({ context, source });
28-
const url = new URL(resolvedPath as string, context.request.href);
29-
const relativeFilePath = url.pathname.substring(1);
3025

31-
const content = await readFile(relativeFilePath, 'utf-8');
32-
const [, exports] = await parse(content, resolvedPath as string);
26+
if (!resolvedPath) {
27+
throw new Error(`Could not resolve "${context.querystring}".`);
28+
}
29+
30+
body = `export * from '${resolvedPath}?intercept-module'`;
31+
} else if (context.querystring === 'intercept-module') {
32+
const url = new URL(context.path, context.request.href);
33+
const response = await fetch(url);
34+
const content = await response.text();
35+
const [, exports] = await parse(content, context.path);
3336

3437
const namedExports = exports.map(e => e.n).filter(n => n !== 'default');
3538
const hasDefaultExport = exports.some(e => e.n === 'default');
3639

3740
body = `
38-
import * as original from '${resolvedPath}';
41+
import * as original from '${url.pathname}';
3942
const newOriginal = {...original};
4043
4144
${namedExports.map(x => `export let ${x} = newOriginal['${x}'];`).join('\n')}
@@ -66,20 +69,22 @@ export function interceptModulePlugin(): Plugin {
6669
},
6770
});
6871
`;
69-
} catch (error) {
70-
// Server side errors might contain ANSI color escape sequences.
71-
// These sequences are not readable in a browser's console, so we strip them.
72-
const errorMessage = stripColor((error as Error).message).replaceAll("'", "\\'");
73-
body = `export const __wtr_error__ = '${errorMessage}';`;
7472
}
75-
return { body, type: 'text/javascript' };
73+
} catch (error) {
74+
// Server side errors might contain ANSI color escape sequences.
75+
// These sequences are not readable in a browser's console, so we strip them.
76+
const errorMessage = stripColor((error as Error).message).replace(/'/g, "\\'");
77+
body = `export const __wtr_error__ = '${errorMessage}';`;
7678
}
77-
return undefined;
79+
80+
return body ? { body, type: 'text/javascript' } : undefined;
7881
},
7982

80-
resolveImport({ source }) {
81-
if (paths.includes(source)) {
82-
return `/__intercept-module__/${source}`;
83+
resolveImport({ source, context }) {
84+
if (context.path === '/__intercept-module__') {
85+
absolutePaths.push(source);
86+
} else if (absolutePaths.includes(source)) {
87+
return `${source}?intercept-module`;
8388
}
8489
return undefined;
8590
},
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { expect } from '../chai.js';
2+
import { interceptModule } from '../../../browser/index.mjs';
3+
4+
const timeLibrary = await interceptModule('time-library/hour');
5+
const { getTimeOfDay } = await import('./fixture/getTimeOfDay.js');
6+
7+
let backup;
8+
it('can run a module normally', () => {
9+
backup = timeLibrary.getCurrentHour;
10+
const timeOfDay = getTimeOfDay();
11+
expect(timeOfDay).to.equal('night');
12+
});
13+
14+
it('can intercept a module', () => {
15+
timeLibrary.getCurrentHour = () => 12;
16+
const timeOfDay = getTimeOfDay();
17+
expect(timeOfDay).to.equal('day');
18+
});
19+
20+
it('can restore an intercepted module', () => {
21+
timeLibrary.getCurrentHour = backup;
22+
const timeOfDay = getTimeOfDay();
23+
expect(timeOfDay).to.equal('night');
24+
});
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { getCurrentHour } from 'time-library/hour';
2+
3+
export function getTimeOfDay() {
4+
const hour = getCurrentHour();
5+
if (hour < 6 || hour > 18) {
6+
return 'night';
7+
}
8+
return 'day';
9+
}

packages/test-runner-intercept/test/fixtures/bare/fixture/node_modules/time-library/index.js

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/test-runner-intercept/test/fixtures/bare/fixture/node_modules/time-library/package.json

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"name": "my-app"
3+
}
4+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/* eslint-env browser */
2+
import '../../../../node_modules/chai/chai.js';
3+
4+
export const expect = window.chai.expect;
5+
export const assert = window.chai.assert;

0 commit comments

Comments
 (0)