-
Notifications
You must be signed in to change notification settings - Fork 4.6k
api-fetch: cleanup and improve unit tests #71439
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
Conversation
| const body = 'FormData'; | ||
|
|
||
| apiFetch( { | ||
| await apiFetch( { |
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.
Example of a synchronous test where the response promise was leaking out of the test. The promise resolves only after the test has already finished running.
| } ); | ||
| await expect( apiFetch( { path: '/random' } ) ).rejects.toEqual( { | ||
| code: 'bad_request', | ||
| message: 'Bad Request', |
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.
This removes the need to disable jest/no-conditional-expect. And also the test checks that the promise really rejects and fails otherwise. In the original code, the expect inside the catch callback would never run, and the test would finish without calling any expect.
| { once: true } | ||
| ); | ||
| } ) | ||
| ); |
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.
This is a realistic implementation of a fetch handler that:
- Returns a promise that never resolves.
- Aborts when someone calls
controller.abort().
The original version of the test just mocked fetch to reject with AbortError and then tested that this error was really thrown. The signal and the controller didn't play any role at all.
| status: 204, | ||
| } ); | ||
|
|
||
| await expect( apiFetch( { path: '/random' } ) ).resolves.toBe( null ); |
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.
This test was wrong! It expected that apiFetch throws null, but in reality it returns null. The "204 No content" response doesn't have any body, so apiFetch returns null. And also avoids calling response.json() because that would throw.
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
|
Size Change: 0 B Total Size: 1.92 MB ℹ️ View Unchanged
|
Mamaduka
left a comment
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.
Love this! Thank you, @jsnajdr!
|
Flaky tests detected in 8128f3d. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/17374318808
|
While working on #67141 I noticed that unit tests for
apiFetchcan be greatly improved:jest/no-conditional-expectrule. It's possible when using theexpect().resolvesandexpect().rejectshelper. One test that was disabling this rule was wrong, namely the one that tests the 204 status with no body. It expectedapiFetchto throw, but that never happened, and the test succeeded anyway..mockResolvedValue,.mockRejectedValue. Together withasyncfunctions, this makes the code more concise.okfield. I plan to do another patch that starts using.okinstead of thecheckStatushelper, and that makes the tests fail.controllerandsignaldidn't play any role.awaitto all calls ofapiFetch, even for synchronous tests (typically checkingmock.toHaveBeenCalled). Otherwise, the async code execution leaks out of the test, continuing even after the test finished.globalThis.fetchinstead ofwindow.fetch: makes the library more compatible with Node and web workers. Admittedly a rather theoretical fix.