Skip to content

Commit

Permalink
Merge pull request #87 from gemini-testing/read-test-api
Browse files Browse the repository at this point in the history
add api for tests reading
  • Loading branch information
DudaGod authored Dec 10, 2016
2 parents 4b1e0fe + 507c58c commit aee7794
Show file tree
Hide file tree
Showing 9 changed files with 253 additions and 58 deletions.
22 changes: 18 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,16 @@ With the help of API you can use Hermione programmatically in your scripts or bu
const Hermione = require('hermione');

const hermione = new Hermione(config, allowOverrides);
```

* **config** (required) `String|Object` - path to configuration file which will be read relatively to `process.cwd` or [configuration object](#hermioneconfjs).
* **allowOverrides** (optional) `Object` - switch on/off [configuration override](#overriding-settings) via environment variables or cli options:
* **env** (optional) `Boolean` – switch on/off configuration override via environment variables. Default is `false`
* **cli** (optional) `Boolean` - switch on/off configuration override via cli options. Default is `false`

### run

```js
hermione.run(testPaths, options)
.then((success) => process.exit(success ? 0 : 1))
.catch((e) => {
Expand All @@ -596,16 +605,21 @@ hermione.run(testPaths, options)
.done();
```

* **config** (required) `String|Object` - path to configuration file which will be read relatively to `process.cwd` or [configuration object](#hermioneconfjs).
* **allowOverrides** (optional) `Object` - switch on/off [configuration override](#overriding-settings) via environment variables or cli options:
* **env** (optional) `Boolean` – switch on/off configuration override via environment variables. Default is `false`
* **cli** (optional) `Boolean` - switch on/off configuration override via cli options. Default is `false`
* **testPaths** (optional) `String[]` - paths to tests relatively to `process.cwd`
* **options** (optional) `Object`
* **reporters** (optional) `String[]` - test result reporters
* **browsers** (optional) `String[]` - browsers in which to run tests
* **grep** (optional) `RegExp` - pattern which indicates which tests to run

### readTests

```js
hermione.readTests(testPaths, browsers).done();
```

* **testPaths** (required) `String[]` - paths to tests relatively to `process.cwd`
* **browsers** (optional) `String[]` - read tests only for specified browsers

## Environment variables

### HERMIONE_SKIP_BROWSERS
Expand Down
7 changes: 7 additions & 0 deletions lib/hermione.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ module.exports = class Hermione {
.then(() => !this._failed);
}

readTests(testPaths, browsers) {
const runner = Runner.create(this._config);

return readTests(testPaths, browsers, this._config)
.then((tests) => runner.buildSuiteTree(tests));
}

_loadPlugins(runner) {
const hermioneFacade = HermioneFacade.create(runner, this._config);

Expand Down
13 changes: 10 additions & 3 deletions lib/runner/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,23 @@ module.exports = class MainRunner extends QEmitter {
}

run(tests) {
const anyTest = () => true;

return this.emitAndWait(RunnerEvents.RUNNER_START, this)
.then(() => this._runTestSession(tests, anyTest))
.then(() => this._runTestSession(tests))
.fin(() => {
return this.emitAndWait(RunnerEvents.RUNNER_END)
.catch(logger.warn);
});
}

buildSuiteTree(tests) {
return _.mapValues(tests, (files, browserId) => {
const browserAgent = BrowserAgent.create(browserId, this._pool);
const mochaRunner = MochaRunner.create(this._config, browserAgent, this._testSkipper);

return mochaRunner.buildSuiteTree(files);
});
}

_runTestSession(tests, filterFn) {
const _this = this;

Expand Down
13 changes: 9 additions & 4 deletions lib/runner/mocha-runner/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,25 @@ module.exports = class MochaRunner extends QEmitter {
const titles = {};

return _(suitePaths)
.map((path) => this._createMocha(path, filterFn, titles))
.map((path) => this._createMocha(path, titles, filterFn))
.map((mocha) => mocha.run())
.thru(utils.waitForResults)
.value();
}

_createMocha(suiteFile, filterFn, titles) {
buildSuiteTree(suitePaths) {
return this._createMocha(suitePaths, {}).suite;
}

_createMocha(suiteFiles, titles, filterFn) {
const mochaAdapter = MochaAdapter.create(this._sharedMochaOpts, this._browserAgent);
suiteFiles = [].concat(suiteFiles);

return mochaAdapter
.attachTestFilter(filterFn)
.attachTitleValidator(titles, suiteFile)
.attachTitleValidator(titles)
.applySkip(this._testSkipper)
.addFile(suiteFile)
.addFiles(suiteFiles)
.attachEmitFn(this.emit.bind(this));
}
};
18 changes: 11 additions & 7 deletions lib/runner/mocha-runner/mocha-adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,32 +47,36 @@ module.exports = class MochaAdapter {
return this;
}

addFile(file) {
clearRequire(path.resolve(file));
addFiles(files) {
files.forEach((file) => {
clearRequire(path.resolve(file));
this._mocha.addFile(file);
});

this._mocha.addFile(file);
this._mocha.loadFiles();
this._mocha.files = [];

return this;
}

attachTitleValidator(titles, suiteFile) {
this._addEventHandler(['test'], (runnable) => {
const fullTitle = runnable.fullTitle();
attachTitleValidator(titles) {
this._addEventHandler('test', (test) => {
const fullTitle = test.fullTitle();

if (titles[fullTitle]) {
throw new Error(`Cannot use tests with the same title: '${fullTitle}'` +
` in file: '${titles[fullTitle]}'`);
}

titles[fullTitle] = path.relative(process.cwd(), suiteFile);
titles[fullTitle] = path.relative(process.cwd(), test.file);
});

return this;
}

attachTestFilter(shouldRunTest) {
shouldRunTest = shouldRunTest || (() => true);

const browserId = this._browserAgent.browserId;

this._addEventHandler('test', (test) => shouldRunTest(test, browserId) || test.parent.tests.pop());
Expand Down
57 changes: 55 additions & 2 deletions test/lib/hermione.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ describe('hermione', () => {
});

sandbox.stub(Config, 'create').returns(makeConfigStub());
sandbox.stub(Runner, 'create').returns(sinon.createStubInstance(Runner));

sandbox.stub(pluginsLoader, 'load');
});

Expand Down Expand Up @@ -58,6 +56,8 @@ describe('hermione', () => {
});

describe('run', () => {
beforeEach(() => sandbox.stub(Runner, 'create').returns(sinon.createStubInstance(Runner)));

const stubRunner = (runFn) => {
const runner = new EventEmitter();

Expand Down Expand Up @@ -187,4 +187,57 @@ describe('hermione', () => {
});
});
});

describe('readTests', () => {
beforeEach(() => sandbox.stub(Runner.prototype, 'buildSuiteTree'));

it('should create runner with specified config', () => {
const config = makeConfigStub();
const createRunner = sandbox.spy(Runner, 'create');
Config.create.returns(config);

return Hermione
.create(config)
.readTests()
.then(() => {
assert.calledOnce(createRunner);
assert.calledWith(createRunner, config);
});
});

it('should read test files using specified paths, browsers and config', () => {
const config = makeConfigStub();
Config.create.returns(config);

return Hermione
.create(config)
.readTests(['some/path'], ['bro1', 'bro2'])
.then(() => assert.calledWith(testsReader, ['some/path'], ['bro1', 'bro2'], config));
});

it('should build suite tree using tests', () => {
const config = makeConfigStub();
Config.create.returns(config);

testsReader.returns(q(['some/path/file.js']));

return Hermione
.create(config)
.readTests()
.then(() => {
assert.calledOnce(Runner.prototype.buildSuiteTree);
assert.calledWith(Runner.prototype.buildSuiteTree, ['some/path/file.js']);
});
});

it('should return suite tree for specified browsers', () => {
const suiteTreeStub = {};
Runner.prototype.buildSuiteTree.returns({bro: suiteTreeStub});

return Hermione
.create()
.readTests()
.then((suiteTree) => assert.deepEqual(suiteTree, {bro: suiteTreeStub}));
});
});
});
61 changes: 49 additions & 12 deletions test/lib/runner/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,19 +140,9 @@ describe('Runner', () => {
});
});

it('should run mocha runner with passed tests and filter function', () => {
it('should run mocha runner with passed tests', () => {
return run_({files: ['test1', 'test2']})
.then(() => {
assert.calledWith(MochaRunner.prototype.run, ['test1', 'test2'], sinon.match.func);
});
});

it('should not filter out any test by default', () => {
return run_()
.then(() => {
const filterFn = MochaRunner.prototype.run.firstCall.args[1];
assert.isTrue(filterFn());
});
.then(() => assert.calledWith(MochaRunner.prototype.run, ['test1', 'test2']));
});

it('should wait until all mocha runners will finish', () => {
Expand Down Expand Up @@ -335,4 +325,51 @@ describe('Runner', () => {
});
});
});

describe('buildSuiteTree', () => {
beforeEach(() => {
sandbox.stub(MochaRunner.prototype, 'buildSuiteTree');
sandbox.stub(BrowserAgent, 'create').returns(sinon.createStubInstance(BrowserAgent));
});

it('should create browser agent for each browser', () => {
const runner = new Runner(makeConfigStub());

runner.buildSuiteTree({bro1: [], bro2: []});

assert.calledTwice(BrowserAgent.create);
assert.calledWith(BrowserAgent.create, 'bro1');
assert.calledWith(BrowserAgent.create, 'bro2');
assert.calledWith(BrowserAgent.create, sinon.match.any, sinon.match.instanceOf(BrowserPool));
});

it('should create mocha runner with the specified config and browser agent', () => {
const config = makeConfigStub();
const runner = new Runner(config);
const createMochaRunner = sinon.spy(MochaRunner, 'create');

runner.buildSuiteTree({bro: []});

assert.calledWith(createMochaRunner, config, sinon.match.instanceOf(BrowserAgent), sinon.match.instanceOf(TestSkipper));
});

it('should assign suite tree from mocha runner to passed browsers', () => {
const config = makeConfigStub();
const runner = new Runner(config);
const suiteTreeStub = sandbox.stub();
MochaRunner.prototype.buildSuiteTree.returns(suiteTreeStub);

const suiteTree = runner.buildSuiteTree({bro: []});

assert.deepEqual(suiteTree, {bro: suiteTreeStub});
});

it('should build suite tree for each set of files', () => {
const runner = new Runner(makeConfigStub());

runner.buildSuiteTree({bro: ['some/path/file1.js', 'other/path/file2.js']});

assert.calledWith(MochaRunner.prototype.buildSuiteTree, ['some/path/file1.js', 'other/path/file2.js']);
});
});
});
Loading

0 comments on commit aee7794

Please sign in to comment.