Skip to content

Commit 91b6995

Browse files
authored
All: Update node-watch dependency and test fixtures for Node 12+
== Test fixtures == Node 6-10: > at process._tickCallback (internal/process/next_tick.js…) > at ontimeout (timers.js…) Node 12-14: > at processTicksAndRejections (internal/process/task_queues.js…) > at listOnTimeout (internal/timers.js…) == Test memory == Also update the memory-leak test to use a different strategy because the V8 native `%GetWeakSetValues` function no longer exists as of V8 7.1 (or 8.1, not sure) per <https://chromium.googlesource.com/v8/v8/+/0cf4a0f82f8f810519ba0d4b3b01adef0a0a6c1d> <https://chromium-review.googlesource.com/c/v8/v8/+/1238574>. Instead, inspect a heap snapshot and validate it that way. Also expand the test so that we first verify our logic actually works, for easier debugging in the future. == Recursive watch == As of Node 14, `fs.watch` can throw ERR_FEATURE_UNAVAILABLE_ON_PLATFORM, which is handled by node-watch 0.6.4 per <yuanchuan/node-watch@fd5d4655ca47db56>. Without this, Node 14 fails as follows: > CLI Watch > runs tests and waits until SIGTERM > > TypeError [ERR_FEATURE_UNAVAILABLE_ON_PLATFORM]: > The feature watch recursively is unavailable on the current platform, … > at Object.watch (fs.js) > at hasNativeRecursive (…/node_modules/node-watch/lib/has-native-recursive.js) > at Watcher.watchDirectory (…/node_modules/node-watch/lib/watch.js) > at watch (…/node_modules/node-watch/lib/watch.js) > at Function.watch (qunitjs/qunit/src/cli/run.js) Fixes #1430. Closes #1448.
1 parent 49d1b72 commit 91b6995

File tree

7 files changed

+65
-43
lines changed

7 files changed

+65
-43
lines changed

.travis.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
os: linux
22
language: node_js
33
node_js:
4+
- "14"
5+
- "12"
46
- "10"
57
- "8"
68
- "6"

