diff --git a/services/web/cypress/support/shared/commands/compile.ts b/services/web/cypress/support/shared/commands/compile.ts index bb772b37e6..e4cd94d3a6 100644 --- a/services/web/cypress/support/shared/commands/compile.ts +++ b/services/web/cypress/support/shared/commands/compile.ts @@ -43,26 +43,111 @@ const outputFiles = () => { ] } -export const interceptCompile = (prefix = 'compile') => { - cy.intercept('POST', '/project/*/compile*', { - body: { - status: 'success', - clsiServerId: 'foo', - compileGroup: 'priority', - pdfDownloadDomain: 'https://clsi.test-overleaf.com', - outputFiles: outputFiles(), - }, - }).as(`${prefix}`) +export const interceptCompile = (prefix = 'compile', times = 1) => { + cy.intercept( + { method: 'POST', url: '/project/*/compile*', times }, + { + body: { + status: 'success', + clsiServerId: 'foo', + compileGroup: 'priority', + pdfDownloadDomain: 'https://clsi.test-overleaf.com', + outputFiles: outputFiles(), + }, + } + ).as(`${prefix}`) - cy.intercept('/build/*/output.pdf*', { - fixture: 'build/output.pdf,null', - }).as(`${prefix}-pdf`) + cy.intercept( + { url: '/build/*/output.pdf*', times }, + { fixture: 'build/output.pdf,null' } + ).as(`${prefix}-pdf`) - cy.intercept('/build/*/output.log*', { - fixture: 'build/output.log', - }).as(`${prefix}-log`) + cy.intercept( + { url: '/build/*/output.log*', times }, + { fixture: 'build/output.log' } + ).as(`${prefix}-log`) - cy.intercept('/build/*/output.blg*', { - fixture: 'build/output.blg', - }).as(`${prefix}-blg`) + cy.intercept( + { url: '/build/*/output.blg*', times }, + { fixture: 'build/output.blg' } + ).as(`${prefix}-blg`) +} + +export const waitForCompile = ({ prefix = 'compile', pdf = false } = {}) => { + cy.wait(`@${prefix}`) + cy.wait(`@${prefix}-log`) + cy.wait(`@${prefix}-blg`) + if (pdf) { + cy.wait(`@${prefix}-pdf`) + } + return cy.wrap(null) +} + +export const interceptDeferredCompile = (beforeResponse?: () => void) => { + let resolveDeferredCompile: (value?: unknown) => void + + const promise = new Promise(resolve => { + resolveDeferredCompile = resolve + }) + + cy.intercept( + { method: 'POST', url: '/project/*/compile*', times: 1 }, + req => { + if (beforeResponse) { + beforeResponse() + } + + // only reply once the Promise is resolved + promise.then(() => { + req.reply({ + body: { + status: 'success', + clsiServerId: 'foo', + compileGroup: 'priority', + pdfDownloadDomain: 'https://clsi.test-overleaf.com', + outputFiles: [ + { + path: 'output.pdf', + build: '123', + url: '/build/123/output.pdf', + type: 'pdf', + }, + { + path: 'output.log', + build: '123', + url: '/build/123/output.log', + type: 'log', + }, + { + path: 'output.blg', + build: '123', + url: '/build/123/output.blg', + type: 'log', + }, + ], + }, + }) + }) + + return promise + } + ).as('compile') + + cy.intercept( + { url: '/build/*/output.pdf*', times: 1 }, + { fixture: 'build/output.pdf,null' } + ).as(`compile-pdf`) + + cy.intercept( + { url: '/build/*/output.log*', times: 1 }, + { fixture: 'build/output.log' } + ).as(`compile-log`) + + cy.intercept( + { url: '/build/*/output.blg*', times: 1 }, + { fixture: 'build/output.blg' } + ).as(`compile-blg`) + + // @ts-ignore + return cy.wrap(resolveDeferredCompile) } diff --git a/services/web/cypress/support/shared/commands/index.ts b/services/web/cypress/support/shared/commands/index.ts index d1f1c135c7..5f611bd61a 100644 --- a/services/web/cypress/support/shared/commands/index.ts +++ b/services/web/cypress/support/shared/commands/index.ts @@ -1,5 +1,9 @@ import '@testing-library/cypress/add-commands' -import { interceptCompile } from './compile' +import { + interceptCompile, + waitForCompile, + interceptDeferredCompile, +} from './compile' import { interceptEvents } from './events' import { interceptSpelling } from './spelling' @@ -12,6 +16,8 @@ declare global { interceptCompile: typeof interceptCompile interceptEvents: typeof interceptEvents interceptSpelling: typeof interceptSpelling + waitForCompile: typeof waitForCompile + interceptDeferredCompile: typeof interceptDeferredCompile index: () => Chainable } } @@ -20,6 +26,8 @@ declare global { Cypress.Commands.add('interceptCompile', interceptCompile) Cypress.Commands.add('interceptEvents', interceptEvents) Cypress.Commands.add('interceptSpelling', interceptSpelling) +Cypress.Commands.add('waitForCompile', waitForCompile) +Cypress.Commands.add('interceptDeferredCompile', interceptDeferredCompile) Cypress.Commands.add('index', { prevSubject: true }, subject => { return cy.wrap(subject).invoke('index') }) diff --git a/services/web/test/frontend/components/pdf-preview/detach-compile-button.spec.tsx b/services/web/test/frontend/components/pdf-preview/detach-compile-button.spec.tsx index 5ecd3dc374..67e9be95a4 100644 --- a/services/web/test/frontend/components/pdf-preview/detach-compile-button.spec.tsx +++ b/services/web/test/frontend/components/pdf-preview/detach-compile-button.spec.tsx @@ -5,7 +5,7 @@ import { testDetachChannel } from '../../helpers/detach-channel' describe('', function () { beforeEach(function () { - cy.interceptCompile() + window.metaAttributesCache = new Map() cy.interceptEvents() }) @@ -14,6 +14,8 @@ describe('', function () { }) it('detacher mode and not linked: does not show button ', function () { + cy.interceptCompile() + cy.window().then(win => { win.metaAttributesCache = new Map([['ol-detachRole', 'detacher']]) }) @@ -26,10 +28,14 @@ describe('', function () { ) + cy.waitForCompile() + cy.findByRole('button', { name: 'Recompile' }).should('not.exist') }) it('detacher mode and linked: show button', function () { + cy.interceptCompile() + cy.window().then(win => { win.metaAttributesCache = new Map([['ol-detachRole', 'detacher']]) }) @@ -42,6 +48,8 @@ describe('', function () { ) + cy.waitForCompile() + cy.wrap(null).then(() => { testDetachChannel.postMessage({ role: 'detached', @@ -53,6 +61,8 @@ describe('', function () { }) it('not detacher mode and linked: does not show button ', function () { + cy.interceptCompile() + cy.window().then(win => { win.metaAttributesCache = new Map([['ol-detachRole', 'detached']]) }) @@ -65,6 +75,8 @@ describe('', function () { ) + cy.waitForCompile() + cy.wrap(null).then(() => { testDetachChannel.postMessage({ role: 'detacher', diff --git a/services/web/test/frontend/components/pdf-preview/pdf-js-viewer.spec.tsx b/services/web/test/frontend/components/pdf-preview/pdf-js-viewer.spec.tsx index 736a9c5ede..7c83f15bca 100644 --- a/services/web/test/frontend/components/pdf-preview/pdf-js-viewer.spec.tsx +++ b/services/web/test/frontend/components/pdf-preview/pdf-js-viewer.spec.tsx @@ -6,11 +6,12 @@ import { unmountComponentAtNode } from 'react-dom' describe('', function () { beforeEach(function () { - cy.interceptCompile() cy.interceptEvents() }) it('loads all PDF pages', function () { + cy.interceptCompile() + const scope = mockScope() cy.mount( @@ -21,6 +22,8 @@ describe('', function () { ) + cy.waitForCompile() + cy.findByLabelText('Page 1') cy.findByLabelText('Page 2') cy.findByLabelText('Page 3') @@ -30,6 +33,8 @@ describe('', function () { }) it('renders pages in a "loading" state', function () { + cy.interceptCompile() + const scope = mockScope() cy.mount( @@ -40,10 +45,14 @@ describe('', function () { ) + cy.waitForCompile() + cy.findByLabelText('Loading…') }) it('can be unmounted while loading a document', function () { + cy.interceptCompile() + const scope = mockScope() cy.mount( @@ -54,10 +63,14 @@ describe('', function () { ) + cy.waitForCompile() + cy.then(() => unmountComponentAtNode(getContainerEl())) }) it('can be unmounted after loading a document', function () { + cy.interceptCompile() + const scope = mockScope() cy.mount( @@ -68,6 +81,8 @@ describe('', function () { ) + cy.waitForCompile() + cy.findByLabelText('Page 1') cy.then(() => unmountComponentAtNode(getContainerEl())) diff --git a/services/web/test/frontend/components/pdf-preview/pdf-preview-detached-root.spec.tsx b/services/web/test/frontend/components/pdf-preview/pdf-preview-detached-root.spec.tsx index 007fa48d76..fe85285cb5 100644 --- a/services/web/test/frontend/components/pdf-preview/pdf-preview-detached-root.spec.tsx +++ b/services/web/test/frontend/components/pdf-preview/pdf-preview-detached-root.spec.tsx @@ -11,9 +11,9 @@ describe('', function () { ['ol-project_id', 'project1'], ['ol-detachRole', 'detached'], ['ol-projectName', 'Project Name'], + ['ol-preventCompileOnLoad', true], ]) - cy.interceptCompile() cy.interceptEvents() }) @@ -22,6 +22,8 @@ describe('', function () { }) it('syncs compiling state', function () { + cy.interceptCompile() + cy.mount() cy.wrap(null).then(() => { @@ -51,6 +53,8 @@ describe('', function () { }) it('sends a clear cache request when the button is pressed', function () { + cy.interceptCompile() + cy.mount() cy.wrap(null).then(() => { diff --git a/services/web/test/frontend/components/pdf-preview/pdf-preview-hybrid-toolbar.spec.tsx b/services/web/test/frontend/components/pdf-preview/pdf-preview-hybrid-toolbar.spec.tsx index c88c9e219a..79878ae338 100644 --- a/services/web/test/frontend/components/pdf-preview/pdf-preview-hybrid-toolbar.spec.tsx +++ b/services/web/test/frontend/components/pdf-preview/pdf-preview-hybrid-toolbar.spec.tsx @@ -4,7 +4,8 @@ import { testDetachChannel } from '../../helpers/detach-channel' describe('', function () { beforeEach(function () { - cy.interceptCompile() + window.metaAttributesCache = new Map() + window.metaAttributesCache.set('ol-preventCompileOnLoad', true) cy.interceptEvents() }) diff --git a/services/web/test/frontend/components/pdf-preview/pdf-preview.spec.tsx b/services/web/test/frontend/components/pdf-preview/pdf-preview.spec.tsx index 2dc517c3ae..4ce761cb37 100644 --- a/services/web/test/frontend/components/pdf-preview/pdf-preview.spec.tsx +++ b/services/web/test/frontend/components/pdf-preview/pdf-preview.spec.tsx @@ -22,11 +22,18 @@ const Layout: FC<{ layout: string; view?: string }> = ({ layout, view }) => { describe('', function () { beforeEach(function () { - cy.interceptCompile() + window.metaAttributesCache.set('ol-preventCompileOnLoad', true) cy.interceptEvents() }) + afterEach(function () { + window.metaAttributesCache = new Map() + }) + it('renders the PDF preview', function () { + window.metaAttributesCache.set('ol-preventCompileOnLoad', false) + cy.interceptCompile('compile') + const scope = mockScope() cy.mount( @@ -38,13 +45,14 @@ describe('', function () { ) // wait for "compile on load" to finish - cy.findByRole('button', { name: 'Compiling…' }) - cy.wait('@compile') + cy.waitForCompile({ pdf: true }) + cy.findByRole('button', { name: 'Recompile' }) - cy.wait('@compile-pdf') }) it('runs a compile when the Recompile button is pressed', function () { + cy.interceptCompile() + const scope = mockScope() cy.mount( @@ -55,28 +63,18 @@ describe('', function () { ) - // wait for "compile on load" to finish - cy.findByRole('button', { name: 'Compiling…' }) - cy.wait('@compile') - cy.wait('@compile-pdf') - - cy.interceptCompile('recompile') - // press the Recompile button => compile cy.findByRole('button', { name: 'Recompile' }).click() - // wait for "recompile" to finish - // cy.findByRole('button', { name: 'Compiling…' }) - cy.wait('@recompile-pdf') - cy.wait('@recompile-log') - cy.wait('@recompile-blg') - - cy.findByRole('button', { name: 'Recompile' }) + // wait for compile to finish + cy.waitForCompile({ pdf: true }) cy.contains('Your Paper') }) it('runs a compile on `pdf:recompile` event', function () { + cy.interceptCompile() + const scope = mockScope() cy.mount( @@ -87,111 +85,79 @@ describe('', function () { ) - // wait for "compile on load" to finish - cy.findByRole('button', { name: 'Compiling…' }) - cy.wait('@compile') - cy.wait('@compile-pdf') - - cy.interceptCompile('recompile') - cy.window().then(win => { win.dispatchEvent(new CustomEvent('pdf:recompile')) }) - // wait for "recompile" to finish - // cy.findByRole('button', { name: 'Compiling…' }) - cy.wait('@recompile') + // wait for compile to finish + cy.waitForCompile({ pdf: true }) - cy.findByRole('button', { name: 'Recompile' }) - - cy.wait('@recompile-pdf') cy.contains('Your Paper') }) it('does not compile while compiling', function () { - let compileResolve: (value?: unknown) => void let counter = 0 + cy.interceptDeferredCompile(() => counter++).then( + resolveDeferredCompile => { + const scope = mockScope() - const promise = new Promise(resolve => { - compileResolve = resolve - }) + cy.mount( + +
+ +
+
+ ) - cy.intercept( - 'POST', - '/project/project123/compile?auto_compile=true', - req => { - counter++ + // start compiling + cy.findByRole('button', { name: 'Recompile' }) + .click() + .then(() => { + cy.findByRole('button', { name: 'Compiling…' }) - promise.then(() => { - req.reply({ - body: { - status: 'success', - clsiServerId: 'foo', - compileGroup: 'priority', - pdfDownloadDomain: 'https://clsi.test-overleaf.com', - outputFiles: [ - { - path: 'output.pdf', - build: '123', - url: '/build/123/output.pdf', - type: 'pdf', - }, - { - path: 'output.log', - build: '123', - url: '/build/123/output.log', - type: 'log', - }, - ], - }, + // trigger a recompile + cy.window().then(win => { + win.dispatchEvent(new CustomEvent('pdf:recompile')) + }) + + // finish the original compile + resolveDeferredCompile() + + // wait for the original compile to finish + cy.waitForCompile({ pdf: true }) + + // NOTE: difficult to assert that a second request won't be sent, at some point + expect(counter).to.equal(1) }) - }) - - return promise } - ).as('compile') - - const scope = mockScope() - - cy.mount( - -
- -
-
- ).then(() => { - cy.findByRole('button', { name: 'Compiling…' }) - - cy.window().then(win => { - win.dispatchEvent(new CustomEvent('pdf:recompile')) - }) - - compileResolve() - - cy.findByRole('button', { name: 'Recompile' }) - - cy.contains('Your Paper').should(() => { - expect(counter).to.equal(1) - }) - }) + ) }) it('disables compile button while compile is running', function () { - const scope = mockScope() + cy.interceptDeferredCompile().then(resolveDeferredCompile => { + const scope = mockScope() - cy.mount( - -
- -
-
- ) + cy.mount( + +
+ +
+
+ ) - cy.findByRole('button', { name: 'Compiling…' }).should('be.disabled') - cy.findByRole('button', { name: 'Recompile' }).should('not.be.disabled') + cy.findByRole('button', { name: 'Recompile' }).click() + cy.findByRole('button', { name: 'Compiling…' }) + .should('be.disabled') + .then(resolveDeferredCompile) + + cy.waitForCompile() + cy.findByRole('button', { name: 'Recompile' }).should('not.be.disabled') + }) }) it('runs a compile on doc change if autocompile is enabled', function () { + cy.interceptCompile() + const scope = mockScope() cy.mount( @@ -202,11 +168,6 @@ describe('', function () { ) - // wait for "compile on load" to finish - cy.findByRole('button', { name: 'Compiling…' }) - cy.wait('@compile') - cy.findByRole('button', { name: 'Recompile' }) - cy.window().then(win => { cy.clock() @@ -216,16 +177,21 @@ describe('', function () { // fire a doc:changed event => compile win.dispatchEvent(new CustomEvent('doc:changed')) + // wait enough time for the compile to start cy.tick(6000) // > AUTO_COMPILE_DEBOUNCE cy.clock().invoke('restore') }) - cy.findByRole('button', { name: 'Compiling…' }) + // wait for compile to finish + cy.waitForCompile({ pdf: true }) + cy.findByRole('button', { name: 'Recompile' }) }) it('does not run a compile on doc change if autocompile is disabled', function () { + cy.interceptCompile() + const scope = mockScope() cy.mount( @@ -236,10 +202,6 @@ describe('', function () { ) - // wait for "compile on load" to finish - cy.findByRole('button', { name: 'Compiling…' }) - cy.findByRole('button', { name: 'Recompile' }) - cy.window().then(win => { cy.clock() @@ -249,15 +211,19 @@ describe('', function () { // fire a doc:changed event => no compile win.dispatchEvent(new CustomEvent('doc:changed')) - cy.tick(5000) // AUTO_COMPILE_DEBOUNCE + // wait enough time for the compile to start + cy.tick(6000) // AUTO_COMPILE_DEBOUNCE cy.clock().invoke('restore') }) + // NOTE: difficult to assert that a request hasn't been sent cy.findByRole('button', { name: 'Recompile' }) }) it('does not run a compile on doc change if autocompile is blocked by syntax check', function () { + cy.interceptCompile() + const scope = mockScope() // enable linting in the editor scope.settings.syntaxValidation = true @@ -272,10 +238,6 @@ describe('', function () { ) - // wait for "compile on load" to finish - cy.findByRole('button', { name: 'Compiling…' }) - cy.findByRole('button', { name: 'Recompile' }) - cy.window().then(win => { cy.clock() @@ -288,16 +250,21 @@ describe('', function () { // fire a doc:changed event => no compile win.dispatchEvent(new CustomEvent('doc:changed')) - cy.tick(5000) // AUTO_COMPILE_DEBOUNCE + // wait enough time for the compile to start + cy.tick(6000) // AUTO_COMPILE_DEBOUNCE cy.clock().invoke('restore') }) + // NOTE: difficult to assert that a request hasn't been sent cy.findByRole('button', { name: 'Recompile' }) + cy.findByText('Code check failed') }) it('does not run a compile on doc change if the PDF preview is not open', function () { + cy.interceptCompile() + const scope = mockScope() cy.mount( @@ -309,11 +276,6 @@ describe('', function () { ) - // wait for "compile on load" to finish - cy.findByRole('button', { name: 'Compiling…' }) - cy.wait('@compile') - cy.findByRole('button', { name: 'Recompile' }) - cy.window().then(win => { cy.clock() @@ -323,15 +285,17 @@ describe('', function () { // fire a doc:changed event => compile win.dispatchEvent(new CustomEvent('doc:changed')) + // wait enough time for the compile to start cy.tick(6000) // > AUTO_COMPILE_DEBOUNCE cy.clock().invoke('restore') }) + // NOTE: difficult to assert that a request hasn't been sent cy.findByRole('button', { name: 'Recompile' }) }) - describe('displays error messages', function () { + describe('error messages', function () { const compileErrorStatuses = { 'clear-cache': 'Sorry, something went wrong and your project could not be compiled. Please try again in a few moments.', @@ -355,7 +319,7 @@ describe('', function () { for (const [status, message] of Object.entries(compileErrorStatuses)) { it(`displays error message for '${status}' status`, function () { - cy.intercept('POST', '/project/*/compile?*', { + cy.intercept('POST', '/project/*/compile*', { body: { status, clsiServerId: 'foo', @@ -373,86 +337,86 @@ describe('', function () { ) - // wait for "compile on load" to finish - cy.findByRole('button', { name: 'Compiling…' }) - cy.findByRole('button', { name: 'Recompile' }) - + cy.findByRole('button', { name: 'Recompile' }).click() + cy.wait('@compile') cy.findByText(message) }) } + }) - it('displays expandable raw logs', function () { - const scope = mockScope() + it('displays expandable raw logs', function () { + cy.interceptCompile() - cy.mount( - -
- -
-
- ) + const scope = mockScope() - // wait for "compile on load" to finish - cy.findByRole('button', { name: 'Compiling…' }) - cy.findByRole('button', { name: 'Recompile' }) + cy.mount( + +
+ +
+
+ ) - cy.findByRole('button', { name: 'View logs' }).click() - cy.findByRole('button', { name: 'View PDF' }) + cy.findByRole('button', { name: 'Recompile' }).click() + cy.waitForCompile({ pdf: true }) - cy.findByRole('button', { name: 'Expand' }).click() - cy.findByRole('button', { name: 'Collapse' }).click() - }) + cy.findByRole('button', { name: 'View logs' }).click() + cy.findByRole('button', { name: 'View PDF' }) - it('displays error messages if there were validation problems', function () { - const validationProblems = { - sizeCheck: { - resources: [ - { path: 'foo/bar', kbSize: 76221 }, - { path: 'bar/baz', kbSize: 2342 }, - ], - }, - mainFile: true, - conflictedPaths: [ - { - path: 'foo/bar', - }, - { - path: 'foo/baz', - }, + cy.findByRole('button', { name: 'Expand' }).click() + cy.findByRole('button', { name: 'Collapse' }).click() + }) + + it('displays error messages if there were validation problems', function () { + const validationProblems = { + sizeCheck: { + resources: [ + { path: 'foo/bar', kbSize: 76221 }, + { path: 'bar/baz', kbSize: 2342 }, ], - } - - cy.intercept('POST', '/project/*/compile?*', { - body: { - status: 'validation-problems', - validationProblems, - clsiServerId: 'foo', - compileGroup: 'priority', + }, + mainFile: true, + conflictedPaths: [ + { + path: 'foo/bar', }, - }).as('compile') + { + path: 'foo/baz', + }, + ], + } - const scope = mockScope() + cy.intercept('POST', '/project/*/compile*', { + body: { + status: 'validation-problems', + validationProblems, + clsiServerId: 'foo', + compileGroup: 'priority', + }, + }).as('compile') - cy.mount( - -
- -
-
- ) + const scope = mockScope() - // wait for "compile on load" to finish - cy.findByRole('button', { name: 'Compiling…' }) - cy.findByRole('button', { name: 'Recompile' }) + cy.mount( + +
+ +
+
+ ) - cy.wait('@compile') + cy.findByRole('button', { name: 'Recompile' }).click() + cy.wait('@compile') - cy.findByText('Project too large') - cy.findByText('Unknown main document') - cy.findByText('Conflicting Paths Found') - }) + cy.findByText('Project too large') + cy.findByText('Unknown main document') + cy.findByText('Conflicting Paths Found') + }) + describe('clear cache', function () { it('sends a clear cache request when the button is pressed', function () { + cy.interceptCompile() + const scope = mockScope() cy.mount( @@ -463,16 +427,15 @@ describe('', function () { ) - // wait for "compile on load" to finish - cy.findByRole('button', { name: 'Compiling…' }) - cy.findByRole('button', { name: 'Recompile' }) + cy.findByRole('button', { name: 'Recompile' }).click() + cy.waitForCompile({ pdf: true }) cy.findByRole('button', { name: 'View logs' }).click() cy.findByRole('button', { name: 'Clear cached files' }).should( 'not.be.disabled' ) - cy.intercept('DELETE', 'project/*/output?*', { + cy.intercept('DELETE', '/project/*/output*', { statusCode: 204, delay: 100, }).as('clear-cache') @@ -489,6 +452,8 @@ describe('', function () { }) it('handle "recompile from scratch"', function () { + cy.interceptCompile() + const scope = mockScope() cy.mount( @@ -499,10 +464,13 @@ describe('', function () { ) - // wait for "compile on load" to finish - cy.findByRole('button', { name: 'Compiling…' }) - cy.wait('@compile') - cy.findByRole('button', { name: 'Recompile' }) + cy.findByRole('button', { name: 'Recompile' }).click() + cy.waitForCompile({ pdf: true }) + cy.interceptCompile('recompile') + cy.intercept('DELETE', '/project/*/output*', { + statusCode: 204, + delay: 100, + }).as('clear-cache') // show the logs UI cy.findByRole('button', { name: 'View logs' }).click() @@ -511,13 +479,6 @@ describe('', function () { 'not.be.disabled' ) - cy.interceptCompile() - - cy.intercept('DELETE', 'project/*/output?*', { - statusCode: 204, - delay: 100, - }).as('clear-cache') - // TODO: open the menu? cy.findByRole('menuitem', { name: 'Recompile from scratch', @@ -530,14 +491,19 @@ describe('', function () { cy.findByRole('button', { name: 'Compiling…' }) cy.wait('@clear-cache') + + // wait for recompile from scratch to finish + cy.waitForCompile({ pdf: true, prefix: 'recompile' }) + cy.findByRole('button', { name: 'Recompile' }) - - cy.wait('@compile') - cy.wait('@compile-pdf') }) + }) + describe('invalid URLs and broken PDFs', function () { it('shows an error for an invalid URL', function () { - cy.intercept('/build/*/output.pdf?*', { + cy.interceptCompile() + + cy.intercept('/build/*/output.pdf*', { statusCode: 500, body: { message: 'something awful happened', @@ -555,6 +521,8 @@ describe('', function () { ) + cy.findByRole('button', { name: 'Recompile' }).click() + cy.waitForCompile() cy.wait('@compile-pdf-error') cy.contains('Something went wrong while rendering this PDF.') @@ -565,7 +533,9 @@ describe('', function () { }) it('shows an error for a corrupt PDF', function () { - cy.intercept('/build/*/output.pdf?*', { + cy.interceptCompile() + + cy.intercept('/build/*/output.pdf*', { fixture: 'build/output-corrupt.pdf,null', }).as('compile-pdf-corrupt') @@ -579,6 +549,8 @@ describe('', function () { ) + cy.findByRole('button', { name: 'Recompile' }).click() + cy.waitForCompile() cy.wait('@compile-pdf-corrupt') cy.contains('Something went wrong while rendering this PDF.') @@ -591,9 +563,11 @@ describe('', function () { describe('human readable logs', function () { it('shows human readable hint for undefined reference errors', function () { - cy.intercept('/build/*/output.log?*', { + cy.interceptCompile() + + cy.intercept('/build/*/output.log*', { fixture: 'build/output-human-readable.log', - }).as('log') + }).as('compile-log') const scope = mockScope() @@ -605,7 +579,8 @@ describe('', function () { ) - cy.wait('@log') + cy.findByRole('button', { name: 'Recompile' }).click() + cy.waitForCompile() cy.findByRole('button', { name: 'View logs' }).click() cy.findByText( @@ -622,9 +597,10 @@ describe('', function () { }) it('does not show human readable hint when no undefined reference errors', function () { + cy.interceptCompile() cy.intercept('/build/*/output.log?*', { fixture: 'build/output-undefined-references.log', - }).as('log') + }).as('compile-log') const scope = mockScope() @@ -636,7 +612,8 @@ describe('', function () { ) - cy.wait('@log') + cy.findByRole('button', { name: 'Recompile' }).click() + cy.waitForCompile() cy.findByRole('button', { name: 'View logs' }).click() cy.findByText( diff --git a/services/web/test/frontend/components/pdf-preview/pdf-synctex-controls.spec.tsx b/services/web/test/frontend/components/pdf-preview/pdf-synctex-controls.spec.tsx index c44777efe1..eb8b469144 100644 --- a/services/web/test/frontend/components/pdf-preview/pdf-synctex-controls.spec.tsx +++ b/services/web/test/frontend/components/pdf-preview/pdf-synctex-controls.spec.tsx @@ -77,7 +77,7 @@ const WithSelectedEntities = ({ } const interceptSyncCodeAsync = () => { - const output: { resolve: () => void } = { + const deferred: { resolve: () => void } = { resolve: () => { // do nothing }, @@ -85,7 +85,7 @@ const interceptSyncCodeAsync = () => { cy.intercept('/project/*/sync/code?*', req => { return new Promise(resolve => { - output.resolve = () => { + deferred.resolve = () => { req.reply({ body: { pdf: cloneDeep(mockHighlights) }, }) @@ -94,7 +94,7 @@ const interceptSyncCodeAsync = () => { }) }).as('sync-code') - return output + return deferred } const interceptSyncPdfAsync = () => { @@ -127,12 +127,10 @@ const interceptSyncPdf = () => { }).as('sync-pdf') } -// eslint-disable-next-line mocha/no-skipped-tests -describe.skip('', function () { +describe('', function () { beforeEach(function () { window.metaAttributesCache = new Map() - - cy.interceptCompile() + window.metaAttributesCache.set('ol-preventCompileOnLoad', false) cy.interceptEvents() }) @@ -141,6 +139,8 @@ describe.skip('', function () { }) it('handles clicks on sync buttons', function () { + cy.interceptCompile() + const scope = mockScope() cy.mount( @@ -151,6 +151,8 @@ describe.skip('', function () { ) + cy.waitForCompile() + cy.get('.synctex-control-icon').should('have.length', 2) // mock editor cursor position update @@ -162,7 +164,7 @@ describe.skip('', function () { ) }) - cy.wait('@compile').then(() => { + cy.wrap(null).then(() => { setDetachedPosition(mockPosition) }) @@ -190,6 +192,8 @@ describe.skip('', function () { }) it('disables button when multiple entities are selected', function () { + cy.interceptCompile() + const scope = mockScope() cy.mount( @@ -202,12 +206,16 @@ describe.skip('', function () { ) + cy.waitForCompile() + cy.findByRole('button', { name: 'Go to code location in PDF' }).should( 'be.disabled' ) }) it('disables button when a file is selected', function () { + cy.interceptCompile() + const scope = mockScope() cy.mount( @@ -218,6 +226,8 @@ describe.skip('', function () { ) + cy.waitForCompile() + cy.findByRole('button', { name: 'Go to code location in PDF' }).should( 'be.disabled' ) @@ -229,6 +239,8 @@ describe.skip('', function () { }) it('does not have go to PDF location button nor arrow icon', function () { + cy.interceptCompile() + const scope = mockScope() cy.mount( @@ -239,6 +251,8 @@ describe.skip('', function () { ) + cy.waitForCompile() + cy.findByRole('button', { name: /^Go to PDF location in code/ }).should( 'not.exist' ) @@ -247,6 +261,8 @@ describe.skip('', function () { }) it('send set highlights action', function () { + cy.interceptCompile() + const scope = mockScope() cy.mount( @@ -257,7 +273,7 @@ describe.skip('', function () { ) - cy.wait('@compile') + cy.waitForCompile() // mock editor cursor position update cy.window().then(win => { @@ -302,6 +318,7 @@ describe.skip('', function () { }) it('reacts to sync to code action', function () { + cy.interceptCompile() interceptSyncPdf() const scope = mockScope() @@ -312,7 +329,9 @@ describe.skip('', function () { - ).then(() => { + ) + + cy.waitForCompile().then(() => { testDetachChannel.postMessage({ role: 'detached', event: 'action-sync-to-code', @@ -332,6 +351,8 @@ describe.skip('', function () { }) it('does not have go to code location button nor arrow icon', function () { + cy.interceptCompile() + const scope = mockScope() cy.mount( @@ -341,6 +362,8 @@ describe.skip('', function () { ) + cy.waitForCompile() + cy.findByRole('button', { name: 'Go to code location in PDF', }).should('not.exist') @@ -349,6 +372,8 @@ describe.skip('', function () { }) it('send go to code line action', function () { + cy.interceptCompile() + const scope = mockScope() cy.mount( @@ -357,7 +382,7 @@ describe.skip('', function () { ) - cy.wait('@compile').then(() => { + cy.waitForCompile().then(() => { testDetachChannel.postMessage({ role: 'detacher', event: `state-position`, @@ -394,6 +419,8 @@ describe.skip('', function () { }) it('update inflight state', function () { + cy.interceptCompile() + const scope = mockScope() cy.mount( @@ -403,7 +430,7 @@ describe.skip('', function () { ) - cy.wrap(null).then(() => { + cy.waitForCompile().then(() => { testDetachChannel.postMessage({ role: 'detacher', event: `state-position`, diff --git a/services/web/test/frontend/shared/hooks/use-detach-layout.spec.tsx b/services/web/test/frontend/shared/hooks/use-detach-layout.spec.tsx index aceef70bdc..351c4d0687 100644 --- a/services/web/test/frontend/shared/hooks/use-detach-layout.spec.tsx +++ b/services/web/test/frontend/shared/hooks/use-detach-layout.spec.tsx @@ -34,12 +34,13 @@ const DetachLayoutTest = () => { ) } -// eslint-disable-next-line mocha/no-skipped-tests -describe.skip('useDetachLayout', function () { +describe('useDetachLayout', function () { beforeEach(function () { window.metaAttributesCache = new Map() + window.metaAttributesCache.set('ol-preventCompileOnLoad', true) cy.stub(window, 'open').as('openWindow') cy.stub(window, 'close').as('closeWindow') + cy.interceptEvents() }) afterEach(function () {