@temporalio/nyc-test-coverage 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -16
- package/lib/index.d.ts +30 -1
- package/lib/index.js +110 -0
- package/lib/index.js.map +1 -1
- package/package.json +5 -4
- package/src/index.ts +141 -1
package/README.md
CHANGED
|
@@ -2,31 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@temporalio/nyc-test-coverage)
|
|
4
4
|
|
|
5
|
-
[Temporal](https://temporal.io)'s [TypeScript SDK](https://docs.temporal.io/typescript/introduction)
|
|
5
|
+
[Temporal](https://temporal.io)'s [TypeScript SDK](https://docs.temporal.io/typescript/introduction) integration for Workflow code coverage with [nyc](https://npmjs.com/package/nyc) and similar tools.
|
|
6
6
|
|
|
7
7
|
## Getting Started
|
|
8
8
|
|
|
9
|
-
1. `npm install mocha nyc`
|
|
10
|
-
|
|
11
|
-
3. Add this package's sinks and interceptors to your test worker, for example:
|
|
9
|
+
1. `npm install -D mocha nyc @temporalio/nyc-test-coverage`
|
|
10
|
+
1. Instantiate `WorkflowCoverage` from this package, and call `augmentWorkerOptions()` to configure Workflows to gather and export code coverage data:
|
|
12
11
|
|
|
13
12
|
```ts
|
|
14
13
|
import { WorkflowCoverage } from '@temporalio/nyc-test-coverage';
|
|
15
14
|
|
|
16
15
|
const workflowCoverage = new WorkflowCoverage();
|
|
17
16
|
|
|
18
|
-
worker = await Worker.create({
|
|
17
|
+
worker = await Worker.create(workflowCoverage.augmentWorkerOptions({
|
|
19
18
|
connection: nativeConnection,
|
|
20
19
|
taskQueue,
|
|
21
20
|
workflowsPath: require.resolve("./workflows"),
|
|
22
|
-
|
|
23
|
-
workflowModules: [workflowCoverage.interceptorModule]
|
|
24
|
-
},
|
|
25
|
-
sinks: workflowCoverage.sinks,
|
|
26
|
-
});
|
|
21
|
+
}));
|
|
27
22
|
```
|
|
28
23
|
|
|
29
|
-
|
|
24
|
+
3. After your tests are done, call `mergeIntoGlobalCoverage()` to merge your Workflows' code coverage into nyc's global coverage.
|
|
30
25
|
|
|
31
26
|
```ts
|
|
32
27
|
after(() => {
|
|
@@ -34,11 +29,62 @@ after(() => {
|
|
|
34
29
|
});
|
|
35
30
|
```
|
|
36
31
|
|
|
37
|
-
|
|
38
|
-
|
|
32
|
+
## Usage with `bundleWorkflowCode()`
|
|
33
|
+
|
|
34
|
+
If you are pre-bundling your Workflows using `bundleWorkflowCode()`, we recommend using the `augmentBundleOptions()` method to configure your bundle options, followed by `augmentWorkerOptionsWithBundle()` to configure your Worker options as follows.
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
const bundle = await bundleWorkflowCode(
|
|
38
|
+
workflowCoverage.augmentBundleOptions({
|
|
39
|
+
workflowsPath: require.resolve('./workflows'),
|
|
40
|
+
})
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const worker = await Worker.create(
|
|
44
|
+
workflowCoverage.augmentWorkerOptionsWithBundle({
|
|
45
|
+
connection,
|
|
46
|
+
taskQueue,
|
|
47
|
+
workflowBundle: bundle,
|
|
48
|
+
activities,
|
|
49
|
+
})
|
|
50
|
+
);
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
With `bundleWorkflowCode()`, you still need to call `mergeIntoGlobalCoverage()` when your tests are done to merge Workflow test coverage into nyc's global test coverage.
|
|
39
54
|
|
|
55
|
+
```ts
|
|
56
|
+
after(() => {
|
|
57
|
+
workflowCoverage.mergeIntoGlobalCoverage();
|
|
58
|
+
});
|
|
40
59
|
```
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
60
|
+
|
|
61
|
+
## Usage with Jest
|
|
62
|
+
|
|
63
|
+
This package also works with [Jest](https://jestjs.io/) code coverage.
|
|
64
|
+
However, this package _only_ works with the default [`coverageProvider` option `'babel'`](https://jestjs.io/docs/configuration#coverageprovider-string).
|
|
65
|
+
This package does **not** work with `coverageProvider: 'v8'`.
|
|
66
|
+
Complete the following steps to use this package with Jest.
|
|
67
|
+
|
|
68
|
+
1. `npm install jest @temporalio/nyc-test-coverage`
|
|
69
|
+
2. Check your [Jest config](https://jestjs.io/docs/configuration) and make sure the [`coverageProvider` option](https://jestjs.io/docs/configuration#coverageprovider-string) is **not** set to `'v8'`. Set `coverageProvider` to `'babel'`.
|
|
70
|
+
3. Instantiate `WorkflowCoverage` from this package, and call `augmentWorkerOptions()` to configure Workflows to gather and export code coverage data:
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import { WorkflowCoverage } from '@temporalio/nyc-test-coverage';
|
|
74
|
+
|
|
75
|
+
const workflowCoverage = new WorkflowCoverage();
|
|
76
|
+
|
|
77
|
+
worker = await Worker.create(workflowCoverage.augmentWorkerOptions({
|
|
78
|
+
connection: nativeConnection,
|
|
79
|
+
taskQueue,
|
|
80
|
+
workflowsPath: require.resolve("./workflows"),
|
|
81
|
+
}));
|
|
44
82
|
```
|
|
83
|
+
|
|
84
|
+
4. After your tests are done, call `mergeIntoGlobalCoverage()` to merge your Workflows' code coverage into Jest's global coverage.
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
afterAll(() => {
|
|
88
|
+
workflowCoverage.mergeIntoGlobalCoverage();
|
|
89
|
+
});
|
|
90
|
+
```
|
package/lib/index.d.ts
CHANGED
|
@@ -1,8 +1,31 @@
|
|
|
1
|
-
import { InjectedSinks } from '@temporalio/worker';
|
|
1
|
+
import { InjectedSinks, BundleOptions, WorkerOptions } from '@temporalio/worker';
|
|
2
2
|
import { CoverageSinks } from './sinks';
|
|
3
3
|
import libCoverage from 'istanbul-lib-coverage';
|
|
4
|
+
declare type WebpackConfigType = ReturnType<NonNullable<BundleOptions['webpackConfigHook']>>;
|
|
4
5
|
export declare class WorkflowCoverage {
|
|
5
6
|
coverageMap: libCoverage.CoverageMap;
|
|
7
|
+
/**
|
|
8
|
+
* Add all necessary coverage-specific logic to Worker config:
|
|
9
|
+
* interceptors, sinks, and Webpack config hook.
|
|
10
|
+
*/
|
|
11
|
+
augmentWorkerOptions(workerOptions: WorkerOptions & {
|
|
12
|
+
workflowsPath: NonNullable<WorkerOptions['workflowsPath']>;
|
|
13
|
+
}): WorkerOptions;
|
|
14
|
+
/**
|
|
15
|
+
* Add all necessary coverage-specific logic to bundle config:
|
|
16
|
+
* interceptors and Webpack config hook.
|
|
17
|
+
* The end user is still responsible for adding sinks to the worker options!
|
|
18
|
+
*/
|
|
19
|
+
augmentBundleOptions(bundleOptions: BundleOptions & {
|
|
20
|
+
workflowsPath: NonNullable<WorkerOptions['workflowsPath']>;
|
|
21
|
+
}): BundleOptions;
|
|
22
|
+
/**
|
|
23
|
+
* Add sinks to Worker options. Use this method if you are passing a pre-built
|
|
24
|
+
* bundle that was built with `augmentBundleOptions()`.
|
|
25
|
+
*/
|
|
26
|
+
augmentWorkerOptionsWithBundle(workerOptions: WorkerOptions & {
|
|
27
|
+
workflowBundle: NonNullable<WorkerOptions['workflowBundle']>;
|
|
28
|
+
}): WorkerOptions;
|
|
6
29
|
/**
|
|
7
30
|
* Interceptor to inject into `WorkerOptions.interceptors.workflowModules`
|
|
8
31
|
*/
|
|
@@ -11,9 +34,15 @@ export declare class WorkflowCoverage {
|
|
|
11
34
|
* Contains sinks that allow Workflows to gather coverage data.
|
|
12
35
|
*/
|
|
13
36
|
get sinks(): InjectedSinks<CoverageSinks>;
|
|
37
|
+
/**
|
|
38
|
+
* Modify the given Worker config to auto instrument Workflow
|
|
39
|
+
* code using istanbul-instrumenter-loader
|
|
40
|
+
*/
|
|
41
|
+
addInstrumenterRule(workflowsPath: string, config: WebpackConfigType): WebpackConfigType;
|
|
14
42
|
/**
|
|
15
43
|
* Merge this WorkflowCoverage's coverage map into the global coverage
|
|
16
44
|
* map data `global.__coverage__`.
|
|
17
45
|
*/
|
|
18
46
|
mergeIntoGlobalCoverage(): void;
|
|
19
47
|
}
|
|
48
|
+
export {};
|
package/lib/index.js
CHANGED
|
@@ -5,10 +5,93 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.WorkflowCoverage = void 0;
|
|
7
7
|
const istanbul_lib_coverage_1 = __importDefault(require("istanbul-lib-coverage"));
|
|
8
|
+
// Check if running through nyc or some other Istanbul-based tool.
|
|
9
|
+
// If not, any `workflowCoverage()` tools are a no-op.
|
|
10
|
+
const hasCoverageGlobal = '__coverage__' in global;
|
|
8
11
|
class WorkflowCoverage {
|
|
9
12
|
constructor() {
|
|
10
13
|
this.coverageMap = istanbul_lib_coverage_1.default.createCoverageMap();
|
|
11
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Add all necessary coverage-specific logic to Worker config:
|
|
17
|
+
* interceptors, sinks, and Webpack config hook.
|
|
18
|
+
*/
|
|
19
|
+
augmentWorkerOptions(workerOptions) {
|
|
20
|
+
if (!workerOptions.workflowsPath) {
|
|
21
|
+
throw new TypeError('Cannot automatically instrument coverage without specifying `workflowsPath`');
|
|
22
|
+
}
|
|
23
|
+
if (!hasCoverageGlobal) {
|
|
24
|
+
return workerOptions;
|
|
25
|
+
}
|
|
26
|
+
const workflowsPath = workerOptions.workflowsPath;
|
|
27
|
+
return {
|
|
28
|
+
...workerOptions,
|
|
29
|
+
interceptors: {
|
|
30
|
+
...workerOptions.interceptors,
|
|
31
|
+
workflowModules: [...(workerOptions?.interceptors?.workflowModules || []), this.interceptorModule],
|
|
32
|
+
},
|
|
33
|
+
sinks: {
|
|
34
|
+
...workerOptions.sinks,
|
|
35
|
+
...this.sinks,
|
|
36
|
+
},
|
|
37
|
+
bundlerOptions: {
|
|
38
|
+
...workerOptions.bundlerOptions,
|
|
39
|
+
webpackConfigHook: (config) => {
|
|
40
|
+
config = this.addInstrumenterRule(workflowsPath, config);
|
|
41
|
+
const existingWebpackConfigHook = workerOptions?.bundlerOptions?.webpackConfigHook;
|
|
42
|
+
if (existingWebpackConfigHook !== undefined) {
|
|
43
|
+
return existingWebpackConfigHook(config);
|
|
44
|
+
}
|
|
45
|
+
return config;
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Add all necessary coverage-specific logic to bundle config:
|
|
52
|
+
* interceptors and Webpack config hook.
|
|
53
|
+
* The end user is still responsible for adding sinks to the worker options!
|
|
54
|
+
*/
|
|
55
|
+
augmentBundleOptions(bundleOptions) {
|
|
56
|
+
if (!bundleOptions.workflowsPath) {
|
|
57
|
+
throw new TypeError('Cannot automatically instrument coverage without specifying `workflowsPath`');
|
|
58
|
+
}
|
|
59
|
+
if (!hasCoverageGlobal) {
|
|
60
|
+
return bundleOptions;
|
|
61
|
+
}
|
|
62
|
+
const workflowsPath = bundleOptions.workflowsPath;
|
|
63
|
+
return {
|
|
64
|
+
...bundleOptions,
|
|
65
|
+
workflowInterceptorModules: [...(bundleOptions.workflowInterceptorModules || []), this.interceptorModule],
|
|
66
|
+
webpackConfigHook: (config) => {
|
|
67
|
+
config = this.addInstrumenterRule(workflowsPath, config);
|
|
68
|
+
const existingWebpackConfigHook = bundleOptions.webpackConfigHook;
|
|
69
|
+
if (existingWebpackConfigHook !== undefined) {
|
|
70
|
+
return existingWebpackConfigHook(config);
|
|
71
|
+
}
|
|
72
|
+
return config;
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Add sinks to Worker options. Use this method if you are passing a pre-built
|
|
78
|
+
* bundle that was built with `augmentBundleOptions()`.
|
|
79
|
+
*/
|
|
80
|
+
augmentWorkerOptionsWithBundle(workerOptions) {
|
|
81
|
+
if (!workerOptions.workflowBundle) {
|
|
82
|
+
throw new TypeError('Cannot call `augmentWorkerOptionsWithBundle()` unless you specify a `workflowBundle`. Perhaps you meant to use `augmentBundleOptions()` instead?');
|
|
83
|
+
}
|
|
84
|
+
if (!hasCoverageGlobal) {
|
|
85
|
+
return workerOptions;
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
...workerOptions,
|
|
89
|
+
sinks: {
|
|
90
|
+
...workerOptions.sinks,
|
|
91
|
+
...this.sinks,
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
12
95
|
/**
|
|
13
96
|
* Interceptor to inject into `WorkerOptions.interceptors.workflowModules`
|
|
14
97
|
*/
|
|
@@ -30,11 +113,38 @@ class WorkflowCoverage {
|
|
|
30
113
|
},
|
|
31
114
|
};
|
|
32
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* Modify the given Worker config to auto instrument Workflow
|
|
118
|
+
* code using istanbul-instrumenter-loader
|
|
119
|
+
*/
|
|
120
|
+
addInstrumenterRule(workflowsPath, config) {
|
|
121
|
+
if (!hasCoverageGlobal) {
|
|
122
|
+
return config;
|
|
123
|
+
}
|
|
124
|
+
const newRule = {
|
|
125
|
+
use: {
|
|
126
|
+
loader: require.resolve('istanbul-instrumenter-loader'),
|
|
127
|
+
options: { esModules: true },
|
|
128
|
+
},
|
|
129
|
+
enforce: 'post',
|
|
130
|
+
include: workflowsPath,
|
|
131
|
+
};
|
|
132
|
+
return {
|
|
133
|
+
...config,
|
|
134
|
+
module: {
|
|
135
|
+
...config?.module,
|
|
136
|
+
rules: [...(config?.module?.rules || []), newRule],
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
33
140
|
/**
|
|
34
141
|
* Merge this WorkflowCoverage's coverage map into the global coverage
|
|
35
142
|
* map data `global.__coverage__`.
|
|
36
143
|
*/
|
|
37
144
|
mergeIntoGlobalCoverage() {
|
|
145
|
+
if (!hasCoverageGlobal) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
38
148
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
39
149
|
// @ts-ignore
|
|
40
150
|
this.coverageMap.merge(global.__coverage__);
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AAEA,kFAAgD;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@temporalio/nyc-test-coverage",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Temporal.io SDK code coverage integration",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"temporal",
|
|
@@ -21,8 +21,9 @@
|
|
|
21
21
|
"src"
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@temporalio/worker": "^1.
|
|
25
|
-
"@temporalio/workflow": "^1.
|
|
24
|
+
"@temporalio/worker": "^1.4.0",
|
|
25
|
+
"@temporalio/workflow": "^1.4.0",
|
|
26
|
+
"istanbul-instrumenter-loader": "^3.0.1",
|
|
26
27
|
"istanbul-lib-coverage": "^3.2.0"
|
|
27
28
|
},
|
|
28
29
|
"devDependencies": {
|
|
@@ -31,5 +32,5 @@
|
|
|
31
32
|
"publishConfig": {
|
|
32
33
|
"access": "public"
|
|
33
34
|
},
|
|
34
|
-
"gitHead": "
|
|
35
|
+
"gitHead": "4b757ebbc052f327cc37e5693f46c8127c156b0c"
|
|
35
36
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,10 +1,119 @@
|
|
|
1
|
-
import { InjectedSinks } from '@temporalio/worker';
|
|
1
|
+
import { InjectedSinks, BundleOptions, WorkerOptions } from '@temporalio/worker';
|
|
2
2
|
import { CoverageSinks } from './sinks';
|
|
3
3
|
import libCoverage from 'istanbul-lib-coverage';
|
|
4
4
|
|
|
5
|
+
// Pull `webpack.Configuration` type without needing to import Webpack
|
|
6
|
+
type WebpackConfigType = ReturnType<NonNullable<BundleOptions['webpackConfigHook']>>;
|
|
7
|
+
|
|
8
|
+
// Check if running through nyc or some other Istanbul-based tool.
|
|
9
|
+
// If not, any `workflowCoverage()` tools are a no-op.
|
|
10
|
+
const hasCoverageGlobal = '__coverage__' in global;
|
|
11
|
+
|
|
5
12
|
export class WorkflowCoverage {
|
|
6
13
|
coverageMap = libCoverage.createCoverageMap();
|
|
7
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Add all necessary coverage-specific logic to Worker config:
|
|
17
|
+
* interceptors, sinks, and Webpack config hook.
|
|
18
|
+
*/
|
|
19
|
+
augmentWorkerOptions(
|
|
20
|
+
workerOptions: WorkerOptions & { workflowsPath: NonNullable<WorkerOptions['workflowsPath']> }
|
|
21
|
+
): WorkerOptions {
|
|
22
|
+
if (!workerOptions.workflowsPath) {
|
|
23
|
+
throw new TypeError('Cannot automatically instrument coverage without specifying `workflowsPath`');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!hasCoverageGlobal) {
|
|
27
|
+
return workerOptions;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const workflowsPath = workerOptions.workflowsPath;
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
...workerOptions,
|
|
34
|
+
interceptors: {
|
|
35
|
+
...workerOptions.interceptors,
|
|
36
|
+
workflowModules: [...(workerOptions?.interceptors?.workflowModules || []), this.interceptorModule],
|
|
37
|
+
},
|
|
38
|
+
sinks: {
|
|
39
|
+
...workerOptions.sinks,
|
|
40
|
+
...this.sinks,
|
|
41
|
+
},
|
|
42
|
+
bundlerOptions: {
|
|
43
|
+
...workerOptions.bundlerOptions,
|
|
44
|
+
webpackConfigHook: (config: WebpackConfigType) => {
|
|
45
|
+
config = this.addInstrumenterRule(workflowsPath, config);
|
|
46
|
+
|
|
47
|
+
const existingWebpackConfigHook = workerOptions?.bundlerOptions?.webpackConfigHook;
|
|
48
|
+
if (existingWebpackConfigHook !== undefined) {
|
|
49
|
+
return existingWebpackConfigHook(config);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return config;
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Add all necessary coverage-specific logic to bundle config:
|
|
60
|
+
* interceptors and Webpack config hook.
|
|
61
|
+
* The end user is still responsible for adding sinks to the worker options!
|
|
62
|
+
*/
|
|
63
|
+
augmentBundleOptions(
|
|
64
|
+
bundleOptions: BundleOptions & { workflowsPath: NonNullable<WorkerOptions['workflowsPath']> }
|
|
65
|
+
): BundleOptions {
|
|
66
|
+
if (!bundleOptions.workflowsPath) {
|
|
67
|
+
throw new TypeError('Cannot automatically instrument coverage without specifying `workflowsPath`');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (!hasCoverageGlobal) {
|
|
71
|
+
return bundleOptions;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const workflowsPath = bundleOptions.workflowsPath;
|
|
75
|
+
return {
|
|
76
|
+
...bundleOptions,
|
|
77
|
+
workflowInterceptorModules: [...(bundleOptions.workflowInterceptorModules || []), this.interceptorModule],
|
|
78
|
+
webpackConfigHook: (config: WebpackConfigType) => {
|
|
79
|
+
config = this.addInstrumenterRule(workflowsPath, config);
|
|
80
|
+
|
|
81
|
+
const existingWebpackConfigHook = bundleOptions.webpackConfigHook;
|
|
82
|
+
if (existingWebpackConfigHook !== undefined) {
|
|
83
|
+
return existingWebpackConfigHook(config);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return config;
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Add sinks to Worker options. Use this method if you are passing a pre-built
|
|
93
|
+
* bundle that was built with `augmentBundleOptions()`.
|
|
94
|
+
*/
|
|
95
|
+
augmentWorkerOptionsWithBundle(
|
|
96
|
+
workerOptions: WorkerOptions & { workflowBundle: NonNullable<WorkerOptions['workflowBundle']> }
|
|
97
|
+
): WorkerOptions {
|
|
98
|
+
if (!workerOptions.workflowBundle) {
|
|
99
|
+
throw new TypeError(
|
|
100
|
+
'Cannot call `augmentWorkerOptionsWithBundle()` unless you specify a `workflowBundle`. Perhaps you meant to use `augmentBundleOptions()` instead?'
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (!hasCoverageGlobal) {
|
|
105
|
+
return workerOptions;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
...workerOptions,
|
|
110
|
+
sinks: {
|
|
111
|
+
...workerOptions.sinks,
|
|
112
|
+
...this.sinks,
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
8
117
|
/**
|
|
9
118
|
* Interceptor to inject into `WorkerOptions.interceptors.workflowModules`
|
|
10
119
|
*/
|
|
@@ -28,11 +137,42 @@ export class WorkflowCoverage {
|
|
|
28
137
|
};
|
|
29
138
|
}
|
|
30
139
|
|
|
140
|
+
/**
|
|
141
|
+
* Modify the given Worker config to auto instrument Workflow
|
|
142
|
+
* code using istanbul-instrumenter-loader
|
|
143
|
+
*/
|
|
144
|
+
addInstrumenterRule(workflowsPath: string, config: WebpackConfigType): WebpackConfigType {
|
|
145
|
+
if (!hasCoverageGlobal) {
|
|
146
|
+
return config;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const newRule = {
|
|
150
|
+
use: {
|
|
151
|
+
loader: require.resolve('istanbul-instrumenter-loader'),
|
|
152
|
+
options: { esModules: true },
|
|
153
|
+
},
|
|
154
|
+
enforce: 'post' as const,
|
|
155
|
+
include: workflowsPath,
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
return {
|
|
159
|
+
...config,
|
|
160
|
+
module: {
|
|
161
|
+
...config?.module,
|
|
162
|
+
rules: [...(config?.module?.rules || []), newRule],
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
31
167
|
/**
|
|
32
168
|
* Merge this WorkflowCoverage's coverage map into the global coverage
|
|
33
169
|
* map data `global.__coverage__`.
|
|
34
170
|
*/
|
|
35
171
|
mergeIntoGlobalCoverage(): void {
|
|
172
|
+
if (!hasCoverageGlobal) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
|
|
36
176
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
37
177
|
// @ts-ignore
|
|
38
178
|
this.coverageMap.merge(global.__coverage__);
|