Description
Affected URL(s)
https://nodejs.org/api/test.html#event-testfail
Description of the problem
I am writing a custom reporter for the Node.js test runner and I am confused over the types for the events that can be emitted and how they fit with skip/todo flags. Consequently, I'd also appreciate guidance on how skip/todo is supposed to act.
I've added this as a documentation bug, as I believe at the very least the docs could be more specific on the behaviour here. But I rubber-ducked myself while writing all this out, and came up with my own opinions about how this should work and that maybe there should be a behaviour update too. Read to the end to find out what I think!
From what I understand at the moment:
skips
If you skip a test using:
test("this is skipped", { skip: true }, () => {
// test code
});
Then the actual body of the test is replaced with a noop
and the test passes and is marked as skipped. That is, the runner emits a test:pass
event and the data of the event includes skip: true
.
If you skip a test using the context object instead, like this:
test("this is skipped", (t) => {
t.skip();
// test code
});
Then the test is run and the result could either be a pass or a fail, but will have skip: true
set. That is, the test could emit either a test:pass
or a test:fail
but either way the data will include skip: true
.
Also, if a skipped test fails with this method, all its parent tests fail.
todos
However, for todos, if you mark a test as todo using either pattern the test will run and the result may be a test:pass
or a test:fail
with todo: true
in the data.
Further confusing, because the options can both be passed there is further behaviour from using them.
If you pass both todo
and skip
as options, like this:
test("this is skipped", { skip: true, todo: true }, () => {
// test code
});
Then the test will not be run, it will be reported through test:pass
and skip: true
will be part of the data, but todo: true
will not.
Then if you pass todo: true
as an option, but call skip on the context.
test("this is skipped", { todo: true }, (t) => {
t.skip();
// test code
});
If the test fails it will trigger test:fail
with skip: true
set in the data and if it passes it will trigger test:pass
with skip: true
in the data. It will never report as todo: true
. This is also the case if you call both t.skip()
and t.todo()
in the same test body.
Questions
So, skipping a test only really works if you do so in the options passed to the test, otherwise the test will be run and the result reported. Should that be the case, or should calling context.skip()
anywhere within a test cease it's operation and report as a test:pass
with skip: true
?
When using skip
and todo
together, the todo
is always overridden. This is also the case if you set messages for skip
and todo
. Should todo
also be reported if it is used alongside skip
?
When using todo
on its own the test is run regardless and passes or fails are reported. Is that the expected behaviour? From research, that's how tape acts, but jest will not run a todo test (in fact, it throws an error if you try to pass a function to test.todo
) and mocha hasn't implemented todo at all.
My opinions
A skipped test should never report as a failure. I can handle this in the reporter I'm writing, but it's weird to need to handle skips in both the pass and fail event. Plus, if a skipped test fails then all the parent tests fail and they should not be reported as having failed if all their child tests either passed or were skipped. I'd prefer to see a test aborted if context.skip
is called part way through and the result deemed a pass, but marked as skipped. I suspect this makes coverage tough to get right though.
A test marked as "todo" seems to be more of an annotation than any other behaviour. So I'm happy that tests run regardless. But I think that annotation should be present even if the test is also skipped. So if someone uses skip
and todo
on the test, then both flags/messages should appear in the test:pass
event data.
@cjihrig @MoLow I'd love to understand if I've summarised all of this correctly, and if perhaps there are changes to be made here, either in the docs or the behaviour itself?