213 lines
5 KiB
TypeScript
213 lines
5 KiB
TypeScript
|
|
/**
|
||
|
|
* Copyright Microsoft Corporation. All rights reserved.
|
||
|
|
*
|
||
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
|
* you may not use this file except in compliance with the License.
|
||
|
|
* You may obtain a copy of the License at
|
||
|
|
*
|
||
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
|
*
|
||
|
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
|
* See the License for the specific language governing permissions and
|
||
|
|
* limitations under the License.
|
||
|
|
*/
|
||
|
|
|
||
|
|
import Mocha from 'mocha';
|
||
|
|
import { fixturesUI } from './fixturesUI';
|
||
|
|
import { EventEmitter } from 'events';
|
||
|
|
|
||
|
|
export type Configuration = { name: string, value: string }[];
|
||
|
|
|
||
|
|
export class Test {
|
||
|
|
suite: Suite;
|
||
|
|
title: string;
|
||
|
|
file: string;
|
||
|
|
only = false;
|
||
|
|
pending = false;
|
||
|
|
duration = 0;
|
||
|
|
timeout = 0;
|
||
|
|
fn: Function;
|
||
|
|
|
||
|
|
_ordinal: number;
|
||
|
|
_configurationObject: Configuration;
|
||
|
|
_configurationString: string;
|
||
|
|
_overriddenFn: Function;
|
||
|
|
_impl: any;
|
||
|
|
|
||
|
|
constructor(title: string, fn: Function) {
|
||
|
|
this.title = title;
|
||
|
|
this.fn = fn;
|
||
|
|
}
|
||
|
|
|
||
|
|
_materialize(overriddenFn: Function) {
|
||
|
|
this._impl = new Mocha.Test(this.title, overriddenFn);
|
||
|
|
this._impl.pending = this.pending;
|
||
|
|
}
|
||
|
|
|
||
|
|
clone(): Test {
|
||
|
|
const test = new Test(this.title, this.fn);
|
||
|
|
test.suite = this.suite;
|
||
|
|
test.only = this.only;
|
||
|
|
test.file = this.file;
|
||
|
|
test.pending = this.pending;
|
||
|
|
test.timeout = this.timeout;
|
||
|
|
test._overriddenFn = this._overriddenFn;
|
||
|
|
test._materialize(this._overriddenFn);
|
||
|
|
return test;
|
||
|
|
}
|
||
|
|
|
||
|
|
titlePath(): string[] {
|
||
|
|
return [...this.suite.titlePath(), this.title];
|
||
|
|
}
|
||
|
|
|
||
|
|
fullTitle(): string {
|
||
|
|
return this.titlePath().join(' ');
|
||
|
|
}
|
||
|
|
|
||
|
|
slow(): number {
|
||
|
|
return 10000;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export class Suite {
|
||
|
|
title: string;
|
||
|
|
parent?: Suite;
|
||
|
|
suites: Suite[] = [];
|
||
|
|
tests: Test[] = [];
|
||
|
|
only = false;
|
||
|
|
pending = false;
|
||
|
|
file: string;
|
||
|
|
|
||
|
|
_impl: any;
|
||
|
|
|
||
|
|
constructor(title: string, parent?: Suite) {
|
||
|
|
this.title = title;
|
||
|
|
this.parent = parent;
|
||
|
|
this._impl = new Mocha.Suite(title, new Mocha.Context());
|
||
|
|
this._impl.__nomocha = this;
|
||
|
|
}
|
||
|
|
|
||
|
|
titlePath(): string[] {
|
||
|
|
if (!this.parent)
|
||
|
|
return [this.title];
|
||
|
|
return [...this.parent.titlePath(), this.title];
|
||
|
|
}
|
||
|
|
|
||
|
|
total(): number {
|
||
|
|
let count = 0;
|
||
|
|
this.eachTest(fn => ++count);
|
||
|
|
return count;
|
||
|
|
}
|
||
|
|
|
||
|
|
isPending(): boolean {
|
||
|
|
return this.pending || (this.parent && this.parent.isPending());
|
||
|
|
}
|
||
|
|
|
||
|
|
addTest(test: Test) {
|
||
|
|
test.suite = this;
|
||
|
|
this.tests.push(test);
|
||
|
|
this._impl.addTest(test._impl);
|
||
|
|
}
|
||
|
|
|
||
|
|
addSuite(suite: Suite) {
|
||
|
|
suite.parent = this;
|
||
|
|
this.suites.push(suite);
|
||
|
|
this._impl.addSuite(suite._impl);
|
||
|
|
}
|
||
|
|
|
||
|
|
eachTest(fn: (test: Test) => void) {
|
||
|
|
for (const suite of this.suites)
|
||
|
|
suite.eachTest(fn);
|
||
|
|
for (const test of this.tests)
|
||
|
|
fn(test);
|
||
|
|
}
|
||
|
|
|
||
|
|
clone(): Suite {
|
||
|
|
const suite = new Suite(this.title);
|
||
|
|
suite.only = this.only;
|
||
|
|
suite.file = this.file;
|
||
|
|
suite.pending = this.pending;
|
||
|
|
suite._impl = this._impl.clone();
|
||
|
|
return suite;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
class NullReporter {
|
||
|
|
stats = {
|
||
|
|
suites: 0,
|
||
|
|
tests: 0,
|
||
|
|
passes: 0,
|
||
|
|
pending: 0,
|
||
|
|
failures: 0
|
||
|
|
};
|
||
|
|
runner = null;
|
||
|
|
failures = [];
|
||
|
|
epilogue: () => {};
|
||
|
|
}
|
||
|
|
|
||
|
|
type NoMockaOptions = {
|
||
|
|
forbidOnly?: boolean;
|
||
|
|
timeout: number;
|
||
|
|
testWrapper: (test: Test, fn: Function) => Function;
|
||
|
|
hookWrapper: (hook: any, fn: Function) => Function;
|
||
|
|
};
|
||
|
|
|
||
|
|
class PatchedMocha extends Mocha {
|
||
|
|
suite: any;
|
||
|
|
static pendingSuite: Suite;
|
||
|
|
|
||
|
|
constructor(suite, options) {
|
||
|
|
PatchedMocha.pendingSuite = suite;
|
||
|
|
super(options);
|
||
|
|
}
|
||
|
|
|
||
|
|
grep(...args) {
|
||
|
|
this.suite = new Mocha.Suite('', new Mocha.Context());
|
||
|
|
this.suite.__nomocha = PatchedMocha.pendingSuite;
|
||
|
|
PatchedMocha.pendingSuite._impl = this.suite;
|
||
|
|
return super.grep(...args);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export class Runner extends EventEmitter {
|
||
|
|
private _mochaRunner: any;
|
||
|
|
|
||
|
|
constructor(mochaRunner: any) {
|
||
|
|
super();
|
||
|
|
const constants = Mocha.Runner.constants;
|
||
|
|
this._mochaRunner = mochaRunner;
|
||
|
|
this._mochaRunner.on(constants.EVENT_TEST_BEGIN, test => this.emit('test', test));
|
||
|
|
this._mochaRunner.on(constants.EVENT_TEST_PENDING, test => this.emit('pending', test));
|
||
|
|
this._mochaRunner.on(constants.EVENT_TEST_PASS, test => this.emit('pass', test));
|
||
|
|
this._mochaRunner.on(constants.EVENT_TEST_FAIL, (test, err) => this.emit('fail', test, err));
|
||
|
|
this._mochaRunner.on(constants.EVENT_RUN_END, () => this.emit('done'));
|
||
|
|
}
|
||
|
|
|
||
|
|
duration(): number {
|
||
|
|
return this._mochaRunner.stats.duration || 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export class NoMocha {
|
||
|
|
suite: Suite;
|
||
|
|
private _mocha: Mocha;
|
||
|
|
|
||
|
|
constructor(file: string, options: NoMockaOptions) {
|
||
|
|
this.suite = new Suite('');
|
||
|
|
this._mocha = new PatchedMocha(this.suite, {
|
||
|
|
forbidOnly: options.forbidOnly,
|
||
|
|
reporter: NullReporter,
|
||
|
|
timeout: options.timeout,
|
||
|
|
ui: fixturesUI.bind(null, options)
|
||
|
|
});
|
||
|
|
this._mocha.addFile(file);
|
||
|
|
(this._mocha as any).loadFiles();
|
||
|
|
}
|
||
|
|
|
||
|
|
run(cb: () => void): Runner {
|
||
|
|
return new Runner(this._mocha.run(cb));
|
||
|
|
}
|
||
|
|
}
|