-
Notifications
You must be signed in to change notification settings - Fork 30.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
test_runner: remove Promise return values from test(), suite(), and t.test() #56664
Conversation
Review requested:
|
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #56664 +/- ##
=======================================
Coverage 89.21% 89.21%
=======================================
Files 663 663
Lines 192002 192028 +26
Branches 36928 36925 -3
=======================================
+ Hits 171292 171319 +27
+ Misses 13583 13582 -1
Partials 7127 7127
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aside from the nits: I think this is a great devEx enhancement! LGTM
doc/api/test.md
Outdated
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no change here regarding how a test is recognized as finished. The test is either a synchronous function, a function that returns a Promise, or a function that takes a callback. The test is finished after awaiting the return value or the callback is invoked. That part is already documented.
For example, how would it understand this one completes?
Unrelated to this change - I believe this first snippet has a bug, assuming someCallback()
is asynchronous? If it is asynchronous, there should be a Promise or a done
callback involved. The second code snippet looks correct, but a Promise could have been used as well.
Does this PR make the done callback required for all subtests?
No.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have a test for ensuring dynamically added test cases finish before the suite closes? This await behaviour was previously required in order to orchestrate that in userland, so I'm just concerned this could break that.
Yes, dynamically added tests still work. The breaking change (aside from the return value change) is that you can no longer await subtests for control flow purposes. For users of |
I'm confused. The docs still say that a test can return a promise: Lines 32 to 43 in 2b34ffe
Are you saying that we can no longer await those returned promises in order to keep the parent test alive? |
const r = test('foo', () => {
return new Promise((resolve) => {
resolve();
});
}); This test returns a Promise (the Promise that is resolved()). When that Promise settles, the test is considered finished. That has not changed.
Previously, if you were writing a test inside of another test, you needed to The only scenario where this is breaking: test('foo', async (t) => {
await t.test('subtest 1');
// It is no longer guaranteed that the subtest on the previous line has
// finished by the time this line executes. But the test runner still ensures
// the order that subtest 1 and subtest 2 are executed in.
await t.test('subtest 2');
}); |
Thank you for the clarification. I was unaware of |
So, is |
As far as I know, that was already the case. The difference was that |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approving the breaking change.
Can we keep the return The main reason is that
|
This is ready to land, but before it does, I'd like to hear from @JoshuaKGoldberg, who opened #51292. Do you still think changing the return types of these APIs is an improvement, with the assumption that people will need to lint their code across multiple versions of Node? As a linter maintainer, what will you tell users to do here? Also note that we can make the 'automatically await subtests' change without changing the types, but we can't change the types without awaiting the subtests. |
First of all, ❤️ you do fantastic work @cjihrig and I hope nothing around the linting / tl;dr: this change looks great to me and I appreciate you working on it. Thank you!
I do. Both as a general user of
IME: people don't generally lint across multiple versions of Node.js. Projects generally run linting in the user's editor and in a single task in CI. I think the versioning concern really only applies to the single version of So, I don't see this as being a problem cross-Node.js-versions for linters. Unless I misinterpreted something? |
So, I do think both of those problems could be solved with just the first commit here (automatically awaiting subtests). Obviously parallel tests can always interact, but you would not need to await any subtests or try to manage Promises. From the linter point of view, everything would become fire-and-forget.
This is the part that concerns me. My experience has been that a lot of projects linting is run in the CI for all versions. For example, in the Kubernetes client we recently migrated to typescript-eslint, and it is run on every version even though that might not be the most efficient thing. Another pattern is running the linter as part of |
What benefits are there to running linting across versions? Are there any examples of past issues that have been caught by it? In general, for linting, I just don't see any motivation to run it matrixed in CI across the Node version:
|
I will add me to the "lint once" evidence. I have never considered linting across multiple versions of Node. It's either JavaScript that is good, or it isn't. |
I agree that there is not much benefit to doing it, but people do it a lot. I did not setup the CI on that project, but my guess is that it's just easier to do it at the same time as running the tests rather than setting up something separate. For my own projects, I generally run the linter as part of From a quick search a few larger projects that lint across versions that I think would have problems with this type of update:
|
To follow on from JoshuaKGoldberg's point, since each version's lint run will be linting against the same type definitions for the test runner API (from whichever version of @types/node is installed in the project), I wouldn't imagine this would be an issue? Either all the lint runs would fail, or none would? |
👍 I checked just now and none of those repositories swap what version of So, I think the only way this change would likely+reasonably get in the way via linting is if they:
To get around that, I'd advise using inline // eslint-disable-next-line @typescript-eslint/await-thenable
await t.test(...); If there are a ton they could always disable {
files: ['src/**/*.test.*'],
rules: { '@typescript-eslint/await-thenable': 'off' }
} |
Thanks @JoshuaKGoldberg. I've been thinking about this PR for the past few days. I still have a lot of apprehension about landing the return type change, but given the number of folks who appear to be on board with it, I think I'm going to rebase and get this landed. |
This commit updates the test runner to automatically wait for subtests to finish. This makes the experience more consistent with suites and removes the need to await anything.
This commit updates the test() and suite() APIs to no longer return a Promise. Fixes: nodejs#51292
This commit updates the TestContext.prototype.test() API to no longer return a Promise. Fixes: nodejs#51292
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This commit updates the test runner to automatically wait for subtests to finish. This makes the experience more consistent with suites and removes the need to await anything. PR-URL: #56664 Fixes: #51292 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Pietro Marchini <[email protected]> Reviewed-By: Michaël Zasso <[email protected]> Reviewed-By: Jacob Smith <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Raz Luvaton <[email protected]> Reviewed-By: Chemi Atlow <[email protected]>
This commit updates the test() and suite() APIs to no longer return a Promise. Fixes: #51292 PR-URL: #56664 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Pietro Marchini <[email protected]> Reviewed-By: Michaël Zasso <[email protected]> Reviewed-By: Jacob Smith <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Raz Luvaton <[email protected]> Reviewed-By: Chemi Atlow <[email protected]>
This commit updates the TestContext.prototype.test() API to no longer return a Promise. Fixes: #51292 PR-URL: #56664 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Pietro Marchini <[email protected]> Reviewed-By: Michaël Zasso <[email protected]> Reviewed-By: Jacob Smith <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Raz Luvaton <[email protected]> Reviewed-By: Chemi Atlow <[email protected]>
Landed in ba4587c...1a2eb15 |
test_runner: automatically wait for subtests to finish
This commit updates the test runner to automatically wait for
subtests to finish. This makes the experience more consistent
with suites and removes the need to await anything.
test_runner: remove promises returned by test()
This commit updates the test() and suite() APIs to no longer
return a Promise.
Fixes: #51292
test_runner: remove promises returned by t.test()
This commit updates the TestContext.prototype.test() API to no
longer return a Promise.
Fixes: #51292