Skip to content

Commit 51f0d66

Browse files
authored
Merge pull request #437 from choheekim/enhance-metadata-file
This pr is equivalent to #380
2 parents e685407 + 699cdfa commit 51f0d66

File tree

9 files changed

+173
-66
lines changed

9 files changed

+173
-66
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ It creates a json file, `module-metadata-<timestamp>.json`, which contains an ar
155155
{
156156
"name": "Module-name",
157157
"total": "Total number of tests in the module",
158-
"runtime": "ms in Total duration to execute the module"
158+
"duration": "ms in Total duration to execute the module"
159159
}
160160
]
161161
```
@@ -166,12 +166,12 @@ and it looks something like below:
166166
{
167167
"name": "Slowest Module",
168168
"total": 12,
169-
"runtime": 2159
169+
"duration": 2159
170170
},
171171
{
172172
"name": "Fastest Module",
173173
"total": 9,
174-
"runtime": 125
174+
"duration": 125
175175
}
176176
]
177177
```

addon-test-support/-private/ember-exam-qunit-test-loader.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,12 @@ export default class EmberExamQUnitTestLoader extends TestLoader {
123123
* setupModuleMetadataHandler() register QUnit callback to enable generating module metadata file.
124124
*/
125125
setupModuleMetadataHandler() {
126-
this._qunit.moduleDone((metadata) => {
127-
// testem:module-done-metadata is sent to server to keep track of test module details.
128-
// 'metadata' contains module name, total number of assertion ran in the module, and module runtime.
126+
this._qunit.testDone((metadata) => {
129127
if (typeof this._testem !== 'undefined' && this._testem !== null) {
130-
this._testem.emit('testem:module-done-metadata', metadata);
128+
// testem:test-done-metadata is sent to server to track test module details.
129+
// metadata contains name, module, failed, passed, total, duration, skipped, and todo.
130+
// https://api.qunitjs.com/callbacks/QUnit.testDone
131+
this._testem.emit('testem:test-done-metadata', metadata);
131132
}
132133
});
133134
}

lib/commands/exam.js

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -378,18 +378,20 @@ module.exports = TestCommand.extend({
378378
browserTerminationHandler.bind(this)();
379379
}
380380

381-
events['testem:module-done-metadata'] = (details) => {
381+
events['testem:test-done-metadata'] = (details) => {
382382
// Ensure module detail is available
383383
if (typeof details === 'object' && details !== null) {
384-
this.testemEvents.recordModuleMetaData(
384+
//store module name, test name, # of failed assertion, and duration.
385+
this.testemEvents.recordModuleMetadata(
385386
{
386-
name: details.name,
387-
total: details.total,
388-
runtime: details.runtime
387+
moduleName: details.module,
388+
testName: details.name,
389+
failed: (details.failed > 0),
390+
duration: details.runtime
389391
}
390-
);
392+
)
391393
}
392-
};
394+
}
393395

394396
return events;
395397
},

lib/utils/execution-state-manager.js

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77
*/
88
class ExecutionStateManager {
99
constructor(replayExecutionMap) {
10-
// A map of browerId to test modules executed on that browser read from test-execution.json.
10+
// A map of browserId to test modules executed on that browser read from test-execution.json.
1111
this._replayExecutionMap = replayExecutionMap || null;
1212

13-
// A map of browerId to test modules executed for the current test execution.
13+
// A map of browserId to test modules executed for the current test execution.
1414
this._browserToModuleMap = new Map();
1515

16-
// An array keeping the module execution details
17-
this._moduleMetadata = [];
16+
// A map keeping the module execution details
17+
this._moduleMetadata = new Map();
1818

1919
// An array keeping the browserId of a browser with failing test
2020
this._failedBrowsers = [];
@@ -161,6 +161,7 @@ class ExecutionStateManager {
161161
return this._moduleMetadata;
162162
}
163163

164+
164165
/**
165166
* Pushes the moduleName into the moduleArray of browserId
166167
*
@@ -177,13 +178,54 @@ class ExecutionStateManager {
177178
this._browserToModuleMap.set(browserId, browserModuleList);
178179
}
179180

181+
/**
182+
* Add module metadata mapped by moduleName to moduleMetadata Map.
183+
*
184+
* @param {string} moduleName
185+
* @param {number} total - Total number of tests
186+
* @param {number} passed - Number of passed tests
187+
* @param {number} failed - Number of failed tests
188+
* @param {number} duration - duration to execute tests in module in ms
189+
* @param {Array<string>} failedTests - A list of failed test names
190+
*/
191+
_injectModuleMetadata(moduleName, total, passed, failed, duration, failedTests) {
192+
this._moduleMetadata.set(
193+
moduleName,
194+
{
195+
moduleName,
196+
total,
197+
passed,
198+
failed,
199+
duration,
200+
failedTests
201+
}
202+
);
203+
}
204+
180205
/**
181206
* Pushes the module detail into the moduleMetadata array
182207
*
183-
* @param {*} metaData
208+
* @param {Object} metaData
184209
*/
185-
addToModuleMetadata(metaData) {
186-
return this._moduleMetadata.push(metaData);
210+
addToModuleMetadata(metadata) {
211+
if (!this._moduleMetadata.has(metadata.moduleName)) {
212+
this._injectModuleMetadata(metadata.moduleName, 0, 0, 0, 0, []);
213+
}
214+
215+
const curModuleMetadata = this._moduleMetadata.get(metadata.moduleName);
216+
217+
if (metadata.failed) {
218+
curModuleMetadata.failedTests.push(metadata.testName);
219+
}
220+
221+
this._injectModuleMetadata(
222+
metadata.moduleName,
223+
curModuleMetadata.total + 1,
224+
( metadata.failed ? curModuleMetadata.passed : curModuleMetadata.passed + 1),
225+
( metadata.failed ? curModuleMetadata.failed + 1 : curModuleMetadata.failed),
226+
curModuleMetadata.duration + metadata.duration,
227+
curModuleMetadata.failedTests
228+
);
187229
}
188230

189231
/**

lib/utils/testem-events.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ const ExecutionStateManager = require('./execution-state-manager');
66
const writeJsonToFile = require('./file-system-helper');
77

88
/**
9-
* Return sorted module metadata object by module runtime.
9+
* Return sorted module metadata object by module duration.
1010
*
11-
* @param {Object} moduleMetadata
11+
* @param {Map} moduleMetadata
1212
*/
1313
function getSortedModuleMetaData(moduleMetadata) {
14-
return moduleMetadata.slice().sort((a, b) => b.runtime - a.runtime );
14+
return new Map([...moduleMetadata.entries()].sort((a, b) => b[1].duration - a[1].duration));
1515
}
1616

1717
/**
@@ -136,7 +136,7 @@ class TestemEvents {
136136
*
137137
* @param {Object} metaData
138138
*/
139-
recordModuleMetaData(metaData) {
139+
recordModuleMetadata(metaData) {
140140
this.stateManager.addToModuleMetadata(metaData);
141141
}
142142

@@ -190,16 +190,16 @@ class TestemEvents {
190190
const moduleDetailFileName = path.join(this.root, `module-metadata-${currentDate}.json`);
191191
const sortedModuleMetadata = getSortedModuleMetaData(this.stateManager.getModuleMetadata());
192192

193-
writeJsonToFile(moduleDetailFileName, sortedModuleMetadata, { spaces: 2 });
194-
ui.writeLine(`\nThis execution module details was recorded at ${moduleDetailFileName}`);
193+
writeJsonToFile(moduleDetailFileName, Array.from(sortedModuleMetadata.values()),{ spaces: 2 });
194+
ui.writeLine(`\nExecution module details were recorded at ${moduleDetailFileName}`);
195195
}
196196

197197
if (commands.get('writeExecutionFile') && commands.get('loadBalance')) {
198198
const moduleMapJson = this._generatesModuleMapJsonObject(browserCount);
199199
const testExecutionPath = path.join(this.root, `test-execution-${currentDate}.json`);
200200

201201
writeJsonToFile(testExecutionPath, moduleMapJson, { spaces: 2 });
202-
ui.writeLine(`\nThis execution was recorded at ${testExecutionPath}`);
202+
ui.writeLine(`\nExecution was recorded at ${testExecutionPath}`);
203203
}
204204

205205
// --server mode allows rerun of tests by refreshing the browser

node-tests/unit/utils/execution-state-manager-test.js

Lines changed: 68 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -100,35 +100,89 @@ describe('ExecutionStateManager', function() {
100100
});
101101

102102
describe('moduleRunDetails', function() {
103-
// test addModuleDoneDetailToModuleRunDetails
104-
it('returns an empty array', function() {
103+
it('returns a map size of 0', function() {
105104
assert.equal(
106-
this.stateManager.getModuleMetadata().length,
105+
this.stateManager.getModuleMetadata().size,
107106
0
108107
);
109108
});
110109

111-
it('adds module detail to moduleMetadata', function() {
110+
it('adds a single testDone module metadata to moduleMetadata.', function() {
111+
const testModuleName = 'foo';
112112
const moduleMetadata = {
113-
name: 'foo',
114-
total: 1,
115-
runtime: 1
113+
moduleName: testModuleName,
114+
testName: 'testing foo',
115+
failed: 0,
116+
duration: 1
116117
};
117118

118119
this.stateManager.addToModuleMetadata(moduleMetadata);
119120

121+
const fooModuleMetadata = this.stateManager
122+
.getModuleMetadata()
123+
.get(testModuleName);
124+
125+
assert.equal(
126+
fooModuleMetadata.passed,
127+
1
128+
);
129+
assert.equal(
130+
fooModuleMetadata.failed,
131+
0
132+
);
133+
assert.equal(
134+
fooModuleMetadata.duration,
135+
1
136+
);
137+
assert.equal(
138+
fooModuleMetadata.failedTests.length,
139+
0
140+
);
141+
});
142+
143+
it('adds two test metadata and returns cumulative module data', function() {
144+
const fooTestModule = 'foo';
145+
const fooTestMetadata = {
146+
moduleName: fooTestModule,
147+
testName: 'testing foo',
148+
failed: 0,
149+
duration: 1
150+
};
151+
152+
const barTestMetadata = {
153+
moduleName: fooTestModule,
154+
testName: 'testing bar',
155+
failed: 1,
156+
duration: 1.8
157+
};
158+
159+
this.stateManager.addToModuleMetadata(fooTestMetadata);
160+
this.stateManager.addToModuleMetadata(barTestMetadata);
161+
162+
const fooModuleMetadata = this.stateManager
163+
.getModuleMetadata()
164+
.get(fooTestModule);
165+
166+
assert.equal(
167+
fooModuleMetadata.total,
168+
2
169+
);
120170
assert.equal(
121-
this.stateManager.getModuleMetadata()[0].name,
122-
moduleMetadata.name
171+
fooModuleMetadata.passed,
172+
1
123173
);
124174
assert.equal(
125-
this.stateManager.getModuleMetadata()[0].total,
126-
moduleMetadata.total
175+
fooModuleMetadata.failed,
176+
1
127177
);
128178
assert.equal(
129-
this.stateManager.getModuleMetadata()[0].runtime,
130-
moduleMetadata.runtime
179+
fooModuleMetadata.duration,
180+
2.8
131181
);
132-
})
182+
assert.equal(
183+
fooModuleMetadata.failedTests.length,
184+
1
185+
);
186+
});
133187
})
134188
});

node-tests/unit/utils/testem-events-test.js

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ describe('TestemEvents', function() {
223223
});
224224

225225
it('should write module-run-details file and cleanup state when completedBrowsers equals browserCount, load-balance is true, and write-execution-file is false', function() {
226-
this.testemEvents.stateManager.addToModuleMetadata({ name: 'a', total: 1, runtime: 1});
226+
this.testemEvents.stateManager.addToModuleMetadata({ moduleName: 'a', testName: 'test', failed: false, duration: 1});
227227
this.testemEvents.completedBrowsersHandler(
228228
1,
229229
1,
@@ -239,17 +239,23 @@ describe('TestemEvents', function() {
239239
path.join(fixtureDir, 'module-metadata-0000.json')
240240
);
241241

242-
assert.deepEqual(JSON.parse(actual), [{
243-
name: 'a',
244-
total: 1,
245-
runtime: 1
246-
}]);
242+
assert.deepEqual(JSON.parse(actual), [
243+
{
244+
moduleName: 'a',
245+
total: 1,
246+
passed: 1,
247+
failed: 0,
248+
duration: 1,
249+
failedTests: []
250+
}
251+
]);
247252
});
248253

249-
it('should write module-run-details file with sorted by runtime', function() {
250-
this.testemEvents.stateManager.addToModuleMetadata({ name: 'foo', total: 1, runtime: 1});
251-
this.testemEvents.stateManager.addToModuleMetadata({ name: 'bar', total: 4, runtime: 8});
252-
this.testemEvents.stateManager.addToModuleMetadata({ name: 'baz', total: 2, runtime: 2});
254+
it('should write module-run-details file with sorted by duration', function() {
255+
this.testemEvents.stateManager.addToModuleMetadata({ moduleName: 'a', testName: 'test 1', failed: false, duration: 1});
256+
this.testemEvents.stateManager.addToModuleMetadata({ moduleName: 'a', testName: 'test 2', failed: true, duration: 8});
257+
this.testemEvents.stateManager.addToModuleMetadata({ moduleName: 'b', testName: 'test 1', failed: false, duration: 1});
258+
253259

254260
this.testemEvents.completedBrowsersHandler(
255261
1,
@@ -268,20 +274,21 @@ describe('TestemEvents', function() {
268274

269275
assert.deepEqual(JSON.parse(actual), [
270276
{
271-
name: 'bar',
272-
total: 4,
273-
runtime: 8
274-
},
275-
{
276-
name: 'baz',
277+
moduleName: 'a',
277278
total: 2,
278-
runtime: 2
279+
passed: 1,
280+
failed: 1,
281+
duration: 9,
282+
failedTests: ['test 2']
279283
},
280284
{
281-
name: 'foo',
285+
moduleName: 'b',
282286
total: 1,
283-
runtime: 1
284-
},
287+
passed: 1,
288+
failed: 0,
289+
duration: 1,
290+
failedTests: []
291+
}
285292
]);
286293
});
287294

0 commit comments

Comments
 (0)