| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 2574bef commit ec86c69
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1259,6 +1259,9 @@ class Test extends AsyncResource { | |||
| 1259 | 1259 | ||
| 1260 | 1260 | let stopPromise; | |
| 1261 | 1261 | ||
| 1262 | + let publishEnd = () => testChannel.end.publish(channelContext); | ||
| 1263 | + let publishError = (err) => testChannel.error.publish({ __proto__: null, ...channelContext, error: err }); | ||
| 1264 | + | ||
| 1262 | 1265 | try { | |
| 1263 | 1266 | if (this.parent?.hooks.before.length > 0) { | |
| 1264 | 1267 | // This hook usually runs immediately, we need to wait for it to finish | |
@@ -1277,9 +1280,11 @@ class Test extends AsyncResource { | |||
| 1277 | 1280 | // not the runInAsyncScope call itself, to maintain AsyncLocalStorage bindings. | |
| 1278 | 1281 | let testFn = this.fn; | |
| 1279 | 1282 | if (channelContext !== null && testChannel.start.hasSubscribers) { | |
| 1280 | - testFn = (...fnArgs) => testChannel.start.runStores(channelContext, | ||
| 1281 | - () => ReflectApply(this.fn, this, fnArgs), | ||
| 1282 | - ); | ||
| 1283 | + testFn = (...fnArgs) => testChannel.start.runStores(channelContext, () => { | ||
| 1284 | + publishEnd = AsyncResource.bind(publishEnd); | ||
| 1285 | + publishError = AsyncResource.bind(publishError); | ||
| 1286 | + return ReflectApply(this.fn, this, fnArgs); | ||
| 1287 | + }); | ||
| 1283 | 1288 | } | |
| 1284 | 1289 | ||
| 1285 | 1290 | ArrayPrototypeUnshift(runArgs, testFn, ctx); | |
@@ -1331,9 +1336,8 @@ class Test extends AsyncResource { | |||
| 1331 | 1336 | await afterEach(); | |
| 1332 | 1337 | await after(); | |
| 1333 | 1338 | } catch (err) { | |
| 1334 | - // Publish diagnostics_channel error event if the channel has subscribers | ||
| 1335 | 1339 | if (channelContext !== null && testChannel.error.hasSubscribers) { | |
| 1336 | - testChannel.error.publish({ __proto__: null, ...channelContext, error: err }); | ||
| 1340 | + publishError(err); | ||
| 1337 | 1341 | } | |
| 1338 | 1342 | if (isTestFailureError(err)) { | |
| 1339 | 1343 | if (err.failureType === kTestTimeoutFailure) { | |
@@ -1357,7 +1361,7 @@ class Test extends AsyncResource { | |||
| 1357 | 1361 | ||
| 1358 | 1362 | // Publish diagnostics_channel end event if the channel has subscribers (in both success and error cases) | |
| 1359 | 1363 | if (channelContext !== null && testChannel.end.hasSubscribers) { | |
| 1360 | - testChannel.end.publish(channelContext); | ||
| 1364 | + publishEnd(); | ||
| 1361 | 1365 | } | |
| 1362 | 1366 | } | |
| 1363 | 1367 | ||
@@ -1702,6 +1706,9 @@ class Suite extends Test { | |||
| 1702 | 1706 | file: this.entryFile, | |
| 1703 | 1707 | type: this.reportedType, | |
| 1704 | 1708 | }; | |
| 1709 | + let publishEnd = () => testChannel.end.publish(channelContext); | ||
| 1710 | + let publishError = (err) => testChannel.error.publish({ __proto__: null, ...channelContext, error: err }); | ||
| 1711 | + | ||
| 1705 | 1712 | try { | |
| 1706 | 1713 | const { ctx, args } = this.getRunArgs(); | |
| 1707 | 1714 | ||
@@ -1713,9 +1720,11 @@ class Suite extends Test { | |||
| 1713 | 1720 | let suiteFn = this.fn; | |
| 1714 | 1721 | if (testChannel.start.hasSubscribers) { | |
| 1715 | 1722 | const baseFn = this.fn; | |
| 1716 | - suiteFn = (...fnArgs) => testChannel.start.runStores(channelContext, | ||
| 1717 | - () => ReflectApply(baseFn, this, fnArgs), | ||
| 1718 | - ); | ||
| 1723 | + suiteFn = (...fnArgs) => testChannel.start.runStores(channelContext, () => { | ||
| 1724 | + publishEnd = AsyncResource.bind(publishEnd); | ||
| 1725 | + publishError = AsyncResource.bind(publishError); | ||
| 1726 | + return ReflectApply(baseFn, this, fnArgs); | ||
| 1727 | + }); | ||
| 1719 | 1728 | } | |
| 1720 | 1729 | ||
| 1721 | 1730 | const runArgs = [suiteFn, ctx]; | |
@@ -1724,12 +1733,12 @@ class Suite extends Test { | |||
| 1724 | 1733 | await ReflectApply(this.runInAsyncScope, this, runArgs); | |
| 1725 | 1734 | } catch (err) { | |
| 1726 | 1735 | if (testChannel.error.hasSubscribers) { | |
| 1727 | - testChannel.error.publish({ __proto__: null, ...channelContext, error: err }); | ||
| 1736 | + publishError(err); | ||
| 1728 | 1737 | } | |
| 1729 | 1738 | this.fail(new ERR_TEST_FAILURE(err, kTestCodeFailure)); | |
| 1730 | 1739 | } finally { | |
| 1731 | 1740 | if (testChannel.end.hasSubscribers) { | |
| 1732 | - testChannel.end.publish(channelContext); | ||
| 1741 | + publishEnd(); | ||
| 1733 | 1742 | } | |
| 1734 | 1743 | } | |
| 1735 | 1744 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,27 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + const dc = require('node:diagnostics_channel'); | ||
| 3 | + const { AsyncLocalStorage } = require('node:async_hooks'); | ||
| 4 | + const { test } = require('node:test'); | ||
| 5 | + | ||
| 6 | + const als = new AsyncLocalStorage(); | ||
| 7 | + const ch = dc.tracingChannel('node.test'); | ||
| 8 | + | ||
| 9 | + ch.start.bindStore(als, (data) => data.name); | ||
| 10 | + | ||
| 11 | + const storeAtEnd = {}; | ||
| 12 | + const storeAtError = {}; | ||
| 13 | + | ||
| 14 | + ch.end.subscribe((data) => { | ||
| 15 | + storeAtEnd[data.name] = als.getStore(); | ||
| 16 | + }); | ||
| 17 | + | ||
| 18 | + ch.error.subscribe((data) => { | ||
| 19 | + storeAtError[data.name] = als.getStore(); | ||
| 20 | + }); | ||
| 21 | + | ||
| 22 | + test('passing test', () => {}); | ||
| 23 | + test('failing test', () => { throw new Error('boom'); }); | ||
| 24 | + | ||
| 25 | + process.on('exit', () => { | ||
| 26 | + console.log(JSON.stringify({ storeAtEnd, storeAtError })); | ||
| 27 | + }); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -119,6 +119,26 @@ test('context is available in async operations within test', async () => { | |||
| 119 | 119 | assert.strictEqual(valueInTimeout, testName); | |
| 120 | 120 | }); | |
| 121 | 121 | ||
| 122 | + test('bindStore propagates store to end and error subscribers', async () => { | ||
| 123 | + // Spawn a fixture that records `als.getStore()` at end/error publish time so | ||
| 124 | + // we can assert subscribers see the bound store, not undefined. | ||
| 125 | + const fixturePath = join(__dirname, '../fixtures/test-runner/diagnostics-channel-bindstore-end.js'); | ||
| 126 | + const result = spawnSync(process.execPath, [fixturePath], { encoding: 'utf8' }); | ||
| 127 | + // The fixture contains an intentionally failing test, so exit is non-zero. | ||
| 128 | + assert.notStrictEqual(result.status, 0); | ||
| 129 | + const line = result.stdout.split('\n').find((l) => l.includes('storeAtEnd')); | ||
| 130 | + assert.ok(line, `expected storeAtEnd line in stdout:\n${result.stdout}`); | ||
| 131 | + const { storeAtEnd, storeAtError } = JSON.parse(line); | ||
| 132 | + assert.deepStrictEqual(storeAtEnd, { | ||
| 133 | + '<root>': '<root>', | ||
| 134 | + 'passing test': 'passing test', | ||
| 135 | + 'failing test': 'failing test', | ||
| 136 | + }); | ||
| 137 | + assert.deepStrictEqual(storeAtError, { | ||
| 138 | + 'failing test': 'failing test', | ||
| 139 | + }); | ||
| 140 | + }); | ||
| 141 | + | ||
| 122 | 142 | test('error events fire for failing tests in fixture', async () => { | |
| 123 | 143 | // Run the fixture test that intentionally fails | |
| 124 | 144 | const fixturePath = join(__dirname, '../fixtures/test-runner/diagnostics-channel-error-test.js'); | |
| Back | FazBrowse Home | New Git URL |
0 commit comments