tape-testing / tape

tap-producing test harness for node and browsers
MIT License
5.77k stars 307 forks source link

How to run a conditional unit test, in which TEST B runs only if TEST A passes? #533

Closed cagross closed 3 years ago

cagross commented 3 years ago

Is there a way to run conditional tests, i.e. run TEST A, and if it passes, run TEST B? See below for an example of this scenario.

The t.test() method indicates you can add subtests to a test, which run after the parent test has 'finished.' Just to confirm, the subtest will run regardless of whether the parent test passes or fails--correct? I guess I can always try this out to see.

So if the t.test() method is only to run a subtest after the parent test finishes, how would I add a test to run only after the parent test passes?


Example

Let's say my code has function which returns a value. I want to write unit tests to ensure this value is an array of numbers. So I write two different unit tests:

With the tests setup this way, if Test A fails, then Test B will always throw an error. So I thought that, if I could, why not run Test B only when Test A passes. That way I can prevent Test B from throwing an error with Test A fails.

ljharb commented 3 years ago

This seems like something you could do with:

const isArray = Array.isArray(value);
t.ok(isArray, 'is an array');
t.test('other stuff', { skip: !isArray }, …);

?

cagross commented 3 years ago

OK thanks so for that. I gave it a shot, and it definitely does what I want, and will be a viable option for me. Big help.

While we're here though, I have a couple follow up questions if that's OK :-)

In your code, you kind of need to confirm that isArray is an array value in two different places (lines one and three). It would be nice to programatically check if t.ok() passes or fails. Is that possible? If so, then could execute the t.test() line only when t.ok() passes. With your code, the t.test() line doesn't depend on the result of t.ok() at all--it would be nice if I could link them. That's admittedly a little nitpicky, but I'm mainly curious for the future is all.

Alternatively, with the ok() or test() methods, Is there any way to print a custom message to the console--one based on logic in the callback function? That way I could create a single assertion for t.test()--one that asserts the return value is both an array and an array of numbers. Then, when one failed, I could print exactly which failed to the console so the user would know which one failed. Again, a little nitpicky, but more curious than anything.

Is there example code for how the skip property is used in this way? The documentation on the main GitHub page doesn't really make that clear. It first says opts.skip is a property with a boolean value, but then says see test.skip(), which is a method that takes three parameters. So it wasn't entirely obvious how to use it.

cagross commented 3 years ago

I think the best option for conditional testing would be to write my own code to check whether the first test passed/failed (as opposed to using t.ok, t.equal, etc). In my code, when I determine the test passed/failed, I can generate a pass/fail assertion using t.pass/t.fail. From there, I can then execute test-b, only if test-a passes. Hope that makes sense to anyone reading.

Alternatively, if tape allows me to print custom messages to the console--a message that depends on logic in my test--then I could accomplish what I want. I could then combine both tests into one single test. But when either of the test failed, I would be ble to indicate to the user which of the two conditions failed.

I'll close this issue.

ljharb commented 3 years ago

You can use t.comment() but i suspect that’s not what you mean.

cagross commented 3 years ago

I didn't know about t.comment(), and it actually could be what I want here. I'll have a look--thanks.