associate metadata with runnables (#53245)

This commit is contained in:
Spencer 2019-12-17 12:26:50 -07:00 committed by GitHub
parent 2d36b216af
commit e5c562b5c1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 28 additions and 30 deletions

View file

@ -25,7 +25,7 @@ it('collects metadata for the current test', async () => {
const failureMetadata = new FailureMetadata(lifecycle);
const test1 = {};
await lifecycle.beforeEachTest.trigger(test1);
await lifecycle.beforeEachRunnable.trigger(test1);
failureMetadata.add({ foo: 'bar' });
expect(failureMetadata.get(test1)).toMatchInlineSnapshot(`
@ -35,7 +35,7 @@ it('collects metadata for the current test', async () => {
`);
const test2 = {};
await lifecycle.beforeEachTest.trigger(test2);
await lifecycle.beforeEachRunnable.trigger(test2);
failureMetadata.add({ test: 2 });
expect(failureMetadata.get(test1)).toMatchInlineSnapshot(`
@ -55,7 +55,7 @@ it('adds messages to the messages state', () => {
const failureMetadata = new FailureMetadata(lifecycle);
const test1 = {};
lifecycle.beforeEachTest.trigger(test1);
lifecycle.beforeEachRunnable.trigger(test1);
failureMetadata.addMessages(['foo', 'bar']);
failureMetadata.addMessages(['baz']);

View file

@ -29,7 +29,7 @@ interface Metadata {
export class FailureMetadata {
// mocha's global types mean we can't import Mocha or it will override the global jest types..............
private currentTest?: any;
private currentRunnable?: any;
private readonly allMetadata = new Map<any, Metadata>();
constructor(lifecycle: Lifecycle) {
@ -39,18 +39,18 @@ export class FailureMetadata {
);
}
lifecycle.beforeEachTest.add(test => {
this.currentTest = test;
lifecycle.beforeEachRunnable.add(runnable => {
this.currentRunnable = runnable;
});
}
add(metadata: Metadata | ((current: Metadata) => Metadata)) {
if (!this.currentTest) {
throw new Error('no current test to associate metadata with');
if (!this.currentRunnable) {
throw new Error('no current runnable to associate metadata with');
}
const current = this.allMetadata.get(this.currentTest);
this.allMetadata.set(this.currentTest, {
const current = this.allMetadata.get(this.currentRunnable);
this.allMetadata.set(this.currentRunnable, {
...current,
...(typeof metadata === 'function' ? metadata(current || {}) : metadata),
});
@ -98,7 +98,7 @@ export class FailureMetadata {
return screenshot;
}
get(test: any) {
return this.allMetadata.get(test);
get(runnable: any) {
return this.allMetadata.get(runnable);
}
}

View file

@ -22,11 +22,13 @@ import { LifecyclePhase } from './lifecycle_phase';
// mocha's global types mean we can't import Mocha or it will override the global jest types..............
type ItsASuite = any;
type ItsATest = any;
type ItsARunnable = any;
export class Lifecycle {
public readonly beforeTests = new LifecyclePhase<[]>({
singular: true,
});
public readonly beforeEachRunnable = new LifecyclePhase<[ItsARunnable]>();
public readonly beforeTestSuite = new LifecyclePhase<[ItsASuite]>();
public readonly beforeEachTest = new LifecyclePhase<[ItsATest]>();
public readonly afterTestSuite = new LifecyclePhase<[ItsASuite]>();

View file

@ -19,7 +19,7 @@
import { createAssignmentProxy } from './assignment_proxy';
import { wrapFunction } from './wrap_function';
import { wrapRunnableArgsWithErrorHandler } from './wrap_runnable_args';
import { wrapRunnableArgs } from './wrap_runnable_args';
export function decorateMochaUi(lifecycle, context) {
// incremented at the start of each suite, decremented after
@ -93,7 +93,7 @@ export function decorateMochaUi(lifecycle, context) {
function wrapTestFunction(name, fn) {
return wrapNonSuiteFunction(
name,
wrapRunnableArgsWithErrorHandler(fn, async (err, test) => {
wrapRunnableArgs(fn, lifecycle, async (err, test) => {
await lifecycle.testFailure.trigger(err, test);
})
);
@ -111,7 +111,7 @@ export function decorateMochaUi(lifecycle, context) {
function wrapTestHookFunction(name, fn) {
return wrapNonSuiteFunction(
name,
wrapRunnableArgsWithErrorHandler(fn, async (err, test) => {
wrapRunnableArgs(fn, lifecycle, async (err, test) => {
await lifecycle.testHookFailure.trigger(err, test);
})
);

View file

@ -23,28 +23,24 @@ import { wrapFunction, wrapAsyncFunction } from './wrap_function';
* Wraps a "runnable" defining function (it(), beforeEach(), etc.)
* so that any "runnable" arguments passed to it are wrapped and will
* trigger a lifecycle event if they throw an error.
*
* @param {Function} fn
* @param {String} eventName
* @return {Function}
*/
export function wrapRunnableArgsWithErrorHandler(fn, handler) {
export function wrapRunnableArgs(fn, lifecycle, handler) {
return wrapFunction(fn, {
before(target, thisArg, argumentsList) {
for (let i = 0; i < argumentsList.length; i++) {
if (typeof argumentsList[i] === 'function') {
argumentsList[i] = wrapRunnableError(argumentsList[i], handler);
argumentsList[i] = wrapAsyncFunction(argumentsList[i], {
async before(target, thisArg) {
await lifecycle.beforeEachRunnable.trigger(thisArg);
},
async handleError(target, thisArg, argumentsList, err) {
await handler(err, thisArg.test);
throw err;
},
});
}
}
},
});
}
function wrapRunnableError(runnable, handler) {
return wrapAsyncFunction(runnable, {
async handleError(target, thisArg, argumentsList, err) {
await handler(err, thisArg.test);
throw err;
},
});
}