Skip to content

Commit 1cac4c3

Browse files
committed
docs(test-runner-module-mocking): ✏️ test-moduleMocking details on plugin import order
Adding details on the order of plugin import in test config. Module mocking must be in first position to avoid conflict with modified path due to other plugins. + refactoring
1 parent f7fcf29 commit 1cac4c3

File tree

10 files changed

+231
-38
lines changed

10 files changed

+231
-38
lines changed

.changeset/sixty-maps-call.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@web/test-runner-module-mocking': patch
3+
---
4+
5+
Add docs on plugin import order to avoid conflict with other plugins
6+
+ refactoring
7+
+ using sinon dependency for new test using stub

package-lock.json

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

packages/test-runner-module-mocking/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ export default {
3838
};
3939
```
4040

41+
Take care of the plugins order, some plugins can modify path of imported modules and moduleMockingPlugin may be not able to retreive them correctly, so it's advise to use it first in the list.
42+
4143
### Simple test scenario
4244

4345
```js

packages/test-runner-module-mocking/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
},
5454
"devDependencies": {
5555
"@web/test-runner-chrome": "^0.15.0",
56-
"@web/test-runner-core": "^0.13.0"
56+
"@web/test-runner-core": "^0.13.0",
57+
"sinon": "^17.0.1"
5758
}
5859
}

packages/test-runner-module-mocking/src/createResolveImport.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export type ResolveImport = (
1515
) => ResolveResult | Promise<ResolveResult>;
1616

1717
/**
18-
* TODO: check if `resolveImport()` can be provied by `@web/dev-server-core`'s API
18+
* TODO: check if `resolveImport()` can be provided by `@web/dev-server-core`'s API
1919
* @param args start param args
2020
* @param thisPlugin plugin to exclude
2121
*/

packages/test-runner-module-mocking/src/moduleMockingPlugin.ts

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,37 @@ export function moduleMockingPlugin(): Plugin {
3737
const namedExports = exports.map(e => e.n).filter(n => n !== 'default');
3838
const hasDefaultExport = exports.some(e => e.n === 'default');
3939

40-
body = `
40+
body = generateInterceptedModuleBody(body, url, namedExports, hasDefaultExport);
41+
}
42+
} catch (error) {
43+
// Server side errors might contain ANSI color escape sequences.
44+
// These sequences are not readable in a browser's console, so we strip them.
45+
const errorMessage = stripColor((error as Error).message).replace(/'/g, "\\'");
46+
body = `export const __wtr_error__ = '${errorMessage}';`;
47+
}
48+
49+
return body ? { body, type: 'text/javascript' } : undefined;
50+
},
51+
52+
resolveImport({ source, context }) {
53+
if (context.path === '/__intercept-module__') {
54+
absolutePaths.push(source);
55+
} else if (absolutePaths.includes(source)) {
56+
return `${source}?intercept-module`;
57+
}
58+
return undefined;
59+
},
60+
};
61+
62+
function generateInterceptedModuleBody(body: any, url: URL, namedExports: string[], hasDefaultExport: boolean) {
63+
body = `
4164
import * as original from '${url.pathname}';
4265
const newOriginal = {...original};
4366
4467
${namedExports.map(x => `export let ${x} = newOriginal['${x}'];`).join('\n')}
4568
46-
${
47-
hasDefaultExport
48-
? `
69+
${hasDefaultExport
70+
? `
4971
function computeDefault() {
5072
if(typeof newOriginal.default === 'function'){
5173
return (...args) => newOriginal.default.call(undefined, ...args);
@@ -55,8 +77,7 @@ export function moduleMockingPlugin(): Plugin {
5577
5678
export default computeDefault()
5779
`
58-
: ''
59-
}
80+
: ''}
6081
6182
export const __wtr_intercepted_module__ = new Proxy(newOriginal, {
6283
set: function(obj, prop, value) {
@@ -69,24 +90,6 @@ export function moduleMockingPlugin(): Plugin {
6990
},
7091
});
7192
`;
72-
}
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}';`;
78-
}
79-
80-
return body ? { body, type: 'text/javascript' } : undefined;
81-
},
82-
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`;
88-
}
89-
return undefined;
90-
},
91-
};
93+
return body;
94+
}
9295
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export function getCurrentHour() {
2+
return 2;
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { getCurrentHour } from '../libs/time-library.js';
2+
3+
export function getTimeOfDay() {
4+
const hour = getCurrentHour();
5+
if (hour < 6 || hour > 18) {
6+
return 'night';
7+
}
8+
return 'day';
9+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { expect } from '../../../chai.js';
2+
import sinon from 'sinon'
3+
import { importMockable } from '../../../../../browser/index.js';
4+
5+
const path = new URL(import.meta.resolve('../../fixture/src/flow/libs/time-library.js')).pathname;
6+
const timeLibrary = await importMockable(path);
7+
const { getTimeOfDay } = await import('../../fixture/src/flow/step/getTimeOfDay.js');
8+
9+
let backup;
10+
it('can run a module normally', () => {
11+
backup = timeLibrary.getCurrentHour;
12+
const timeOfDay = getTimeOfDay();
13+
expect(timeOfDay).to.equal('night');
14+
});
15+
16+
it('can intercept a module', () => {
17+
timeLibrary.getCurrentHour = () => 12;
18+
const timeOfDay = getTimeOfDay();
19+
expect(timeOfDay).to.equal('day');
20+
});
21+
22+
it('can restore an intercepted module', () => {
23+
timeLibrary.getCurrentHour = backup;
24+
const timeOfDay = getTimeOfDay();
25+
expect(timeOfDay).to.equal('night');
26+
});
27+
28+
it('can have stub applied on intercepted module', () => {
29+
const stub = sinon.stub(timeLibrary, 'getCurrentHour').returns(15)
30+
const timeOfDay = getTimeOfDay();
31+
expect(timeOfDay).to.equal('day');
32+
expect(stub.calledOnce).to.be.true;
33+
});

0 commit comments

Comments
 (0)