From b901bb6c75ef910f6a2de27ec1a236a3f1a940f9 Mon Sep 17 00:00:00 2001 From: Antoine Clausse Date: Thu, 17 Apr 2025 09:43:23 +0200 Subject: [PATCH] [web] Update `fetch-mock` to version 12 (#24837) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update fetch-mock to version 12 * Replace `fetchMock.done` by `fetchMock.callHistory.done` * Replace `…Mock.called` by `…Mock.callHistory.called` * Replace `fetchMock.reset` by `fetchMock.hardReset` * Replace `fetchMock.restore` by `fetchMock.hardReset` * Replace `fetchMock.resetHistory` by `fetchMock.clearHistory` * Replace `fetchMock.calls` by `fetchMock.callHistory.calls` * Replace `fetchMock.flush` by `fetchMock.callHistory.flush` * Update tests for fetch-mock version 12 See https://www.wheresrhys.co.uk/fetch-mock/docs/Usage/upgrade-guide * Update stories for fetch-mock version 12 * Remove `overwriteRoutes` option * Add `fetchMock.spyGlobal()` to storybook * Remove deprecated `sendAsJson` param * Replace `fetchMock.hardReset()` by `fetchMock.removeRoutes().clearHistory()` * Fixup fetch-mock in storybook: Call `mockGlobal` inside the hook, call `removeRoutes` and `unmockGlobal` on cleanup Behaviour can be tested by navigating between https://storybook.dev-overleaf.com/main/?path=/story/editor-ai-error-assistant-compile-log-entries--first-log-entry https://storybook.dev-overleaf.com/main/?path=/story/editor-ai-error-assistant-compile-log-entries--rate-limited https://storybook.dev-overleaf.com/main/?path=/story/project-list-notifications--project-invite https://storybook.dev-overleaf.com/main/?path=/story/project-list-notifications--project-invite-network-error And clicking the buttons GitOrigin-RevId: 35611b4430259e4c21c3d819ad18b2e6dab66242 --- package-lock.json | 112 ++++---------- .../stories/file-view/file-view.stories.jsx | 16 +- .../web/frontend/stories/fixtures/compile.js | 101 ++++++------ .../frontend/stories/hooks/use-fetch-mock.tsx | 9 +- .../create-file/create-file-modal.stories.jsx | 8 +- .../frontend/stories/notification.stories.tsx | 6 +- .../stories/project-list/helpers/emails.ts | 30 ++-- .../project-list/system-messages.stories.tsx | 6 +- .../stories/settings/helpers/emails.js | 2 - .../js/components/register-form.test.jsx | 6 +- .../user-activate-register.test.jsx | 14 +- services/web/package.json | 2 +- services/web/test/frontend/bootstrap.js | 6 + .../chat/components/chat-pane.test.jsx | 6 +- .../chat/context/chat-context.test.jsx | 106 ++++++------- .../components/clone-project-modal.test.jsx | 26 ++-- .../components/actions-copy-project.test.jsx | 2 +- .../components/actions-menu.test.jsx | 2 +- .../components/actions-word-count.test.jsx | 10 +- .../components/download-menu.test.jsx | 2 +- .../components/help-contact-us.test.jsx | 2 +- .../components/help-menu.test.jsx | 2 +- .../components/help-show-hotkeys.test.jsx | 2 +- .../settings-auto-close-brackets.test.tsx | 2 +- .../settings/settings-auto-complete.test.tsx | 2 +- .../settings/settings-compiler.test.tsx | 2 +- .../settings/settings-document.test.tsx | 2 +- .../settings/settings-editor-theme.test.tsx | 2 +- .../settings/settings-font-family.test.tsx | 2 +- .../settings/settings-font-size.test.tsx | 2 +- .../settings/settings-image-name.test.tsx | 2 +- .../settings/settings-keybindings.test.tsx | 2 +- .../settings/settings-line-height.test.tsx | 2 +- .../settings/settings-math-preview.test.tsx | 2 +- .../settings/settings-overall-theme.test.tsx | 2 +- .../settings/settings-pdf-viewer.test.tsx | 2 +- .../settings-spell-check-language.test.tsx | 2 +- .../settings-syntax-validation.test.tsx | 2 +- .../layout-dropdown-button.test.jsx | 2 +- .../components/file-view-header.test.jsx | 2 +- .../file-view-refresh-button.test.jsx | 2 +- .../components/file-view-text.test.jsx | 2 +- .../file-view/components/file-view.test.jsx | 2 +- .../members-table/unlink-user-modal.test.tsx | 2 +- .../components/load-more.test.tsx | 2 +- .../components/new-project-button.test.tsx | 2 +- .../modal-content-new-project-form.test.tsx | 10 +- .../components/notifications.test.tsx | 109 ++++++------- .../components/project-list-root.test.tsx | 145 ++++++++++-------- .../components/project-search.test.tsx | 4 +- .../sidebar/add-affiliation.test.tsx | 20 +-- .../components/sidebar/tags-list.test.tsx | 26 ++-- .../components/system-messages.test.tsx | 10 +- .../archive-project-button.test.tsx | 7 +- ...e-and-download-project-pdf-button.test.tsx | 2 +- .../copy-project-button.test.tsx | 7 +- .../delete-project-button.test.tsx | 3 +- .../leave-project-button.test.tsx | 5 +- .../rename-project-button.test.tsx | 5 +- .../trash-project-button.test.tsx | 5 +- .../unarchive-project-button.test.tsx | 7 +- .../untrash-project-button.test.tsx | 5 +- .../table/cells/inline-tags.test.tsx | 9 +- .../table/project-list-table.test.tsx | 14 +- .../project-tools-rename.test.tsx | 2 +- .../rename-project-modal.test.tsx | 6 +- .../helpers/render-with-context.tsx | 2 +- .../components/account-info-section.test.tsx | 54 +++---- .../emails/add-email-input.test.tsx | 33 ++-- .../components/emails/emails-row.test.tsx | 10 +- .../emails/emails-section-actions.test.tsx | 8 +- .../emails-section-add-new-email.test.tsx | 58 +++---- ...ails-section-institution-and-role.test.tsx | 24 ++- .../components/emails/emails-section.test.tsx | 4 +- .../emails/reconfirmation-info.test.tsx | 8 +- .../components/leave/modal-content.test.tsx | 2 +- .../components/leave/modal-form.test.tsx | 12 +- .../settings/components/leave/modal.test.tsx | 2 +- .../components/leavers-survey-alert.test.tsx | 2 +- .../components/linking-section.test.tsx | 2 +- .../components/password-section.test.tsx | 20 +-- .../components/security-section.test.tsx | 2 +- .../settings/context/sso-context.test.tsx | 6 +- .../context/user-email-context.test.tsx | 44 +++--- .../components/share-project-modal.test.jsx | 101 ++++++------ .../group-subscription-memberships.test.tsx | 4 +- .../dashboard/managed-institutions.test.tsx | 19 ++- .../dashboard/managed-publishers.test.tsx | 2 +- .../components/dashboard/pause-modal.test.tsx | 2 +- .../dashboard/personal-subscription.test.tsx | 8 +- .../dashboard/states/active/active.test.tsx | 2 +- .../active/change-plan/change-plan.test.tsx | 2 +- ...s-individual-recurly-subscription.test.tsx | 2 +- .../group-invite/join-group.test.tsx | 2 +- .../render-with-subscription-dash-context.tsx | 2 +- .../components/word-count-modal.test.jsx | 2 +- .../infrastructure/fetch-json.test.js | 17 +- .../infrastructure/project-snapshot.test.ts | 66 ++++---- .../hooks/use-abort-controller.test.tsx | 8 +- 99 files changed, 728 insertions(+), 729 deletions(-) diff --git a/package-lock.json b/package-lock.json index 986630ccc3..0b9de29e3e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12218,6 +12218,13 @@ "@types/node": "*" } }, + "node_modules/@types/glob-to-regexp": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@types/glob-to-regexp/-/glob-to-regexp-0.4.4.tgz", + "integrity": "sha512-nDKoaKJYbnn1MZxUY0cA1bPmmgZbg0cTq7Rh13d0KWYNOiKbqoR+2d89SnRPszGh7ROzSwZ/GOjZ4jPbmmZ6Eg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/hapi__catbox": { "version": "10.2.4", "resolved": "https://registry.npmjs.org/@types/hapi__catbox/-/hapi__catbox-10.2.4.tgz", @@ -22764,45 +22771,6 @@ "node": ">=4.0.0" } }, - "node_modules/fetch-mock": { - "version": "9.11.0", - "resolved": "https://registry.npmjs.org/fetch-mock/-/fetch-mock-9.11.0.tgz", - "integrity": "sha512-PG1XUv+x7iag5p/iNHD4/jdpxL9FtVSqRMUQhPab4hVDt80T1MH5ehzVrL2IdXO9Q2iBggArFvPqjUbHFuI58Q==", - "dev": true, - "dependencies": { - "@babel/core": "^7.0.0", - "@babel/runtime": "^7.0.0", - "core-js": "^3.0.0", - "debug": "^4.1.1", - "glob-to-regexp": "^0.4.0", - "is-subset": "^0.1.1", - "lodash.isequal": "^4.5.0", - "path-to-regexp": "^2.2.1", - "querystring": "^0.2.0", - "whatwg-url": "^6.5.0" - }, - "engines": { - "node": ">=4.0.0" - }, - "funding": { - "type": "charity", - "url": "https://www.justgiving.com/refugee-support-europe" - }, - "peerDependencies": { - "node-fetch": "*" - }, - "peerDependenciesMeta": { - "node-fetch": { - "optional": true - } - } - }, - "node_modules/fetch-mock/node_modules/path-to-regexp": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.3.0.tgz", - "integrity": "sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==", - "dev": true - }, "node_modules/figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", @@ -26431,12 +26399,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-subset": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-subset/-/is-subset-0.1.1.tgz", - "integrity": "sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY=", - "dev": true - }, "node_modules/is-symbol": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", @@ -28433,12 +28395,6 @@ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" }, - "node_modules/lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true - }, "node_modules/lodash.support": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/lodash.support/-/lodash.support-2.4.1.tgz", @@ -35391,6 +35347,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/regexparam": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/regexparam/-/regexparam-3.0.0.tgz", + "integrity": "sha512-RSYAtP31mvYLkAHrOlh25pCNQ5hWnT106VukGaaFfuJrZFkGRX5GhUAdPqpSDXxOhA2c4akmRuplv1mRqnBn6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -39423,15 +39389,6 @@ "node": ">= 4.0.0" } }, - "node_modules/tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, "node_modules/traverse": { "version": "0.6.9", "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.9.tgz", @@ -41219,23 +41176,6 @@ "node": ">=12" } }, - "node_modules/whatwg-url": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", - "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", - "dev": true, - "dependencies": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "node_modules/whatwg-url/node_modules/webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -44521,7 +44461,7 @@ "esmock": "^2.6.7", "events": "^3.3.0", "fake-indexeddb": "^6.0.0", - "fetch-mock": "^9.10.2", + "fetch-mock": "^12.5.2", "formik": "^2.2.9", "fuse.js": "^3.0.0", "glob": "^7.1.6", @@ -45294,6 +45234,22 @@ "integrity": "sha512-g/aje2noHivrRSLbAUtBPWFbxKdKhgj/xr1vATDdUXPOFYJlQ62Ft0oy+72V6XLIpDJfHs6gXLbBLAolqOXYRw==", "dev": true }, + "services/web/node_modules/fetch-mock": { + "version": "12.5.2", + "resolved": "https://registry.npmjs.org/fetch-mock/-/fetch-mock-12.5.2.tgz", + "integrity": "sha512-b5KGDFmdmado2MPQjZl6ix3dAG3iwCitb0XQwN72y2s9VnWZ3ObaGNy+bkpm1390foiLDybdJ7yjRGKD36kATw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/glob-to-regexp": "^0.4.4", + "dequal": "^2.0.3", + "glob-to-regexp": "^0.4.1", + "regexparam": "^3.0.0" + }, + "engines": { + "node": ">=18.11.0" + } + }, "services/web/node_modules/google-auth-library": { "version": "8.7.0", "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.7.0.tgz", diff --git a/services/web/frontend/stories/file-view/file-view.stories.jsx b/services/web/frontend/stories/file-view/file-view.stories.jsx index bad7002755..5622e6eb52 100644 --- a/services/web/frontend/stories/file-view/file-view.stories.jsx +++ b/services/web/frontend/stories/file-view/file-view.stories.jsx @@ -158,11 +158,9 @@ ImageFile.args = { export const TextFile = args => { useFetchMock(fetchMock => - setupFetchMock(fetchMock).get( - 'express:/project/:project_id/blob/:hash', - { body: bodies.text }, - { overwriteRoutes: true } - ) + setupFetchMock(fetchMock).get('express:/project/:project_id/blob/:hash', { + body: bodies.text, + }) ) return } @@ -180,11 +178,9 @@ TextFile.args = { export const UploadedFile = args => { useFetchMock(fetchMock => - setupFetchMock(fetchMock).head( - 'express:/project/:project_id/blob/:hash', - { status: 500 }, - { overwriteRoutes: true } - ) + setupFetchMock(fetchMock).head('express:/project/:project_id/blob/:hash', { + status: 500, + }) ) return } diff --git a/services/web/frontend/stories/fixtures/compile.js b/services/web/frontend/stories/fixtures/compile.js index 595998d3da..9471ff04ff 100644 --- a/services/web/frontend/stories/fixtures/compile.js +++ b/services/web/frontend/stories/fixtures/compile.js @@ -58,7 +58,7 @@ export const mockCompile = (fetchMock, delay = 1000) => outputFiles: cloneDeep(outputFiles), }, }, - { delay, overwriteRoutes: true } + { delay } ) export const mockCompileError = (fetchMock, status = 'success', delay = 1000) => @@ -91,27 +91,24 @@ export const mockCompileValidationIssues = ( }, } }, - { delay, overwriteRoutes: true } + { delay } ) export const mockClearCache = fetchMock => fetchMock.delete('express:/project/:projectId/output', 204, { delay: 1000, - overwriteRoutes: true, }) export const mockBuildFile = fetchMock => - fetchMock.get( - 'express:/build/:file', - (url, options, request) => { - const { pathname } = new URL(url, 'https://example.com') + fetchMock.get('express:/build/:file', (url, options, request) => { + const { pathname } = new URL(url, 'https://example.com') - switch (pathname) { - case '/build/output.blg': - return 'This is BibTeX, Version 4.0' // FIXME + switch (pathname) { + case '/build/output.blg': + return 'This is BibTeX, Version 4.0' // FIXME - case '/build/output.log': - return ` + case '/build/output.log': + return ` The LaTeX compiler output * With a lot of details @@ -134,31 +131,29 @@ LaTeX Font Info: External font \`cmex10' loaded for size ` - case '/build/output.pdf': - return new Promise(resolve => { - const xhr = new XMLHttpRequest() - xhr.addEventListener('load', () => { - resolve({ - status: 200, - headers: { - 'Content-Length': xhr.getResponseHeader('Content-Length'), - 'Content-Type': xhr.getResponseHeader('Content-Type'), - }, - body: xhr.response, - }) + case '/build/output.pdf': + return new Promise(resolve => { + const xhr = new XMLHttpRequest() + xhr.addEventListener('load', () => { + resolve({ + status: 200, + headers: { + 'Content-Length': xhr.getResponseHeader('Content-Length'), + 'Content-Type': xhr.getResponseHeader('Content-Type'), + }, + body: xhr.response, }) - xhr.open('GET', examplePdf) - xhr.responseType = 'arraybuffer' - xhr.send() }) + xhr.open('GET', examplePdf) + xhr.responseType = 'arraybuffer' + xhr.send() + }) - default: - console.log(pathname) - return 404 - } - }, - { sendAsJson: false, overwriteRoutes: true } - ) + default: + console.log(pathname) + return 404 + } + }) const mockHighlights = [ { @@ -195,29 +190,25 @@ export const mockEventTracking = fetchMock => fetchMock.get('express:/event/:event', 204) export const mockValidPdf = fetchMock => - fetchMock.get( - 'express:/build/output.pdf', - (url, options, request) => { - return new Promise(resolve => { - const xhr = new XMLHttpRequest() - xhr.addEventListener('load', () => { - resolve({ - status: 200, - headers: { - 'Content-Length': xhr.getResponseHeader('Content-Length'), - 'Content-Type': xhr.getResponseHeader('Content-Type'), - 'Accept-Ranges': 'bytes', - }, - body: xhr.response, - }) + fetchMock.get('express:/build/output.pdf', (url, options, request) => { + return new Promise(resolve => { + const xhr = new XMLHttpRequest() + xhr.addEventListener('load', () => { + resolve({ + status: 200, + headers: { + 'Content-Length': xhr.getResponseHeader('Content-Length'), + 'Content-Type': xhr.getResponseHeader('Content-Type'), + 'Accept-Ranges': 'bytes', + }, + body: xhr.response, }) - xhr.open('GET', examplePdf) - xhr.responseType = 'arraybuffer' - xhr.send() }) - }, - { sendAsJson: false, overwriteRoutes: true } - ) + xhr.open('GET', examplePdf) + xhr.responseType = 'arraybuffer' + xhr.send() + }) + }) export const mockSynctex = fetchMock => fetchMock diff --git a/services/web/frontend/stories/hooks/use-fetch-mock.tsx b/services/web/frontend/stories/hooks/use-fetch-mock.tsx index c5a527c81d..7f00118aac 100644 --- a/services/web/frontend/stories/hooks/use-fetch-mock.tsx +++ b/services/web/frontend/stories/hooks/use-fetch-mock.tsx @@ -1,18 +1,19 @@ import { useLayoutEffect } from 'react' import fetchMock from 'fetch-mock' -fetchMock.config.fallbackToNetwork = true /** - * Run callback to mock fetch routes, call restore() when unmounted + * Run callback to mock fetch routes, call removeRoutes() and unmockGlobal() when unmounted */ export default function useFetchMock( callback: (value: typeof fetchMock) => void ) { + fetchMock.mockGlobal() + useLayoutEffect(() => { callback(fetchMock) - return () => { - fetchMock.restore() + fetchMock.removeRoutes() + fetchMock.unmockGlobal() } }, [callback]) } diff --git a/services/web/frontend/stories/modals/create-file/create-file-modal.stories.jsx b/services/web/frontend/stories/modals/create-file/create-file-modal.stories.jsx index 1ff2b46c79..ba5ad45d22 100644 --- a/services/web/frontend/stories/modals/create-file/create-file-modal.stories.jsx +++ b/services/web/frontend/stories/modals/create-file/create-file-modal.stories.jsx @@ -37,9 +37,7 @@ export const ErrorImportingFileFromExternalURL = args => { useFetchMock(fetchMock => { mockCreateFileModalFetch(fetchMock) - fetchMock.post('express:/project/:projectId/linked_file', 500, { - overwriteRoutes: true, - }) + fetchMock.post('express:/project/:projectId/linked_file', 500) }) getMeta('ol-ExposedSettings').hasLinkUrlFeature = true @@ -52,9 +50,7 @@ export const ErrorImportingFileFromReferenceProvider = args => { useFetchMock(fetchMock => { mockCreateFileModalFetch(fetchMock) - fetchMock.post('express:/project/:projectId/linked_file', 500, { - overwriteRoutes: true, - }) + fetchMock.post('express:/project/:projectId/linked_file', 500) }) return diff --git a/services/web/frontend/stories/notification.stories.tsx b/services/web/frontend/stories/notification.stories.tsx index 321e7e3e33..0c55606278 100644 --- a/services/web/frontend/stories/notification.stories.tsx +++ b/services/web/frontend/stories/notification.stories.tsx @@ -315,11 +315,7 @@ export const OverlayedWithCustomClass = (args: Args) => { export const SuccessFlow = (args: Args) => { console.log('.....render') - fetchMock.post( - 'express:/test-success', - { status: 200 }, - { delay: 250, overwriteRoutes: true } - ) + fetchMock.post('express:/test-success', { status: 200 }, { delay: 250 }) const { isLoading, isSuccess, runAsync } = useAsync() function handleClick() { diff --git a/services/web/frontend/stories/project-list/helpers/emails.ts b/services/web/frontend/stories/project-list/helpers/emails.ts index 06c12eb577..83c09fd527 100644 --- a/services/web/frontend/stories/project-list/helpers/emails.ts +++ b/services/web/frontend/stories/project-list/helpers/emails.ts @@ -1,5 +1,5 @@ import { merge, cloneDeep } from 'lodash' -import { FetchMockStatic } from 'fetch-mock' +import { type FetchMock } from 'fetch-mock' import { UserEmailData } from '../../../../types/user-email' import { Institution, @@ -32,7 +32,7 @@ export const fakeReconfirmationUsersData = { default: false, } as DeepReadonly -export function defaultSetupMocks(fetchMock: FetchMockStatic) { +export function defaultSetupMocks(fetchMock: FetchMock) { // at least one project is required to show some notifications const projects = [{}] as Project[] fetchMock.post(/\/api\/project/, { @@ -54,7 +54,7 @@ export function setDefaultMeta() { window.metaAttributesCache.set('ol-userEmails', []) } -export function errorsMocks(fetchMock: FetchMockStatic) { +export function errorsMocks(fetchMock: FetchMock) { defaultSetupMocks(fetchMock) fetchMock.post(/\/user\/emails\/*/, 500, { delay: MOCK_DELAY }) fetchMock.post( @@ -74,7 +74,7 @@ export function setInstitutionMeta(institutionData: Partial) { ]) } -export function institutionSetupMocks(fetchMock: FetchMockStatic) { +export function institutionSetupMocks(fetchMock: FetchMock) { defaultSetupMocks(fetchMock) fetchMock.delete(/\/notifications\/*/, 200, { delay: MOCK_DELAY }) } @@ -84,7 +84,7 @@ export function setCommonMeta(notificationData: DeepPartial) { window.metaAttributesCache.set('ol-notifications', [notificationData]) } -export function commonSetupMocks(fetchMock: FetchMockStatic) { +export function commonSetupMocks(fetchMock: FetchMock) { defaultSetupMocks(fetchMock) fetchMock.post( /\/project\/[A-Za-z0-9]+\/invite\/token\/[A-Za-z0-9]+\/accept/, @@ -98,7 +98,7 @@ export function setReconfirmationMeta() { window.metaAttributesCache.set('ol-userEmails', [fakeReconfirmationUsersData]) } -export function reconfirmationSetupMocks(fetchMock: FetchMockStatic) { +export function reconfirmationSetupMocks(fetchMock: FetchMock) { defaultSetupMocks(fetchMock) fetchMock.post(/\/user\/emails\/resend_confirmation/, 200, { delay: MOCK_DELAY, @@ -113,19 +113,15 @@ export function setReconfirmAffiliationMeta() { ) } -export function reconfirmAffiliationSetupMocks(fetchMock: FetchMockStatic) { +export function reconfirmAffiliationSetupMocks(fetchMock: FetchMock) { defaultSetupMocks(fetchMock) - fetchMock.post( - /\/api\/project/, - { - status: 200, - body: { - projects: [{}], - totalSize: 0, - }, + fetchMock.post(/\/api\/project/, { + status: 200, + body: { + projects: [{}], + totalSize: 0, }, - { overwriteRoutes: true } - ) + }) fetchMock.post(/\/user\/emails\/send-reconfirmation/, 200, { delay: MOCK_DELAY, }) diff --git a/services/web/frontend/stories/project-list/system-messages.stories.tsx b/services/web/frontend/stories/project-list/system-messages.stories.tsx index 0628d6b4fd..d97ca4537c 100644 --- a/services/web/frontend/stories/project-list/system-messages.stories.tsx +++ b/services/web/frontend/stories/project-list/system-messages.stories.tsx @@ -1,9 +1,9 @@ import SystemMessages from '@/shared/components/system-messages' import useFetchMock from '../hooks/use-fetch-mock' -import { FetchMockStatic } from 'fetch-mock' +import { type FetchMock } from 'fetch-mock' export const SystemMessage = (args: any) => { - useFetchMock((fetchMock: FetchMockStatic) => { + useFetchMock((fetchMock: FetchMock) => { fetchMock.get(/\/system\/messages/, [ { _id: 1, @@ -23,7 +23,7 @@ export const SystemMessage = (args: any) => { } export const TranslationMessage = (args: any) => { - useFetchMock((fetchMock: FetchMockStatic) => { + useFetchMock((fetchMock: FetchMock) => { fetchMock.get(/\/system\/messages/, []) }) diff --git a/services/web/frontend/stories/settings/helpers/emails.js b/services/web/frontend/stories/settings/helpers/emails.js index 2afe6a3014..546ccb2d96 100644 --- a/services/web/frontend/stories/settings/helpers/emails.js +++ b/services/web/frontend/stories/settings/helpers/emails.js @@ -174,7 +174,6 @@ export function reconfirmationSetupMocks(fetchMock) { defaultSetupMocks(fetchMock) fetchMock.get(/\/user\/emails/, fakeReconfirmationUsersData, { delay: MOCK_DELAY, - overwriteRoutes: true, }) } @@ -186,7 +185,6 @@ export function emailLimitSetupMocks(fetchMock) { defaultSetupMocks(fetchMock) fetchMock.get(/\/user\/emails/, userData, { delay: MOCK_DELAY, - overwriteRoutes: true, }) } diff --git a/services/web/modules/user-activate/test/frontend/js/components/register-form.test.jsx b/services/web/modules/user-activate/test/frontend/js/components/register-form.test.jsx index 39c6e98c1b..58833f1faf 100644 --- a/services/web/modules/user-activate/test/frontend/js/components/register-form.test.jsx +++ b/services/web/modules/user-activate/test/frontend/js/components/register-form.test.jsx @@ -6,10 +6,10 @@ import RegisterForm from '../../../../frontend/js/components/register-form' describe('RegisterForm', function () { beforeEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('should render the register form', async function () { const setRegistrationSuccessStub = sinon.stub() @@ -57,6 +57,6 @@ describe('RegisterForm', function () { const registerButton = screen.getByRole('button', { name: /register/i }) fireEvent.change(registerInput, { target: { value: email } }) fireEvent.click(registerButton) - expect(registerMock.called()).to.be.true + expect(registerMock.callHistory.called()).to.be.true }) }) diff --git a/services/web/modules/user-activate/test/frontend/js/components/user-activate-register.test.jsx b/services/web/modules/user-activate/test/frontend/js/components/user-activate-register.test.jsx index 773170feec..2089986976 100644 --- a/services/web/modules/user-activate/test/frontend/js/components/user-activate-register.test.jsx +++ b/services/web/modules/user-activate/test/frontend/js/components/user-activate-register.test.jsx @@ -5,10 +5,10 @@ import UserActivateRegister from '../../../../frontend/js/components/user-activa describe('UserActivateRegister', function () { beforeEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('should display the error message', async function () { const email = 'abc@gmail.com' @@ -23,7 +23,7 @@ describe('UserActivateRegister', function () { fireEvent.change(registerInput, { target: { value: email } }) fireEvent.click(registerButton) - expect(registerMock.called()).to.be.true + expect(registerMock.callHistory.called()).to.be.true await screen.findByText('Sorry, an error occured', { exact: false }) }) @@ -44,7 +44,7 @@ describe('UserActivateRegister', function () { fireEvent.change(registerInput, { target: { value: email } }) fireEvent.click(registerButton) - expect(registerMock.called()).to.be.true + expect(registerMock.callHistory.called()).to.be.true await screen.findByText( "We've sent out welcome emails to the registered users." ) @@ -78,7 +78,7 @@ describe('UserActivateRegister', function () { fireEvent.change(registerInput, { target: { value: email } }) fireEvent.click(registerButton) - expect(registerMock.called()).to.be.true + expect(registerMock.callHistory.called()).to.be.true await screen.findByText('abc@gmail.com') await screen.findByText('def@gmail.com') }) @@ -103,7 +103,7 @@ describe('UserActivateRegister', function () { fireEvent.change(registerInput, { target: { value: email } }) fireEvent.click(registerButton) - expect(registerMock.called()).to.be.true + expect(registerMock.callHistory.called()).to.be.true await screen.findByText('abc@') await screen.findByText('def@') }) @@ -133,7 +133,7 @@ describe('UserActivateRegister', function () { fireEvent.change(registerInput, { target: { value: email } }) fireEvent.click(registerButton) - expect(registerMock.called()).to.be.true + expect(registerMock.callHistory.called()).to.be.true await screen.findByText('abc@gmail.com') await screen.findByText('def@') }) diff --git a/services/web/package.json b/services/web/package.json index b2ba9c2c7d..b03c0ac472 100644 --- a/services/web/package.json +++ b/services/web/package.json @@ -295,7 +295,7 @@ "esmock": "^2.6.7", "events": "^3.3.0", "fake-indexeddb": "^6.0.0", - "fetch-mock": "^9.10.2", + "fetch-mock": "^12.5.2", "formik": "^2.2.9", "fuse.js": "^3.0.0", "glob": "^7.1.6", diff --git a/services/web/test/frontend/bootstrap.js b/services/web/test/frontend/bootstrap.js index cdc9300138..e98d2c35de 100644 --- a/services/web/test/frontend/bootstrap.js +++ b/services/web/test/frontend/bootstrap.js @@ -98,3 +98,9 @@ globalThis.DOMParser = window.DOMParser // Polyfill for IndexedDB require('fake-indexeddb/auto') + +const fetchMock = require('fetch-mock').default + +fetchMock.spyGlobal() +fetchMock.config.fetch = global.fetch +fetchMock.config.Response = fetch.Response diff --git a/services/web/test/frontend/features/chat/components/chat-pane.test.jsx b/services/web/test/frontend/features/chat/components/chat-pane.test.jsx index 5caf51097e..514993a5e5 100644 --- a/services/web/test/frontend/features/chat/components/chat-pane.test.jsx +++ b/services/web/test/frontend/features/chat/components/chat-pane.test.jsx @@ -26,7 +26,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) const testMessages = [ @@ -45,7 +45,7 @@ describe('', function () { ] beforeEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() cleanUpContext() stubMathJax() @@ -73,7 +73,7 @@ describe('', function () { await screen.findByText('Try again') // bring chat back up - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() fetchMock.get(/messages/, []) const reconnectButton = screen.getByRole('button', { diff --git a/services/web/test/frontend/features/chat/context/chat-context.test.jsx b/services/web/test/frontend/features/chat/context/chat-context.test.jsx index 3d14a11355..5bc71c1d0d 100644 --- a/services/web/test/frontend/features/chat/context/chat-context.test.jsx +++ b/services/web/test/frontend/features/chat/context/chat-context.test.jsx @@ -23,7 +23,7 @@ describe('ChatContext', function () { const uuidValue = '00000000-0000-0000-0000-000000000000' beforeEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() cleanUpContext() stubMathJax() @@ -43,14 +43,15 @@ describe('ChatContext', function () { describe('socket connection', function () { beforeEach(function () { // Mock GET messages to return no messages - fetchMock.get('express:/project/:projectId/messages', []) + // FIXME? + // fetchMock.get('express:/project/:projectId/messages', []) // Mock POST new message to return 200 fetchMock.post('express:/project/:projectId/messages', 200) }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('subscribes when mounted', function () { @@ -106,22 +107,18 @@ describe('ChatContext', function () { socket, }) - fetchMock.get( - 'express:/project/:projectId/messages', - [ - { - id: 'msg_1', - content: 'new message', - timestamp: Date.now(), - user: { - id: 'another_fake_user', - first_name: 'another_fake_user_first_name', - email: 'another_fake@example.com', - }, + fetchMock.get('express:/project/:projectId/messages', [ + { + id: 'msg_1', + content: 'new message', + timestamp: Date.now(), + user: { + id: 'another_fake_user', + first_name: 'another_fake_user_first_name', + email: 'another_fake@example.com', }, - ], - { overwriteRoutes: true } - ) + }, + ]) // Mock message being received from another user socket.emitToClient('new-chat-message', { @@ -157,22 +154,18 @@ describe('ChatContext', function () { socket, }) - fetchMock.get( - 'express:/project/:projectId/messages', - [ - { - id: 'msg_1', - content: 'new message', - timestamp: Date.now(), - user: { - id: 'another_fake_user', - first_name: 'another_fake_user_first_name', - email: 'another_fake@example.com', - }, + fetchMock.get('express:/project/:projectId/messages', [ + { + id: 'msg_1', + content: 'new message', + timestamp: Date.now(), + user: { + id: 'another_fake_user', + first_name: 'another_fake_user_first_name', + email: 'another_fake@example.com', }, - ], - { overwriteRoutes: true } - ) + }, + ]) // Wait until initial messages have loaded result.current.loadInitialMessages() @@ -320,11 +313,13 @@ describe('ChatContext', function () { // Calling a second time won't do anything result.current.loadInitialMessages() - expect(fetchMock.calls()).to.have.lengthOf(1) + expect( + fetchMock.callHistory.calls('express:/project/:projectId/messages') + ).to.have.lengthOf(1) }) it('provides an error on failure', async function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() fetchMock.get('express:/project/:projectId/messages', 500) const { result, waitForNextUpdate } = renderChatContextHook({}) @@ -369,18 +364,14 @@ describe('ChatContext', function () { // Resolve a full "page" of messages (50) createMessages(50, user, new Date('2021-03-04T10:00:00').getTime()) ) - .getOnce( - 'express:/project/:projectId/messages', - [ - { - id: 'msg_51', - content: 'message from second page', - user, - timestamp: new Date('2021-03-04T11:00:00').getTime(), - }, - ], - { overwriteRoutes: false } - ) + .getOnce('express:/project/:projectId/messages', [ + { + id: 'msg_51', + content: 'message from second page', + user, + timestamp: new Date('2021-03-04T11:00:00').getTime(), + }, + ]) const { result, waitForNextUpdate } = renderChatContextHook({}) @@ -422,7 +413,9 @@ describe('ChatContext', function () { result.current.loadMoreMessages() expect(result.current.atEnd).to.be.true - expect(fetchMock.calls()).to.have.lengthOf(1) + expect( + fetchMock.callHistory.calls('express:/project/:projectId/messages') + ).to.have.lengthOf(1) }) it('handles socket messages while loading', async function () { @@ -479,7 +472,7 @@ describe('ChatContext', function () { }) it('provides an error on failures', async function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() fetchMock.get('express:/project/:projectId/messages', 500) const { result, waitForNextUpdate } = renderChatContextHook({}) @@ -515,10 +508,11 @@ describe('ChatContext', function () { result.current.sendMessage('sent message') - const [, { body }] = fetchMock.lastCall( - 'express:/project/:projectId/messages', - 'POST' - ) + const { + options: { body }, + } = fetchMock.callHistory + .calls('express:/project/:projectId/messages', { method: 'POST' }) + .at(-1) expect(JSON.parse(body)).to.deep.include({ content: 'sent message' }) }) @@ -529,14 +523,14 @@ describe('ChatContext', function () { expect(result.current.messages).to.be.empty expect( - fetchMock.called('express:/project/:projectId/messages', { + fetchMock.callHistory.called('express:/project/:projectId/messages', { method: 'post', }) ).to.be.false }) it('provides an error on failure', async function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() fetchMock .get('express:/project/:projectId/messages', []) .postOnce('express:/project/:projectId/messages', 500) @@ -614,7 +608,7 @@ function createMessages(number, user, timestamp = Date.now()) { * Get query param by key from the last fetchMock response */ function getLastFetchMockQueryParam(key) { - const url = fetchMock.lastUrl() + const { url } = fetchMock.callHistory.calls().at(-1) const { searchParams } = new URL(url, 'https://www.overleaf.com') return searchParams.get(key) } diff --git a/services/web/test/frontend/features/clone-project-modal/components/clone-project-modal.test.jsx b/services/web/test/frontend/features/clone-project-modal/components/clone-project-modal.test.jsx index 4c6d49f752..3b0db2339f 100644 --- a/services/web/test/frontend/features/clone-project-modal/components/clone-project-modal.test.jsx +++ b/services/web/test/frontend/features/clone-project-modal/components/clone-project-modal.test.jsx @@ -7,11 +7,11 @@ import { renderWithEditorContext } from '../../../helpers/render-with-context' describe('', function () { beforeEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) after(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) const project = { @@ -78,19 +78,23 @@ describe('', function () { fireEvent.click(submitButton) expect(submitButton.disabled).to.be.true - await fetchMock.flush(true) - expect(fetchMock.done()).to.be.true - const [url, options] = fetchMock.lastCall( - 'express:/project/:projectId/clone' + await fetchMock.callHistory.flush(true) + expect(fetchMock.callHistory.done()).to.be.true + const { url, options } = fetchMock.callHistory + .calls('express:/project/:projectId/clone') + .at(-1) + expect(url).to.equal( + 'https://www.test-overleaf.com/project/project-1/clone' ) - expect(url).to.equal('/project/project-1/clone') expect(JSON.parse(options.body)).to.deep.equal({ projectName: 'A Cloned Project', tags: [], }) - expect(openProject).to.be.calledOnce + await waitFor(() => { + expect(openProject).to.be.calledOnce + }) const errorMessage = screen.queryByText('Sorry, something went wrong') expect(errorMessage).to.be.null @@ -129,7 +133,7 @@ describe('', function () { fireEvent.click(button) - expect(fetchMock.done(matcher)).to.be.true + expect(fetchMock.callHistory.done(matcher)).to.be.true expect(openProject).not.to.be.called await screen.findByText('Sorry, something went wrong') @@ -165,9 +169,9 @@ describe('', function () { expect(cancelButton.disabled).to.be.false fireEvent.click(button) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) - expect(fetchMock.done(matcher)).to.be.true + expect(fetchMock.callHistory.done(matcher)).to.be.true expect(openProject).not.to.be.called await screen.findByText('There was an error!') diff --git a/services/web/test/frontend/features/editor-left-menu/components/actions-copy-project.test.jsx b/services/web/test/frontend/features/editor-left-menu/components/actions-copy-project.test.jsx index 1a239e8147..5e38e25af9 100644 --- a/services/web/test/frontend/features/editor-left-menu/components/actions-copy-project.test.jsx +++ b/services/web/test/frontend/features/editor-left-menu/components/actions-copy-project.test.jsx @@ -20,7 +20,7 @@ describe('', function () { afterEach(function () { this.locationStub.restore() - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('shows correct modal when clicked', async function () { diff --git a/services/web/test/frontend/features/editor-left-menu/components/actions-menu.test.jsx b/services/web/test/frontend/features/editor-left-menu/components/actions-menu.test.jsx index 5f1b7d790c..d48e172c49 100644 --- a/services/web/test/frontend/features/editor-left-menu/components/actions-menu.test.jsx +++ b/services/web/test/frontend/features/editor-left-menu/components/actions-menu.test.jsx @@ -21,7 +21,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('shows correct menu for non-anonymous users', async function () { diff --git a/services/web/test/frontend/features/editor-left-menu/components/actions-word-count.test.jsx b/services/web/test/frontend/features/editor-left-menu/components/actions-word-count.test.jsx index 86667b8f17..ec45304035 100644 --- a/services/web/test/frontend/features/editor-left-menu/components/actions-word-count.test.jsx +++ b/services/web/test/frontend/features/editor-left-menu/components/actions-word-count.test.jsx @@ -6,7 +6,7 @@ import { renderWithEditorContext } from '../../../helpers/render-with-context' describe('', function () { afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('shows correct modal when clicked after document is compiled', async function () { @@ -51,11 +51,15 @@ describe('', function () { // when loading, we don't render the "Word Count" as button yet expect(screen.queryByRole('button', { name: 'Word Count' })).to.equal(null) - await waitFor(() => expect(fetchMock.called(compileEndpoint)).to.be.true) + await waitFor( + () => expect(fetchMock.callHistory.called(compileEndpoint)).to.be.true + ) const button = await screen.findByRole('button', { name: 'Word Count' }) button.click() - await waitFor(() => expect(fetchMock.called(wordcountEndpoint)).to.be.true) + await waitFor( + () => expect(fetchMock.callHistory.called(wordcountEndpoint)).to.be.true + ) }) }) diff --git a/services/web/test/frontend/features/editor-left-menu/components/download-menu.test.jsx b/services/web/test/frontend/features/editor-left-menu/components/download-menu.test.jsx index 065a9316a1..b6295dfa07 100644 --- a/services/web/test/frontend/features/editor-left-menu/components/download-menu.test.jsx +++ b/services/web/test/frontend/features/editor-left-menu/components/download-menu.test.jsx @@ -6,7 +6,7 @@ import { renderWithEditorContext } from '../../../helpers/render-with-context' describe('', function () { afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('shows download links with correct url', async function () { diff --git a/services/web/test/frontend/features/editor-left-menu/components/help-contact-us.test.jsx b/services/web/test/frontend/features/editor-left-menu/components/help-contact-us.test.jsx index 1a29a5d2e5..9b37107fad 100644 --- a/services/web/test/frontend/features/editor-left-menu/components/help-contact-us.test.jsx +++ b/services/web/test/frontend/features/editor-left-menu/components/help-contact-us.test.jsx @@ -14,7 +14,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('open contact us modal when clicked', function () { diff --git a/services/web/test/frontend/features/editor-left-menu/components/help-menu.test.jsx b/services/web/test/frontend/features/editor-left-menu/components/help-menu.test.jsx index 4831939e88..eec6fdce31 100644 --- a/services/web/test/frontend/features/editor-left-menu/components/help-menu.test.jsx +++ b/services/web/test/frontend/features/editor-left-menu/components/help-menu.test.jsx @@ -14,7 +14,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('shows correct menu if `showSupport` is `true`', function () { diff --git a/services/web/test/frontend/features/editor-left-menu/components/help-show-hotkeys.test.jsx b/services/web/test/frontend/features/editor-left-menu/components/help-show-hotkeys.test.jsx index 2376e056cd..369fd5bbbd 100644 --- a/services/web/test/frontend/features/editor-left-menu/components/help-show-hotkeys.test.jsx +++ b/services/web/test/frontend/features/editor-left-menu/components/help-show-hotkeys.test.jsx @@ -6,7 +6,7 @@ import fetchMock from 'fetch-mock' describe('', function () { afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('open hotkeys modal when clicked', function () { diff --git a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-auto-close-brackets.test.tsx b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-auto-close-brackets.test.tsx index af0a625ca7..fff0f3ada7 100644 --- a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-auto-close-brackets.test.tsx +++ b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-auto-close-brackets.test.tsx @@ -7,7 +7,7 @@ import { EditorProviders } from '../../../../helpers/editor-providers' describe('', function () { afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('shows correct menu', async function () { diff --git a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-auto-complete.test.tsx b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-auto-complete.test.tsx index 82539b39f6..c0b58d307d 100644 --- a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-auto-complete.test.tsx +++ b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-auto-complete.test.tsx @@ -7,7 +7,7 @@ import { EditorProviders } from '../../../../helpers/editor-providers' describe('', function () { afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('shows correct menu', async function () { diff --git a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-compiler.test.tsx b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-compiler.test.tsx index 8dd848a1f6..3471b3dcf7 100644 --- a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-compiler.test.tsx +++ b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-compiler.test.tsx @@ -7,7 +7,7 @@ import { EditorProviders } from '../../../../helpers/editor-providers' describe('', function () { afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('shows correct menu', async function () { diff --git a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-document.test.tsx b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-document.test.tsx index f7ade270cb..41b6d67746 100644 --- a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-document.test.tsx +++ b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-document.test.tsx @@ -30,7 +30,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() window.metaAttributesCache.set('ol-ExposedSettings', originalSettings) }) diff --git a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-editor-theme.test.tsx b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-editor-theme.test.tsx index 2b42838a3f..f7b716e984 100644 --- a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-editor-theme.test.tsx +++ b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-editor-theme.test.tsx @@ -16,7 +16,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('shows correct menu', async function () { diff --git a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-font-family.test.tsx b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-font-family.test.tsx index 2a896982c8..36a4f3838a 100644 --- a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-font-family.test.tsx +++ b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-font-family.test.tsx @@ -7,7 +7,7 @@ import { EditorProviders } from '../../../../helpers/editor-providers' describe('', function () { afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('shows correct menu', async function () { diff --git a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-font-size.test.tsx b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-font-size.test.tsx index 964e81ac46..b65dabb758 100644 --- a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-font-size.test.tsx +++ b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-font-size.test.tsx @@ -9,7 +9,7 @@ describe('', function () { const sizes = ['10', '11', '12', '13', '14', '16', '18', '20', '22', '24'] afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('shows correct menu', async function () { diff --git a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-image-name.test.tsx b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-image-name.test.tsx index c59a44acef..b164c02f65 100644 --- a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-image-name.test.tsx +++ b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-image-name.test.tsx @@ -23,7 +23,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('shows correct menu', async function () { diff --git a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-keybindings.test.tsx b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-keybindings.test.tsx index d924a64c9c..d02f4a0701 100644 --- a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-keybindings.test.tsx +++ b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-keybindings.test.tsx @@ -7,7 +7,7 @@ import { EditorLeftMenuProvider } from '@/features/editor-left-menu/components/e describe('', function () { afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('shows correct menu', async function () { diff --git a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-line-height.test.tsx b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-line-height.test.tsx index 7bc18eb028..c914a9e295 100644 --- a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-line-height.test.tsx +++ b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-line-height.test.tsx @@ -7,7 +7,7 @@ import { EditorLeftMenuProvider } from '@/features/editor-left-menu/components/e describe('', function () { afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('shows correct menu', async function () { diff --git a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-math-preview.test.tsx b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-math-preview.test.tsx index 0fced14737..ecd2fbe34a 100644 --- a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-math-preview.test.tsx +++ b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-math-preview.test.tsx @@ -7,7 +7,7 @@ import { EditorLeftMenuProvider } from '@/features/editor-left-menu/components/e describe('', function () { afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('shows correct menu', async function () { diff --git a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-overall-theme.test.tsx b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-overall-theme.test.tsx index 8a5cc00338..83a46e662d 100644 --- a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-overall-theme.test.tsx +++ b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-overall-theme.test.tsx @@ -32,7 +32,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('shows correct menu', async function () { diff --git a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-pdf-viewer.test.tsx b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-pdf-viewer.test.tsx index 388016cbb3..d9b15e6bfa 100644 --- a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-pdf-viewer.test.tsx +++ b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-pdf-viewer.test.tsx @@ -7,7 +7,7 @@ import { EditorLeftMenuProvider } from '@/features/editor-left-menu/components/e describe('', function () { afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('shows correct menu', async function () { diff --git a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-spell-check-language.test.tsx b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-spell-check-language.test.tsx index ed7e4404ed..1b345f9ef6 100644 --- a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-spell-check-language.test.tsx +++ b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-spell-check-language.test.tsx @@ -25,7 +25,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('shows correct menu', async function () { diff --git a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-syntax-validation.test.tsx b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-syntax-validation.test.tsx index 1c38ca039f..3b1034f7b5 100644 --- a/services/web/test/frontend/features/editor-left-menu/components/settings/settings-syntax-validation.test.tsx +++ b/services/web/test/frontend/features/editor-left-menu/components/settings/settings-syntax-validation.test.tsx @@ -7,7 +7,7 @@ import { EditorLeftMenuProvider } from '@/features/editor-left-menu/components/e describe('', function () { afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('shows correct menu', async function () { diff --git a/services/web/test/frontend/features/editor-navigation-toolbar/components/layout-dropdown-button.test.jsx b/services/web/test/frontend/features/editor-navigation-toolbar/components/layout-dropdown-button.test.jsx index 19173c69e3..e7eb625d90 100644 --- a/services/web/test/frontend/features/editor-navigation-toolbar/components/layout-dropdown-button.test.jsx +++ b/services/web/test/frontend/features/editor-navigation-toolbar/components/layout-dropdown-button.test.jsx @@ -22,7 +22,7 @@ describe('', function () { afterEach(function () { openStub.restore() sendMBSpy.restore() - fetchMock.restore() + fetchMock.removeRoutes().clearHistory() }) it('should mark current layout option as selected', async function () { diff --git a/services/web/test/frontend/features/file-view/components/file-view-header.test.jsx b/services/web/test/frontend/features/file-view/components/file-view-header.test.jsx index 83c8edb7bc..11a61d9905 100644 --- a/services/web/test/frontend/features/file-view/components/file-view-header.test.jsx +++ b/services/web/test/frontend/features/file-view/components/file-view-header.test.jsx @@ -39,7 +39,7 @@ describe('', function () { } beforeEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) describe('header text', function () { diff --git a/services/web/test/frontend/features/file-view/components/file-view-refresh-button.test.jsx b/services/web/test/frontend/features/file-view/components/file-view-refresh-button.test.jsx index 6e05e4e5d9..da29252be0 100644 --- a/services/web/test/frontend/features/file-view/components/file-view-refresh-button.test.jsx +++ b/services/web/test/frontend/features/file-view/components/file-view-refresh-button.test.jsx @@ -23,7 +23,7 @@ describe('', function () { } beforeEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) // eslint-disable-next-line mocha/no-skipped-tests diff --git a/services/web/test/frontend/features/file-view/components/file-view-text.test.jsx b/services/web/test/frontend/features/file-view/components/file-view-text.test.jsx index ec19f57ecf..8ab978b82a 100644 --- a/services/web/test/frontend/features/file-view/components/file-view-text.test.jsx +++ b/services/web/test/frontend/features/file-view/components/file-view-text.test.jsx @@ -19,7 +19,7 @@ describe('', function () { } beforeEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('renders a text view', async function () { diff --git a/services/web/test/frontend/features/file-view/components/file-view.test.jsx b/services/web/test/frontend/features/file-view/components/file-view.test.jsx index be32d1fa4f..07ad612865 100644 --- a/services/web/test/frontend/features/file-view/components/file-view.test.jsx +++ b/services/web/test/frontend/features/file-view/components/file-view.test.jsx @@ -32,7 +32,7 @@ describe('', function () { } beforeEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) describe('for a text file', function () { diff --git a/services/web/test/frontend/features/group-management/components/members-table/unlink-user-modal.test.tsx b/services/web/test/frontend/features/group-management/components/members-table/unlink-user-modal.test.tsx index b4787e97c0..c52e83a00e 100644 --- a/services/web/test/frontend/features/group-management/components/members-table/unlink-user-modal.test.tsx +++ b/services/web/test/frontend/features/group-management/components/members-table/unlink-user-modal.test.tsx @@ -31,7 +31,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('displays the modal', async function () { diff --git a/services/web/test/frontend/features/project-list/components/load-more.test.tsx b/services/web/test/frontend/features/project-list/components/load-more.test.tsx index bc99584212..553fbcc487 100644 --- a/services/web/test/frontend/features/project-list/components/load-more.test.tsx +++ b/services/web/test/frontend/features/project-list/components/load-more.test.tsx @@ -11,7 +11,7 @@ import { renderWithProjectListContext } from '../helpers/render-with-context' describe('', function () { afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('renders on a project list longer than 40', async function () { diff --git a/services/web/test/frontend/features/project-list/components/new-project-button.test.tsx b/services/web/test/frontend/features/project-list/components/new-project-button.test.tsx index 93c7a68e3a..1c86b861a3 100644 --- a/services/web/test/frontend/features/project-list/components/new-project-button.test.tsx +++ b/services/web/test/frontend/features/project-list/components/new-project-button.test.tsx @@ -7,7 +7,7 @@ import getMeta from '@/utils/meta' describe('', function () { beforeEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) describe('for every user (affiliated and non-affiliated)', function () { diff --git a/services/web/test/frontend/features/project-list/components/new-project-button/modal-content-new-project-form.test.tsx b/services/web/test/frontend/features/project-list/components/new-project-button/modal-content-new-project-form.test.tsx index f33ad2f345..3db0c66ab2 100644 --- a/services/web/test/frontend/features/project-list/components/new-project-button/modal-content-new-project-form.test.tsx +++ b/services/web/test/frontend/features/project-list/components/new-project-button/modal-content-new-project-form.test.tsx @@ -20,7 +20,7 @@ describe('', function () { afterEach(function () { this.locationStub.restore() - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('submits form', async function () { @@ -49,7 +49,7 @@ describe('', function () { fireEvent.click(createButton) - expect(newProjectMock.called()).to.be.true + expect(newProjectMock.callHistory.called()).to.be.true await waitFor(() => { sinon.assert.calledOnce(assignStub) @@ -76,7 +76,7 @@ describe('', function () { }) fireEvent.click(createButton) - expect(newProjectMock.called()).to.be.true + expect(newProjectMock.callHistory.called()).to.be.true await waitFor(() => { screen.getByText(errorMessage) @@ -102,7 +102,7 @@ describe('', function () { }) fireEvent.click(createButton) - expect(newProjectMock.called()).to.be.true + expect(newProjectMock.callHistory.called()).to.be.true await waitFor(() => { screen.getByText(errorMessage) @@ -141,7 +141,7 @@ describe('', function () { }) fireEvent.click(createButton) - expect(newProjectMock.called()).to.be.true + expect(newProjectMock.callHistory.called()).to.be.true await waitFor(() => { screen.getByText(errorMessage) diff --git a/services/web/test/frontend/features/project-list/components/notifications.test.tsx b/services/web/test/frontend/features/project-list/components/notifications.test.tsx index e238e95b48..c75b0dcb0d 100644 --- a/services/web/test/frontend/features/project-list/components/notifications.test.tsx +++ b/services/web/test/frontend/features/project-list/components/notifications.test.tsx @@ -69,7 +69,7 @@ describe('', function () { } beforeEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() // at least one project is required to show some notifications const projects = [{}] as Project[] @@ -83,7 +83,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) describe('', function () { @@ -93,7 +93,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('accepts project invite', async function () { @@ -106,14 +106,14 @@ describe('', function () { ]) renderWithinProjectListProvider(Common) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) const deleteMock = fetchMock.delete( `/notifications/${reconfiguredNotification._id}`, 200 ) const acceptMock = fetchMock.post( - `project/${notificationProjectInvite.messageOpts.projectId}/invite/token/${notificationProjectInvite.messageOpts.token}/accept`, + `/project/${notificationProjectInvite.messageOpts.projectId}/invite/token/${notificationProjectInvite.messageOpts.token}/accept`, 200 ) @@ -134,8 +134,9 @@ describe('', function () { screen.getByRole('button', { name: /joining/i }) ) - expect(acceptMock.called()).to.be.true - screen.getByText(/joined/i) + expect(acceptMock.callHistory.called()).to.be.true + await screen.findByText(/joined/i) + expect(screen.queryByRole('button', { name: /join project/i })).to.be.null const openProject = screen.getByRole('button', { name: /open project/i }) @@ -146,7 +147,7 @@ describe('', function () { const closeBtn = screen.getByRole('button', { name: /close/i }) fireEvent.click(closeBtn) - expect(deleteMock.called()).to.be.true + expect(deleteMock.callHistory.called()).to.be.true expect(screen.queryByRole('alert')).to.be.null }) @@ -160,9 +161,9 @@ describe('', function () { ]) renderWithinProjectListProvider(Common) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) fetchMock.post( - `project/${notificationProjectInvite.messageOpts.projectId}/invite/token/${notificationProjectInvite.messageOpts.token}/accept`, + `/project/${notificationProjectInvite.messageOpts.projectId}/invite/token/${notificationProjectInvite.messageOpts.token}/accept`, 500 ) @@ -179,7 +180,7 @@ describe('', function () { screen.getByRole('button', { name: /joining/i }) ) - expect(fetchMock.called()).to.be.true + expect(fetchMock.callHistory.called()).to.be.true screen.getByRole('button', { name: /join project/i }) expect(screen.queryByRole('button', { name: /open project/i })).to.be.null }) @@ -194,7 +195,7 @@ describe('', function () { ]) renderWithinProjectListProvider(Common) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) fetchMock.delete(`/notifications/${reconfiguredNotification._id}`, 200) screen.getByRole('alert') @@ -207,7 +208,7 @@ describe('', function () { const closeBtn = screen.getByRole('button', { name: /close/i }) fireEvent.click(closeBtn) - expect(fetchMock.called()).to.be.true + expect(fetchMock.callHistory.called()).to.be.true expect(screen.queryByRole('alert')).to.be.null }) @@ -225,7 +226,7 @@ describe('', function () { ]) renderWithinProjectListProvider(Common) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) fetchMock.delete(`/notifications/${reconfiguredNotification._id}`, 200) screen.getByRole('alert') @@ -246,7 +247,7 @@ describe('', function () { const closeBtn = screen.getByRole('button', { name: /close/i }) fireEvent.click(closeBtn) - expect(fetchMock.called()).to.be.true + expect(fetchMock.callHistory.called()).to.be.true expect(screen.queryByRole('alert')).to.be.null }) @@ -264,7 +265,7 @@ describe('', function () { ]) renderWithinProjectListProvider(Common) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) fetchMock.delete(`/notifications/${reconfiguredNotification._id}`, 200) screen.getByRole('alert') @@ -281,7 +282,7 @@ describe('', function () { const closeBtn = screen.getByRole('button', { name: /close/i }) fireEvent.click(closeBtn) - expect(fetchMock.called()).to.be.true + expect(fetchMock.callHistory.called()).to.be.true expect(screen.queryByRole('alert')).to.be.null }) @@ -294,7 +295,7 @@ describe('', function () { ]) renderWithinProjectListProvider(Common) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) screen.getByRole('alert') screen.getByText(/file limit/i) @@ -323,7 +324,7 @@ describe('', function () { ]) renderWithinProjectListProvider(Common) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) fetchMock.delete(`/notifications/${reconfiguredNotification._id}`, 200) screen.getByRole('alert') @@ -337,7 +338,7 @@ describe('', function () { const closeBtn = screen.getByRole('button', { name: /close/i }) fireEvent.click(closeBtn) - expect(fetchMock.called()).to.be.true + expect(fetchMock.callHistory.called()).to.be.true expect(screen.queryByRole('alert')).to.be.null }) @@ -355,7 +356,7 @@ describe('', function () { ]) renderWithinProjectListProvider(Common) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) fetchMock.delete(`/notifications/${reconfiguredNotification._id}`, 200) screen.getByRole('alert') @@ -371,7 +372,7 @@ describe('', function () { const closeBtn = screen.getByRole('button', { name: /close/i }) fireEvent.click(closeBtn) - expect(fetchMock.called()).to.be.true + expect(fetchMock.callHistory.called()).to.be.true expect(screen.queryByRole('alert')).to.be.null }) @@ -385,7 +386,7 @@ describe('', function () { ]) renderWithinProjectListProvider(Common) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) fetchMock.delete(`/notifications/${reconfiguredNotification._id}`, 200) screen.getByRole('alert') @@ -394,7 +395,7 @@ describe('', function () { const closeBtn = screen.getByRole('button', { name: /close/i }) fireEvent.click(closeBtn) - expect(fetchMock.called()).to.be.true + expect(fetchMock.callHistory.called()).to.be.true expect(screen.queryByRole('alert')).to.be.null }) @@ -414,7 +415,7 @@ describe('', function () { ]) renderWithinProjectListProvider(Common) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) fetchMock.delete(`/notifications/${notificationGroupInvite._id}`, 200) screen.getByRole('alert') screen.getByText('inviter@overleaf.com') @@ -444,7 +445,7 @@ describe('', function () { ) renderWithinProjectListProvider(Common) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) fetchMock.delete( `/notifications/${notificationGroupInvite._id}`, 200 @@ -465,11 +466,11 @@ describe('', function () { describe('', function () { beforeEach(function () { Object.assign(getMeta('ol-ExposedSettings'), exposedSettings) - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('shows sso available', function () { @@ -513,7 +514,7 @@ describe('', function () { const closeBtn = screen.getByRole('button', { name: /close/i }) fireEvent.click(closeBtn) - expect(fetchMock.called()).to.be.true + expect(fetchMock.callHistory.called()).to.be.true expect(screen.queryByRole('alert')).to.be.null }) @@ -537,7 +538,7 @@ describe('', function () { const closeBtn = screen.getByRole('button', { name: /close/i }) fireEvent.click(closeBtn) - expect(fetchMock.called()).to.be.true + expect(fetchMock.callHistory.called()).to.be.true expect(screen.queryByRole('alert')).to.be.null }) @@ -563,7 +564,7 @@ describe('', function () { const closeBtn = screen.getByRole('button', { name: /close/i }) fireEvent.click(closeBtn) - expect(fetchMock.called()).to.be.true + expect(fetchMock.callHistory.called()).to.be.true expect(screen.queryByRole('alert')).to.be.null }) @@ -658,7 +659,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() this.clock.restore() }) @@ -670,7 +671,7 @@ describe('', function () { window.metaAttributesCache.set('ol-userEmails', userEmails) renderWithinProjectListProvider(ConfirmEmail) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) fetchMock.post('/user/emails/resend_confirmation', 200) const email = userEmails[0].email @@ -693,7 +694,7 @@ describe('', function () { screen.getByRole('button', { name: /resend/i }) ) - expect(fetchMock.called()).to.be.true + expect(fetchMock.callHistory.called()).to.be.true expect(screen.queryByRole('alert')).to.be.null }) } @@ -712,7 +713,7 @@ describe('', function () { window.metaAttributesCache.set('ol-userEmails', [untrustedUserData]) renderWithinProjectListProvider(ConfirmEmail) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) fetchMock.post('/user/emails/resend_confirmation', 200) const email = untrustedUserData.email @@ -730,7 +731,7 @@ describe('', function () { screen.getByRole('button', { name: /resend/i }) ) - expect(fetchMock.called()).to.be.true + expect(fetchMock.callHistory.called()).to.be.true expect(screen.queryByRole('alert')).to.be.null }) @@ -738,7 +739,7 @@ describe('', function () { window.metaAttributesCache.set('ol-userEmails', [unconfirmedUserData]) renderWithinProjectListProvider(ConfirmEmail) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) fetchMock.post('/user/emails/resend_confirmation', 500) const resendButtons = screen.getAllByRole('button', { name: /resend/i }) @@ -752,7 +753,7 @@ describe('', function () { ) ) - expect(fetchMock.called()).to.be.true + expect(fetchMock.callHistory.called()).to.be.true screen.getByText(/something went wrong/i) }) @@ -764,7 +765,7 @@ describe('', function () { window.metaAttributesCache.set('ol-usersBestSubscription', subscription) renderWithinProjectListProvider(ConfirmEmail) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) const alert = screen.getByRole('alert') const email = unconfirmedCommonsUserData.email @@ -785,7 +786,7 @@ describe('', function () { window.metaAttributesCache.set('ol-usersBestSubscription', subscription) renderWithinProjectListProvider(ConfirmEmail) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) const alert = screen.getByRole('alert') const email = unconfirmedCommonsUserData.email @@ -818,12 +819,12 @@ describe('', function () { reload: sinon.stub(), setHash: sinon.stub(), }) - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) afterEach(function () { this.locationStub.restore() - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('shows reconfirm message with SSO disabled', async function () { @@ -860,12 +861,12 @@ describe('', function () { .be.null expect(screen.queryByRole('link', { name: /remove it/i })).to.be.null expect(screen.queryByRole('link', { name: /learn more/i })).to.be.null - expect(sendReconfirmationMock.called()).to.be.true + expect(sendReconfirmationMock.callHistory.called()).to.be.true fireEvent.click( screen.getByRole('button', { name: /resend confirmation email/i }) ) await waitForElementToBeRemoved(() => screen.getByText('Sending…')) - expect(sendReconfirmationMock.calls()).to.have.lengthOf(2) + expect(sendReconfirmationMock.callHistory.calls()).to.have.lengthOf(2) }) it('shows reconfirm message with SSO enabled', async function () { @@ -905,7 +906,7 @@ describe('', function () { describe('', function () { beforeEach(function () { localStorage.clear() - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() // at least one project is required to show some notifications const projects = [{}] as Project[] @@ -924,14 +925,14 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('does not show the banner for users that are in group or are affiliated', async function () { window.metaAttributesCache.set('ol-showGroupsAndEnterpriseBanner', false) renderWithinProjectListProvider(GroupsAndEnterpriseBanner) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) expect(screen.queryByRole('button', { name: 'Contact Sales' })).to.be.null }) @@ -941,7 +942,7 @@ describe('', function () { localStorage.setItem('has_dismissed_groups_and_enterprise_banner', true) renderWithinProjectListProvider(GroupsAndEnterpriseBanner) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) expect(screen.queryByRole('button', { name: 'Contact Sales' })).to.not.be .null @@ -957,7 +958,7 @@ describe('', function () { ) renderWithinProjectListProvider(GroupsAndEnterpriseBanner) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) expect(screen.queryByRole('button', { name: 'Contact Sales' })).to.not.be .null @@ -973,7 +974,7 @@ describe('', function () { ) renderWithinProjectListProvider(GroupsAndEnterpriseBanner) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) expect(screen.queryByRole('button', { name: 'Contact Sales' })).to.be.null }) @@ -981,7 +982,7 @@ describe('', function () { describe('users that are not in group and are not affiliated', function () { beforeEach(function () { localStorage.clear() - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() // at least one project is required to show some notifications const projects = [{}] as Project[] @@ -997,7 +998,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) after(function () { @@ -1011,7 +1012,7 @@ describe('', function () { ) renderWithinProjectListProvider(GroupsAndEnterpriseBanner) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) screen.getByText( 'Overleaf On-Premises: Does your company want to keep its data within its firewall? Overleaf offers Server Pro, an on-premises solution for companies. Get in touch to learn more.' @@ -1028,7 +1029,7 @@ describe('', function () { ) renderWithinProjectListProvider(GroupsAndEnterpriseBanner) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) screen.getByText( 'Why do Fortune 500 companies and top research institutions trust Overleaf to streamline their collaboration? Get in touch to learn more.' diff --git a/services/web/test/frontend/features/project-list/components/project-list-root.test.tsx b/services/web/test/frontend/features/project-list/components/project-list-root.test.tsx index 3145280f63..91331da9c0 100644 --- a/services/web/test/frontend/features/project-list/components/project-list-root.test.tsx +++ b/services/web/test/frontend/features/project-list/components/project-list-root.test.tsx @@ -79,7 +79,7 @@ describe('', function () { afterEach(function () { sendMBSpy.restore() - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() this.locationStub.restore() }) @@ -88,11 +88,11 @@ describe('', function () { renderWithProjectListContext(, { projects: [], }) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) }) it('the welcome page is displayed', async function () { - screen.getByRole('heading', { name: 'Welcome to Overleaf' }) + await screen.findByRole('heading', { name: 'Welcome to Overleaf' }) }) it('the email confirmation alert is not displayed', async function () { @@ -110,7 +110,7 @@ describe('', function () { projects: fullList, }) this.unmount = unmount - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) await screen.findByRole('table') }) @@ -172,13 +172,17 @@ describe('', function () { await waitFor( () => expect( - archiveProjectMock.called(`/project/${project1Id}/archive`) + archiveProjectMock.callHistory.called( + `/project/${project1Id}/archive` + ) ).to.be.true ) await waitFor( () => expect( - archiveProjectMock.called(`/project/${project2Id}/archive`) + archiveProjectMock.callHistory.called( + `/project/${project2Id}/archive` + ) ).to.be.true ) }) @@ -203,13 +207,19 @@ describe('', function () { await waitFor( () => - expect(trashProjectMock.called(`/project/${project1Id}/trash`)).to - .be.true + expect( + trashProjectMock.callHistory.called( + `/project/${project1Id}/trash` + ) + ).to.be.true ) await waitFor( () => - expect(trashProjectMock.called(`/project/${project2Id}/trash`)).to - .be.true + expect( + trashProjectMock.callHistory.called( + `/project/${project2Id}/trash` + ) + ).to.be.true ) }) @@ -281,8 +291,8 @@ describe('', function () { }) fireEvent.click(unarchiveButton) - await fetchMock.flush(true) - expect(fetchMock.done()).to.be.true + await fetchMock.callHistory.flush(true) + expect(fetchMock.callHistory.done()).to.be.true await screen.findByText('No projects') }) @@ -296,8 +306,8 @@ describe('', function () { archivedProjects.length - 1 ) - await fetchMock.flush(true) - expect(fetchMock.done()).to.be.true + await fetchMock.callHistory.flush(true) + expect(fetchMock.callHistory.done()).to.be.true expect(screen.queryByText('No projects')).to.be.null }) @@ -348,8 +358,8 @@ describe('', function () { within(actionsToolbar).getByText('Restore') fireEvent.click(untrashButton) - await fetchMock.flush(true) - expect(fetchMock.done()).to.be.true + await fetchMock.callHistory.flush(true) + expect(fetchMock.callHistory.done()).to.be.true await screen.findByText('No projects') }) @@ -361,8 +371,8 @@ describe('', function () { const allCheckboxesChecked = allCheckboxes.filter(c => c.checked) expect(allCheckboxesChecked.length).to.equal(trashedList.length - 1) - await fetchMock.flush(true) - expect(fetchMock.done()).to.be.true + await fetchMock.callHistory.flush(true) + expect(fetchMock.callHistory.done()).to.be.true expect(screen.queryByText('No projects')).to.be.null }) @@ -386,26 +396,28 @@ describe('', function () { fireEvent.click(confirmButton) expect(confirmButton.disabled).to.be.true - await fetchMock.flush(true) - expect(fetchMock.done()).to.be.true + await fetchMock.callHistory.flush(true) + expect(fetchMock.callHistory.done()).to.be.true - const calls = fetchMock.calls().map(([url]) => url) + const calls = fetchMock.callHistory.calls().map(({ url }) => url) trashedList.forEach(project => { - expect(calls).to.contain(`/project/${project.id}/archive`) + expect(calls).to.contain( + `https://www.test-overleaf.com/project/${project.id}/archive` + ) }) }) it('removes only selected projects from view when leaving', async function () { // rerender content with different projects this.unmount() - fetchMock.restore() + fetchMock.removeRoutes().clearHistory() renderWithProjectListContext(, { projects: leavableList, }) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) await screen.findByRole('table') expect(leavableList.length).to.be.greaterThan(0) @@ -446,25 +458,27 @@ describe('', function () { fireEvent.click(confirmButton) expect(confirmButton.disabled).to.be.true - await fetchMock.flush(true) - expect(fetchMock.done()).to.be.true + await fetchMock.callHistory.flush(true) + expect(fetchMock.callHistory.done()).to.be.true - const calls = fetchMock.calls().map(([url]) => url) + const calls = fetchMock.callHistory.calls().map(({ url }) => url) leavableList.forEach(project => { - expect(calls).to.contain(`/project/${project.id}/leave`) + expect(calls).to.contain( + `https://www.test-overleaf.com/project/${project.id}/leave` + ) }) }) it('removes only selected projects from view when deleting', async function () { // rerender content with different projects this.unmount() - fetchMock.restore() + fetchMock.removeRoutes().clearHistory() renderWithProjectListContext(, { projects: deletableList, }) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) await screen.findByRole('table') expect(deletableList.length).to.be.greaterThan(0) @@ -505,19 +519,21 @@ describe('', function () { fireEvent.click(confirmButton) expect(confirmButton.disabled).to.be.true - await fetchMock.flush(true) - expect(fetchMock.done()).to.be.true + await fetchMock.callHistory.flush(true) + expect(fetchMock.callHistory.done()).to.be.true - const calls = fetchMock.calls().map(([url]) => url) + const calls = fetchMock.callHistory.calls().map(({ url }) => url) deletableList.forEach(project => { - expect(calls).to.contain(`/project/${project.id}`) + expect(calls).to.contain( + `https://www.test-overleaf.com/project/${project.id}` + ) }) }) it('removes only selected projects from view when deleting and leaving', async function () { // rerender content with different projects this.unmount() - fetchMock.restore() + fetchMock.removeRoutes().clearHistory() const deletableAndLeavableList = [...deletableList, ...leavableList] @@ -525,7 +541,7 @@ describe('', function () { projects: deletableAndLeavableList, }) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) await screen.findByRole('table') expect(deletableList.length).to.be.greaterThan(0) @@ -573,14 +589,14 @@ describe('', function () { fireEvent.click(confirmButton) expect(confirmButton.disabled).to.be.true - await fetchMock.flush(true) - expect(fetchMock.done()).to.be.true + await fetchMock.callHistory.flush(true) + expect(fetchMock.callHistory.done()).to.be.true - const calls = fetchMock.calls().map(([url]) => url) + const calls = fetchMock.callHistory.calls().map(({ url }) => url) deletableAndLeavableList.forEach(project => { expect(calls).to.contain.oneOf([ - `/project/${project.id}`, - `/project/${project.id}/leave`, + `https://www.test-overleaf.com/project/${project.id}`, + `https://www.test-overleaf.com/project/${project.id}/leave`, ]) }) }) @@ -589,7 +605,7 @@ describe('', function () { describe('tags', function () { it('does not show archived or trashed project', async function () { this.unmount() - fetchMock.restore() + fetchMock.removeRoutes().clearHistory() window.metaAttributesCache.set('ol-tags', [ { _id: this.tagId, @@ -642,7 +658,7 @@ describe('', function () { ) await waitFor(() => { expect( - trashProjectMock.called( + trashProjectMock.callHistory.called( `/project/${projectsData[index].id}/trash` ) ).to.be.true @@ -702,11 +718,13 @@ describe('', function () { }) fireEvent.click(createButton) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) - expect(fetchMock.called('/tag', { name: this.newTagName })).to.be.true expect( - fetchMock.called(`/tag/${this.newTagId}/projects`, { + fetchMock.callHistory.called('/tag', { name: this.newTagName }) + ).to.be.true + expect( + fetchMock.callHistory.called(`/tag/${this.newTagId}/projects`, { body: { projectIds: [projectsData[0].id, projectsData[1].id], }, @@ -734,10 +752,10 @@ describe('', function () { ) fireEvent.click(tagButton) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) expect( - deleteProjectsFromTagMock.called( + deleteProjectsFromTagMock.callHistory.called( `/tag/${this.tagId}/projects/remove`, { body: { @@ -770,14 +788,17 @@ describe('', function () { ) fireEvent.click(tagButton) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) expect( - addProjectsToTagMock.called(`/tag/${this.tagId}/projects`, { - body: { - projectIds: [projectsData[2].id], - }, - }) + addProjectsToTagMock.callHistory.called( + `/tag/${this.tagId}/projects`, + { + body: { + projectIds: [projectsData[2].id], + }, + } + ) ).to.be.true screen.getByRole('button', { name: `${this.tagName} (3)` }) }) @@ -919,10 +940,12 @@ describe('', function () { expect(confirmButton.disabled).to.be.false fireEvent.click(confirmButton) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) expect( - renameProjectMock.called(`/project/${projectsData[0].id}/rename`) + renameProjectMock.callHistory.called( + `/project/${projectsData[0].id}/rename` + ) ).to.be.true const table = await screen.findByRole('table') @@ -982,10 +1005,12 @@ describe('', function () { ) as HTMLElement fireEvent.click(copyConfirmButton) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) expect( - cloneProjectMock.called(`/project/${projectsData[1].id}/clone`) + cloneProjectMock.callHistory.called( + `/project/${projectsData[1].id}/clone` + ) ).to.be.true expect(sendMBSpy).to.have.been.calledTwice @@ -1149,8 +1174,8 @@ describe('', function () { ) as HTMLElement fireEvent.click(copyConfirmButton) - await fetchMock.flush(true) - expect(fetchMock.done()).to.be.true + await fetchMock.callHistory.flush(true) + expect(fetchMock.callHistory.done()).to.be.true expect(sendMBSpy).to.have.been.calledTwice expect(sendMBSpy).to.have.been.calledWith('loads_v2_dash') diff --git a/services/web/test/frontend/features/project-list/components/project-search.test.tsx b/services/web/test/frontend/features/project-list/components/project-search.test.tsx index f8c482740b..06820a38ca 100644 --- a/services/web/test/frontend/features/project-list/components/project-search.test.tsx +++ b/services/web/test/frontend/features/project-list/components/project-search.test.tsx @@ -12,11 +12,11 @@ describe('Project list search form', function () { beforeEach(function () { sendMBSpy = sinon.spy(eventTracking, 'sendMB') - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() sendMBSpy.restore() }) diff --git a/services/web/test/frontend/features/project-list/components/sidebar/add-affiliation.test.tsx b/services/web/test/frontend/features/project-list/components/sidebar/add-affiliation.test.tsx index cfedf93978..852c06909d 100644 --- a/services/web/test/frontend/features/project-list/components/sidebar/add-affiliation.test.tsx +++ b/services/web/test/frontend/features/project-list/components/sidebar/add-affiliation.test.tsx @@ -14,11 +14,11 @@ describe('Add affiliation widget', function () { } beforeEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('renders the component', async function () { @@ -27,8 +27,8 @@ describe('Add affiliation widget', function () { renderWithProjectListContext() - await fetchMock.flush(true) - await waitFor(() => expect(fetchMock.called('/api/project'))) + await fetchMock.callHistory.flush(true) + await waitFor(() => expect(fetchMock.callHistory.called('/api/project'))) screen.getByText(/are you affiliated with an institution/i) const addAffiliationLink = screen.getByRole('button', { @@ -43,8 +43,8 @@ describe('Add affiliation widget', function () { renderWithProjectListContext() - await fetchMock.flush(true) - await waitFor(() => expect(fetchMock.called('/api/project'))) + await fetchMock.callHistory.flush(true) + await waitFor(() => expect(fetchMock.callHistory.called('/api/project'))) validateNonExistence() }) @@ -57,8 +57,8 @@ describe('Add affiliation widget', function () { projects: [], }) - await fetchMock.flush(true) - await waitFor(() => expect(fetchMock.called('/api/project'))) + await fetchMock.callHistory.flush(true) + await waitFor(() => expect(fetchMock.callHistory.called('/api/project'))) validateNonExistence() }) @@ -69,8 +69,8 @@ describe('Add affiliation widget', function () { renderWithProjectListContext() - await fetchMock.flush(true) - await waitFor(() => expect(fetchMock.called('/api/project'))) + await fetchMock.callHistory.flush(true) + await waitFor(() => expect(fetchMock.callHistory.called('/api/project'))) validateNonExistence() }) diff --git a/services/web/test/frontend/features/project-list/components/sidebar/tags-list.test.tsx b/services/web/test/frontend/features/project-list/components/sidebar/tags-list.test.tsx index 1543e2e90d..199319a45b 100644 --- a/services/web/test/frontend/features/project-list/components/sidebar/tags-list.test.tsx +++ b/services/web/test/frontend/features/project-list/components/sidebar/tags-list.test.tsx @@ -29,16 +29,16 @@ describe('', function () { }) fetchMock.post('express:/tag/:tagId/projects', 200) fetchMock.post('express:/tag/:tagId/edit', 200) - fetchMock.delete('express:/tag/:tagId', 200) + fetchMock.delete('express:/tag/:tagId', 200, { name: 'delete tag' }) renderWithProjectListContext() - await fetchMock.flush(true) - await waitFor(() => expect(fetchMock.called('/api/project'))) + await fetchMock.callHistory.flush(true) + await waitFor(() => expect(fetchMock.callHistory.called('/api/project'))) }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('displays the tags list', function () { @@ -146,7 +146,9 @@ describe('', function () { await fireEvent.click(createButton) - await waitFor(() => expect(fetchMock.called(`/tag`)).to.be.true) + await waitFor( + () => expect(fetchMock.callHistory.called(`/tag`)).to.be.true + ) expect(screen.queryByRole('dialog', { hidden: false })).to.be.null @@ -237,7 +239,9 @@ describe('', function () { await fireEvent.click(saveButton) - await waitFor(() => expect(fetchMock.called(`/tag/abc123def456/rename`))) + await waitFor(() => + expect(fetchMock.callHistory.called(`/tag/abc123def456/rename`)) + ) expect(screen.queryByRole('dialog', { hidden: false })).to.be.null @@ -278,7 +282,9 @@ describe('', function () { const deleteButton = within(modal).getByRole('button', { name: 'Delete' }) await fireEvent.click(deleteButton) - await waitFor(() => expect(fetchMock.called(`/tag/bcd234efg567`))) + await waitFor(() => + expect(fetchMock.callHistory.called(`/tag/bcd234efg567`)) + ) expect(screen.queryByRole('dialog', { hidden: false })).to.be.null expect( @@ -289,13 +295,15 @@ describe('', function () { }) it('a failed request displays an error message', async function () { - fetchMock.delete('express:/tag/:tagId', 500, { overwriteRoutes: true }) + fetchMock.modifyRoute('delete tag', { response: { status: 500 } }) const modal = screen.getAllByRole('dialog', { hidden: false })[0] const deleteButton = within(modal).getByRole('button', { name: 'Delete' }) await fireEvent.click(deleteButton) - await waitFor(() => expect(fetchMock.called(`/tag/bcd234efg567`))) + await waitFor(() => + expect(fetchMock.callHistory.called(`/tag/bcd234efg567`)) + ) within(modal).getByText('Sorry, something went wrong') }) diff --git a/services/web/test/frontend/features/project-list/components/system-messages.test.tsx b/services/web/test/frontend/features/project-list/components/system-messages.test.tsx index e825f3c57a..0433ebc7eb 100644 --- a/services/web/test/frontend/features/project-list/components/system-messages.test.tsx +++ b/services/web/test/frontend/features/project-list/components/system-messages.test.tsx @@ -5,12 +5,12 @@ import SystemMessages from '@/shared/components/system-messages' describe('', function () { beforeEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() localStorage.clear() }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() localStorage.clear() }) @@ -22,7 +22,7 @@ describe('', function () { fetchMock.get(/\/system\/messages/, [data]) render() - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) screen.getByText(data.content) expect(screen.queryByRole('button', { name: /close/i })).to.be.null @@ -36,7 +36,7 @@ describe('', function () { fetchMock.get(/\/system\/messages/, [data]) render() - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) screen.getByText(data.content) const closeBtn = screen.getByRole('button', { name: /close/i }) @@ -60,7 +60,7 @@ describe('', function () { window.metaAttributesCache.set('ol-currentUrl', currentUrl) render() - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) const link = screen.getByRole('link', { name: /click here/i }) expect(link.getAttribute('href')).to.equal(`${data.url}${currentUrl}`) diff --git a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/archive-project-button.test.tsx b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/archive-project-button.test.tsx index 6a4eee370f..216f08a89b 100644 --- a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/archive-project-button.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/archive-project-button.test.tsx @@ -67,8 +67,11 @@ describe('', function () { await waitFor( () => - expect(archiveProjectMock.called(`/project/${project.id}/archive`)).to - .be.true + expect( + archiveProjectMock.callHistory.called( + `/project/${project.id}/archive` + ) + ).to.be.true ) }) }) diff --git a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/compile-and-download-project-pdf-button.test.tsx b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/compile-and-download-project-pdf-button.test.tsx index ba0b3fd3b9..86bbf543d3 100644 --- a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/compile-and-download-project-pdf-button.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/compile-and-download-project-pdf-button.test.tsx @@ -28,7 +28,7 @@ describe('', function () { afterEach(function () { locationStub.restore() - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() sendMBSpy.restore() }) diff --git a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/copy-project-button.test.tsx b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/copy-project-button.test.tsx index d50a8cff0a..37c38d13d9 100644 --- a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/copy-project-button.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/copy-project-button.test.tsx @@ -66,8 +66,11 @@ describe('', function () { await waitFor( () => - expect(copyProjectMock.called(`/project/${copyableProject.id}/clone`)) - .to.be.true + expect( + copyProjectMock.callHistory.called( + `/project/${copyableProject.id}/clone` + ) + ).to.be.true ) }) }) diff --git a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/delete-project-button.test.tsx b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/delete-project-button.test.tsx index 15555728c9..1f51d4b39a 100644 --- a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/delete-project-button.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/delete-project-button.test.tsx @@ -69,7 +69,8 @@ describe('', function () { await waitFor( () => - expect(deleteProjectMock.called(`/project/${project.id}`)).to.be.true + expect(deleteProjectMock.callHistory.called(`/project/${project.id}`)) + .to.be.true ) }) }) diff --git a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/leave-project-button.test.tsx b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/leave-project-button.test.tsx index fcbea5a22c..ef0fc52b73 100644 --- a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/leave-project-button.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/leave-project-button.test.tsx @@ -75,8 +75,9 @@ describe('', function () { await waitFor( () => - expect(leaveProjectMock.called(`/project/${project.id}/leave`)).to.be - .true + expect( + leaveProjectMock.callHistory.called(`/project/${project.id}/leave`) + ).to.be.true ) }) }) diff --git a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/rename-project-button.test.tsx b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/rename-project-button.test.tsx index e5a8e051b7..b383c705ac 100644 --- a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/rename-project-button.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/rename-project-button.test.tsx @@ -63,8 +63,9 @@ describe('', function () { await waitFor( () => - expect(renameProjectMock.called(`/project/${project.id}/rename`)).to.be - .true + expect( + renameProjectMock.callHistory.called(`/project/${project.id}/rename`) + ).to.be.true ) }) }) diff --git a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/trash-project-button.test.tsx b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/trash-project-button.test.tsx index 960d506b2b..7b4dac0b79 100644 --- a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/trash-project-button.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/trash-project-button.test.tsx @@ -57,8 +57,9 @@ describe('', function () { await waitFor( () => - expect(trashProjectMock.called(`/project/${project.id}/trash`)).to.be - .true + expect( + trashProjectMock.callHistory.called(`/project/${project.id}/trash`) + ).to.be.true ) }) }) diff --git a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/unarchive-project-button.test.tsx b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/unarchive-project-button.test.tsx index f4541de3f8..c7f6c342d9 100644 --- a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/unarchive-project-button.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/unarchive-project-button.test.tsx @@ -57,8 +57,11 @@ describe('', function () { await waitFor( () => - expect(unarchiveProjectMock.called(`/project/${project.id}/archive`)).to - .be.true + expect( + unarchiveProjectMock.callHistory.called( + `/project/${project.id}/archive` + ) + ).to.be.true ) }) }) diff --git a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/untrash-project-button.test.tsx b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/untrash-project-button.test.tsx index d72b7f9344..cde2987f6b 100644 --- a/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/untrash-project-button.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/cells/action-buttons/untrash-project-button.test.tsx @@ -49,8 +49,9 @@ describe('', function () { await waitFor( () => - expect(untrashProjectMock.called(`/project/${project.id}/trash`)).to.be - .true + expect( + untrashProjectMock.callHistory.called(`/project/${project.id}/trash`) + ).to.be.true ) }) }) diff --git a/services/web/test/frontend/features/project-list/components/table/cells/inline-tags.test.tsx b/services/web/test/frontend/features/project-list/components/table/cells/inline-tags.test.tsx index 0f12e72265..99550b4dab 100644 --- a/services/web/test/frontend/features/project-list/components/table/cells/inline-tags.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/cells/inline-tags.test.tsx @@ -60,9 +60,12 @@ describe('', function () { await fireEvent.click(removeButton) await waitFor(() => expect( - fetchMock.called(`/tag/789fff789fff/project/${copyableProject.id}`, { - method: 'DELETE', - }) + fetchMock.callHistory.called( + `/tag/789fff789fff/project/${copyableProject.id}`, + { + method: 'DELETE', + } + ) ) ) expect(screen.queryByText('My Test Tag')).to.not.exist diff --git a/services/web/test/frontend/features/project-list/components/table/project-list-table.test.tsx b/services/web/test/frontend/features/project-list/components/table/project-list-table.test.tsx index e0accb3c06..33b14ebf7e 100644 --- a/services/web/test/frontend/features/project-list/components/table/project-list-table.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/project-list-table.test.tsx @@ -11,11 +11,11 @@ describe('', function () { beforeEach(function () { window.metaAttributesCache.set('ol-tags', []) window.metaAttributesCache.set('ol-user_id', userId) - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('renders the table', function () { @@ -65,7 +65,7 @@ describe('', function () { this.timeout(10000) renderWithProjectListContext() - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) const rows = screen.getAllByRole('row') rows.shift() // remove first row since it's the header @@ -138,7 +138,7 @@ describe('', function () { it('selects all projects when header checkbox checked', async function () { renderWithProjectListContext() - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) const checkbox = screen.getByLabelText('Select all projects') fireEvent.click(checkbox) const allCheckboxes = screen.getAllByRole('checkbox') @@ -149,7 +149,7 @@ describe('', function () { it('unselects all projects when select all checkbox uchecked', async function () { renderWithProjectListContext() - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) const checkbox = screen.getByLabelText('Select all projects') fireEvent.click(checkbox) fireEvent.click(checkbox) @@ -160,7 +160,7 @@ describe('', function () { it('unselects select all projects checkbox when one project is unchecked', async function () { renderWithProjectListContext() - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) const checkbox = screen.getByLabelText('Select all projects') fireEvent.click(checkbox) let allCheckboxes = screen.getAllByRole('checkbox') @@ -173,7 +173,7 @@ describe('', function () { it('only checks the checked project', async function () { renderWithProjectListContext() - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) const checkbox = screen.getByLabelText(`Select ${currentProjects[0].name}`) fireEvent.click(checkbox) const allCheckboxes = screen.getAllByRole('checkbox') diff --git a/services/web/test/frontend/features/project-list/components/table/project-tools/project-tools-rename.test.tsx b/services/web/test/frontend/features/project-list/components/table/project-tools/project-tools-rename.test.tsx index 22de2f1551..842e6647e8 100644 --- a/services/web/test/frontend/features/project-list/components/table/project-tools/project-tools-rename.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/project-tools/project-tools-rename.test.tsx @@ -65,7 +65,7 @@ describe('', function () { afterEach(function () { window.metaAttributesCache.clear() - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('does not show the Rename option for a project owned by a different user', function () { diff --git a/services/web/test/frontend/features/project-list/components/table/project-tools/rename-project-modal.test.tsx b/services/web/test/frontend/features/project-list/components/table/project-tools/rename-project-modal.test.tsx index 607aa32e74..230f861bb0 100644 --- a/services/web/test/frontend/features/project-list/components/table/project-tools/rename-project-modal.test.tsx +++ b/services/web/test/frontend/features/project-list/components/table/project-tools/rename-project-modal.test.tsx @@ -58,7 +58,9 @@ describe('', function () { await waitFor( () => expect( - renameProjectMock.called(`/project/${currentProjects[0].id}/rename`) + renameProjectMock.callHistory.called( + `/project/${currentProjects[0].id}/rename` + ) ).to.be.true ) }) @@ -88,7 +90,7 @@ describe('', function () { const submitButton = within(modal).getByText('Rename') as HTMLButtonElement fireEvent.click(submitButton) - await waitFor(() => expect(postRenameMock.called()).to.be.true) + await waitFor(() => expect(postRenameMock.callHistory.called()).to.be.true) screen.getByText('Something went wrong. Please try again.') }) diff --git a/services/web/test/frontend/features/project-list/helpers/render-with-context.tsx b/services/web/test/frontend/features/project-list/helpers/render-with-context.tsx index c28dcd0c94..ef807db4c7 100644 --- a/services/web/test/frontend/features/project-list/helpers/render-with-context.tsx +++ b/services/web/test/frontend/features/project-list/helpers/render-with-context.tsx @@ -58,5 +58,5 @@ export function renderWithProjectListContext( } export function resetProjectListContextFetch() { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() } diff --git a/services/web/test/frontend/features/settings/components/account-info-section.test.tsx b/services/web/test/frontend/features/settings/components/account-info-section.test.tsx index 8e723cf8d1..112e7d90e7 100644 --- a/services/web/test/frontend/features/settings/components/account-info-section.test.tsx +++ b/services/web/test/frontend/features/settings/components/account-info-section.test.tsx @@ -29,7 +29,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('submits all inputs', async function () { @@ -50,14 +50,14 @@ describe('', function () { name: 'Update', }) ) - expect(updateMock.called()).to.be.true - expect(JSON.parse(updateMock.lastCall()![1]!.body as string)).to.deep.equal( - { - email: 'john@watson.co.uk', - first_name: 'John', - last_name: 'Watson', - } - ) + expect(updateMock.callHistory.called()).to.be.true + expect( + JSON.parse(updateMock.callHistory.calls().at(-1)?.options.body as string) + ).to.deep.equal({ + email: 'john@watson.co.uk', + first_name: 'John', + last_name: 'Watson', + }) }) it('disables button on invalid email', async function () { @@ -74,7 +74,7 @@ describe('', function () { expect(button.disabled).to.be.true fireEvent.click(button) - expect(updateMock.called()).to.be.false + expect(updateMock.callHistory.called()).to.be.false }) it('shows inflight state and success message', async function () { @@ -156,12 +156,12 @@ describe('', function () { name: 'Update', }) ) - expect(JSON.parse(updateMock.lastCall()![1]!.body as string)).to.deep.equal( - { - first_name: 'Sherlock', - last_name: 'Holmes', - } - ) + expect( + JSON.parse(updateMock.callHistory.calls().at(-1)?.options.body as string) + ).to.deep.equal({ + first_name: 'Sherlock', + last_name: 'Holmes', + }) }) it('disables email input', async function () { @@ -187,12 +187,12 @@ describe('', function () { name: 'Update', }) ) - expect(JSON.parse(updateMock.lastCall()![1]!.body as string)).to.deep.equal( - { - first_name: 'Sherlock', - last_name: 'Holmes', - } - ) + expect( + JSON.parse(updateMock.callHistory.calls().at(-1)?.options.body as string) + ).to.deep.equal({ + first_name: 'Sherlock', + last_name: 'Holmes', + }) }) it('disables names input', async function () { @@ -215,10 +215,10 @@ describe('', function () { name: 'Update', }) ) - expect(JSON.parse(updateMock.lastCall()![1]!.body as string)).to.deep.equal( - { - email: 'sherlock@holmes.co.uk', - } - ) + expect( + JSON.parse(updateMock.callHistory.calls().at(-1)?.options.body as string) + ).to.deep.equal({ + email: 'sherlock@holmes.co.uk', + }) }) }) diff --git a/services/web/test/frontend/features/settings/components/emails/add-email-input.test.tsx b/services/web/test/frontend/features/settings/components/emails/add-email-input.test.tsx index c7707d9efb..dae80cd76e 100644 --- a/services/web/test/frontend/features/settings/components/emails/add-email-input.test.tsx +++ b/services/web/test/frontend/features/settings/components/emails/add-email-input.test.tsx @@ -19,7 +19,7 @@ describe('', function () { beforeEach(function () { clearDomainCache() - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) describe('on initial render', function () { @@ -69,7 +69,7 @@ describe('', function () { }) it('should not make any request for institution domains', function () { - expect(fetchMock.called()).to.be.false + expect(fetchMock.callHistory.called()).to.be.false }) it('should submit on Enter if email looks valid', async function () { @@ -118,11 +118,18 @@ describe('', function () { }) describe('when there is a domain match', function () { - beforeEach(function () { + beforeEach(async function () { fetchMock.get('express:/institutions/domains', testInstitutionData) fireEvent.change(screen.getByTestId('affiliations-email'), { target: { value: 'user@d' }, }) + // Wait for component to process the change and update the shadow input + await waitFor(() => { + const shadowInput = screen.getByTestId( + 'affiliations-email-shadow' + ) as HTMLInputElement + expect(shadowInput.value).to.equal('user@domain.edu') + }) }) it('should render the text being typed along with the suggestion', async function () { @@ -146,7 +153,7 @@ describe('', function () { fireEvent.change(screen.getByTestId('affiliations-email'), { target: { value: 'user@domain.edu' }, }) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) expect( onChangeStub.calledWith( 'user@domain.edu', @@ -231,7 +238,7 @@ describe('', function () { }) it('should cache the result and skip subsequent requests', async function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() // clear input fireEvent.change(screen.getByTestId('affiliations-email'), { @@ -242,7 +249,7 @@ describe('', function () { target: { value: 'user@d' }, }) - expect(fetchMock.called()).to.be.false + expect(fetchMock.callHistory.called()).to.be.false expect(onChangeStub.calledWith('user@d')).to.equal(true) await waitFor(() => { const shadowInput = screen.getByTestId( @@ -258,7 +265,7 @@ describe('', function () { afterEach(function () { clearDomainCache() - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('should not render the suggestion with blocked domain', async function () { @@ -269,7 +276,7 @@ describe('', function () { fireEvent.change(screen.getByTestId('affiliations-email'), { target: { value: `user@${blockedDomain.split('.')[0]}` }, }) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) expect(screen.queryByText(`user@${blockedDomain}`)).to.be.null }) @@ -286,7 +293,7 @@ describe('', function () { value: `user@subdomain.${blockedDomain.split('.')[0]}`, }, }) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) expect(screen.queryByText(`user@subdomain.${blockedDomain}`)).to.be.null }) }) @@ -307,7 +314,7 @@ describe('', function () { // make sure the next suggestions are delayed clearDomainCache() - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() fetchMock.get('express:/institutions/domains', 200, { delay: 1000 }) }) @@ -354,7 +361,7 @@ describe('', function () { }) // subsequent requests fail - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() fetchMock.get('express:/institutions/domains', 500) }) @@ -373,7 +380,7 @@ describe('', function () { expect(shadowInput.value).to.equal('') }) - expect(fetchMock.called()).to.be.true // ensures `domainCache` hasn't been hit + expect(fetchMock.callHistory.called()).to.be.true // ensures `domainCache` hasn't been hit }) }) @@ -384,7 +391,7 @@ describe('', function () { fireEvent.change(screen.getByTestId('affiliations-email'), { target: { value: 'user@other' }, }) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) const shadowInput = screen.getByTestId( 'affiliations-email-shadow' ) as HTMLInputElement diff --git a/services/web/test/frontend/features/settings/components/emails/emails-row.test.tsx b/services/web/test/frontend/features/settings/components/emails/emails-row.test.tsx index 08928ff23d..990d905ba8 100644 --- a/services/web/test/frontend/features/settings/components/emails/emails-row.test.tsx +++ b/services/web/test/frontend/features/settings/components/emails/emails-row.test.tsx @@ -37,7 +37,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) describe('with unaffiliated email data', function () { @@ -86,9 +86,9 @@ describe('', function () { describe('when the email is not yet linked to the institution', function () { beforeEach(async function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() fetchMock.get(/\/user\/emails/, [affiliatedEmail, unconfirmedUserData]) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) }) it('prompts the user to link to their institutional account', function () { @@ -103,9 +103,9 @@ describe('', function () { describe('when the email is already linked to the institution', function () { beforeEach(async function () { affiliatedEmail.samlProviderId = '1' - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() fetchMock.get(/\/user\/emails/, [affiliatedEmail, unconfirmedUserData]) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) }) it('prompts the user to login using their institutional account', function () { diff --git a/services/web/test/frontend/features/settings/components/emails/emails-section-actions.test.tsx b/services/web/test/frontend/features/settings/components/emails/emails-section-actions.test.tsx index c1b83b3421..fca5714fe9 100644 --- a/services/web/test/frontend/features/settings/components/emails/emails-section-actions.test.tsx +++ b/services/web/test/frontend/features/settings/components/emails/emails-section-actions.test.tsx @@ -37,11 +37,11 @@ describe('email actions - make primary', function () { Object.assign(getMeta('ol-ExposedSettings'), { hasAffiliationsFeature: true, }) - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) describe('disabled `make primary` button', function () { @@ -236,11 +236,11 @@ describe('email actions - delete', function () { Object.assign(getMeta('ol-ExposedSettings'), { hasAffiliationsFeature: true, }) - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('shows loader when deleting and removes the row', async function () { diff --git a/services/web/test/frontend/features/settings/components/emails/emails-section-add-new-email.test.tsx b/services/web/test/frontend/features/settings/components/emails/emails-section-add-new-email.test.tsx index ed3c227083..4a96308893 100644 --- a/services/web/test/frontend/features/settings/components/emails/emails-section-add-new-email.test.tsx +++ b/services/web/test/frontend/features/settings/components/emails/emails-section-add-new-email.test.tsx @@ -56,7 +56,7 @@ const institutionDomainData = [ ] as const function resetFetchMock() { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() fetchMock.get('express:/institutions/domains', []) } @@ -80,7 +80,7 @@ describe('', function () { hasSamlFeature: true, samlInitPath: 'saml/init', }) - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) afterEach(function () { @@ -97,7 +97,7 @@ describe('', function () { it('renders input', async function () { fetchMock.get('/user/emails?ensureAffiliation=true', []) render() - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) const button = await screen.findByRole('button', { name: /add another email/i, @@ -112,7 +112,7 @@ describe('', function () { fetchMock.get(`/institutions/domains?hostname=email.com&limit=1`, 200) fetchMock.get(`/institutions/domains?hostname=email&limit=1`, 200) render() - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) const button = await screen.findByRole('button', { name: /add another email/i, @@ -190,7 +190,7 @@ describe('', function () { { name: /add another email/i } ) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) resetFetchMock() fetchMock .get('/user/emails?ensureAffiliation=true', [userEmailData]) @@ -233,7 +233,7 @@ describe('', function () { { name: /add another email/i } ) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) resetFetchMock() fetchMock .get('/user/emails?ensureAffiliation=true', []) @@ -271,8 +271,8 @@ describe('', function () { name: /add another email/i, }) - await fetchMock.flush(true) - fetchMock.reset() + await fetchMock.callHistory.flush(true) + fetchMock.removeRoutes().clearHistory() fetchMock.get('express:/institutions/domains', institutionDomainData) await userEvent.click(button) @@ -295,7 +295,7 @@ describe('', function () { name: /add another email/i, }) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) resetFetchMock() await userEvent.click(button) @@ -330,7 +330,7 @@ describe('', function () { expect(universityInput.disabled).to.be.false - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) resetFetchMock() // Select the university from dropdown @@ -364,9 +364,11 @@ describe('', function () { }) ) - const [[, request]] = fetchMock.calls(/\/user\/emails/) + const request = fetchMock.callHistory.calls(/\/user\/emails/).at(0) - expect(JSON.parse(request?.body?.toString() || '{}')).to.deep.include({ + expect( + JSON.parse(request?.options.body?.toString() || '{}') + ).to.deep.include({ email: userEmailData.email, university: { id: userEmailData.affiliation?.institution.id, @@ -393,7 +395,7 @@ describe('', function () { name: /add another email/i, }) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) resetFetchMock() fetchMock.get('/institutions/list?country_code=de', [ @@ -446,7 +448,7 @@ describe('', function () { name: /add another email/i, }) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) resetFetchMock() await userEvent.click(button) @@ -481,7 +483,7 @@ describe('', function () { expect(universityInput.disabled).to.be.false - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) resetFetchMock() // Enter the university manually @@ -516,9 +518,11 @@ describe('', function () { await confirmCodeForEmail(userEmailData.email) - const [[, request]] = fetchMock.calls(/\/user\/emails/) + const request = fetchMock.callHistory.calls(/\/user\/emails/).at(0) - expect(JSON.parse(request?.body?.toString() || '{}')).to.deep.include({ + expect( + JSON.parse(request?.options.body?.toString() || '{}') + ).to.deep.include({ email: userEmailData.email, university: { name: newUniversity, @@ -554,8 +558,8 @@ describe('', function () { name: /add another email/i, }) - await fetchMock.flush(true) - fetchMock.reset() + await fetchMock.callHistory.flush(true) + fetchMock.removeRoutes().clearHistory() fetchMock.get( `/institutions/domains?hostname=${hostnameFirstChar}&limit=1`, institutionDomainDataCopy @@ -569,8 +573,8 @@ describe('', function () { ) await userEvent.keyboard('{Tab}') - await fetchMock.flush(true) - fetchMock.reset() + await fetchMock.callHistory.flush(true) + fetchMock.removeRoutes().clearHistory() expect( screen.queryByRole('textbox', { @@ -627,8 +631,8 @@ describe('', function () { name: /add another email/i, }) - await fetchMock.flush(true) - fetchMock.reset() + await fetchMock.callHistory.flush(true) + fetchMock.removeRoutes().clearHistory() fetchMock.get( `/institutions/domains?hostname=${hostnameFirstChar}&limit=1`, institutionDomainDataCopy @@ -642,8 +646,8 @@ describe('', function () { ) await userEvent.keyboard('{Tab}') - await fetchMock.flush(true) - fetchMock.reset() + await fetchMock.callHistory.flush(true) + fetchMock.removeRoutes().clearHistory() screen.getByText(institutionDomainDataCopy[0].university.name) @@ -679,8 +683,8 @@ describe('', function () { await confirmCodeForEmail('user@autocomplete.edu') - await fetchMock.flush(true) - fetchMock.reset() + await fetchMock.callHistory.flush(true) + fetchMock.removeRoutes().clearHistory() screen.getByText(userEmailDataCopy.affiliation.institution.name, { exact: false, diff --git a/services/web/test/frontend/features/settings/components/emails/emails-section-institution-and-role.test.tsx b/services/web/test/frontend/features/settings/components/emails/emails-section-institution-and-role.test.tsx index 4906f28fd9..56366ef258 100644 --- a/services/web/test/frontend/features/settings/components/emails/emails-section-institution-and-role.test.tsx +++ b/services/web/test/frontend/features/settings/components/emails/emails-section-institution-and-role.test.tsx @@ -79,12 +79,14 @@ describe('user role and institution', function () { Object.assign(getMeta('ol-ExposedSettings'), { hasAffiliationsFeature: true, }) - fetchMock.reset() - fetchMock.get('/user/emails?ensureAffiliation=true', []) + fetchMock.removeRoutes().clearHistory() + fetchMock.get('/user/emails?ensureAffiliation=true', [], { + name: 'get user emails', + }) }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('renders affiliation name with add role/department button', function () { @@ -122,13 +124,11 @@ describe('user role and institution', function () { it('fetches institution data and replaces departments dropdown on add/change', async function () { const userEmailData = userData1 - fetchMock.get('/user/emails?ensureAffiliation=true', [userEmailData], { - overwriteRoutes: true, - }) + fetchMock.modifyRoute('get user emails', { response: [userEmailData] }) render() - await fetchMock.flush(true) - fetchMock.reset() + await fetchMock.callHistory.flush(true) + fetchMock.removeRoutes().clearHistory() const fakeDepartment = 'Fake department' const institution = userEmailData.affiliation.institution @@ -143,8 +143,8 @@ describe('user role and institution', function () { screen.getByRole('button', { name: /add role and department/i }) ) - await fetchMock.flush(true) - fetchMock.reset() + await fetchMock.callHistory.flush(true) + fetchMock.removeRoutes().clearHistory() fireEvent.click(screen.getByRole('textbox', { name: /department/i })) @@ -153,9 +153,7 @@ describe('user role and institution', function () { it('adds new role and department', async function () { fetchMock - .get('/user/emails?ensureAffiliation=true', [userData1], { - overwriteRoutes: true, - }) + .modifyRoute('get user emails', { response: [userData1] }) .get(/\/institutions\/list/, { departments: [] }) .post('/user/emails/endorse', 200) render() diff --git a/services/web/test/frontend/features/settings/components/emails/emails-section.test.tsx b/services/web/test/frontend/features/settings/components/emails/emails-section.test.tsx index e4183e6e3f..451a510855 100644 --- a/services/web/test/frontend/features/settings/components/emails/emails-section.test.tsx +++ b/services/web/test/frontend/features/settings/components/emails/emails-section.test.tsx @@ -22,11 +22,11 @@ describe('', function () { Object.assign(getMeta('ol-ExposedSettings'), { hasAffiliationsFeature: true, }) - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('renders translated heading', function () { diff --git a/services/web/test/frontend/features/settings/components/emails/reconfirmation-info.test.tsx b/services/web/test/frontend/features/settings/components/emails/reconfirmation-info.test.tsx index ef921ac6b7..8eccdac557 100644 --- a/services/web/test/frontend/features/settings/components/emails/reconfirmation-info.test.tsx +++ b/services/web/test/frontend/features/settings/components/emails/reconfirmation-info.test.tsx @@ -42,7 +42,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() this.locationStub.restore() }) @@ -145,13 +145,13 @@ describe('', function () { await waitFor(() => { expect(confirmButton.disabled).to.be.true }) - expect(fetchMock.called()).to.be.true + expect(fetchMock.callHistory.called()).to.be.true // the confirmation text should now be displayed await screen.findByText(/Please check your email inbox to confirm/) // try the resend button - fetchMock.resetHistory() + fetchMock.clearHistory() const resendButton = await screen.findByRole('button', { name: 'Resend confirmation email', }) @@ -160,7 +160,7 @@ describe('', function () { // commented out as it's already gone by this point // await screen.findByText(/Sending/) - expect(fetchMock.called()).to.be.true + expect(fetchMock.callHistory.called()).to.be.true await waitForElementToBeRemoved(() => screen.getByText('Sending…')) await screen.findByRole('button', { name: 'Resend confirmation email', diff --git a/services/web/test/frontend/features/settings/components/leave/modal-content.test.tsx b/services/web/test/frontend/features/settings/components/leave/modal-content.test.tsx index eba7176e19..475998064d 100644 --- a/services/web/test/frontend/features/settings/components/leave/modal-content.test.tsx +++ b/services/web/test/frontend/features/settings/components/leave/modal-content.test.tsx @@ -12,7 +12,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('disable delete button if form is not valid', function () { diff --git a/services/web/test/frontend/features/settings/components/leave/modal-form.test.tsx b/services/web/test/frontend/features/settings/components/leave/modal-form.test.tsx index 52c07de20f..5c3863d0ad 100644 --- a/services/web/test/frontend/features/settings/components/leave/modal-form.test.tsx +++ b/services/web/test/frontend/features/settings/components/leave/modal-form.test.tsx @@ -1,7 +1,7 @@ import { expect } from 'chai' import sinon from 'sinon' import { fireEvent, screen, render, waitFor } from '@testing-library/react' -import fetchMock, { FetchMockStatic } from 'fetch-mock' +import fetchMock, { type FetchMock } from 'fetch-mock' import LeaveModalForm from '../../../../../../frontend/js/features/settings/components/leave/modal-form' import * as useLocationModule from '../../../../../../frontend/js/shared/hooks/use-location' @@ -14,7 +14,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('validates form', async function () { @@ -50,7 +50,7 @@ describe('', function () { describe('submits', async function () { let setInFlight: sinon.SinonStub let setIsFormValid: sinon.SinonStub - let deleteMock: FetchMockStatic + let deleteMock: FetchMock let assignStub: sinon.SinonStub beforeEach(function () { @@ -68,7 +68,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() this.locationStub.restore() }) @@ -85,7 +85,7 @@ describe('', function () { sinon.assert.calledOnce(setInFlight) sinon.assert.calledWithMatch(setInFlight, true) - expect(deleteMock.called()).to.be.true + expect(deleteMock.callHistory.called()).to.be.true await waitFor(() => { sinon.assert.calledTwice(setInFlight) sinon.assert.calledWithMatch(setInFlight, false) @@ -105,7 +105,7 @@ describe('', function () { fireEvent.submit(screen.getByLabelText('Email')) - expect(deleteMock.called()).to.be.false + expect(deleteMock.callHistory.called()).to.be.false sinon.assert.notCalled(setInFlight) }) }) diff --git a/services/web/test/frontend/features/settings/components/leave/modal.test.tsx b/services/web/test/frontend/features/settings/components/leave/modal.test.tsx index 442afb9319..3e52f01638 100644 --- a/services/web/test/frontend/features/settings/components/leave/modal.test.tsx +++ b/services/web/test/frontend/features/settings/components/leave/modal.test.tsx @@ -13,7 +13,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('closes modal on cancel', async function () { diff --git a/services/web/test/frontend/features/settings/components/leavers-survey-alert.test.tsx b/services/web/test/frontend/features/settings/components/leavers-survey-alert.test.tsx index 2ffa2e5051..b5de65d392 100644 --- a/services/web/test/frontend/features/settings/components/leavers-survey-alert.test.tsx +++ b/services/web/test/frontend/features/settings/components/leavers-survey-alert.test.tsx @@ -21,7 +21,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('should render before the expiration date', function () { diff --git a/services/web/test/frontend/features/settings/components/linking-section.test.tsx b/services/web/test/frontend/features/settings/components/linking-section.test.tsx index 8567769fc4..d134ffeae6 100644 --- a/services/web/test/frontend/features/settings/components/linking-section.test.tsx +++ b/services/web/test/frontend/features/settings/components/linking-section.test.tsx @@ -52,7 +52,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('shows header', async function () { diff --git a/services/web/test/frontend/features/settings/components/password-section.test.tsx b/services/web/test/frontend/features/settings/components/password-section.test.tsx index ae6a620f1f..63f151a3df 100644 --- a/services/web/test/frontend/features/settings/components/password-section.test.tsx +++ b/services/web/test/frontend/features/settings/components/password-section.test.tsx @@ -17,7 +17,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('shows password managed externally message', async function () { @@ -45,14 +45,14 @@ describe('', function () { render() submitValidForm() - expect(updateMock.called()).to.be.true - expect(JSON.parse(updateMock.lastCall()![1]!.body as string)).to.deep.equal( - { - currentPassword: 'foobar', - newPassword1: 'barbaz', - newPassword2: 'barbaz', - } - ) + expect(updateMock.callHistory.called()).to.be.true + expect( + JSON.parse(updateMock.callHistory.calls().at(-1)?.options.body as string) + ).to.deep.equal({ + currentPassword: 'foobar', + newPassword1: 'barbaz', + newPassword2: 'barbaz', + }) }) it('disables button on invalid form', async function () { @@ -64,7 +64,7 @@ describe('', function () { name: 'Change', }) ) - expect(updateMock.called()).to.be.false + expect(updateMock.callHistory.called()).to.be.false }) it('validates inputs', async function () { diff --git a/services/web/test/frontend/features/settings/components/security-section.test.tsx b/services/web/test/frontend/features/settings/components/security-section.test.tsx index 48146e82cf..08aa89e9a4 100644 --- a/services/web/test/frontend/features/settings/components/security-section.test.tsx +++ b/services/web/test/frontend/features/settings/components/security-section.test.tsx @@ -5,7 +5,7 @@ import fetchMock from 'fetch-mock' describe('', function () { afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('shows Group SSO rows in security section', async function () { diff --git a/services/web/test/frontend/features/settings/context/sso-context.test.tsx b/services/web/test/frontend/features/settings/context/sso-context.test.tsx index 2c7cbebd2b..e6b3113567 100644 --- a/services/web/test/frontend/features/settings/context/sso-context.test.tsx +++ b/services/web/test/frontend/features/settings/context/sso-context.test.tsx @@ -35,7 +35,7 @@ describe('SSOContext', function () { google: 'google-id', }) window.metaAttributesCache.set('ol-oauthProviders', mockOauthProviders) - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('should initialise subscriptions with their linked status', function () { @@ -69,13 +69,13 @@ describe('SSOContext', function () { it('when the provider is not linked, should do nothing', function () { const { result } = renderSSOContext() result.current.unlink('orcid') - expect(fetchMock.called()).to.be.false + expect(fetchMock.callHistory.called()).to.be.false }) it('supports unmounting the component while the request is inflight', async function () { const { result, unmount } = renderSSOContext() result.current.unlink('google') - expect(fetchMock.called()).to.be.true + expect(fetchMock.callHistory.called()).to.be.true unmount() }) }) diff --git a/services/web/test/frontend/features/settings/context/user-email-context.test.tsx b/services/web/test/frontend/features/settings/context/user-email-context.test.tsx index 7d9544ffe7..6398be1d64 100644 --- a/services/web/test/frontend/features/settings/context/user-email-context.test.tsx +++ b/services/web/test/frontend/features/settings/context/user-email-context.test.tsx @@ -1,6 +1,8 @@ import { expect } from 'chai' import { cloneDeep } from 'lodash' import { renderHook } from '@testing-library/react-hooks' +import { waitFor } from '@testing-library/react' + import { EmailContextType, UserEmailsProvider, @@ -26,7 +28,7 @@ const renderUserEmailsContext = () => describe('UserEmailContext', function () { beforeEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) describe('context bootstrap', function () { @@ -49,8 +51,8 @@ describe('UserEmailContext', function () { it('should load all user emails and update the initialisation state to "success"', async function () { fetchMock.get(/\/user\/emails/, fakeUsersData) const { result } = renderUserEmailsContext() - await fetchMock.flush(true) - expect(fetchMock.calls()).to.have.lengthOf(1) + await fetchMock.callHistory.flush(true) + expect(fetchMock.callHistory.calls()).to.have.lengthOf(1) expect(result.current.state.data.byId).to.deep.equal({ 'bar@overleaf.com': { ...untrustedUserData, ...confirmedUserData }, 'baz@overleaf.com': unconfirmedUserData, @@ -66,10 +68,12 @@ describe('UserEmailContext', function () { it('when loading user email fails, it should update the initialisation state to "failed"', async function () { fetchMock.get(/\/user\/emails/, 500) const { result } = renderUserEmailsContext() - await fetchMock.flush() + await fetchMock.callHistory.flush() - expect(result.current.isInitializing).to.equal(false) - expect(result.current.isInitializingError).to.equal(true) + await waitFor(() => { + expect(result.current.isInitializing).to.equal(false) + expect(result.current.isInitializingError).to.equal(true) + }) }) describe('state.isLoading', function () { @@ -94,12 +98,12 @@ describe('UserEmailContext', function () { fetchMock.get(/\/user\/emails/, fakeUsersData) const value = renderUserEmailsContext() result = value.result - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) }) describe('getEmails()', function () { beforeEach(async function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('should set `isLoading === true`', function () { @@ -120,7 +124,7 @@ describe('UserEmailContext', function () { } fetchMock.get(/\/user\/emails/, [emailData]) result.current.getEmails() - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) expect(result.current.state.data.byId).to.deep.equal({ 'new@email.com': emailData, }) @@ -133,7 +137,7 @@ describe('UserEmailContext', function () { { ...professionalUserData, samlProviderId: 'saml_provider_2' }, ]) const { result } = renderUserEmailsContext() - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) expect(result.current.state.data.linkedInstitutionIds).to.deep.equal([ 'saml_provider_1', 'saml_provider_2', @@ -257,11 +261,11 @@ describe('UserEmailContext', function () { const affiliatedEmail2 = cloneDeep(professionalUserData) affiliatedEmail2.emailHasInstitutionLicence = true - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() fetchMock.get(/\/user\/emails/, [affiliatedEmail1, affiliatedEmail2]) result.current.getEmails() - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) // `resetLeaversSurveyExpiration` always happens after deletion result.current.deleteEmail(affiliatedEmail1.email) @@ -281,11 +285,11 @@ describe('UserEmailContext', function () { const affiliatedEmail2 = cloneDeep(professionalUserData) affiliatedEmail2.emailHasInstitutionLicence = true - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() fetchMock.get(/\/user\/emails/, [affiliatedEmail1, affiliatedEmail2]) result.current.getEmails() - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) // `resetLeaversSurveyExpiration` always happens after deletion result.current.deleteEmail(affiliatedEmail1.email) @@ -303,11 +307,11 @@ describe('UserEmailContext', function () { affiliatedEmail1.email = 'institution-test@example.com' affiliatedEmail1.affiliation.pastReconfirmDate = true - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() fetchMock.get(/\/user\/emails/, [confirmedUserData, affiliatedEmail1]) result.current.getEmails() - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) // `resetLeaversSurveyExpiration` always happens after deletion result.current.deleteEmail(affiliatedEmail1.email) @@ -323,11 +327,11 @@ describe('UserEmailContext', function () { emailWithInstitutionLicense.email = 'institution-licensed@example.com' emailWithInstitutionLicense.emailHasInstitutionLicence = false - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() fetchMock.get(/\/user\/emails/, [emailWithInstitutionLicense]) result.current.getEmails() - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) // `resetLeaversSurveyExpiration` always happens after deletion result.current.deleteEmail(emailWithInstitutionLicense.email) @@ -342,11 +346,11 @@ describe('UserEmailContext', function () { emailWithInstitutionLicense.email = 'institution-licensed@example.com' emailWithInstitutionLicense.affiliation.pastReconfirmDate = false - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() fetchMock.get(/\/user\/emails/, [emailWithInstitutionLicense]) result.current.getEmails() - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) // `resetLeaversSurveyExpiration` always happens after deletion result.current.deleteEmail(emailWithInstitutionLicense.email) diff --git a/services/web/test/frontend/features/share-project-modal/components/share-project-modal.test.jsx b/services/web/test/frontend/features/share-project-modal/components/share-project-modal.test.jsx index 0ecacfe5b2..e44a7d9a30 100644 --- a/services/web/test/frontend/features/share-project-modal/components/share-project-modal.test.jsx +++ b/services/web/test/frontend/features/share-project-modal/components/share-project-modal.test.jsx @@ -102,7 +102,7 @@ describe('', function () { afterEach(function () { this.locationStub.restore() - fetchMock.restore() + fetchMock.removeRoutes().clearHistory() cleanUpContext() }) @@ -414,7 +414,7 @@ describe('', function () { await waitFor(() => expect(closeButton.disabled).to.be.true) - expect(fetchMock.done()).to.be.true + expect(fetchMock.callHistory.done()).to.be.true expect(closeButton.disabled).to.be.false }) @@ -447,7 +447,7 @@ describe('', function () { fireEvent.click(revokeButton) await waitFor(() => expect(closeButton.disabled).to.be.true) - expect(fetchMock.done()).to.be.true + expect(fetchMock.callHistory.done()).to.be.true expect(closeButton.disabled).to.be.false }) @@ -484,10 +484,10 @@ describe('', function () { await waitFor(() => expect(closeButton.disabled).to.be.true) - const { body } = fetchMock.lastOptions() + const { body } = fetchMock.callHistory.calls().at(-1).options expect(JSON.parse(body)).to.deep.equal({ privilegeLevel: 'readAndWrite' }) - expect(fetchMock.done()).to.be.true + expect(fetchMock.callHistory.done()).to.be.true expect(closeButton.disabled).to.be.false }) @@ -525,10 +525,12 @@ describe('', function () { }) fireEvent.click(removeButton) - const url = fetchMock.lastUrl() - expect(url).to.equal('/project/test-project/users/member-viewer') + const url = fetchMock.callHistory.calls().at(-1).url + expect(url).to.equal( + 'https://www.test-overleaf.com/project/test-project/users/member-viewer' + ) - expect(fetchMock.done()).to.be.true + expect(fetchMock.callHistory.done()).to.be.true }) it('changes member privileges to owner with confirmation', async function () { @@ -573,10 +575,10 @@ describe('', function () { fireEvent.click(confirmButton) await waitFor(() => expect(confirmButton.disabled).to.be.true) - const { body } = fetchMock.lastOptions() + const { body } = fetchMock.callHistory.calls().at(-1).options expect(JSON.parse(body)).to.deep.equal({ user_id: 'member-viewer' }) - expect(fetchMock.done()).to.be.true + expect(fetchMock.callHistory.done()).to.be.true }) it('sends invites to input email addresses', async function () { @@ -593,7 +595,7 @@ describe('', function () { // loading contacts await waitFor(() => { - expect(fetchMock.called('express:/user/contacts')).to.be.true + expect(fetchMock.callHistory.called('express:/user/contacts')).to.be.true }) // displaying a list of matching contacts @@ -604,26 +606,29 @@ describe('', function () { // sending invitations - fetchMock.post('express:/project/:projectId/invite', (url, req) => { - const data = JSON.parse(req.body) + fetchMock.post( + 'express:/project/:projectId/invite', + ({ args: [url, req] }) => { + const data = JSON.parse(req.body) + + if (data.email === 'a@b.c') { + return { + status: 400, + body: { errorReason: 'invalid_email' }, + } + } - if (data.email === 'a@b.c') { return { - status: 400, - body: { errorReason: 'invalid_email' }, + status: 200, + body: { + invite: { + ...data, + _id: data.email, + }, + }, } } - - return { - status: 200, - body: { - invite: { - ...data, - _id: data.email, - }, - }, - } - }) + ) fireEvent.paste(inputElement, { clipboardData: { @@ -643,22 +648,24 @@ describe('', function () { let calls await waitFor( () => { - calls = fetchMock.calls('express:/project/:projectId/invite') + calls = fetchMock.callHistory.calls( + 'express:/project/:projectId/invite' + ) expect(calls).to.have.length(4) }, { timeout: 5000 } // allow time for delay between each request ) - expect(calls[0][1].body).to.equal( + expect(calls[0].args[1].body).to.equal( JSON.stringify({ email: 'test@example.com', privileges: 'readOnly' }) ) - expect(calls[1][1].body).to.equal( + expect(calls[1].args[1].body).to.equal( JSON.stringify({ email: 'foo@example.com', privileges: 'readOnly' }) ) - expect(calls[2][1].body).to.equal( + expect(calls[2].args[1].body).to.equal( JSON.stringify({ email: 'bar@example.com', privileges: 'readOnly' }) ) - expect(calls[3][1].body).to.equal( + expect(calls[3].args[1].body).to.equal( JSON.stringify({ email: 'a@b.c', privileges: 'readOnly' }) ) @@ -752,7 +759,7 @@ describe('', function () { // loading contacts await waitFor(() => { - expect(fetchMock.called('express:/user/contacts')).to.be.true + expect(fetchMock.callHistory.called('express:/user/contacts')).to.be.true }) const [inputElement] = await screen.findAllByLabelText('Add people') @@ -766,19 +773,15 @@ describe('', function () { }) fireEvent.blur(inputElement) - fetchMock.postOnce( - 'express:/project/:projectId/invite', - { - status: 400, - body: { errorReason }, - }, - { overwriteRoutes: true } - ) + fetchMock.postOnce('express:/project/:projectId/invite', { + status: 400, + body: { errorReason }, + }) expect(submitButton.disabled).to.be.false await userEvent.click(submitButton) - await fetchMock.flush(true) - expect(fetchMock.done()).to.be.true + await fetchMock.callHistory.flush(true) + expect(fetchMock.callHistory.done()).to.be.true } await respondWithError('cannot_invite_non_user') @@ -820,7 +823,7 @@ describe('', function () { fireEvent.click(enableButton) await waitFor(() => expect(enableButton.disabled).to.be.true) - const { body: tokenBody } = fetchMock.lastOptions() + const { body: tokenBody } = fetchMock.callHistory.calls().at(-1).options expect(JSON.parse(tokenBody)).to.deep.equal({ publicAccessLevel: 'tokenBased', }) @@ -840,7 +843,7 @@ describe('', function () { fireEvent.click(disableButton) await waitFor(() => expect(disableButton.disabled).to.be.true) - const { body: privateBody } = fetchMock.lastOptions() + const { body: privateBody } = fetchMock.callHistory.calls().at(-1).options expect(JSON.parse(privateBody)).to.deep.equal({ publicAccessLevel: 'private', }) @@ -865,7 +868,7 @@ describe('', function () { // Wait for contacts to load await waitFor(() => { - expect(fetchMock.called('express:/user/contacts')).to.be.true + expect(fetchMock.callHistory.called('express:/user/contacts')).to.be.true }) // Enter a prefix that matches a contact @@ -919,7 +922,7 @@ describe('', function () { // Wait for contacts to load await waitFor(() => { - expect(fetchMock.called('express:/user/contacts')).to.be.true + expect(fetchMock.callHistory.called('express:/user/contacts')).to.be.true }) // Enter a prefix that matches a contact @@ -954,7 +957,7 @@ describe('', function () { // Wait for contacts to load await waitFor(() => { - expect(fetchMock.called('express:/user/contacts')).to.be.true + expect(fetchMock.callHistory.called('express:/user/contacts')).to.be.true }) // Enter a prefix that matches a contact @@ -988,7 +991,7 @@ describe('', function () { // Wait for contacts to load await waitFor(() => { - expect(fetchMock.called('express:/user/contacts')).to.be.true + expect(fetchMock.callHistory.called('express:/user/contacts')).to.be.true }) // Enter a prefix that matches a contact diff --git a/services/web/test/frontend/features/subscription/components/dashboard/group-subscription-memberships.test.tsx b/services/web/test/frontend/features/subscription/components/dashboard/group-subscription-memberships.test.tsx index 830787afc1..f861193207 100644 --- a/services/web/test/frontend/features/subscription/components/dashboard/group-subscription-memberships.test.tsx +++ b/services/web/test/frontend/features/subscription/components/dashboard/group-subscription-memberships.test.tsx @@ -51,7 +51,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('renders all group subscriptions not managed', function () { @@ -129,7 +129,7 @@ describe('', function () { fireEvent.click(this.leaveNowButton) - expect(leaveGroupApiMock.called()).to.be.true + expect(leaveGroupApiMock.callHistory.called()).to.be.true await waitFor(() => { expect(reloadStub).to.have.been.called }) diff --git a/services/web/test/frontend/features/subscription/components/dashboard/managed-institutions.test.tsx b/services/web/test/frontend/features/subscription/components/dashboard/managed-institutions.test.tsx index c9a28403fd..7253e0c6f1 100644 --- a/services/web/test/frontend/features/subscription/components/dashboard/managed-institutions.test.tsx +++ b/services/web/test/frontend/features/subscription/components/dashboard/managed-institutions.test.tsx @@ -37,7 +37,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('renders all managed institutions', function () { @@ -98,7 +98,9 @@ describe('', function () { const unsubscribeLink = screen.getByText('Unsubscribe') await fireEvent.click(unsubscribeLink) - await waitFor(() => expect(fetchMock.called(unsubscribeUrl)).to.be.true) + await waitFor( + () => expect(fetchMock.callHistory.called(unsubscribeUrl)).to.be.true + ) await waitFor(() => { expect(screen.getByText('Subscribe')).to.exist @@ -122,13 +124,14 @@ describe('', function () { ) - const subscribeLink = screen.getByText('Subscribe') - await fireEvent.click(subscribeLink) - await waitFor(() => expect(fetchMock.called(subscribeUrl)).to.be.true) + const subscribeLink = await screen.findByText('Subscribe') - await waitFor(() => { - expect(screen.getByText('Unsubscribe')).to.exist - }) + await fireEvent.click(subscribeLink) + await waitFor( + () => expect(fetchMock.callHistory.called(subscribeUrl)).to.be.true + ) + + await screen.findByText('Unsubscribe') }) it('renders nothing when there are no institutions', function () { diff --git a/services/web/test/frontend/features/subscription/components/dashboard/managed-publishers.test.tsx b/services/web/test/frontend/features/subscription/components/dashboard/managed-publishers.test.tsx index 7c696841db..e350e3efd5 100644 --- a/services/web/test/frontend/features/subscription/components/dashboard/managed-publishers.test.tsx +++ b/services/web/test/frontend/features/subscription/components/dashboard/managed-publishers.test.tsx @@ -28,7 +28,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('renders all managed publishers', function () { diff --git a/services/web/test/frontend/features/subscription/components/dashboard/pause-modal.test.tsx b/services/web/test/frontend/features/subscription/components/dashboard/pause-modal.test.tsx index c555f5b7ee..1292a93cdd 100644 --- a/services/web/test/frontend/features/subscription/components/dashboard/pause-modal.test.tsx +++ b/services/web/test/frontend/features/subscription/components/dashboard/pause-modal.test.tsx @@ -59,7 +59,7 @@ describe('', function () { }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() this.locationStub.restore() this.replaceStateStub.restore() }) diff --git a/services/web/test/frontend/features/subscription/components/dashboard/personal-subscription.test.tsx b/services/web/test/frontend/features/subscription/components/dashboard/personal-subscription.test.tsx index 29dcd83b11..2680f1e4bf 100644 --- a/services/web/test/frontend/features/subscription/components/dashboard/personal-subscription.test.tsx +++ b/services/web/test/frontend/features/subscription/components/dashboard/personal-subscription.test.tsx @@ -106,18 +106,18 @@ describe('', function () { fetchMock.postOnce(reactivateSubscriptionUrl, 400) fireEvent.click(reactivateBtn) expect(reactivateBtn.disabled).to.be.true - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) expect(reactivateBtn.disabled).to.be.false expect(reloadStub).not.to.have.been.called - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() // 2nd click - success fetchMock.postOnce(reactivateSubscriptionUrl, 200) fireEvent.click(reactivateBtn) - await fetchMock.flush(true) + await fetchMock.callHistory.flush(true) expect(reloadStub).to.have.been.calledOnce expect(reactivateBtn.disabled).to.be.true - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('renders the expired dash', function () { diff --git a/services/web/test/frontend/features/subscription/components/dashboard/states/active/active.test.tsx b/services/web/test/frontend/features/subscription/components/dashboard/states/active/active.test.tsx index 0c54486228..14e08bbda5 100644 --- a/services/web/test/frontend/features/subscription/components/dashboard/states/active/active.test.tsx +++ b/services/web/test/frontend/features/subscription/components/dashboard/states/active/active.test.tsx @@ -208,7 +208,7 @@ describe('', function () { afterEach(function () { this.locationStub.restore() - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) function showConfirmCancelUI() { diff --git a/services/web/test/frontend/features/subscription/components/dashboard/states/active/change-plan/change-plan.test.tsx b/services/web/test/frontend/features/subscription/components/dashboard/states/active/change-plan/change-plan.test.tsx index 6c75d77583..787866304e 100644 --- a/services/web/test/frontend/features/subscription/components/dashboard/states/active/change-plan/change-plan.test.tsx +++ b/services/web/test/frontend/features/subscription/components/dashboard/states/active/change-plan/change-plan.test.tsx @@ -38,7 +38,7 @@ describe('', function () { afterEach(function () { cleanUpContext() - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() this.locationStub.restore() }) diff --git a/services/web/test/frontend/features/subscription/components/group-invite/has-individual-recurly-subscription.test.tsx b/services/web/test/frontend/features/subscription/components/group-invite/has-individual-recurly-subscription.test.tsx index 32a02810cb..b5bf4ec97d 100644 --- a/services/web/test/frontend/features/subscription/components/group-invite/has-individual-recurly-subscription.test.tsx +++ b/services/web/test/frontend/features/subscription/components/group-invite/has-individual-recurly-subscription.test.tsx @@ -7,7 +7,7 @@ import fetchMock from 'fetch-mock' describe('group invite', function () { describe('user has a personal subscription', function () { afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('shows option to cancel subscription', async function () { diff --git a/services/web/test/frontend/features/subscription/components/group-invite/join-group.test.tsx b/services/web/test/frontend/features/subscription/components/group-invite/join-group.test.tsx index e297d30ac6..4899f29595 100644 --- a/services/web/test/frontend/features/subscription/components/group-invite/join-group.test.tsx +++ b/services/web/test/frontend/features/subscription/components/group-invite/join-group.test.tsx @@ -10,7 +10,7 @@ describe('join group', function () { window.metaAttributesCache.set('ol-inviteToken', inviteToken) }) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) it('shows option to join subscription', async function () { diff --git a/services/web/test/frontend/features/subscription/helpers/render-with-subscription-dash-context.tsx b/services/web/test/frontend/features/subscription/helpers/render-with-subscription-dash-context.tsx index 38a5d7c021..1246b7271b 100644 --- a/services/web/test/frontend/features/subscription/helpers/render-with-subscription-dash-context.tsx +++ b/services/web/test/frontend/features/subscription/helpers/render-with-subscription-dash-context.tsx @@ -90,5 +90,5 @@ export function renderWithSubscriptionDashContext( export function cleanUpContext() { // @ts-ignore delete global.recurly - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() } diff --git a/services/web/test/frontend/features/word-count-modal/components/word-count-modal.test.jsx b/services/web/test/frontend/features/word-count-modal/components/word-count-modal.test.jsx index cc2d37158c..baff2c2d22 100644 --- a/services/web/test/frontend/features/word-count-modal/components/word-count-modal.test.jsx +++ b/services/web/test/frontend/features/word-count-modal/components/word-count-modal.test.jsx @@ -7,7 +7,7 @@ import WordCountModal from '../../../../../frontend/js/features/word-count-modal describe('', function () { afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) const contextProps = { diff --git a/services/web/test/frontend/infrastructure/fetch-json.test.js b/services/web/test/frontend/infrastructure/fetch-json.test.js index 66e626758c..b5c095e29d 100644 --- a/services/web/test/frontend/infrastructure/fetch-json.test.js +++ b/services/web/test/frontend/infrastructure/fetch-json.test.js @@ -1,6 +1,5 @@ import { expect } from 'chai' import fetchMock from 'fetch-mock' -import { Response } from 'node-fetch' import { deleteJSON, FetchError, @@ -12,11 +11,11 @@ import { describe('fetchJSON', function () { before(function () { - fetchMock.restore() + fetchMock.removeRoutes().clearHistory() }) afterEach(function () { - fetchMock.restore() + fetchMock.removeRoutes().clearHistory() }) const headers = { @@ -138,17 +137,7 @@ describe('fetchJSON', function () { }) it('handles 5xx responses without a status message', async function () { - // It's hard to make a Response object with statusText=null, - // so we need to do some monkey-work to make it happen - const response = new Response('weird scary error', { - ok: false, - status: 599, - }) - Object.defineProperty(response, 'statusText', { - get: () => null, - set: () => {}, - }) - fetchMock.get('/test', response) + fetchMock.get('/test', { status: 599 }) return expect(getJSON('/test')) .to.eventually.be.rejectedWith('Unexpected Error: 599') diff --git a/services/web/test/frontend/infrastructure/project-snapshot.test.ts b/services/web/test/frontend/infrastructure/project-snapshot.test.ts index 1e9fa6792b..313436a3f5 100644 --- a/services/web/test/frontend/infrastructure/project-snapshot.test.ts +++ b/services/web/test/frontend/infrastructure/project-snapshot.test.ts @@ -139,7 +139,7 @@ describe('ProjectSnapshot', function () { mockLatestChunk() mockBlobs(['main.tex', 'hello.txt']) await snapshot.refresh() - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() } describe('after initialization', function () { @@ -176,7 +176,7 @@ describe('ProjectSnapshot', function () { mockChanges() mockBlobs(['goodbye.txt']) await snapshot.refresh() - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() } describe('after refresh', function () { @@ -184,7 +184,7 @@ describe('ProjectSnapshot', function () { beforeEach(refreshSnapshot) afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) describe('getDocPaths()', function () { @@ -214,7 +214,7 @@ describe('ProjectSnapshot', function () { describe('concurrency', function () { afterEach(function () { - fetchMock.reset() + fetchMock.removeRoutes().clearHistory() }) specify('two concurrent inits', async function () { @@ -226,9 +226,9 @@ describe('ProjectSnapshot', function () { await Promise.all([snapshot.refresh(), snapshot.refresh()]) // The first request initializes, the second request loads changes - expect(fetchMock.calls('flush')).to.have.length(2) - expect(fetchMock.calls('latest-chunk')).to.have.length(1) - expect(fetchMock.calls('changes-1')).to.have.length(1) + expect(fetchMock.callHistory.calls('flush')).to.have.length(2) + expect(fetchMock.callHistory.calls('latest-chunk')).to.have.length(1) + expect(fetchMock.callHistory.calls('changes-1')).to.have.length(1) }) specify('three concurrent inits', async function () { @@ -245,9 +245,9 @@ describe('ProjectSnapshot', function () { // The first request initializes, the second and third are combined and // load changes - expect(fetchMock.calls('flush')).to.have.length(2) - expect(fetchMock.calls('latest-chunk')).to.have.length(1) - expect(fetchMock.calls('changes-1')).to.have.length(1) + expect(fetchMock.callHistory.calls('flush')).to.have.length(2) + expect(fetchMock.callHistory.calls('latest-chunk')).to.have.length(1) + expect(fetchMock.callHistory.calls('changes-1')).to.have.length(1) }) specify('two concurrent inits - first fails', async function () { @@ -262,9 +262,9 @@ describe('ProjectSnapshot', function () { // The first init fails, but the second succeeds expect(results.filter(r => r.status === 'fulfilled')).to.have.length(1) - expect(fetchMock.calls('flush')).to.have.length(2) - expect(fetchMock.calls('latest-chunk')).to.have.length(1) - expect(fetchMock.calls('changes-1')).to.have.length(0) + expect(fetchMock.callHistory.calls('flush')).to.have.length(2) + expect(fetchMock.callHistory.calls('latest-chunk')).to.have.length(1) + expect(fetchMock.callHistory.calls('changes-1')).to.have.length(0) }) specify('three concurrent inits - second fails', async function () { @@ -285,10 +285,10 @@ describe('ProjectSnapshot', function () { // The first init succeeds, the two queued requests fail, the last request // succeeds expect(results.filter(r => r.status === 'fulfilled')).to.have.length(1) - expect(fetchMock.calls('flush')).to.have.length(3) - expect(fetchMock.calls('latest-chunk')).to.have.length(1) - expect(fetchMock.calls('changes-1')).to.have.length(1) - expect(fetchMock.calls('changes-2')).to.have.length(0) + expect(fetchMock.callHistory.calls('flush')).to.have.length(3) + expect(fetchMock.callHistory.calls('latest-chunk')).to.have.length(1) + expect(fetchMock.callHistory.calls('changes-1')).to.have.length(1) + expect(fetchMock.callHistory.calls('changes-2')).to.have.length(0) }) specify('two concurrent load changes', async function () { @@ -304,10 +304,10 @@ describe('ProjectSnapshot', function () { await Promise.all([snapshot.refresh(), snapshot.refresh()]) // One init, two load changes - expect(fetchMock.calls('flush')).to.have.length(3) - expect(fetchMock.calls('latest-chunk')).to.have.length(1) - expect(fetchMock.calls('changes-1')).to.have.length(1) - expect(fetchMock.calls('changes-2')).to.have.length(1) + expect(fetchMock.callHistory.calls('flush')).to.have.length(3) + expect(fetchMock.callHistory.calls('latest-chunk')).to.have.length(1) + expect(fetchMock.callHistory.calls('changes-1')).to.have.length(1) + expect(fetchMock.callHistory.calls('changes-2')).to.have.length(1) }) specify('three concurrent load changes', async function () { @@ -327,10 +327,10 @@ describe('ProjectSnapshot', function () { ]) // One init, two load changes (the two last are queued and combined) - expect(fetchMock.calls('flush')).to.have.length(3) - expect(fetchMock.calls('latest-chunk')).to.have.length(1) - expect(fetchMock.calls('changes-1')).to.have.length(1) - expect(fetchMock.calls('changes-2')).to.have.length(1) + expect(fetchMock.callHistory.calls('flush')).to.have.length(3) + expect(fetchMock.callHistory.calls('latest-chunk')).to.have.length(1) + expect(fetchMock.callHistory.calls('changes-1')).to.have.length(1) + expect(fetchMock.callHistory.calls('changes-2')).to.have.length(1) }) specify('two concurrent load changes - first fails', async function () { @@ -350,10 +350,10 @@ describe('ProjectSnapshot', function () { // One init, one load changes fails, the second succeeds expect(results.filter(r => r.status === 'fulfilled')).to.have.length(1) - expect(fetchMock.calls('flush')).to.have.length(3) - expect(fetchMock.calls('latest-chunk')).to.have.length(1) - expect(fetchMock.calls('changes-1')).to.have.length(1) - expect(fetchMock.calls('changes-2')).to.have.length(0) + expect(fetchMock.callHistory.calls('flush')).to.have.length(3) + expect(fetchMock.callHistory.calls('latest-chunk')).to.have.length(1) + expect(fetchMock.callHistory.calls('changes-1')).to.have.length(1) + expect(fetchMock.callHistory.calls('changes-2')).to.have.length(0) }) specify('three concurrent load changes - second fails', async function () { @@ -378,10 +378,10 @@ describe('ProjectSnapshot', function () { // One init, one load changes succeeds, the second and third are combined // and fail, the last request succeeds expect(results.filter(r => r.status === 'fulfilled')).to.have.length(1) - expect(fetchMock.calls('flush')).to.have.length(4) - expect(fetchMock.calls('latest-chunk')).to.have.length(1) - expect(fetchMock.calls('changes-1')).to.have.length(1) - expect(fetchMock.calls('changes-2')).to.have.length(1) + expect(fetchMock.callHistory.calls('flush')).to.have.length(4) + expect(fetchMock.callHistory.calls('latest-chunk')).to.have.length(1) + expect(fetchMock.callHistory.calls('changes-1')).to.have.length(1) + expect(fetchMock.callHistory.calls('changes-2')).to.have.length(1) }) }) }) diff --git a/services/web/test/frontend/shared/hooks/use-abort-controller.test.tsx b/services/web/test/frontend/shared/hooks/use-abort-controller.test.tsx index fd91fa6faa..3b18913117 100644 --- a/services/web/test/frontend/shared/hooks/use-abort-controller.test.tsx +++ b/services/web/test/frontend/shared/hooks/use-abort-controller.test.tsx @@ -13,7 +13,7 @@ describe('useAbortController', function () { } beforeEach(function () { - fetchMock.restore() + fetchMock.removeRoutes().clearHistory() status = { loading: false, @@ -23,7 +23,7 @@ describe('useAbortController', function () { }) after(function () { - fetchMock.restore() + fetchMock.removeRoutes().clearHistory() }) function AbortableRequest({ url }: { url: string }) { @@ -80,8 +80,8 @@ describe('useAbortController', function () { unmount() - await fetchMock.flush(true) - expect(fetchMock.done()).to.be.true + await fetchMock.callHistory.flush(true) + expect(fetchMock.callHistory.done()).to.be.true // wait for Promises to be resolved await new Promise(resolve => setTimeout(resolve, 0))