1 | 'use strict';
|
2 | const chainRegistry = new WeakMap();
|
3 |
|
4 | function startChain(name, call, defaults) {
|
5 | const fn = (...args) => {
|
6 | call({...defaults}, args);
|
7 | };
|
8 |
|
9 | Object.defineProperty(fn, 'name', {value: name});
|
10 | chainRegistry.set(fn, {call, defaults, fullName: name});
|
11 | return fn;
|
12 | }
|
13 |
|
14 | function extendChain(prev, name, flag) {
|
15 | if (!flag) {
|
16 | flag = name;
|
17 | }
|
18 |
|
19 | const fn = (...args) => {
|
20 | callWithFlag(prev, flag, args);
|
21 | };
|
22 |
|
23 | const fullName = `${chainRegistry.get(prev).fullName}.${name}`;
|
24 | Object.defineProperty(fn, 'name', {value: fullName});
|
25 | prev[name] = fn;
|
26 |
|
27 | chainRegistry.set(fn, {flag, fullName, prev});
|
28 | return fn;
|
29 | }
|
30 |
|
31 | function callWithFlag(prev, flag, args) {
|
32 | const combinedFlags = {[flag]: true};
|
33 | do {
|
34 | const step = chainRegistry.get(prev);
|
35 | if (step.call) {
|
36 | step.call({...step.defaults, ...combinedFlags}, args);
|
37 | prev = null;
|
38 | } else {
|
39 | combinedFlags[step.flag] = true;
|
40 | prev = step.prev;
|
41 | }
|
42 | } while (prev);
|
43 | }
|
44 |
|
45 | function createHookChain(hook, isAfterHook) {
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 | extendChain(hook, 'cb', 'callback');
|
52 | extendChain(hook, 'skip', 'skipped');
|
53 | extendChain(hook.cb, 'skip', 'skipped');
|
54 | if (isAfterHook) {
|
55 | extendChain(hook, 'always');
|
56 | extendChain(hook.always, 'cb', 'callback');
|
57 | extendChain(hook.always, 'skip', 'skipped');
|
58 | extendChain(hook.always.cb, 'skip', 'skipped');
|
59 | }
|
60 |
|
61 | return hook;
|
62 | }
|
63 |
|
64 | function createChain(fn, defaults, meta) {
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 | const root = startChain('test', fn, {...defaults, type: 'test'});
|
72 | extendChain(root, 'cb', 'callback');
|
73 | extendChain(root, 'failing');
|
74 | extendChain(root, 'only', 'exclusive');
|
75 | extendChain(root, 'serial');
|
76 | extendChain(root, 'skip', 'skipped');
|
77 | extendChain(root.cb, 'failing');
|
78 | extendChain(root.cb, 'only', 'exclusive');
|
79 | extendChain(root.cb, 'skip', 'skipped');
|
80 | extendChain(root.cb.failing, 'only', 'exclusive');
|
81 | extendChain(root.cb.failing, 'skip', 'skipped');
|
82 | extendChain(root.failing, 'only', 'exclusive');
|
83 | extendChain(root.failing, 'skip', 'skipped');
|
84 | extendChain(root.serial, 'cb', 'callback');
|
85 | extendChain(root.serial, 'failing');
|
86 | extendChain(root.serial, 'only', 'exclusive');
|
87 | extendChain(root.serial, 'skip', 'skipped');
|
88 | extendChain(root.serial.cb, 'failing');
|
89 | extendChain(root.serial.cb, 'only', 'exclusive');
|
90 | extendChain(root.serial.cb, 'skip', 'skipped');
|
91 | extendChain(root.serial.cb.failing, 'only', 'exclusive');
|
92 | extendChain(root.serial.cb.failing, 'skip', 'skipped');
|
93 | extendChain(root.serial.failing, 'only', 'exclusive');
|
94 | extendChain(root.serial.failing, 'skip', 'skipped');
|
95 |
|
96 | root.after = createHookChain(startChain('test.after', fn, {...defaults, type: 'after'}), true);
|
97 | root.afterEach = createHookChain(startChain('test.afterEach', fn, {...defaults, type: 'afterEach'}), true);
|
98 | root.before = createHookChain(startChain('test.before', fn, {...defaults, type: 'before'}), false);
|
99 | root.beforeEach = createHookChain(startChain('test.beforeEach', fn, {...defaults, type: 'beforeEach'}), false);
|
100 |
|
101 | root.serial.after = createHookChain(startChain('test.after', fn, {...defaults, serial: true, type: 'after'}), true);
|
102 | root.serial.afterEach = createHookChain(startChain('test.afterEach', fn, {...defaults, serial: true, type: 'afterEach'}), true);
|
103 | root.serial.before = createHookChain(startChain('test.before', fn, {...defaults, serial: true, type: 'before'}), false);
|
104 | root.serial.beforeEach = createHookChain(startChain('test.beforeEach', fn, {...defaults, serial: true, type: 'beforeEach'}), false);
|
105 |
|
106 |
|
107 |
|
108 | root.todo = startChain('test.todo', fn, {...defaults, type: 'test', todo: true});
|
109 | root.serial.todo = startChain('test.serial.todo', fn, {...defaults, serial: true, type: 'test', todo: true});
|
110 |
|
111 | root.meta = meta;
|
112 |
|
113 | return root;
|
114 | }
|
115 |
|
116 | module.exports = createChain;
|