UNPKG

4.65 kBJavaScriptView Raw
1"use strict";
2// tslint:disable callable-types
3// tslint:disable no-unused
4Object.defineProperty(exports, "__esModule", { value: true });
5const _ = require("lodash");
6const context = {
7 test: it,
8 plugins: {},
9 chain: [],
10};
11const base = (context) => {
12 const end = (arg1, cb) => {
13 const originalContext = context;
14 if (_.isFunction(arg1)) {
15 cb = arg1;
16 arg1 = undefined;
17 }
18 if (!arg1)
19 arg1 = context.expectation || 'test';
20 async function run(done) {
21 context = assignWithProps({}, originalContext);
22 if (context.retries)
23 this.retries(context.retries);
24 if (cb) {
25 context.chain = [...context.chain, {
26 run: async (input) => {
27 await cb.call(this, input, done);
28 }
29 }];
30 }
31 for (let i = 0; i < context.chain.length; i++) {
32 const handleError = async (err) => {
33 context.error = err;
34 i++;
35 const handler = context.chain[i];
36 if (!handler || !handler.catch)
37 return false;
38 try {
39 await handler.catch(context);
40 delete context.error;
41 return true;
42 }
43 catch (err) {
44 return handleError(err);
45 }
46 };
47 const next = context.chain[i];
48 try {
49 if (next.run)
50 await next.run(context);
51 }
52 catch (err) {
53 if (!await handleError(err))
54 break;
55 }
56 }
57 for (let p of context.chain.reverse()) {
58 if (p.finally)
59 await p.finally(context);
60 }
61 if (context.error)
62 throw context.error;
63 }
64 return context.test(arg1, (cb && cb.length === 2) ? function (done) {
65 if (context.timeout)
66 this.timeout(context.timeout);
67 run.call(this, done).catch(done);
68 } : function () {
69 if (context.timeout)
70 this.timeout(context.timeout);
71 return run.call(this);
72 });
73 };
74 return Object.assign({}, Object.entries(context.plugins)
75 .reduce((plugins, [k, v]) => {
76 plugins[k] = (...args) => {
77 const plugin = v(...args);
78 // clone context first
79 let c = Object.assign({}, context);
80 if (plugin.init)
81 plugin.init(c);
82 return base(Object.assign({}, c, { chain: [...c.chain, plugin] }));
83 };
84 return plugins;
85 }, {}), { register(k, v) {
86 return base(Object.assign({}, context, { plugins: Object.assign({}, context.plugins, { [k]: v }) }));
87 },
88 do(cb) {
89 return base(Object.assign({}, context, { chain: [...context.chain, { run: (input) => cb(input) }] }));
90 },
91 finally(cb) {
92 return base(Object.assign({}, context, { chain: [...context.chain, { finally: (input) => cb(input) }] }));
93 },
94 add(key, v) {
95 return base(Object.assign({}, context, { chain: [...context.chain, {
96 run: async (ctx) => {
97 ctx[key] = await (_.isFunction(v) ? v(ctx) : v);
98 }
99 }] }));
100 },
101 end, it: end });
102};
103function assignWithProps(target, ...sources) {
104 sources.forEach(source => {
105 if (!source)
106 return;
107 let descriptors = Object.keys(source).reduce((descriptors, key) => {
108 descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
109 return descriptors;
110 }, {});
111 // by default, Object.assign copies enumerable Symbols too
112 Object.getOwnPropertySymbols(source).forEach(sym => {
113 let descriptor = Object.getOwnPropertyDescriptor(source, sym);
114 if (descriptor.enumerable) {
115 descriptors[sym] = descriptor;
116 }
117 });
118 Object.defineProperties(target, descriptors);
119 });
120 return target;
121}
122exports.default = base(context)
123 .register('skip', () => ({
124 init: ctx => { ctx.test = it.skip; }
125}))
126 .register('only', () => ({
127 init: ctx => { ctx.test = it.only; }
128}))
129 .register('retries', (count) => ({
130 init: ctx => ctx.retries = count
131}));