Replies: 4 comments 10 replies
-
In my view this proposal is the preferred way forward instead of #10771. It doesn't introduced "mixed" way to define tests (we stick to the declarative one), while vastly expanding ability for 3rd party testing frameworks to integrate into Deno. I would maybe bike-shed on the |
Beta Was this translation helpful? Give feedback.
-
Am for declarative over procedural altho the before and after hooks here are kinda moot with seemingly little wins over having the user wrap their functions? Strawman and just winging this but maybe we could provide some sort of wrapping executor instead? This at-least gives you a closure scope and extension point for prettier things in std/testing (for example, pass along some user defined context). type TestExecutor = (test: TestDefinition) => void | Promise<void>;
export interface TestCollection {
definitions: TestDefinitions;
executor?: TestExecutor;
}
Deno.test({
definitions: [
// ...
],
async executor(test: TestFunction) {
const someState = ...;
await definition.fn(someState);
someState.close();
},
}); |
Beta Was this translation helpful? Give feedback.
-
Speaking of hooks, what about beforeEach/afterEach hooks? Are they left to third-party frameworks? I assume one could mimic beforeEach/afterEach by making each case a subgroup, though, that's a tad bit hackish: let someObject = undefined;
const beforeEach = () => { someObject = {}; };
const afterEach = () => { someObject = undefined; };
Deno.test({
name: "group with subgroup",
cases: [{
name: "subgroup",
before: beforeEach;
after: afterEach;
cases: [{
name: "case 1",
fn: () => {},
},
{
name: "subgroup",
before: beforeEach;
after: afterEach;
cases: [{
name: "case 1",
fn: () => {},
}]
}],
}); |
Beta Was this translation helpful? Give feedback.
-
Just want to point out, that declarative maintains our clean separation between the test harness and test runner. While it's not something we're committed to maintain by any means, this clean separation let me build this little experimental tool to run tests in browsers simply by proxying the module registration with a stub test harness and re-use the test runner in the binary build of demo completely because the two are completely separated. |
Beta Was this translation helpful? Give feedback.
-
#10771 proposed the idea of adding subtests, hooks, and concurrent test execution via a mixed declarative/imperative API similar to what is found in the Go programming language. This proposal is going to explore a similar solution, but keeping the test definitions declarative expanding on @caspervonb's comment. Tests would continue to work in three separate phases of defining, filtering, and finally executing tests.
Interface
The
TestDefinition
interface is the same, but a newTestCollection
interface is added that may be provided toDeno.test
.Behaviours
This document will show many of the same examples as #10771 and largely mirror (copy/paste) the text from there, but written with this proposed declarative API.
Sub tests can be defined by providing a test collection to
Deno.test
:Sub tests can also run concurrently and the resource sanitizers do not need to be disabled as the test executer can move that responsibility to a higher level based on the descendant test definitions (more on that below):
Test collections can have descendant test collections:
Setup and teardown steps are not as convenient as an imperative approach out of the box...
...however, this inconvenience can be mitigated in many ways by userland testing libraries (who would be the consumers of this API).
Only running a specific sub test is possible by adding
only: true
to the test definition similar to today, but this could also be added to a test collection. Similarly, entire test collections can be ignored by addingignored: true
. See the interface JS docs above for more details.Sanitizers
Sanitizers (
sanitizeOps
,sanitizeResources
,sanitizeExit
) would remain at the test definition level, but if a user specifiesconcurrent: true
on a test collection, then the test execution phase would analyze the descendant test definitions to figure out which tests it could run concurrently based on the test definitions. It would then run all these tests in groups and do sanitization checks after each group ran. In most cases, the entire test collection would be run concurrently and the sanitization check would occur afterwards.This has the obvious downside of reduced resolution on which test is leaking, however an instructive message can be given to the user on a failure to tell them to run the tests again with
concurrent: false
to drill down to the specific test or the tests could be run again serially when this occurs in order to tell them which test it is (doesn't always work if it's flaky). Either way, this may provide a good user experience because it does not require manually disabling a lot of test case sanitizers.Permissions
These would work the same way as sanitizers and the test executer would be able to figure out which tests can run concurrently based on the defined test definitions that it knows about.
Reporter Output
Largely the same as #10771, except accurate numbers on how many tests are left to execute and how many total tests there are before filtering are possible to report to the user.
Filtering
Filtering would work well and fast because filtering happens after defining tests and before executing them or their setup code. "Only" is also possible because of this. Additionally filtering based on a substring of a subtest name is possible.
Shuffling
Shuffling sub tests would be possible with this approach.
A Building Block
Similarly to #10771, this API is directed towards testing framework authors (ex. using
describe
andit
like mocha). It would not be very convenient for end users to use this API.cc @lucacasonato @caspervonb
Beta Was this translation helpful? Give feedback.
All reactions