package-lock.json

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

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
"commander": "2.12.2",
4040
"js-reporters": "1.2.1",
4141
"resolve": "1.9.0",
42-
"node-watch": "0.6.1",
42+
"node-watch": "0.6.4",
4343
"minimatch": "3.0.4"
4444
},
4545
"devDependencies": {

test/cli/fixtures/expected/tap-outputs.js

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ not ok 2 global failure
143143
# fail 2
144144
`,
145145

146-
// in node 8, the stack trace includes 'at <anonymous>. But not in node 6 or 10.
146+
// Ignore the last frame about Node processing ticks (differs between Node 10 ad 12+)
147147
"qunit no-tests":
148148
`TAP version 13
149149
not ok 1 global failure
@@ -157,7 +157,7 @@ not ok 1 global failure
157157
at advanceTestQueue (.*)
158158
at Object.advance (.*)
159159
at unblockAndAdvanceQueue (.*)(\n at <anonymous>)?
160-
at process._tickCallback (.*)
160+
at .*
161161
...
162162
1..1
163163
# pass 0
@@ -174,9 +174,8 @@ not ok 1 timeout > first
174174
severity: failed
175175
actual: null
176176
expected: undefined
177-
stack: at ontimeout (.*)
178-
at tryOnTimeout (.*)
179-
(.*)\\s*(.*)?
177+
stack: at .* (.*timers.js.*)
178+
at .*(\n at .*)?(\n at .*)?
180179
...
181180
ok 2 timeout > second
182181
1..2
@@ -195,7 +194,7 @@ ok 1 Zero assertions > has a test
195194
# todo 0
196195
# fail 0`,
197196

198-
// in node 8, the stack trace includes 'at <anonymous>. But not in node 6 or 10.
197+
// Ignore the last frame about Node processing ticks (differs between Node 10 ad 12+)
199198
"qunit qunit --filter 'no matches' test":
200199
`TAP version 13
201200
not ok 1 global failure
@@ -209,7 +208,7 @@ not ok 1 global failure
209208
at advanceTestQueue (.*)
210209
at Object.advance (.*)
211210
at unblockAndAdvanceQueue (.*)(\n at <anonymous>)?
212-
at process._tickCallback (.*)
211+
at .*
213212
...
214213
1..1
215214
# pass 0
@@ -229,7 +228,7 @@ ok 1 Single > has a test
229228
# todo 0
230229
# fail 0`,
231230

232-
"node --expose-gc --allow-natives-syntax ../../../bin/qunit.js memory-leak/*.js":
231+
"node --expose-gc ../../../bin/qunit.js memory-leak/*.js":
233232
`TAP version 13
234233
ok 1 some nested module > can call method on foo
235234
ok 2 later thing > has released all foos
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"parserOptions": {
3+
"ecmaVersion": 2017
4+
}
5+
}
Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
/* globals gc */
22

3+
const v8 = require( "v8" );
4+
35
const foos = new WeakSet();
46
class Foo {
57
constructor() {
@@ -13,48 +15,60 @@ class Foo {
1315
destroy() { }
1416
}
1517

18+
function streamToString( stream ) {
19+
const chunks = [];
20+
return new Promise( ( resolve, reject ) => {
21+
stream.on( "data", chunk => chunks.push( chunk ) );
22+
stream.on( "error", reject );
23+
stream.on( "end", () => resolve( Buffer.concat( chunks ).toString( "utf8" ) ) );
24+
} );
25+
}
26+
1627
QUnit.module( "some nested module", function( hooks ) {
17-
let foo;
28+
let foo1;
1829

1930
hooks.beforeEach( function() {
20-
foo = new Foo();
31+
foo1 = new Foo();
2132
} );
2233

2334
hooks.afterEach( function() {
24-
foo.destroy();
35+
foo1.destroy();
2536
} );
2637

2738
QUnit.test( "can call method on foo", function( assert ) {
28-
assert.equal( foo.sayHello(), "Hi!" );
39+
assert.equal( foo1.sayHello(), "Hi!" );
2940
} );
3041

3142
} );
3243

3344
QUnit.module( "later thing", function() {
34-
QUnit.test( "has released all foos", function( assert ) {
35-
36-
// Without async here, the test runner is recursive, and therefore the `foo`
37-
// instance is still retained.
38-
return Promise.resolve()
39-
.then( () => {
40-
41-
// Requires `--expose-gc` flag to function properly.
42-
gc();
43-
44-
// Using `new Function` here to avoid a syntax error.
45-
const retainedFoos = new Function(
46-
"foos",
47-
"return %GetWeakSetValues(foos, 0)"
48-
)( foos );
49-
50-
assert.equal( retainedFoos.length, 0 );
51-
} )
52-
.catch( error => {
53-
if ( error instanceof SyntaxError ) {
54-
console.log( "Must launch Node 9 with `--expose-gc --allow-natives-syntax`" );
55-
} else {
56-
throw error;
57-
}
58-
} );
45+
QUnit.test( "has released all foos", async function( assert ) {
46+
47+
// Create another one to ensure our heap match logic is working.
48+
let foo2 = new Foo();
49+
50+
// The snapshot is expected to contain something like this:
51+
// > "part of key (Foo @…) -> value (…) pair in WeakMap (…)"
52+
// It is important that the regex uses \d and that the above
53+
// comment doesn't include a number after "@", as otherwise
54+
// it will match the memory relating to this function's code.
55+
const reHeap = /^[^\n]+Foo @\d[^\n]+/gm;
56+
57+
let snapshot = await streamToString( v8.getHeapSnapshot() );
58+
let matches = snapshot.match( reHeap );
59+
assert.ok( matches && matches.length, "found local Foo in heap" );
60+
61+
snapshot = matches = null;
62+
foo2.destroy();
63+
64+
// Comment out the below to test the failure mode
65+
foo2 = null;
66+
67+
// Requires `--expose-gc` flag to function properly.
68+
gc();
69+
70+
snapshot = await streamToString( v8.getHeapSnapshot() );
71+
matches = snapshot.match( reHeap );
72+
assert.strictEqual( null, matches, "the after heap" );
5973
} );
6074
} );

test/cli/main.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,11 @@ QUnit.module( "CLI Main", function() {
158158
assert.equal( execution.stdout, expectedOutput[ command ] );
159159
} ) );
160160

161-
if ( semver.gte( process.versions.node, "9.0.0" ) ) {
161+
// https://nodejs.org/docs/v14.0.0/api/v8.html#v8_v8_getheapsnapshot
162+
// Created in Node 11.x, but starts working the way we need from Node 14.
163+
if ( semver.gte( process.versions.node, "14.0.0" ) ) {
162164
QUnit.test( "callbacks and hooks from modules are properly released for garbage collection", co.wrap( function* ( assert ) {
163-
const command = "node --expose-gc --allow-natives-syntax ../../../bin/qunit.js memory-leak/*.js";
165+
const command = "node --expose-gc ../../../bin/qunit.js memory-leak/*.js";
164166
const execution = yield execute( command );
165167

166168
assert.equal( execution.code, 0 );

0 commit comments

Comments
 (0)