ava 0.16.0 → 0.18.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/sequence.js CHANGED
@@ -1,103 +1,87 @@
1
1
  'use strict';
2
- var isPromise = require('is-promise');
3
- var AvaError = require('./ava-error');
4
-
5
- function noop() {}
6
-
7
- module.exports = Sequence;
8
-
9
- function Sequence(tests, bail) {
10
- if (!(this instanceof Sequence)) {
11
- throw new TypeError('Class constructor Sequence cannot be invoked without \'new\'');
12
- }
13
-
14
- if (!tests) {
15
- throw new Error('Sequence items can\'t be undefined');
16
- }
17
-
18
- this.results = [];
19
- this.passed = true;
20
- this.reason = null;
21
- this.tests = tests;
22
- this.bail = bail || false;
23
-
24
- // TODO(vdemedes): separate into a utility (it's being used in serveral places)
25
- Object.keys(Sequence.prototype).forEach(function (key) {
26
- this[key] = this[key].bind(this);
27
- }, this);
28
- }
29
-
30
- Sequence.prototype.run = function () {
31
- var length = this.tests.length;
32
-
33
- for (var i = 0; i < length; i++) {
34
- // if last item failed and we should bail, return results and stop
35
- if (this.bail && !this.passed) {
36
- return this._results();
2
+ const isPromise = require('is-promise');
3
+ const autoBind = require('auto-bind');
4
+ const AvaError = require('./ava-error');
5
+
6
+ class Sequence {
7
+ constructor(tests, bail) {
8
+ if (!tests) {
9
+ throw new Error('Sequence items can\'t be undefined');
37
10
  }
38
11
 
39
- var result = this.tests[i].run();
12
+ this.results = [];
13
+ this.passed = true;
14
+ this.reason = null;
15
+ this.tests = tests;
16
+ this.bail = bail || false;
40
17
 
41
- // if a Promise returned, we don't need to check for Promises after this test
42
- // so we can just use Promise.each() on the rest of the tests
43
- if (isPromise(result)) {
44
- return result
45
- .then(this._addResult)
46
- .return(this.tests.slice(i + 1))
47
- .each(this._runTest)
48
- .catch(AvaError, noop)
49
- .then(this._results);
50
- }
18
+ autoBind(this);
19
+ }
20
+ run() {
21
+ const length = this.tests.length;
51
22
 
52
- try {
53
- this._addResult(result);
54
- } catch (err) {
55
- // in bail mode, don't execute the next tests
56
- if (err instanceof AvaError) {
23
+ for (let i = 0; i < length; i++) {
24
+ // If last item failed and we should bail, return results and stop
25
+ if (this.bail && !this.passed) {
57
26
  return this._results();
58
27
  }
59
28
 
60
- throw err;
61
- }
62
- }
29
+ const result = this.tests[i].run();
30
+
31
+ // If a Promise returned, we don't need to check for Promises after this test
32
+ // so we can just use Promise.each() on the rest of the tests
33
+ if (isPromise(result)) {
34
+ return result
35
+ .then(this._addResult)
36
+ .return(this.tests.slice(i + 1))
37
+ .each(this._runTest)
38
+ .catch(AvaError, () => {})
39
+ .then(this._results);
40
+ }
63
41
 
64
- return this._results();
65
- };
42
+ try {
43
+ this._addResult(result);
44
+ } catch (err) {
45
+ // In bail mode, don't execute the next tests
46
+ if (err instanceof AvaError) {
47
+ return this._results();
48
+ }
66
49
 
67
- Sequence.prototype._runTest = function (test) {
68
- var result = test.run();
50
+ throw err;
51
+ }
52
+ }
69
53
 
70
- if (isPromise(result)) {
71
- return result
72
- .then(this._addResult);
54
+ return this._results();
73
55
  }
56
+ _runTest(test) {
57
+ const result = test.run();
58
+ return isPromise(result) ? result.then(this._addResult) : this._addResult(result);
59
+ }
60
+ _addResult(result) {
61
+ this.results.push(result);
74
62
 
75
- return this._addResult(result);
76
- };
77
-
78
- Sequence.prototype._addResult = function (result) {
79
- this.results.push(result);
63
+ if (result.passed === false) {
64
+ this.passed = false;
80
65
 
81
- if (result.passed === false) {
82
- this.passed = false;
66
+ // Only set reason once
67
+ if (!this.reason) {
68
+ this.reason = result.reason;
69
+ }
83
70
 
84
- // only set reason once
85
- if (!this.reason) {
86
- this.reason = result.reason;
71
+ if (this.bail) {
72
+ throw new AvaError('Error in Sequence while in bail mode');
73
+ }
87
74
  }
88
75
 
89
- if (this.bail) {
90
- throw new AvaError('Error in Sequence while in bail mode');
91
- }
76
+ return result;
92
77
  }
78
+ _results() {
79
+ return {
80
+ passed: this.passed,
81
+ reason: this.reason,
82
+ result: this.results
83
+ };
84
+ }
85
+ }
93
86
 
94
- return result;
95
- };
96
-
97
- Sequence.prototype._results = function () {
98
- return {
99
- passed: this.passed,
100
- reason: this.reason,
101
- result: this.results
102
- };
103
- };
87
+ module.exports = Sequence;
@@ -1,6 +1,19 @@
1
1
  'use strict';
2
- var cleanYamlObject = require('clean-yaml-object');
3
- var beautifyStack = require('./beautify-stack');
2
+ const path = require('path');
3
+ const cleanYamlObject = require('clean-yaml-object');
4
+ const StackUtils = require('stack-utils');
5
+ const prettyFormat = require('@ava/pretty-format');
6
+ const reactTestPlugin = require('@ava/pretty-format/plugins/ReactTestComponent');
7
+ const beautifyStack = require('./beautify-stack');
8
+ const extractStack = require('./extract-stack');
9
+
10
+ function serializeValue(value) {
11
+ return prettyFormat(value, {
12
+ callToJSON: false,
13
+ plugins: [reactTestPlugin],
14
+ highlight: true
15
+ });
16
+ }
4
17
 
5
18
  function filter(propertyName, isRoot, source, target) {
6
19
  if (!isRoot) {
@@ -12,9 +25,60 @@ function filter(propertyName, isRoot, source, target) {
12
25
  return false;
13
26
  }
14
27
 
28
+ if (propertyName === 'statements') {
29
+ if (source.showOutput) {
30
+ target.statements = JSON.stringify(source[propertyName].map(statement => {
31
+ const path = statement[0];
32
+ const value = serializeValue(statement[1]);
33
+
34
+ return [path, value];
35
+ }));
36
+ }
37
+
38
+ return false;
39
+ }
40
+
41
+ if (propertyName === 'actual' || propertyName === 'expected') {
42
+ if (source.showOutput) {
43
+ const value = source[propertyName];
44
+ target[propertyName + 'Type'] = typeof value;
45
+ target[propertyName] = serializeValue(value);
46
+ }
47
+
48
+ return false;
49
+ }
50
+
15
51
  return true;
16
52
  }
17
53
 
18
- module.exports = function (error) {
19
- return cleanYamlObject(error, filter);
54
+ const stackUtils = new StackUtils();
55
+
56
+ module.exports = error => {
57
+ const err = cleanYamlObject(error, filter);
58
+
59
+ if (err.stack) {
60
+ const firstStackLine = extractStack(err.stack).split('\n')[0];
61
+ const source = stackUtils.parseLine(firstStackLine);
62
+ if (source) {
63
+ // Assume the CWD is the project directory. This holds since this function
64
+ // is only called in test workers, which are created with their working
65
+ // directory set to the project directory.
66
+ const projectDir = process.cwd();
67
+
68
+ const file = path.resolve(projectDir, source.file.trim());
69
+ const rel = path.relative(projectDir, file);
70
+
71
+ const isWithinProject = rel.split(path.sep)[0] !== '..';
72
+ const isDependency = isWithinProject && path.dirname(rel).split(path.sep).indexOf('node_modules') > -1;
73
+
74
+ err.source = {
75
+ isDependency,
76
+ isWithinProject,
77
+ file,
78
+ line: source.line
79
+ };
80
+ }
81
+ }
82
+
83
+ return err;
20
84
  };
@@ -0,0 +1,30 @@
1
+ 'use strict';
2
+ const path = require('path');
3
+ const jestSnapshot = require('jest-snapshot');
4
+ const globals = require('./globals');
5
+
6
+ const x = module.exports;
7
+
8
+ x.get = (initializeState, globalsOptions) => {
9
+ if (!x.state) {
10
+ // Set defaults - this allows tests to mock deps easily
11
+ const options = globalsOptions || globals.options;
12
+ const initializeSnapshotState = initializeState || jestSnapshot.initializeSnapshotState;
13
+
14
+ const filename = options.file;
15
+ const dirname = path.dirname(filename);
16
+ const snapshotFileName = path.basename(filename) + '.snap';
17
+ const snapshotsFolder = path.join(dirname, '__snapshots__', snapshotFileName);
18
+
19
+ x.state = initializeSnapshotState(
20
+ filename,
21
+ options.updateSnapshots,
22
+ snapshotsFolder,
23
+ true
24
+ );
25
+ }
26
+
27
+ return x.state;
28
+ };
29
+
30
+ x.state = null;
@@ -1,196 +1,184 @@
1
1
  'use strict';
2
- var EventEmitter = require('events').EventEmitter;
3
- var util = require('util');
4
- var fnName = require('fn-name');
5
- var Concurrent = require('./concurrent');
6
- var Sequence = require('./sequence');
7
- var Test = require('./test');
8
-
9
- module.exports = TestCollection;
2
+ const EventEmitter = require('events');
3
+ const fnName = require('fn-name');
4
+ const Concurrent = require('./concurrent');
5
+ const Sequence = require('./sequence');
6
+ const Test = require('./test');
7
+
8
+ class TestCollection extends EventEmitter {
9
+ constructor() {
10
+ super();
11
+
12
+ this.hasExclusive = false;
13
+ this.testCount = 0;
14
+
15
+ this.tests = {
16
+ concurrent: [],
17
+ serial: []
18
+ };
19
+
20
+ this.hooks = {
21
+ before: [],
22
+ beforeEach: [],
23
+ after: [],
24
+ afterAlways: [],
25
+ afterEach: [],
26
+ afterEachAlways: []
27
+ };
28
+
29
+ this._emitTestResult = this._emitTestResult.bind(this);
30
+ }
31
+ add(test) {
32
+ const metadata = test.metadata;
33
+ const type = metadata.type;
34
+
35
+ if (!type) {
36
+ throw new Error('Test type must be specified');
37
+ }
10
38
 
11
- function TestCollection() {
12
- if (!(this instanceof TestCollection)) {
13
- throw new TypeError('Class constructor TestCollection cannot be invoked without \'new\'');
14
- }
39
+ if (!test.title && test.fn) {
40
+ test.title = fnName(test.fn);
41
+ }
15
42
 
16
- EventEmitter.call(this);
43
+ // Workaround for Babel giving anonymous functions a name
44
+ if (test.title === 'callee$0$0') {
45
+ test.title = null;
46
+ }
17
47
 
18
- this.hasExclusive = false;
19
- this.tests = {
20
- concurrent: [],
21
- serial: []
22
- };
48
+ if (!test.title) {
49
+ if (type === 'test') {
50
+ test.title = '[anonymous]';
51
+ } else {
52
+ test.title = type;
53
+ }
54
+ }
23
55
 
24
- this.hooks = {
25
- before: [],
26
- beforeEach: [],
27
- after: [],
28
- afterAlways: [],
29
- afterEach: [],
30
- afterEachAlways: []
31
- };
56
+ if (metadata.always && type !== 'after' && type !== 'afterEach') {
57
+ throw new Error('"always" can only be used with after and afterEach hooks');
58
+ }
32
59
 
33
- this._emitTestResult = this._emitTestResult.bind(this);
34
- }
60
+ // Add a hook
61
+ if (type !== 'test') {
62
+ if (metadata.exclusive) {
63
+ throw new Error(`"only" cannot be used with a ${type} hook`);
64
+ }
35
65
 
36
- util.inherits(TestCollection, EventEmitter);
66
+ this.hooks[type + (metadata.always ? 'Always' : '')].push(test);
67
+ return;
68
+ }
37
69
 
38
- TestCollection.prototype.add = function (test) {
39
- var metadata = test.metadata;
40
- var type = metadata.type;
70
+ this.testCount++;
41
71
 
42
- if (!type) {
43
- throw new Error('Test type must be specified');
44
- }
45
-
46
- if (!test.title && test.fn) {
47
- test.title = fnName(test.fn);
48
- }
72
+ // Add `.only()` tests if `.only()` was used previously
73
+ if (this.hasExclusive && !metadata.exclusive) {
74
+ return;
75
+ }
49
76
 
50
- // workaround for Babel giving anonymous functions a name
51
- if (test.title === 'callee$0$0') {
52
- test.title = null;
53
- }
77
+ if (metadata.exclusive && !this.hasExclusive) {
78
+ this.tests.concurrent = [];
79
+ this.tests.serial = [];
80
+ this.hasExclusive = true;
81
+ }
54
82
 
55
- if (!test.title) {
56
- if (type === 'test') {
57
- test.title = '[anonymous]';
83
+ if (metadata.serial) {
84
+ this.tests.serial.push(test);
58
85
  } else {
59
- test.title = type;
86
+ this.tests.concurrent.push(test);
60
87
  }
61
88
  }
89
+ _skippedTest(test) {
90
+ const self = this;
62
91
 
63
- if (metadata.always && type !== 'after' && type !== 'afterEach') {
64
- throw new Error('"always" can only be used with after and afterEach hooks');
65
- }
92
+ return {
93
+ run() {
94
+ const result = {
95
+ passed: true,
96
+ result: test
97
+ };
66
98
 
67
- // add a hook
68
- if (type !== 'test') {
69
- if (metadata.exclusive) {
70
- throw new Error('"only" cannot be used with a ' + type + ' hook');
71
- }
99
+ self._emitTestResult(result);
72
100
 
73
- this.hooks[type + (metadata.always ? 'Always' : '')].push(test);
74
- return;
101
+ return result;
102
+ }
103
+ };
75
104
  }
76
-
77
- // add .only() tests if .only() was used previously
78
- if (this.hasExclusive && !metadata.exclusive) {
79
- return;
105
+ _emitTestResult(test) {
106
+ this.emit('test', test);
80
107
  }
108
+ _buildHooks(hooks, testTitle, context) {
109
+ return hooks.map(hook => {
110
+ const test = this._buildHook(hook, testTitle, context);
81
111
 
82
- if (metadata.exclusive && !this.hasExclusive) {
83
- this.tests.concurrent = [];
84
- this.tests.serial = [];
85
- this.hasExclusive = true;
86
- }
112
+ if (hook.metadata.skipped || hook.metadata.todo) {
113
+ return this._skippedTest(test);
114
+ }
87
115
 
88
- if (metadata.serial) {
89
- this.tests.serial.push(test);
90
- } else {
91
- this.tests.concurrent.push(test);
116
+ return test;
117
+ });
92
118
  }
93
- };
94
-
95
- TestCollection.prototype._skippedTest = function (test) {
96
- var self = this;
119
+ _buildHook(hook, testTitle, context) {
120
+ let title = hook.title;
97
121
 
98
- return {
99
- run: function () {
100
- var result = {
101
- passed: true,
102
- result: test
103
- };
104
-
105
- self._emitTestResult(result);
106
-
107
- return result;
122
+ if (testTitle) {
123
+ title += ` for ${testTitle}`;
108
124
  }
109
- };
110
- };
111
-
112
- TestCollection.prototype._emitTestResult = function (test) {
113
- this.emit('test', test);
114
- };
115
125
 
116
- TestCollection.prototype._buildHooks = function (hooks, testTitle, context) {
117
- return hooks.map(function (hook) {
118
- var test = this._buildHook(hook, testTitle, context);
119
-
120
- if (hook.metadata.skipped || hook.metadata.todo) {
121
- return this._skippedTest(test);
126
+ if (!context) {
127
+ context = null;
122
128
  }
123
129
 
124
- return test;
125
- }, this);
126
- };
127
-
128
- TestCollection.prototype._buildHook = function (hook, testTitle, context) {
129
- var title = hook.title;
130
+ const test = new Test(title, hook.fn, context, this._emitTestResult);
131
+ test.metadata = hook.metadata;
130
132
 
131
- if (testTitle) {
132
- title += ' for ' + testTitle;
133
- }
134
-
135
- if (!context) {
136
- context = null;
133
+ return test;
137
134
  }
135
+ _buildTest(test, context) {
136
+ if (!context) {
137
+ context = null;
138
+ }
138
139
 
139
- var test = new Test(title, hook.fn, context, this._emitTestResult);
140
- test.metadata = hook.metadata;
140
+ const metadata = test.metadata;
141
141
 
142
- return test;
143
- };
142
+ test = new Test(test.title, test.fn, context, this._emitTestResult);
143
+ test.metadata = metadata;
144
144
 
145
- TestCollection.prototype._buildTest = function (test, context) {
146
- if (!context) {
147
- context = null;
145
+ return test;
148
146
  }
147
+ _buildTestWithHooks(test) {
148
+ if (test.metadata.skipped) {
149
+ return new Sequence([this._skippedTest(this._buildTest(test))], true);
150
+ }
149
151
 
150
- var metadata = test.metadata;
151
-
152
- test = new Test(test.title, test.fn, context, this._emitTestResult);
153
- test.metadata = metadata;
152
+ const context = {context: {}};
154
153
 
155
- return test;
156
- };
154
+ const beforeHooks = this._buildHooks(this.hooks.beforeEach, test.title, context);
155
+ const afterHooks = this._buildHooks(this.hooks.afterEach, test.title, context);
157
156
 
158
- TestCollection.prototype._buildTestWithHooks = function (test) {
159
- if (test.metadata.skipped) {
160
- return new Sequence([this._skippedTest(this._buildTest(test))], true);
157
+ let sequence = new Sequence([].concat(beforeHooks, this._buildTest(test, context), afterHooks), true);
158
+ if (this.hooks.afterEachAlways.length > 0) {
159
+ const afterAlwaysHooks = new Sequence(this._buildHooks(this.hooks.afterEachAlways, test.title, context));
160
+ sequence = new Sequence([sequence, afterAlwaysHooks], false);
161
+ }
162
+ return sequence;
161
163
  }
164
+ _buildTests(tests) {
165
+ return tests.map(test => this._buildTestWithHooks(test));
166
+ }
167
+ build(bail) {
168
+ const beforeHooks = new Sequence(this._buildHooks(this.hooks.before));
169
+ const afterHooks = new Sequence(this._buildHooks(this.hooks.after));
162
170
 
163
- var context = {context: {}};
164
-
165
- var beforeHooks = this._buildHooks(this.hooks.beforeEach, test.title, context);
166
- var afterHooks = this._buildHooks(this.hooks.afterEach, test.title, context);
171
+ const serialTests = new Sequence(this._buildTests(this.tests.serial), bail);
172
+ const concurrentTests = new Concurrent(this._buildTests(this.tests.concurrent), bail);
173
+ const allTests = new Sequence([serialTests, concurrentTests]);
167
174
 
168
- var sequence = new Sequence([].concat(beforeHooks, this._buildTest(test, context), afterHooks), true);
169
- if (this.hooks.afterEachAlways.length !== 0) {
170
- var afterAlwaysHooks = new Sequence(this._buildHooks(this.hooks.afterEachAlways, test.title, context));
171
- sequence = new Sequence([sequence, afterAlwaysHooks], false);
172
- }
173
- return sequence;
174
- };
175
-
176
- TestCollection.prototype._buildTests = function (tests) {
177
- return tests.map(function (test) {
178
- return this._buildTestWithHooks(test);
179
- }, this);
180
- };
181
-
182
- TestCollection.prototype.build = function (bail) {
183
- var beforeHooks = new Sequence(this._buildHooks(this.hooks.before));
184
- var afterHooks = new Sequence(this._buildHooks(this.hooks.after));
185
-
186
- var serialTests = new Sequence(this._buildTests(this.tests.serial), bail);
187
- var concurrentTests = new Concurrent(this._buildTests(this.tests.concurrent), bail);
188
- var allTests = new Sequence([serialTests, concurrentTests]);
189
-
190
- var finalTests = new Sequence([beforeHooks, allTests, afterHooks], true);
191
- if (this.hooks.afterAlways.length !== 0) {
192
- var afterAlwaysHooks = new Sequence(this._buildHooks(this.hooks.afterAlways));
193
- finalTests = new Sequence([finalTests, afterAlwaysHooks], false);
175
+ let finalTests = new Sequence([beforeHooks, allTests, afterHooks], true);
176
+ if (this.hooks.afterAlways.length > 0) {
177
+ const afterAlwaysHooks = new Sequence(this._buildHooks(this.hooks.afterAlways));
178
+ finalTests = new Sequence([finalTests, afterAlwaysHooks], false);
179
+ }
180
+ return finalTests;
194
181
  }
195
- return finalTests;
196
- };
182
+ }
183
+
184
+ module.exports = TestCollection;