|
1 | 1 | # Web Test Runner Intercept |
2 | 2 |
|
3 | | -Web test runner plugin that allows the interception of modules during test runs. Often, while creating tests, there is the need to change the behavior of a dependency of the code under test. This is needed to cover all branches of the code under test, for performance reasons or sometimes because the dependency cannot operate correctly in the test environment. Dependencies that are on the global window object are easy to change with a mock or a stub. ES Modules, however, and specifically their exports cannot be altered. This plugin introduces a hook that enables the interception of modules and allows altering its exports. |
| 3 | +Web test runner plugin that allows the interception of modules during test runs. Often, while creating tests, there is the need to change the behavior of a dependency of the system under test. This is needed to cover all branches of the system under test, for performance reasons or sometimes because the dependency cannot operate correctly in the test environment. Dependencies that are on the global window object are easy to change with a mock or a stub. ES Modules, however, and specifically their exports cannot be altered. This plugin introduces a hook that enables the interception of modules and allows altering its exports. |
| 4 | + |
| 5 | +## Concept |
| 6 | + |
| 7 | +Next to a web test runner plugin that enables module interception, this package also exposes a function `interceptModule()` to be used in the test run. This function allows to define what module needs to be intercepted and returns an object with all the exports of the module as its properties. Changing these properties allows to rewire the intercepted module without changing the system under test. |
| 8 | + |
| 9 | +```js |
| 10 | +import { interceptModule } from '@web/test-runner-intercept'; |
| 11 | + |
| 12 | +const externalLibrary = await interceptModule('external-library'); |
| 13 | + |
| 14 | +// Return the original function that 'external-library' exposed in the `externalFunction` named export |
| 15 | +externalLibrary.externalFunction; // f externalFunction() { ... } |
| 16 | + |
| 17 | +// Rewire the 'external-library' module to return this anonymous function as the `externalFunction` export |
| 18 | +externalLibrary.externalFunction = () => console.log('hello world'); // () => console.log('hello world') |
| 19 | + |
| 20 | +const { externalFunction } = await import('external-library'); |
| 21 | +externalFunction; // () => console.log('hello world') |
| 22 | +``` |
| 23 | + |
| 24 | +### Caveats |
| 25 | + |
| 26 | +#### Order of imports |
| 27 | + |
| 28 | +In order to intercept a module, the module should not be referenced yet. (Once a module is loaded, the module loader also loads all its dependent modules) This means the module containing the system under test should be loaded _after_ the module interception. As interception is achieved using a function, this also means the system under test should _always_ be loaded using a dynamic import in order to be done after the interception. |
| 29 | + |
| 30 | +```js |
| 31 | +import { interceptModule } from '@web/test-runner-intercept'; |
| 32 | + |
| 33 | +// First, intercept |
| 34 | +const externalLibrary = await interceptModule('external-library'); |
| 35 | + |
| 36 | +// Second, load the system under test. |
| 37 | +const systemUnderTest = await import('../../src/system-under-test.js'); |
| 38 | + |
| 39 | +// Run tests |
| 40 | +... |
| 41 | +``` |
| 42 | + |
| 43 | +#### Types of module specifiers |
| 44 | + |
| 45 | +Currently, two types of module specifiers are supported: bare modules and server relative modules. |
| 46 | + |
| 47 | +```javascript |
| 48 | +// bare module, located in `node_modules` |
| 49 | +await interceptModule('external-library'); |
| 50 | + |
| 51 | +// server relative module |
| 52 | +await interceptModule('/src/library-to-intercept.js'); |
| 53 | +``` |
| 54 | + |
| 55 | +In order to use regular relative references, `import.meta.resolve()` and `new URL().pathname` can be used. |
| 56 | + |
| 57 | +```javascript |
| 58 | +// relative module |
| 59 | +await interceptModule(new URL(import.meta.resolve('../src/library-to-intercept.js')).pathname); |
| 60 | +``` |
4 | 61 |
|
5 | 62 | ## Usage |
6 | 63 |
|
|
0 commit comments