Skip to content

Commit

Permalink
fix: inject failed should make suite/test failed (#154)
Browse files Browse the repository at this point in the history
  • Loading branch information
killagu committed Jan 30, 2023
1 parent 7ebe3fa commit f9f2d4c
Show file tree
Hide file tree
Showing 16 changed files with 279 additions and 52 deletions.
4 changes: 2 additions & 2 deletions lib/app_handler.js
Expand Up @@ -43,9 +43,9 @@ exports.setGetAppCallback = cb => {
getAppCallback = cb;
};

exports.getApp = async suite => {
exports.getApp = async (suite, test) => {
if (getAppCallback) {
return getAppCallback(suite);
return getAppCallback(suite, test);
}
if (app) {
await app.ready();
Expand Down
82 changes: 50 additions & 32 deletions lib/inject_context.js
@@ -1,6 +1,5 @@
const debug = require('util').debuglog('egg-mock:inject_context');
const appHandler = require('./app_handler');
const EGG_CONTEXT = Symbol.for('mocha#suite#ctx#eggCtx');

/**
* Monkey patch the mocha instance with egg context.
Expand All @@ -16,47 +15,65 @@ function injectContext(mocha) {
const runSuite = Runner.prototype.runSuite;
const runTests = Runner.prototype.runTests;

function getTestTitle(suite, test) {
const suiteTitle = suite.root ? 'root suite' : suite.title;
if (!test) {
return `"${suiteTitle}"`;
}
return `"${suiteTitle} - ${test.title}"`;
}

// Inject ctx for before/after.
Runner.prototype.runSuite = async function(suite, fn) {
debug('run suite: %j %s', suite.title, !!(suite.ctx && suite[EGG_CONTEXT]));
const app = await appHandler.getApp(suite);
debug('get app: %s', !!app);
debug('run suite: %s', suite.title);
let app;
try {
app = await appHandler.getApp(suite);
debug('get app: %s', !!app);
} catch (err) {
err.message = `[egg-mock/runSuite] get app for ${getTestTitle(suite)}: ${err.message}`;
this.fail(suite, err);
return fn(suite);
}
const self = this;
if (!app) {
return runSuite.call(self, suite, fn);
}
let errSuite;
try {
await app.ready();
suite.ctx.app = app;
const mockContextFun = app.mockModuleContextScope || app.mockContextScope;
await mockContextFun.call(app, async function(eggCtx) {
suite.ctx[EGG_CONTEXT] = eggCtx;
await mockContextFun.call(app, async function() {
await new Promise(resolve => {
runSuite.call(self, suite, aErrSuite => {
errSuite = aErrSuite;
resolve();
});
});
});
} catch (e) {
e.message = '[egg-mock] inject context error: ' + e.message;
console.error(e);
} catch (err) {
err.message = `[egg-mock/runSuite] inject context for ${getTestTitle(suite)}: ${err.message}`;
self.fail(suite, err);
}
return fn(errSuite);
};

// Inject ctx for beforeEach/it/afterEach.
// And ctx with before/after is not same as beforeEach/it/afterEach.
Runner.prototype.runTests = async function(suite, fn) {
debug('run tests: %j %s', suite.title);
const app = await appHandler.getApp(suite);
const tests = suite.tests.slice();
if (!tests.length) {
return runTests.call(this, suite, fn);
}

const app = suite.ctx.app;

const self = this;
if (!app) {
return runTests.call(self, suite, fn);
}

const tests = suite.tests.slice();

function done(errSuite) {
suite.tests = tests;
return fn(errSuite);
Expand All @@ -69,34 +86,35 @@ function injectContext(mocha) {
}
suite.tests = [ test ];

const app = await appHandler.getApp(suite);
await app.ready();
const mockContextFun = app.mockModuleContextScope || app.mockContextScope;
let testPassed = false;
let app;
try {
testPassed = await mockContextFun.call(app, async function() {
app = await appHandler.getApp(suite, test);
await app.ready();
} catch (err) {
err.message = `[egg-mock/runTests] get app for ${getTestTitle(suite, test)}: ${err.message}`;
self.fail(test, err);
return next(i + 1);
}

try {
const mockContextFun = app.mockModuleContextScope || app.mockContextScope;
await mockContextFun.call(app, async function() {
return await new Promise(resolve => {
runTests.call(self, suite, err => {
if (err) {
return resolve(false);
}
return resolve(true);
runTests.call(self, suite, () => {
return resolve();
});
});
});
} catch (err) {
err.message = '[egg-mock] run mock context error: ' + err.message;
console.error(err);
return done(suite);
}
if (testPassed) {
err.message = `[egg-mock/runTests] create context for ${getTestTitle(suite)} error: ${err.message}`;
self.fail(test, err);
return next(i + 1);
}
return done(suite);
return next(i + 1);
}
next(0).catch(e => {
e.message = '[egg-mock] inject context error: ' + e.message;
console.error(e);
next(0).catch(err => {
err.message = `[egg-mock/runTests] unknown error ${getTestTitle(suite)} error: ${err.message}`;
self.fail(suite, err);
done(suite);
});
};
Expand Down
5 changes: 5 additions & 0 deletions test/fixtures/create-context-failed/config/config.default.js
@@ -0,0 +1,5 @@
'use strict';

module.exports = {
keys: '123',
};
3 changes: 3 additions & 0 deletions test/fixtures/create-context-failed/package.json
@@ -0,0 +1,3 @@
{
"name": "app"
}
17 changes: 17 additions & 0 deletions test/fixtures/create-context-failed/test/index.test.js
@@ -0,0 +1,17 @@
const { setGetAppCallback } = require('../../../..');

setGetAppCallback(() => {
return {
ready: async () => {
// ...
},
mockContextScope: async () => {
throw new Error('mock create context failed');
},
};
});

describe('test case create context error', () => {
it('should not print', () => {
});
});
53 changes: 37 additions & 16 deletions test/fixtures/failed-app/test/index.test.js
@@ -1,32 +1,53 @@
const assert = require('assert');
const { app } = require('../../../../bootstrap');

describe('test/index.test.ts', () => {
describe('hook error', () => {
describe('before error', () => {
before(() => {
throw new Error('before error');
});

it('should not print', () => {
assert.fail('never arrive');
});
});

describe('after error', () => {
after(() => {
throw new Error('after error');
});

it('should print', () => {
console.log('after error test case should print');
});
});

describe('beforeEach error', () => {
beforeEach(() => {
assert.fail('failed hook');
throw new Error('beforeEach error');
});

it('should fail', () => {
// eslint-disable-next-line no-undef
assert(app.currentContext);
assert.fail('failed case');
it('should not print', () => {
assert.fail('never arrive');
});
});

describe('mockContext failed', () => {
before(() => {
app.mockContextScope = () => {
throw new Error('mockContextScope error');
};
describe('afterEach error', () => {
afterEach(() => {
throw new Error('afterEach error');
});

it('foo', () => {
//...
it('should print', () => {
console.log('afterEach error test case should print');
});
});

describe('case error', () => {
it('should failed', () => {
assert.fail('should fail');
});

it('should not run', () => {
console.log('it should not run');
it('should work', () => {
// ...
});
});
});
5 changes: 5 additions & 0 deletions test/fixtures/get-app-failed/config/config.default.js
@@ -0,0 +1,5 @@
'use strict';

module.exports = {
keys: '123',
};
3 changes: 3 additions & 0 deletions test/fixtures/get-app-failed/package.json
@@ -0,0 +1,3 @@
{
"name": "app"
}
10 changes: 10 additions & 0 deletions test/fixtures/get-app-failed/test/index.test.js
@@ -0,0 +1,10 @@
const { setGetAppCallback } = require('../../../..');

setGetAppCallback(() => {
throw new Error('mock get app failed');
});

describe('test case create context error', () => {
it('should not print', () => {
});
});
@@ -0,0 +1,5 @@
'use strict';

module.exports = {
keys: '123',
};
3 changes: 3 additions & 0 deletions test/fixtures/test-case-create-context-failed/package.json
@@ -0,0 +1,3 @@
{
"name": "app"
}
21 changes: 21 additions & 0 deletions test/fixtures/test-case-create-context-failed/test/index.test.js
@@ -0,0 +1,21 @@
const { setGetAppCallback } = require('../../../..');

setGetAppCallback((suite, test) => {
return {
ready: async () => {
// ...
},
mockContextScope: async scope => {
if (!test) {
await scope({});
} else {
throw new Error('mock create context failed');
}
},
};
});

describe('test case create context error', function() {
it('should not print', () => {
});
});
@@ -0,0 +1,5 @@
'use strict';

module.exports = {
keys: '123',
};
3 changes: 3 additions & 0 deletions test/fixtures/test-case-get-app-failed/package.json
@@ -0,0 +1,3 @@
{
"name": "app"
}
20 changes: 20 additions & 0 deletions test/fixtures/test-case-get-app-failed/test/index.test.js
@@ -0,0 +1,20 @@
const { setGetAppCallback } = require('../../../..');

setGetAppCallback((suite, test) => {
if (test) {
throw new Error('mock get app failed');
}
return {
ready: async () => {
// ...
},
mockContextScope: async scope => {
await scope({});
},
};
});

describe('test case get app error', () => {
it('should not print', () => {
});
});

0 comments on commit f9f2d4c

Please sign in to comment.