1'use strict';
2const common = require('../common');
3const assert = require('assert');
4const { promiseHooks } = require('v8');
5
6for (const hook of ['init', 'before', 'after', 'settled']) {
7  assert.throws(() => {
8    promiseHooks.createHook({
9      [hook]: async function() { }
10    });
11  }, new RegExp(`The "${hook}Hook" argument must be of type function`));
12
13  assert.throws(() => {
14    promiseHooks.createHook({
15      [hook]: async function*() { }
16    });
17  }, new RegExp(`The "${hook}Hook" argument must be of type function`));
18}
19
20let init;
21let initParent;
22let before;
23let after;
24let settled;
25
26const stop = promiseHooks.createHook({
27  init: common.mustCall((promise, parent) => {
28    init = promise;
29    initParent = parent;
30  }, 3),
31  before: common.mustCall((promise) => {
32    before = promise;
33  }, 2),
34  after: common.mustCall((promise) => {
35    after = promise;
36  }, 1),
37  settled: common.mustCall((promise) => {
38    settled = promise;
39  }, 2)
40});
41
42// Clears state on each check so only the delta needs to be checked.
43function assertState(expectedInit, expectedInitParent, expectedBefore,
44                     expectedAfter, expectedSettled) {
45  assert.strictEqual(init, expectedInit);
46  assert.strictEqual(initParent, expectedInitParent);
47  assert.strictEqual(before, expectedBefore);
48  assert.strictEqual(after, expectedAfter);
49  assert.strictEqual(settled, expectedSettled);
50  init = undefined;
51  initParent = undefined;
52  before = undefined;
53  after = undefined;
54  settled = undefined;
55}
56
57const parent = Promise.resolve(1);
58// After calling `Promise.resolve(...)`, the returned promise should have
59// produced an init event with no parent and a settled event.
60assertState(parent, undefined, undefined, undefined, parent);
61
62const child = parent.then(() => {
63  // When a callback to `promise.then(...)` is called, the promise it resolves
64  // to should have produced a before event to mark the start of this callback.
65  assertState(undefined, undefined, child, undefined, undefined);
66});
67// After calling `promise.then(...)`, the returned promise should have
68// produced an init event with a parent of the promise the `then(...)`
69// was called on.
70assertState(child, parent);
71
72const grandChild = child.then(() => {
73  // Since the check for the before event in the `then(...)` call producing the
74  // `child` promise, there should have been both a before event for this
75  // promise but also settled and after events for the `child` promise.
76  assertState(undefined, undefined, grandChild, child, child);
77  stop();
78});
79// After calling `promise.then(...)`, the returned promise should have
80// produced an init event with a parent of the promise the `then(...)`
81// was called on.
82assertState(grandChild, child);
83