答案 0 :(得分:2)
我做了些争吵,但对我有用。
stopOnFirstFailed.js
:
/**
* This is a realisation of "stop on first failed" with Jest
* @type {{globalFailure: boolean}}
*/
module.exports = {
globalFailure: false
};
// Injects to jasmine.Spec for checking "status === failed"
!function (OriginalSpec) {
function PatchedSpec(attrs) {
OriginalSpec.apply(this, arguments);
if (attrs && attrs.id) {
let status = undefined;
Object.defineProperty(this.result, 'status', {
get: function () {
return status;
},
set: function (newValue) {
if (newValue === 'failed') module.exports.globalFailure = true;
status = newValue;
},
})
}
}
PatchedSpec.prototype = Object.create(OriginalSpec.prototype, {
constructor: {
value: PatchedSpec,
enumerable: false,
writable: true,
configurable: true
}
});
jasmine.Spec = PatchedSpec;
}(jasmine.Spec);
// Injects to "test" function for disabling that tasks
test = ((testOrig) => function () {
let fn = arguments[1];
arguments[1] = () => {
return module.exports.globalFailure ? new Promise((res, rej) => rej('globalFailure is TRUE')) : fn();
};
testOrig.apply(this, arguments);
})(test);
在所有测试之前(在第一个test(...)
之前)导入该文件,例如我的index.test.js
:
require('./core/stopOnFirstFailed'); // before all tests
test(..., ()=>...);
...
当发生第一个错误时,该代码会将所有后续测试failed
标记为globalFailure is TRUE
。
例如,如果要排除failing
,请执行以下操作。您可以像这样进行一些清理测试:
const stopOnFirstFailed = require('../core/stopOnFirstFailed');
describe('some protected group', () => {
beforeAll(() => {
stopOnFirstFailed.globalFailure = false
});
test(..., ()=>...);
...
它从failing
中排除了整个群组。
在Node 8.9.1和Jest 23.6.0上进行了测试
答案 1 :(得分:0)
我猜该套件中的其他测试是否成功取决于所有先前的测试。这是单元测试中的不良做法。尝试使用beforeEach
和afterEach
来解开套件中的各个测试用例,以免它们相互依赖。
答案 2 :(得分:0)
hack global.jasmine.currentEnv_.fail对我有用。
describe('Name of the group', () => {
beforeAll(() => {
global.__CASE_FAILED__= false
global.jasmine.currentEnv_.fail = new Proxy(global.jasmine.currentEnv_.fail,{
apply(target, that, args) {
global.__CASE__FAILED__ = true
// you also can record the failed info...
target.apply(that, args)
}
}
)
})
afterAll(async () => {
if(global.__CASE_FAILED__) {
console.log("there are some case failed");
// TODO ...
}
})
it("should xxxx", async () => {
// TODO ...
expect(false).toBe(true)
})
});
答案 3 :(得分:0)
感谢 this comment on github,我能够使用自定义 testEnvironment
解决此问题。为此,jest-circus
需要通过 npm
/yarn
安装。
值得注意的是 jest will set jest-circus to the default runner with jest v27.
首先需要适配jest配置:
jest.config.js
module.exports = {
rootDir: ".",
testRunner: "jest-circus/runner",
testEnvironment: "<rootDir>/NodeEnvironmentFailFast.js",
}
然后你需要实现一个自定义环境,上面的配置已经引用了:
NodeEnvironmentFailFast.js
const NodeEnvironment = require("jest-environment-node")
class NodeEnvironmentFailFast extends NodeEnvironment {
failedDescribeMap = {}
registeredEventHandler = []
async setup() {
await super.setup()
this.global.testEnvironment = this
}
registerTestEventHandler(registeredEventHandler) {
this.registeredEventHandler.push(registeredEventHandler)
}
async executeTestEventHandlers(event, state) {
for (let handler of this.registeredEventHandler) {
await handler(event, state)
}
}
async handleTestEvent(event, state) {
await this.executeTestEventHandlers(event, state)
switch (event.name) {
case "hook_failure": {
const describeBlockName = event.hook.parent.name
this.failedDescribeMap[describeBlockName] = true
// hook errors are not displayed if tests are skipped, so display them manually
console.error(`ERROR: ${describeBlockName} > ${event.hook.type}\n\n`, event.error, "\n")
break
}
case "test_fn_failure": {
this.failedDescribeMap[event.test.parent.name] = true
break
}
case "test_start": {
if (this.failedDescribeMap[event.test.parent.name]) {
event.test.mode = "skip"
}
break
}
}
if (super.handleTestEvent) {
super.handleTestEvent(event, state)
}
}
}
module.exports = NodeEnvironmentFailFast
注意
我添加了 registerTestEventHandler
功能,这对于快速失败功能不是必需的,但我认为它非常有用,尤其是如果您之前使用过 jasmine.getEnv()
并且它与 async
/{{ 1}}!
您可以在测试中内部注册自定义处理程序(例如 await
钩子),如下所示:
beforeAll
当一个 // testEnvironment is globally available (see above NodeEnvironmentFailFast.setup)
testEnvironment.registerTestEventHandler(async (event) => {
if (event.name === "test_fn_failure") {
await takeScreenshot()
}
})
失败时,将跳过同一个 test
中的其他 test
语句。这也适用于嵌套的 describe
块,但 describe
块必须具有不同的名称。
执行以下测试:
describe
将产生以下日志:
describe("TestJest 3 ", () => {
describe("TestJest 2 ", () => {
describe("TestJest 1", () => {
beforeAll(() => expect(1).toBe(2))
test("1", () => {})
test("1.1", () => {})
test("1.2", () => {})
})
test("2", () => expect(1).toBe(2))
test("2.1", () => {})
test("2.2", () => {})
})
test("3", () => {})
test("3.1", () => expect(1).toBe(2))
test("3.2", () => {})
})
答案 4 :(得分:0)
这是我的 solution
-- 如果有重大缺点,请告诉我,就我而言,它似乎按预期工作
我只有一个顶级描述块,出于我的目的,我希望在一个测试失败时整个测试文件都失败
export class FailEarly {
msg: string | undefined;
failed: boolean = false;
jestIt: jest.It;
constructor(jestIt: jest.It) {
this.jestIt = jestIt;
}
test = (name: string, fn: jest.EmptyFunction, timeout?: number) => {
const failEarlyFn = async () => {
if (this.failed) {
throw new Error(`failEarly: ${this.msg}`);
}
try {
await fn();
} catch (error) {
this.msg = name;
this.failed = true;
throw error;
}
};
this.jestIt(name, failEarlyFn, timeout);
};
}
给我一个上下文(类属性)来存储 global-esq 变量
const failEarlyTestRunner = new FailEarly(global.it);
const test = failEarlyTestRunner.test;
const it = failEarlyTestRunner.test;
使用我的类的方法重载 test
和 it
函数(从而访问类属性)
describe('my stuff', () => {
it('passes', async () => {
expect(1).toStrictEqual(1);
})
test('it fails', async () => {
expect(1).toStrictEqual(2);
})
it('is skipped', async () => {
expect(1).toStrictEqual(1);
})
})
结果:
my stuff
✓ can create a sector (2 ms)
✕ it fails (2 ms)
✕ is skipped (1 ms)
● my stuff › it fails
expect(received).toStrictEqual(expected) // deep equality
Expected: 2
Received: 1
> ### | expect(1).toStrictEqual(2);
| ^
### | });
● my stuff › is skipped
failEarly: it fails
69 | const failEarlyFn = async () => {
70 | if (this.failed) {
> 71 | throw new Error(`failEarly: ${this.msg}`);
| ^
72 | }
73 |
74 | try {
每个跳过的测试都失败了,并有一个错误指示上游,失败的测试
正如其他人指出的那样——你必须用 --runInBand
标志来开玩笑
希望这对某人有所帮助——如果有有意义的缺点或更好的方法,请发表评论;我总是乐于学习