diff --git a/lib/reporters/html/view-model.js b/lib/reporters/html/view-model.js
index 89e0ce2f6..080237181 100644
--- a/lib/reporters/html/view-model.js
+++ b/lib/reporters/html/view-model.js
@@ -123,6 +123,7 @@ module.exports = class ViewModel {
const suite = result.suite;
const metaInfo = suite ? suite.metaInfo : {};
metaInfo.sessionId = result.sessionId || 'unknown session id';
+ metaInfo.file = suite.file;
const testResult = _.assign({
suiteUrl: rootUrl + suite.url,
diff --git a/lib/suite.js b/lib/suite.js
index 9198d3226..200b27581 100644
--- a/lib/suite.js
+++ b/lib/suite.js
@@ -24,6 +24,7 @@ module.exports = class Suite {
this.afterActions = [];
this.browsers = [];
this.context = {};
+ this.file = null;
definePrivate(this);
}
diff --git a/lib/test-reader.js b/lib/test-reader.js
index 13b958196..ddeba9f59 100644
--- a/lib/test-reader.js
+++ b/lib/test-reader.js
@@ -1,6 +1,7 @@
'use strict';
const _ = require('lodash');
+const path = require('path');
const SetsBuilder = require('gemini-core').SetsBuilder;
const Suite = require('./suite');
const Events = require('./constants/events');
@@ -9,15 +10,17 @@ const utils = require('./utils');
const DEFAULT_DIR = require('../package').name;
-const loadSuites = (sets, emitter) => {
+const loadSuites = (sets, emitter, projectRoot) => {
const rootSuite = Suite.create('');
- _.forEach(sets.groupByFile(), (browsers, path) => {
- global.gemini = testsApi(rootSuite, browsers);
+ _.forEach(sets.groupByFile(), (browsers, filePath) => {
+ const relativeFilePath = path.relative(projectRoot, filePath);
- emitter.emit(Events.BEFORE_FILE_READ, path);
- utils.requireWithNoCache(path);
- emitter.emit(Events.AFTER_FILE_READ, path);
+ global.gemini = testsApi(rootSuite, browsers, relativeFilePath);
+
+ emitter.emit(Events.BEFORE_FILE_READ, filePath);
+ utils.requireWithNoCache(filePath);
+ emitter.emit(Events.AFTER_FILE_READ, filePath);
delete global.gemini;
});
@@ -32,5 +35,5 @@ module.exports = (emitter, config, opts) => {
.useFiles(opts.paths)
.useBrowsers(opts.browsers)
.build(config.system.projectRoot, {ignore: config.system.exclude})
- .then((setCollection) => loadSuites(setCollection, emitter));
+ .then((setCollection) => loadSuites(setCollection, emitter, config.system.projectRoot));
};
diff --git a/lib/tests-api/index.js b/lib/tests-api/index.js
index 40912d62f..c8b59b539 100644
--- a/lib/tests-api/index.js
+++ b/lib/tests-api/index.js
@@ -4,7 +4,7 @@ const Suite = require('../suite');
const SuiteBuilder = require('./suite-builder');
const keysCodes = require('./keys-codes');
-module.exports = (suite, browsers) => {
+module.exports = (suite, browsers, file) => {
let suiteId = 1;
const testsAPI = keysCodes;
@@ -25,9 +25,17 @@ module.exports = (suite, browsers) => {
suite = Suite.create(name, parent);
parent.addChild(suite);
suite.id = suiteId++;
- if (browsers && suite.parent.isRoot) {
- suite.browsers = browsers;
+
+ if (suite.parent.isRoot) {
+ if (browsers) {
+ suite.browsers = browsers;
+ }
+
+ if (file) {
+ suite.file = file;
+ }
}
+
callback(new SuiteBuilder(suite));
if (suite.hasStates) {
if (!suite.url) {
diff --git a/test/unit/reporters/html/view-model.js b/test/unit/reporters/html/view-model.js
new file mode 100644
index 000000000..1a1324d97
--- /dev/null
+++ b/test/unit/reporters/html/view-model.js
@@ -0,0 +1,38 @@
+'use strict';
+
+const _ = require('lodash');
+
+const ViewModel = require('lib/reporters/html/view-model');
+
+describe('ViewModel', () => {
+ const sandbox = sinon.sandbox.create();
+ const stubTest_ = (opts) => {
+ opts = opts || {};
+
+ return _.defaultsDeep(opts, {
+ state: {name: 'name-default'},
+ suite: {
+ path: ['suite'],
+ metaInfo: {sessionId: 'sessionId-default'},
+ file: 'default/path/file.js'
+ }
+ });
+ };
+ const getResult_ = (model) => model.getResult().suites[0].children[0].browsers[0].result;
+ const createViewModel_ = () =>{
+ const config = {forBrowser: sandbox.stub().returns({})};
+ return new ViewModel(config);
+ };
+
+ it('should contain "file" in "metaInfo"', () => {
+ const model = createViewModel_();
+
+ model.addSuccess(stubTest_({
+ suite: {file: '/path/file.js'}
+ }));
+
+ const metaInfo = JSON.parse(getResult_(model).metaInfo);
+
+ assert.equal(metaInfo.file, '/path/file.js');
+ });
+});
diff --git a/test/unit/test-reader.js b/test/unit/test-reader.js
index 2c05617e2..e9aab9c42 100644
--- a/test/unit/test-reader.js
+++ b/test/unit/test-reader.js
@@ -135,6 +135,19 @@ describe('test-reader', () => {
);
});
});
+
+ it('should call "testsApi" with relative file path', () => {
+ const groupByFile = () => ({'/project/root/path/file1.js': []});
+
+ const config = mkConfigStub({
+ system: {projectRoot: '/project/root'}
+ });
+
+ SetsBuilder.prototype.build.returns(Promise.resolve({groupByFile}));
+
+ return readTests_({config})
+ .then(() => assert.calledWith(testsApi, sinon.match.any, sinon.match.any, 'path/file1.js'));
+ });
});
describe('global "gemini" variable', () => {
diff --git a/test/unit/tests-api/index.js b/test/unit/tests-api/index.js
index dc2f885bc..347f01568 100644
--- a/test/unit/tests-api/index.js
+++ b/test/unit/tests-api/index.js
@@ -1,58 +1,54 @@
'use strict';
-var testsAPI = require('lib/tests-api'),
- Suite = require('lib/suite');
+const testsAPI = require('lib/tests-api');
+const Suite = require('lib/suite');
-describe('tests-api', function() {
- beforeEach(function() {
- this.suite = Suite.create('');
+describe('tests-api', () => {
+ let rootSuite;
+
+ beforeEach(() => {
+ rootSuite = Suite.create('');
});
- describe('.suite method', function() {
- var gemini;
+ describe('.suite method', () => {
+ let gemini;
- beforeEach(function() {
- gemini = testsAPI(this.suite);
+ beforeEach(() => {
+ gemini = testsAPI(rootSuite);
});
- it('should throw an error if first argument is not a string', function() {
- assert.throws(function() {
- gemini.suite(123, function() {});
- }, TypeError);
+ it('should throw an error if first argument is not a string', () => {
+ assert.throws(() => gemini.suite(123, () => {}), TypeError);
});
- it('should throw an error if second argument is not a function', function() {
- assert.throws(function() {
- gemini.suite('name');
- }, TypeError);
+ it('should throw an error if second argument is not a function', () => {
+ assert.throws(() => gemini.suite('name'), TypeError);
});
- it('should create new suite with corresponding name', function() {
- gemini.suite('name', function() {});
+ it('should create new suite with corresponding name', () => {
+ gemini.suite('name', () => {});
- assert.equal(this.suite.children[0].name, 'name');
+ assert.equal(rootSuite.children[0].name, 'name');
});
- it('should call callback', function() {
- var spy = sinon.spy();
+ it('should call callback', () => {
+ const spy = sinon.spy();
gemini.suite('name', spy);
assert.called(spy);
});
- it('should created nested suites when called nestedly', function() {
- gemini.suite('name', function() {
- gemini.suite('child', function() {});
- });
+ it('should created nested suites when called nestedly', () => {
+ gemini.suite('name', () => gemini.suite('child', () => {}));
- assert.equal(this.suite.children[0].children[0].name, 'child');
+ assert.equal(rootSuite.children[0].children[0].name, 'child');
});
describe('child suites of the same name', () => {
- beforeEach(function() {
- gemini = testsAPI(this.suite, ['browser1']);
+ beforeEach(() => {
+ gemini = testsAPI(rootSuite, ['browser1']);
});
- it('should not allow to create with intersect browsers', function() {
+ it('should not allow to create with intersect browsers', () => {
assert.throws(() => {
gemini.suite('name', () => {
gemini.suite('child', () => {});
@@ -61,12 +57,10 @@ describe('tests-api', function() {
});
});
- it('should allow to create with not intersecting browser sets', function() {
- gemini.suite('name', () => {
- gemini.suite('child', () => {});
- });
+ it('should allow to create with not intersecting browser sets', () => {
+ gemini.suite('name', () => gemini.suite('child', () => {}));
- gemini = testsAPI(this.suite, ['browser2']);
+ gemini = testsAPI(rootSuite, ['browser2']);
assert.doesNotThrow(() => {
gemini.suite('name', () => {
@@ -76,35 +70,35 @@ describe('tests-api', function() {
});
});
- it('should create non-nested suite at the root level', function() {
- gemini.suite('first', function() {});
- gemini.suite('second', function() {});
+ it('should create non-nested suite at the root level', () => {
+ gemini.suite('first', () => {});
+ gemini.suite('second', () => {});
- assert.equal(this.suite.children[1].name, 'second');
+ assert.equal(rootSuite.children[1].name, 'second');
});
- it('should throw when suite has states but does not has URL', function() {
- assert.throws(function() {
- gemini.suite('first', function(suite) {
+ it('should throw when suite has states but does not has URL', () => {
+ assert.throws(() => {
+ gemini.suite('first', (suite) => {
suite.setCaptureElements('.element')
.capture('plain');
});
});
});
- it('should throw when suite has no states nor URL', function() {
- assert.doesNotThrow(function() {
- gemini.suite('first', function(suite) {
+ it('should throw when suite has no states nor URL', () => {
+ assert.doesNotThrow(() => {
+ gemini.suite('first', (suite) => {
suite.setCaptureElements('.element');
});
});
});
- it('should not throw when suite has states and url is inherited from parent', function() {
- assert.doesNotThrow(function() {
- gemini.suite('first', function(suite) {
+ it('should not throw when suite has states and url is inherited from parent', () => {
+ assert.doesNotThrow(() => {
+ gemini.suite('first', (suite) => {
suite.setUrl('/url');
- gemini.suite('child', function(suite) {
+ gemini.suite('child', (suite) => {
suite.setCaptureElements('.element')
.capture('plain');
});
@@ -112,28 +106,28 @@ describe('tests-api', function() {
});
});
- it('should throw if suite has states but does not has captureSelectors', function() {
- assert.throws(function() {
- gemini.suite('first', function(suite) {
+ it('should throw if suite has states but does not has captureSelectors', () => {
+ assert.throws(() => {
+ gemini.suite('first', (suite) => {
suite.setUrl('/url')
.capture('plain');
});
});
});
- it('should not throw if suite has no states nor captureSelectors', function() {
- assert.doesNotThrow(function() {
- gemini.suite('first', function(suite) {
+ it('should not throw if suite has no states nor captureSelectors', () => {
+ assert.doesNotThrow(() => {
+ gemini.suite('first', (suite) => {
suite.setUrl('/url');
});
});
});
- it('should not throw when suite has states and captureSelectors are inherited from parent', function() {
- assert.doesNotThrow(function() {
- gemini.suite('first', function(suite) {
+ it('should not throw when suite has states and captureSelectors are inherited from parent', () => {
+ assert.doesNotThrow(() => {
+ gemini.suite('first', (suite) => {
suite.setCaptureElements('.element');
- gemini.suite('child', function(suite) {
+ gemini.suite('child', (suite) => {
suite.setUrl('/url')
.capture('plain');
});
@@ -141,58 +135,83 @@ describe('tests-api', function() {
});
});
- it('should assign suite ids', function() {
- gemini.suite('suite', function() {});
- assert.equal(this.suite.children[0].id, 1);
+ it('should assign suite ids', () => {
+ gemini.suite('suite', () => {});
+ assert.equal(rootSuite.children[0].id, 1);
});
- it('should assign incrementing suite ids for following suites', function() {
- gemini.suite('suite', function() {});
- gemini.suite('suite2', function() {});
- assert.equal(this.suite.children[1].id, 2);
+ it('should assign incrementing suite ids for following suites', () => {
+ gemini.suite('suite', () => {});
+ gemini.suite('suite2', () => {});
+ assert.equal(rootSuite.children[1].id, 2);
});
- it('should assign incrementing suite ids for child suites', function() {
- gemini.suite('suite', function() {
- gemini.suite('suite2', function() {});
+ it('should assign incrementing suite ids for child suites', () => {
+ gemini.suite('suite', () => {
+ gemini.suite('suite2', () => {});
});
- assert.equal(this.suite.children[0].children[0].id, 2);
+ assert.equal(rootSuite.children[0].children[0].id, 2);
});
- it('should assign child suite ids before siblings', function() {
- gemini.suite('suite', function() {
- gemini.suite('suite2', function() {});
+ it('should assign child suite ids before siblings', () => {
+ gemini.suite('suite', () => {
+ gemini.suite('suite2', () => {});
});
- gemini.suite('suite3', function() {});
+ gemini.suite('suite3', () => {});
+
+ assert.equal(rootSuite.children[0].children[0].id, 2);
+ assert.equal(rootSuite.children[1].id, 3);
+ });
+ });
+
+ describe('browsers', () => {
+ const browsers = ['some-browser', 'other-browser'];
+ let gemini;
+
+ beforeEach(() => {
+ gemini = testsAPI(rootSuite, browsers);
+ });
+
+ it('should be set for top level suite', () => {
+ gemini.suite('suite', () => {});
+
+ assert.equal(rootSuite.children[0].browsers, browsers);
+ assert.isTrue(rootSuite.children[0].hasOwnProperty('browsers'));
+ });
+
+ it('should not be set for not top level suite', () => {
+ gemini.suite('suite', () => {
+ gemini.suite('child', () => {});
+ });
- assert.equal(this.suite.children[0].children[0].id, 2);
- assert.equal(this.suite.children[1].id, 3);
+ assert.equal(rootSuite.children[0].children[0].browsers, browsers);
+ assert.isFalse(rootSuite.children[0].children[0].hasOwnProperty('browsers'));
});
});
- describe('browsers', function() {
- var browsers = ['some-browser', 'other-browser'],
- gemini;
+ describe('file path', () => {
+ const file = 'path/file.js';
+ let gemini;
- beforeEach(function() {
- gemini = testsAPI(this.suite, browsers);
+ beforeEach(() => {
+ gemini = testsAPI(rootSuite, [], file);
});
- it('should be set for top level suite', function() {
- gemini.suite('suite', function() {});
+ it('should be set for suite', () => {
+ gemini.suite('suite', () => {});
- assert.equal(this.suite.children[0].browsers, browsers);
- assert.isTrue(this.suite.children[0].hasOwnProperty('browsers'));
+ assert.equal(rootSuite.children[0].file, file);
+ assert.isTrue(rootSuite.children[0].hasOwnProperty('file'));
});
- it('should not be set for not top level suite', function() {
- gemini.suite('suite', function() {
- gemini.suite('child', function() {});
+ it('should not be set for not top level suite', () => {
+ gemini.suite('suite', () => {
+ gemini.suite('child', () => {});
});
- assert.equal(this.suite.children[0].children[0].browsers, browsers);
- assert.isFalse(this.suite.children[0].children[0].hasOwnProperty('browsers'));
+ assert.equal(rootSuite.children[0].children[0].file, file);
+ assert.isFalse(rootSuite.children[0].children[0].hasOwnProperty('file'));
});
});
});