| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 4baf463 commit 64442fc
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,34 @@ | |||
| 1 | + // Flags: --no-warnings --expose-gc --expose-internals | ||
| 2 | + 'use strict'; | ||
| 3 | + require('../common'); | ||
| 4 | + | ||
| 5 | + const { | ||
| 6 | + strictEqual, | ||
| 7 | + } = require('assert'); | ||
| 8 | + | ||
| 9 | + const { | ||
| 10 | + test, | ||
| 11 | + } = require('node:test'); | ||
| 12 | + | ||
| 13 | + const { | ||
| 14 | + kWeakHandler, | ||
| 15 | + } = require('internal/event_target'); | ||
| 16 | + | ||
| 17 | + const { setTimeout: sleep } = require('timers/promises'); | ||
| 18 | + | ||
| 19 | + // The tests in this file depend on Node.js internal APIs. These are not necessarily | ||
| 20 | + // portable to other runtimes | ||
| 21 | + | ||
| 22 | + test('A weak event listener should not prevent gc', async () => { | ||
| 23 | + // If the event listener is weak, however, it should not prevent gc | ||
| 24 | + let ref; | ||
| 25 | + function handler() {} | ||
| 26 | + { | ||
| 27 | + ref = new globalThis.WeakRef(AbortSignal.timeout(1_200_000)); | ||
| 28 | + ref.deref().addEventListener('abort', handler, { [kWeakHandler]: {} }); | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + await sleep(10); | ||
| 32 | + globalThis.gc(); | ||
| 33 | + strictEqual(ref.deref(), undefined); | ||
| 34 | + }); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,7 +1,7 @@ | |||
| 1 | - // Flags: --no-warnings --expose-gc --expose-internals | ||
| 1 | + // Flags: --expose-gc | ||
| 2 | 2 | 'use strict'; | |
| 3 | 3 | ||
| 4 | - const common = require('../common'); | ||
| 4 | + require('../common'); | ||
| 5 | 5 | const { inspect } = require('util'); | |
| 6 | 6 | ||
| 7 | 7 | const { | |
@@ -12,80 +12,93 @@ const { | |||
| 12 | 12 | } = require('assert'); | |
| 13 | 13 | ||
| 14 | 14 | const { | |
| 15 | - kWeakHandler, | ||
| 16 | - } = require('internal/event_target'); | ||
| 15 | + test, | ||
| 16 | + mock, | ||
| 17 | + } = require('node:test'); | ||
| 17 | 18 | ||
| 18 | 19 | const { setTimeout: sleep } = require('timers/promises'); | |
| 19 | 20 | ||
| 20 | - { | ||
| 21 | + // All of the the tests in this file depend on public-facing Node.js APIs. | ||
| 22 | + // For tests that depend on Node.js internal APIs, please add them to | ||
| 23 | + // test-abortcontroller-internal.js instead. | ||
| 24 | + | ||
| 25 | + test('Abort is fired with the correct event type on AbortControllers', () => { | ||
| 21 | 26 | // Tests that abort is fired with the correct event type on AbortControllers | |
| 22 | 27 | const ac = new AbortController(); | |
| 23 | 28 | ok(ac.signal); | |
| 24 | - ac.signal.onabort = common.mustCall((event) => { | ||
| 29 | + | ||
| 30 | + const fn = mock.fn((event) => { | ||
| 25 | 31 | ok(event); | |
| 26 | 32 | strictEqual(event.type, 'abort'); | |
| 27 | 33 | }); | |
| 28 | - ac.signal.addEventListener('abort', common.mustCall((event) => { | ||
| 29 | - ok(event); | ||
| 30 | - strictEqual(event.type, 'abort'); | ||
| 31 | - }), { once: true }); | ||
| 34 | + | ||
| 35 | + ac.signal.onabort = fn; | ||
| 36 | + ac.signal.addEventListener('abort', fn); | ||
| 37 | + | ||
| 32 | 38 | ac.abort(); | |
| 33 | 39 | ac.abort(); | |
| 34 | 40 | ok(ac.signal.aborted); | |
| 35 | - } | ||
| 36 | 41 | ||
| 37 | - { | ||
| 42 | + strictEqual(fn.mock.calls.length, 2); | ||
| 43 | + }); | ||
| 44 | + | ||
| 45 | + test('Abort events are trusted', () => { | ||
| 38 | 46 | // Tests that abort events are trusted | |
| 39 | 47 | const ac = new AbortController(); | |
| 40 | - ac.signal.addEventListener('abort', common.mustCall((event) => { | ||
| 48 | + | ||
| 49 | + const fn = mock.fn((event) => { | ||
| 41 | 50 | ok(event.isTrusted); | |
| 42 | - })); | ||
| 51 | + }); | ||
| 52 | + | ||
| 53 | + ac.signal.onabort = fn; | ||
| 43 | 54 | ac.abort(); | |
| 44 | - } | ||
| 55 | + strictEqual(fn.mock.calls.length, 1); | ||
| 56 | + }); | ||
| 45 | 57 | ||
| 46 | - { | ||
| 58 | + test('Abort events have the same isTrusted reference', () => { | ||
| 47 | 59 | // Tests that abort events have the same `isTrusted` reference | |
| 48 | 60 | const first = new AbortController(); | |
| 49 | 61 | const second = new AbortController(); | |
| 50 | 62 | let ev1, ev2; | |
| 51 | 63 | const ev3 = new Event('abort'); | |
| 52 | - first.signal.addEventListener('abort', common.mustCall((event) => { | ||
| 64 | + | ||
| 65 | + first.signal.addEventListener('abort', (event) => { | ||
| 53 | 66 | ev1 = event; | |
| 54 | - })); | ||
| 55 | - second.signal.addEventListener('abort', common.mustCall((event) => { | ||
| 67 | + }); | ||
| 68 | + second.signal.addEventListener('abort', (event) => { | ||
| 56 | 69 | ev2 = event; | |
| 57 | - })); | ||
| 70 | + }); | ||
| 58 | 71 | first.abort(); | |
| 59 | 72 | second.abort(); | |
| 60 | 73 | const firstTrusted = Reflect.getOwnPropertyDescriptor(Object.getPrototypeOf(ev1), 'isTrusted').get; | |
| 61 | 74 | const secondTrusted = Reflect.getOwnPropertyDescriptor(Object.getPrototypeOf(ev2), 'isTrusted').get; | |
| 62 | 75 | const untrusted = Reflect.getOwnPropertyDescriptor(Object.getPrototypeOf(ev3), 'isTrusted').get; | |
| 63 | 76 | strictEqual(firstTrusted, secondTrusted); | |
| 64 | 77 | strictEqual(untrusted, firstTrusted); | |
| 65 | - } | ||
| 78 | + }); | ||
| 66 | 79 | ||
| 67 | - { | ||
| 80 | + test('AbortSignal is impossible to construct manually', () => { | ||
| 68 | 81 | // Tests that AbortSignal is impossible to construct manually | |
| 69 | 82 | const ac = new AbortController(); | |
| 70 | 83 | throws(() => new ac.signal.constructor(), { | |
| 71 | 84 | code: 'ERR_ILLEGAL_CONSTRUCTOR', | |
| 72 | 85 | }); | |
| 73 | - } | ||
| 74 | - { | ||
| 86 | + }); | ||
| 87 | + | ||
| 88 | + test('Symbol.toStringTag is correct', () => { | ||
| 75 | 89 | // Symbol.toStringTag | |
| 76 | 90 | const toString = (o) => Object.prototype.toString.call(o); | |
| 77 | 91 | const ac = new AbortController(); | |
| 78 | 92 | strictEqual(toString(ac), '[object AbortController]'); | |
| 79 | 93 | strictEqual(toString(ac.signal), '[object AbortSignal]'); | |
| 80 | - } | ||
| 94 | + }); | ||
| 81 | 95 | ||
| 82 | - { | ||
| 96 | + test('AbortSignal.abort() creates an already aborted signal', () => { | ||
| 83 | 97 | const signal = AbortSignal.abort(); | |
| 84 | 98 | ok(signal.aborted); | |
| 85 | - } | ||
| 99 | + }); | ||
| 86 | 100 | ||
| 87 | - { | ||
| 88 | - // Test that AbortController properties and methods validate the receiver | ||
| 101 | + test('AbortController properties and methods valiate the receiver', () => { | ||
| 89 | 102 | const acSignalGet = Object.getOwnPropertyDescriptor( | |
| 90 | 103 | AbortController.prototype, | |
| 91 | 104 | 'signal' | |
@@ -115,10 +128,9 @@ const { setTimeout: sleep } = require('timers/promises'); | |||
| 115 | 128 | { name: 'TypeError' } | |
| 116 | 129 | ); | |
| 117 | 130 | } | |
| 118 | - } | ||
| 131 | + }); | ||
| 119 | 132 | ||
| 120 | - { | ||
| 121 | - // Test that AbortSignal properties validate the receiver | ||
| 133 | + test('AbortSignal properties validate the receiver', () => { | ||
| 122 | 134 | const signalAbortedGet = Object.getOwnPropertyDescriptor( | |
| 123 | 135 | AbortSignal.prototype, | |
| 124 | 136 | 'aborted' | |
@@ -142,96 +154,87 @@ const { setTimeout: sleep } = require('timers/promises'); | |||
| 142 | 154 | { name: 'TypeError' } | |
| 143 | 155 | ); | |
| 144 | 156 | } | |
| 145 | - } | ||
| 157 | + }); | ||
| 146 | 158 | ||
| 147 | - { | ||
| 159 | + test('AbortController inspection depth 1 or null works', () => { | ||
| 148 | 160 | const ac = new AbortController(); | |
| 149 | 161 | strictEqual(inspect(ac, { depth: 1 }), | |
| 150 | 162 | 'AbortController { signal: [AbortSignal] }'); | |
| 151 | 163 | strictEqual(inspect(ac, { depth: null }), | |
| 152 | 164 | 'AbortController { signal: AbortSignal { aborted: false } }'); | |
| 153 | - } | ||
| 165 | + }); | ||
| 154 | 166 | ||
| 155 | - { | ||
| 167 | + test('AbortSignal reason is set correctly', () => { | ||
| 156 | 168 | // Test AbortSignal.reason | |
| 157 | 169 | const ac = new AbortController(); | |
| 158 | 170 | ac.abort('reason'); | |
| 159 | 171 | strictEqual(ac.signal.reason, 'reason'); | |
| 160 | - } | ||
| 172 | + }); | ||
| 161 | 173 | ||
| 162 | - { | ||
| 174 | + test('AbortSignal reasonable is set correctly with AbortSignal.abort()', () => { | ||
| 163 | 175 | // Test AbortSignal.reason | |
| 164 | 176 | const signal = AbortSignal.abort('reason'); | |
| 165 | 177 | strictEqual(signal.reason, 'reason'); | |
| 166 | - } | ||
| 178 | + }); | ||
| 167 | 179 | ||
| 168 | - { | ||
| 180 | + test('AbortSignal.timeout() works as expected', async () => { | ||
| 169 | 181 | // Test AbortSignal timeout | |
| 170 | 182 | const signal = AbortSignal.timeout(10); | |
| 171 | 183 | ok(!signal.aborted); | |
| 172 | - setTimeout(common.mustCall(() => { | ||
| 184 | + | ||
| 185 | + const { promise, resolve } = Promise.withResolvers(); | ||
| 186 | + | ||
| 187 | + const fn = mock.fn(() => { | ||
| 173 | 188 | ok(signal.aborted); | |
| 174 | 189 | strictEqual(signal.reason.name, 'TimeoutError'); | |
| 175 | 190 | strictEqual(signal.reason.code, 23); | |
| 176 | - }), 20); | ||
| 177 | - } | ||
| 178 | - | ||
| 179 | - { | ||
| 180 | - (async () => { | ||
| 181 | - // Test AbortSignal timeout doesn't prevent the signal | ||
| 182 | - // from being garbage collected. | ||
| 183 | - let ref; | ||
| 184 | - { | ||
| 185 | - ref = new globalThis.WeakRef(AbortSignal.timeout(1_200_000)); | ||
| 186 | - } | ||
| 187 | - | ||
| 188 | - await sleep(10); | ||
| 189 | - globalThis.gc(); | ||
| 190 | - strictEqual(ref.deref(), undefined); | ||
| 191 | - })().then(common.mustCall()); | ||
| 192 | - | ||
| 193 | - (async () => { | ||
| 194 | - // Test that an AbortSignal with a timeout is not gc'd while | ||
| 195 | - // there is an active listener on it. | ||
| 196 | - let ref; | ||
| 197 | - function handler() {} | ||
| 198 | - { | ||
| 199 | - ref = new globalThis.WeakRef(AbortSignal.timeout(1_200_000)); | ||
| 200 | - ref.deref().addEventListener('abort', handler); | ||
| 201 | - } | ||
| 202 | - | ||
| 203 | - await sleep(10); | ||
| 204 | - globalThis.gc(); | ||
| 205 | - notStrictEqual(ref.deref(), undefined); | ||
| 206 | - ok(ref.deref() instanceof AbortSignal); | ||
| 207 | - | ||
| 208 | - ref.deref().removeEventListener('abort', handler); | ||
| 209 | - | ||
| 210 | - await sleep(10); | ||
| 211 | - globalThis.gc(); | ||
| 212 | - strictEqual(ref.deref(), undefined); | ||
| 213 | - })().then(common.mustCall()); | ||
| 214 | - | ||
| 215 | - (async () => { | ||
| 216 | - // If the event listener is weak, however, it should not prevent gc | ||
| 217 | - let ref; | ||
| 218 | - function handler() {} | ||
| 219 | - { | ||
| 220 | - ref = new globalThis.WeakRef(AbortSignal.timeout(1_200_000)); | ||
| 221 | - ref.deref().addEventListener('abort', handler, { [kWeakHandler]: {} }); | ||
| 222 | - } | ||
| 223 | - | ||
| 224 | - await sleep(10); | ||
| 225 | - globalThis.gc(); | ||
| 226 | - strictEqual(ref.deref(), undefined); | ||
| 227 | - })().then(common.mustCall()); | ||
| 228 | - | ||
| 229 | - // Setting a long timeout (20 minutes here) should not | ||
| 230 | - // keep the Node.js process open (the timer is unref'd) | ||
| 191 | + resolve(); | ||
| 192 | + }); | ||
| 193 | + | ||
| 194 | + setTimeout(fn, 20); | ||
| 195 | + await promise; | ||
| 196 | + }); | ||
| 197 | + | ||
| 198 | + test('AbortSignal.timeout() does not prevent the signal from being collected', async () => { | ||
| 199 | + // Test AbortSignal timeout doesn't prevent the signal | ||
| 200 | + // from being garbage collected. | ||
| 201 | + let ref; | ||
| 202 | + { | ||
| 203 | + ref = new globalThis.WeakRef(AbortSignal.timeout(1_200_000)); | ||
| 204 | + } | ||
| 205 | + | ||
| 206 | + await sleep(10); | ||
| 207 | + globalThis.gc(); | ||
| 208 | + strictEqual(ref.deref(), undefined); | ||
| 209 | + }); | ||
| 210 | + | ||
| 211 | + test('AbortSignal with a timeout is not collected while there is an active listener', async () => { | ||
| 212 | + // Test that an AbortSignal with a timeout is not gc'd while | ||
| 213 | + // there is an active listener on it. | ||
| 214 | + let ref; | ||
| 215 | + function handler() {} | ||
| 216 | + { | ||
| 217 | + ref = new globalThis.WeakRef(AbortSignal.timeout(1_200_000)); | ||
| 218 | + ref.deref().addEventListener('abort', handler); | ||
| 219 | + } | ||
| 220 | + | ||
| 221 | + await sleep(10); | ||
| 222 | + globalThis.gc(); | ||
| 223 | + notStrictEqual(ref.deref(), undefined); | ||
| 224 | + ok(ref.deref() instanceof AbortSignal); | ||
| 225 | + | ||
| 226 | + ref.deref().removeEventListener('abort', handler); | ||
| 227 | + | ||
| 228 | + await sleep(10); | ||
| 229 | + globalThis.gc(); | ||
| 230 | + strictEqual(ref.deref(), undefined); | ||
| 231 | + }); | ||
| 232 | + | ||
| 233 | + test('Setting a long timeout should not keep the process open', () => { | ||
| 231 | 234 | AbortSignal.timeout(1_200_000); | |
| 232 | - } | ||
| 235 | + }); | ||
| 233 | 236 | ||
| 234 | - { | ||
| 237 | + test('AbortSignal.reason should default', () => { | ||
| 235 | 238 | // Test AbortSignal.reason default | |
| 236 | 239 | const signal = AbortSignal.abort(); | |
| 237 | 240 | ok(signal.reason instanceof DOMException); | |
@@ -241,9 +244,9 @@ const { setTimeout: sleep } = require('timers/promises'); | |||
| 241 | 244 | ac.abort(); | |
| 242 | 245 | ok(ac.signal.reason instanceof DOMException); | |
| 243 | 246 | strictEqual(ac.signal.reason.code, 20); | |
| 244 | - } | ||
| 247 | + }); | ||
| 245 | 248 | ||
| 246 | - { | ||
| 249 | + test('abortSignal.throwIfAborted() works as expected', () => { | ||
| 247 | 250 | // Test abortSignal.throwIfAborted() | |
| 248 | 251 | throws(() => AbortSignal.abort().throwIfAborted(), { | |
| 249 | 252 | code: 20, | |
@@ -253,21 +256,21 @@ const { setTimeout: sleep } = require('timers/promises'); | |||
| 253 | 256 | // Does not throw because it's not aborted. | |
| 254 | 257 | const ac = new AbortController(); | |
| 255 | 258 | ac.signal.throwIfAborted(); | |
| 256 | - } | ||
| 259 | + }); | ||
| 257 | 260 | ||
| 258 | - { | ||
| 261 | + test('abortSignal.throwIfAobrted() works as expected (2)', () => { | ||
| 259 | 262 | const originalDesc = Reflect.getOwnPropertyDescriptor(AbortSignal.prototype, 'aborted'); | |
| 260 | 263 | const actualReason = new Error(); | |
| 261 | 264 | Reflect.defineProperty(AbortSignal.prototype, 'aborted', { value: false }); | |
| 262 | 265 | throws(() => AbortSignal.abort(actualReason).throwIfAborted(), actualReason); | |
| 263 | 266 | Reflect.defineProperty(AbortSignal.prototype, 'aborted', originalDesc); | |
| 264 | - } | ||
| 267 | + }); | ||
| 265 | 268 | ||
| 266 | - { | ||
| 269 | + test('abortSignal.throwIfAobrted() works as expected (3)', () => { | ||
| 267 | 270 | const originalDesc = Reflect.getOwnPropertyDescriptor(AbortSignal.prototype, 'reason'); | |
| 268 | 271 | const actualReason = new Error(); | |
| 269 | 272 | const fakeExcuse = new Error(); | |
| 270 | 273 | Reflect.defineProperty(AbortSignal.prototype, 'reason', { value: fakeExcuse }); | |
| 271 | 274 | throws(() => AbortSignal.abort(actualReason).throwIfAborted(), actualReason); | |
| 272 | 275 | Reflect.defineProperty(AbortSignal.prototype, 'reason', originalDesc); | |
| 273 | - } | ||
| 276 | + }); | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments