Просмотр исходного кода

Upgrade Cypress to v10 (#8322)

GitOrigin-RevId: 856c523a4ca34f8ccdc38067cef6fcd8a5c20250
Alf Eaton 4 лет назад
Родитель
Сommit
716f186fed
24 измененных файлов с 225 добавлено и 214 удалено
  1. 44 74
      package-lock.json
  2. 21 0
      services/web/cypress.config.ts
  3. 0 11
      services/web/cypress.json
  4. 0 45
      services/web/cypress/plugins/index.js
  5. 12 0
      services/web/cypress/support/component-index.html
  6. 6 0
      services/web/cypress/support/component.ts
  7. 16 0
      services/web/cypress/support/ct/commands/index.ts
  8. 0 5
      services/web/cypress/support/ct/index.ts
  9. 3 1
      services/web/cypress/support/ct/window.ts
  10. 0 3
      services/web/cypress/support/shared/commands.ts
  11. 2 2
      services/web/cypress/support/shared/commands/compile.ts
  12. 2 2
      services/web/cypress/support/shared/commands/events.ts
  13. 18 0
      services/web/cypress/support/shared/commands/index.ts
  14. 0 8
      services/web/cypress/support/shared/types.d.ts
  15. 46 0
      services/web/cypress/support/webpack.cypress.ts
  16. 5 7
      services/web/package.json
  17. 3 4
      services/web/test/frontend/components/pdf-preview/detach-compile-button.spec.tsx
  18. 6 7
      services/web/test/frontend/components/pdf-preview/pdf-js-viewer.spec.tsx
  19. 4 5
      services/web/test/frontend/components/pdf-preview/pdf-logs-entries.spec.tsx
  20. 2 3
      services/web/test/frontend/components/pdf-preview/pdf-preview-detached-root.spec.tsx
  21. 5 6
      services/web/test/frontend/components/pdf-preview/pdf-preview-hybrid-toolbar.spec.tsx
  22. 17 18
      services/web/test/frontend/components/pdf-preview/pdf-preview.spec.tsx
  23. 12 11
      services/web/test/frontend/components/pdf-preview/pdf-synctex-controls.spec.tsx
  24. 1 2
      services/web/test/frontend/components/shared/beta-badge.spec.tsx

+ 44 - 74
package-lock.json

@@ -2778,9 +2778,9 @@
       "dev": true
     },
     "node_modules/@cypress/react": {
-      "version": "5.12.4",
-      "resolved": "https://registry.npmjs.org/@cypress/react/-/react-5.12.4.tgz",
-      "integrity": "sha512-d44InxWKmwQKyCMQT/3n1UplYa39yKEQTPlb2HhXF6ickqtmhxw7kePv00yrJpBc9gy2jUkNUOfCbtt2uz1kUw==",
+      "version": "5.12.5",
+      "resolved": "https://registry.npmjs.org/@cypress/react/-/react-5.12.5.tgz",
+      "integrity": "sha512-9ARxdLMVrrmh853xe6j9gNdXdh+vqM7lMrvJ+MGoT4Wae+nE0q3guNgotFZjFot0ZP/npw8r3NFyJO216ddbEA==",
       "dev": true,
       "dependencies": {
         "@cypress/mount-utils": "1.0.2",
@@ -2941,6 +2941,8 @@
       "resolved": "https://registry.npmjs.org/@cypress/webpack-dev-server/-/webpack-dev-server-1.8.3.tgz",
       "integrity": "sha512-r5udgc5ZhXYsnjhen+CI3CRjAjqY2UszbLQcda0np2JjLfLQX+F/bTF6g5NYWr3BMurXalC8JAZUrsBgvE0Wqw==",
       "dev": true,
+      "optional": true,
+      "peer": true,
       "dependencies": {
         "debug": "^4.3.2",
         "semver": "^7.3.4",
@@ -2957,6 +2959,8 @@
       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
       "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
       "dev": true,
+      "optional": true,
+      "peer": true,
       "dependencies": {
         "yallist": "^4.0.0"
       },
@@ -2969,6 +2973,8 @@
       "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
       "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
       "dev": true,
+      "optional": true,
+      "peer": true,
       "dependencies": {
         "lru-cache": "^6.0.0"
       },
@@ -2983,30 +2989,9 @@
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
       "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
-      "dev": true
-    },
-    "node_modules/@cypress/webpack-preprocessor": {
-      "version": "5.11.1",
-      "resolved": "https://registry.npmjs.org/@cypress/webpack-preprocessor/-/webpack-preprocessor-5.11.1.tgz",
-      "integrity": "sha512-kfdF+W/Tns81rFplnqlgZ+t6V+FJ7vegeQCYolLyhh0nJ8eG3s5HvV/ak/zSlbQnaOmAuYiZIChJFVZLUWuNOA==",
       "dev": true,
-      "dependencies": {
-        "bluebird": "3.7.1",
-        "debug": "^4.3.2",
-        "lodash": "^4.17.20"
-      },
-      "peerDependencies": {
-        "@babel/core": "^7.0.1",
-        "@babel/preset-env": "^7.0.0",
-        "babel-loader": "^8.0.2",
-        "webpack": "^4 || ^5"
-      }
-    },
-    "node_modules/@cypress/webpack-preprocessor/node_modules/bluebird": {
-      "version": "3.7.1",
-      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.1.tgz",
-      "integrity": "sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==",
-      "dev": true
+      "optional": true,
+      "peer": true
     },
     "node_modules/@cypress/xvfb": {
       "version": "1.2.4",
@@ -5139,9 +5124,9 @@
       }
     },
     "node_modules/@testing-library/cypress": {
-      "version": "8.0.2",
-      "resolved": "https://registry.npmjs.org/@testing-library/cypress/-/cypress-8.0.2.tgz",
-      "integrity": "sha512-KVdm7n37sg/A4e3wKMD4zUl0NpzzVhx06V9Tf0hZHZ7nrZ4yFva6Zwg2EFF1VzHkEfN/ahUzRtT1qiW+vuWnJw==",
+      "version": "8.0.3",
+      "resolved": "https://registry.npmjs.org/@testing-library/cypress/-/cypress-8.0.3.tgz",
+      "integrity": "sha512-nY2YaSbmuPo5k6kL0iLj/pGPPfka3iwb3kpTx8QN/vOCns92Saz9wfACqB8FJzcR7+lfA4d5HUOWqmTddBzczg==",
       "dev": true,
       "dependencies": {
         "@babel/runtime": "^7.14.6",
@@ -5152,7 +5137,7 @@
         "npm": ">=6"
       },
       "peerDependencies": {
-        "cypress": "^2.1.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0"
+        "cypress": "^2.1.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0"
       }
     },
     "node_modules/@testing-library/cypress/node_modules/@testing-library/dom": {
@@ -10685,9 +10670,9 @@
       "dev": true
     },
     "node_modules/cypress": {
-      "version": "9.5.2",
-      "resolved": "https://registry.npmjs.org/cypress/-/cypress-9.5.2.tgz",
-      "integrity": "sha512-gYiQYvJozMzDOriUV1rCt6CeRM/pRK4nhwGJj3nJQyX2BoUdTCVwp30xDMKc771HiNVhBtgj5o5/iBdVDVXQUg==",
+      "version": "10.0.3",
+      "resolved": "https://registry.npmjs.org/cypress/-/cypress-10.0.3.tgz",
+      "integrity": "sha512-8C82XTybsEmJC9POYSNITGUhMLCRwB9LadP0x33H+52QVoBjhsWvIzrI+ybCe0+TyxaF0D5/9IL2kSTgjqCB9A==",
       "dev": true,
       "hasInstallScript": true,
       "dependencies": {
@@ -10723,7 +10708,7 @@
         "listr2": "^3.8.3",
         "lodash": "^4.17.21",
         "log-symbols": "^4.0.0",
-        "minimist": "^1.2.5",
+        "minimist": "^1.2.6",
         "ospath": "^1.2.2",
         "pretty-bytes": "^5.6.0",
         "proxy-from-env": "1.0.0",
@@ -35110,11 +35095,9 @@
       },
       "devDependencies": {
         "@babel/register": "^7.14.5",
-        "@cypress/react": "^5.12.1",
-        "@cypress/webpack-dev-server": "^1.8.0",
-        "@cypress/webpack-preprocessor": "^5.11.1",
+        "@cypress/react": "^5.12.5",
         "@juggle/resize-observer": "^3.3.1",
-        "@testing-library/cypress": "^8.0.2",
+        "@testing-library/cypress": "^8.0.3",
         "@testing-library/dom": "^7.31.2",
         "@testing-library/react": "^11.2.7",
         "@testing-library/react-hooks": "^7.0.0",
@@ -35145,7 +35128,7 @@
         "copy-webpack-plugin": "^10.2.4",
         "css-loader": "^6.7.1",
         "css-minimizer-webpack-plugin": "^3.4.1",
-        "cypress": "^9.5.1",
+        "cypress": "^10.0.3",
         "es6-promise": "^4.2.8",
         "escodegen": "^2.0.0",
         "eslint-config-standard-jsx": "^11.0.0-0",
@@ -38534,9 +38517,9 @@
       "dev": true
     },
     "@cypress/react": {
-      "version": "5.12.4",
-      "resolved": "https://registry.npmjs.org/@cypress/react/-/react-5.12.4.tgz",
-      "integrity": "sha512-d44InxWKmwQKyCMQT/3n1UplYa39yKEQTPlb2HhXF6ickqtmhxw7kePv00yrJpBc9gy2jUkNUOfCbtt2uz1kUw==",
+      "version": "5.12.5",
+      "resolved": "https://registry.npmjs.org/@cypress/react/-/react-5.12.5.tgz",
+      "integrity": "sha512-9ARxdLMVrrmh853xe6j9gNdXdh+vqM7lMrvJ+MGoT4Wae+nE0q3guNgotFZjFot0ZP/npw8r3NFyJO216ddbEA==",
       "dev": true,
       "requires": {
         "@cypress/mount-utils": "1.0.2",
@@ -38640,6 +38623,8 @@
       "resolved": "https://registry.npmjs.org/@cypress/webpack-dev-server/-/webpack-dev-server-1.8.3.tgz",
       "integrity": "sha512-r5udgc5ZhXYsnjhen+CI3CRjAjqY2UszbLQcda0np2JjLfLQX+F/bTF6g5NYWr3BMurXalC8JAZUrsBgvE0Wqw==",
       "dev": true,
+      "optional": true,
+      "peer": true,
       "requires": {
         "debug": "^4.3.2",
         "semver": "^7.3.4",
@@ -38651,6 +38636,8 @@
           "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
           "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
           "dev": true,
+          "optional": true,
+          "peer": true,
           "requires": {
             "yallist": "^4.0.0"
           }
@@ -38660,6 +38647,8 @@
           "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
           "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
           "dev": true,
+          "optional": true,
+          "peer": true,
           "requires": {
             "lru-cache": "^6.0.0"
           }
@@ -38668,26 +38657,9 @@
           "version": "4.0.0",
           "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
           "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
-          "dev": true
-        }
-      }
-    },
-    "@cypress/webpack-preprocessor": {
-      "version": "5.11.1",
-      "resolved": "https://registry.npmjs.org/@cypress/webpack-preprocessor/-/webpack-preprocessor-5.11.1.tgz",
-      "integrity": "sha512-kfdF+W/Tns81rFplnqlgZ+t6V+FJ7vegeQCYolLyhh0nJ8eG3s5HvV/ak/zSlbQnaOmAuYiZIChJFVZLUWuNOA==",
-      "dev": true,
-      "requires": {
-        "bluebird": "3.7.1",
-        "debug": "^4.3.2",
-        "lodash": "^4.17.20"
-      },
-      "dependencies": {
-        "bluebird": {
-          "version": "3.7.1",
-          "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.1.tgz",
-          "integrity": "sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==",
-          "dev": true
+          "dev": true,
+          "optional": true,
+          "peer": true
         }
       }
     },
@@ -42683,9 +42655,7 @@
         "@codemirror/search": "^0.20.1",
         "@codemirror/state": "^0.20.0",
         "@codemirror/view": "^0.20.2",
-        "@cypress/react": "^5.12.1",
-        "@cypress/webpack-dev-server": "^1.8.0",
-        "@cypress/webpack-preprocessor": "^5.11.1",
+        "@cypress/react": "^5.12.5",
         "@juggle/resize-observer": "^3.3.1",
         "@lezer/common": "^0.16.0",
         "@lezer/highlight": "^0.16.0",
@@ -42703,7 +42673,7 @@
         "@replit/codemirror-emacs": "^0.20.0",
         "@replit/codemirror-vim": "^0.20.0",
         "@sentry/browser": "^6.3.5",
-        "@testing-library/cypress": "^8.0.2",
+        "@testing-library/cypress": "^8.0.3",
         "@testing-library/dom": "^7.31.2",
         "@testing-library/react": "^11.2.7",
         "@testing-library/react-hooks": "^7.0.0",
@@ -42766,7 +42736,7 @@
         "css-loader": "^6.7.1",
         "css-minimizer-webpack-plugin": "^3.4.1",
         "csurf": "^1.11.0",
-        "cypress": "^9.5.1",
+        "cypress": "^10.0.3",
         "d3": "^3.5.16",
         "dateformat": "1.0.4-1.2.3",
         "daterangepicker": "https://github.com/overleaf/daterangepicker/archive/e496d2d44ca53e208c930e4cb4bcf29bcefa4550.tar.gz",
@@ -44848,9 +44818,9 @@
       }
     },
     "@testing-library/cypress": {
-      "version": "8.0.2",
-      "resolved": "https://registry.npmjs.org/@testing-library/cypress/-/cypress-8.0.2.tgz",
-      "integrity": "sha512-KVdm7n37sg/A4e3wKMD4zUl0NpzzVhx06V9Tf0hZHZ7nrZ4yFva6Zwg2EFF1VzHkEfN/ahUzRtT1qiW+vuWnJw==",
+      "version": "8.0.3",
+      "resolved": "https://registry.npmjs.org/@testing-library/cypress/-/cypress-8.0.3.tgz",
+      "integrity": "sha512-nY2YaSbmuPo5k6kL0iLj/pGPPfka3iwb3kpTx8QN/vOCns92Saz9wfACqB8FJzcR7+lfA4d5HUOWqmTddBzczg==",
       "dev": true,
       "requires": {
         "@babel/runtime": "^7.14.6",
@@ -49278,9 +49248,9 @@
       "dev": true
     },
     "cypress": {
-      "version": "9.5.2",
-      "resolved": "https://registry.npmjs.org/cypress/-/cypress-9.5.2.tgz",
-      "integrity": "sha512-gYiQYvJozMzDOriUV1rCt6CeRM/pRK4nhwGJj3nJQyX2BoUdTCVwp30xDMKc771HiNVhBtgj5o5/iBdVDVXQUg==",
+      "version": "10.0.3",
+      "resolved": "https://registry.npmjs.org/cypress/-/cypress-10.0.3.tgz",
+      "integrity": "sha512-8C82XTybsEmJC9POYSNITGUhMLCRwB9LadP0x33H+52QVoBjhsWvIzrI+ybCe0+TyxaF0D5/9IL2kSTgjqCB9A==",
       "dev": true,
       "requires": {
         "@cypress/request": "^2.88.10",
@@ -49315,7 +49285,7 @@
         "listr2": "^3.8.3",
         "lodash": "^4.17.21",
         "log-symbols": "^4.0.0",
-        "minimist": "^1.2.5",
+        "minimist": "^1.2.6",
         "ospath": "^1.2.2",
         "pretty-bytes": "^5.6.0",
         "proxy-from-env": "1.0.0",

+ 21 - 0
services/web/cypress.config.ts

@@ -0,0 +1,21 @@
+import { defineConfig } from 'cypress'
+import { webpackConfig } from './cypress/support/webpack.cypress'
+
+export default defineConfig({
+  fixturesFolder: 'cypress/fixtures',
+  video: false,
+  viewportHeight: 800,
+  viewportWidth: 800,
+  component: {
+    devServer: {
+      framework: 'react',
+      bundler: 'webpack',
+      webpackConfig,
+    },
+    setupNodeEvents(on, config) {
+      //
+    },
+    specPattern:
+      './{test,modules/**/test}/frontend/components/**/*.spec.{js,ts,tsx}',
+  },
+})

+ 0 - 11
services/web/cypress.json

@@ -1,11 +0,0 @@
-{
-  "component": {
-    "componentFolder": ".",
-    "testFiles": "./{test,modules/**/test}/frontend/components/**/*.spec.{js,ts,tsx}",
-    "supportFile": "cypress/support/ct/index.ts"
-  },
-  "fixturesFolder": "cypress/fixtures",
-  "video": false,
-  "viewportHeight": 800,
-  "viewportWidth": 800
-}

+ 0 - 45
services/web/cypress/plugins/index.js

@@ -1,45 +0,0 @@
-module.exports = (on, config) => {
-  if (config.testingType === 'component') {
-    const { startDevServer } = require('@cypress/webpack-dev-server')
-    const { merge } = require('webpack-merge')
-    const path = require('path')
-    const webpack = require('webpack')
-    const devConfig = require('../../webpack.config.dev')
-
-    const webpackConfig = merge(devConfig, {
-      devServer: {
-        static: path.join(__dirname, '../../public'),
-        port: 3200,
-      },
-      stats: 'none',
-      plugins: [
-        new webpack.EnvironmentPlugin({
-          CYPRESS: true,
-        }),
-      ],
-    })
-
-    delete webpackConfig.devServer.client
-
-    webpackConfig.entry = {}
-    const addWorker = (name, importPath) => {
-      webpackConfig.entry[name] = require.resolve(importPath)
-    }
-
-    // add entrypoint under '/' for latex-linter worker
-    addWorker(
-      'latex-linter-worker',
-      '../../modules/source-editor/frontend/js/languages/latex/linter/latex-linter.worker.js'
-    )
-
-    // add entrypoints under '/' for pdfjs workers
-    const pdfjsVersions = ['pdfjs-dist210', 'pdfjs-dist213']
-    for (const name of pdfjsVersions) {
-      addWorker(name, `${name}/legacy/build/pdf.worker.js`)
-    }
-
-    on('dev-server:start', options => {
-      return startDevServer({ options, webpackConfig })
-    })
-  }
-}

+ 12 - 0
services/web/cypress/support/component-index.html

@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
+    <title>Components App</title>
+  </head>
+  <body>
+    <div data-cy-root></div>
+  </body>
+</html>

+ 6 - 0
services/web/cypress/support/component.ts

@@ -0,0 +1,6 @@
+import '../../frontend/stylesheets/style.less'
+import './ct/window' // needs to be before i18n
+import '../../frontend/js/i18n'
+import './shared/commands'
+import './shared/exceptions'
+import './ct/commands'

+ 16 - 0
services/web/cypress/support/ct/commands/index.ts

@@ -0,0 +1,16 @@
+import { mount, unmount } from 'cypress/react' // NOTE: not '@cypress/react'?
+
+// eslint-disable-next-line no-unused-vars,@typescript-eslint/no-namespace
+declare global {
+  // eslint-disable-next-line @typescript-eslint/no-namespace,no-unused-vars
+  namespace Cypress {
+    // eslint-disable-next-line no-unused-vars
+    interface Chainable {
+      mount: typeof mount
+      unmount: typeof unmount
+    }
+  }
+}
+
+Cypress.Commands.add('mount', mount)
+Cypress.Commands.add('unmount', unmount)

+ 0 - 5
services/web/cypress/support/ct/index.ts

@@ -1,5 +0,0 @@
-import '../../../frontend/stylesheets/style.less'
-import './window' // needs to be before i18n
-import '../../../frontend/js/i18n'
-import '../shared/commands'
-import '../shared/exceptions'

+ 3 - 1
services/web/cypress/support/ct/window.ts

@@ -1,2 +1,4 @@
 window.i18n = { currentLangCode: 'en' }
-window.ExposedSettings = { ...window?.ExposedSettings, appName: 'Overleaf' }
+window.ExposedSettings = {
+  appName: 'Overleaf',
+} as typeof window.ExposedSettings

+ 0 - 3
services/web/cypress/support/shared/commands.ts

@@ -1,3 +0,0 @@
-import '@testing-library/cypress/add-commands'
-import './compile'
-import './events'

+ 2 - 2
services/web/cypress/support/shared/compile.ts → services/web/cypress/support/shared/commands/compile.ts

@@ -43,7 +43,7 @@ const outputFiles = () => {
   ]
 }
 
-Cypress.Commands.add('interceptCompile', (prefix = 'compile') => {
+export const interceptCompile = (prefix = 'compile') => {
   cy.intercept('POST', '/project/*/compile*', {
     body: {
       status: 'success',
@@ -65,4 +65,4 @@ Cypress.Commands.add('interceptCompile', (prefix = 'compile') => {
   cy.intercept('/build/*/output.blg*', {
     fixture: 'build/output.blg',
   }).as(`${prefix}-blg`)
-})
+}

+ 2 - 2
services/web/cypress/support/shared/events.ts → services/web/cypress/support/shared/commands/events.ts

@@ -1,5 +1,5 @@
-Cypress.Commands.add('interceptEvents', () => {
+export const interceptEvents = () => {
   cy.intercept('POST', '/event/*', {
     statusCode: 204,
   })
-})
+}

+ 18 - 0
services/web/cypress/support/shared/commands/index.ts

@@ -0,0 +1,18 @@
+import '@testing-library/cypress/add-commands'
+import { interceptCompile } from './compile'
+import { interceptEvents } from './events'
+
+// eslint-disable-next-line no-unused-vars,@typescript-eslint/no-namespace
+declare global {
+  // eslint-disable-next-line @typescript-eslint/no-namespace,no-unused-vars
+  namespace Cypress {
+    // eslint-disable-next-line no-unused-vars
+    interface Chainable {
+      interceptCompile: typeof interceptCompile
+      interceptEvents: typeof interceptEvents
+    }
+  }
+}
+
+Cypress.Commands.add('interceptCompile', interceptCompile)
+Cypress.Commands.add('interceptEvents', interceptEvents)

+ 0 - 8
services/web/cypress/support/shared/types.d.ts

@@ -1,8 +0,0 @@
-// eslint-disable-next-line no-unused-vars
-declare namespace Cypress {
-  // eslint-disable-next-line no-unused-vars
-  interface Chainable {
-    interceptCompile(prefix?: string): void
-    interceptEvents(): void
-  }
-}

+ 46 - 0
services/web/cypress/support/webpack.cypress.ts

@@ -0,0 +1,46 @@
+import { merge } from 'webpack-merge'
+import path from 'path'
+import webpack from 'webpack'
+import HtmlWebpackPlugin from 'html-webpack-plugin'
+import devConfig from '../../webpack.config.dev'
+
+const buildConfig = () => {
+  const webpackConfig = merge(devConfig, {
+    devServer: {
+      static: path.join(__dirname, '../../public'),
+      port: 3200,
+    },
+    stats: 'none',
+    plugins: [
+      new webpack.EnvironmentPlugin({
+        CYPRESS: true,
+      }),
+      new HtmlWebpackPlugin({
+        template: path.resolve('./component-index.html'),
+      }),
+    ],
+  } as any)
+
+  delete webpackConfig.devServer.client
+
+  webpackConfig.entry = {}
+  const addWorker = (name: string, importPath: string) => {
+    webpackConfig.entry[name] = require.resolve(importPath)
+  }
+
+  // add entrypoint under '/' for latex-linter worker
+  addWorker(
+    'latex-linter-worker',
+    '../../modules/source-editor/frontend/js/languages/latex/linter/latex-linter.worker.js'
+  )
+
+  // add entrypoints under '/' for pdfjs workers
+  const pdfjsVersions = ['pdfjs-dist210', 'pdfjs-dist213']
+  for (const name of pdfjsVersions) {
+    addWorker(name, `${name}/legacy/build/pdf.worker.js`)
+  }
+
+  return webpackConfig
+}
+
+export const webpackConfig = buildConfig()

+ 5 - 7
services/web/package.json

@@ -32,8 +32,8 @@
     "extract-translations": "i18next-scanner",
     "migrations": "east",
     "convert-themes": "node modules/source-editor/frontend/js/themes/convert.js",
-    "cypress:open-ct": "SHARELATEX_CONFIG=$PWD/config/settings.webpack.js cypress open-ct",
-    "cypress:run-ct": "SHARELATEX_CONFIG=$PWD/config/settings.webpack.js cypress run-ct",
+    "cypress:open-ct": "SHARELATEX_CONFIG=$PWD/config/settings.webpack.js cypress open --component",
+    "cypress:run-ct": "SHARELATEX_CONFIG=$PWD/config/settings.webpack.js cypress run --component",
     "routes": "bin/routes"
   },
   "browserslist": [
@@ -203,11 +203,9 @@
   },
   "devDependencies": {
     "@babel/register": "^7.14.5",
-    "@cypress/react": "^5.12.1",
-    "@cypress/webpack-dev-server": "^1.8.0",
-    "@cypress/webpack-preprocessor": "^5.11.1",
+    "@cypress/react": "^5.12.5",
     "@juggle/resize-observer": "^3.3.1",
-    "@testing-library/cypress": "^8.0.2",
+    "@testing-library/cypress": "^8.0.3",
     "@testing-library/dom": "^7.31.2",
     "@testing-library/react": "^11.2.7",
     "@testing-library/react-hooks": "^7.0.0",
@@ -238,7 +236,7 @@
     "copy-webpack-plugin": "^10.2.4",
     "css-loader": "^6.7.1",
     "css-minimizer-webpack-plugin": "^3.4.1",
-    "cypress": "^9.5.1",
+    "cypress": "^10.0.3",
     "es6-promise": "^4.2.8",
     "escodegen": "^2.0.0",
     "eslint-config-standard-jsx": "^11.0.0-0",

+ 3 - 4
services/web/test/frontend/components/pdf-preview/detach-compile-button.spec.tsx

@@ -1,4 +1,3 @@
-import { mount } from '@cypress/react'
 import sysendTestHelper from '../../helpers/sysend'
 import { EditorProviders } from '../../helpers/editor-providers'
 import DetachCompileButton from '../../../../frontend/js/features/pdf-preview/components/detach-compile-button'
@@ -22,7 +21,7 @@ describe('<DetachCompileButton/>', function () {
 
     const scope = mockScope()
 
-    mount(
+    cy.mount(
       <EditorProviders scope={scope}>
         <DetachCompileButton />
       </EditorProviders>
@@ -38,7 +37,7 @@ describe('<DetachCompileButton/>', function () {
 
     const scope = mockScope()
 
-    mount(
+    cy.mount(
       <EditorProviders scope={scope}>
         <DetachCompileButton />
       </EditorProviders>
@@ -59,7 +58,7 @@ describe('<DetachCompileButton/>', function () {
 
     const scope = mockScope()
 
-    mount(
+    cy.mount(
       <EditorProviders scope={scope}>
         <DetachCompileButton />
       </EditorProviders>

+ 6 - 7
services/web/test/frontend/components/pdf-preview/pdf-js-viewer.spec.tsx

@@ -1,4 +1,3 @@
-import { mount, unmount } from '@cypress/react'
 import { EditorProviders } from '../../helpers/editor-providers'
 import PdfJsViewer from '../../../../frontend/js/features/pdf-preview/components/pdf-js-viewer'
 import { mockScope } from './scope'
@@ -12,7 +11,7 @@ describe('<PdfJSViewer/>', function () {
   it('loads all PDF pages', function () {
     const scope = mockScope()
 
-    mount(
+    cy.mount(
       <EditorProviders scope={scope}>
         <div className="pdf-viewer">
           <PdfJsViewer url="/build/123/output.pdf" />
@@ -31,7 +30,7 @@ describe('<PdfJSViewer/>', function () {
   it('renders pages in a "loading" state', function () {
     const scope = mockScope()
 
-    mount(
+    cy.mount(
       <EditorProviders scope={scope}>
         <div className="pdf-viewer">
           <PdfJsViewer url="/build/123/output.pdf" />
@@ -45,7 +44,7 @@ describe('<PdfJSViewer/>', function () {
   it('can be unmounted while loading a document', function () {
     const scope = mockScope()
 
-    mount(
+    cy.mount(
       <EditorProviders scope={scope}>
         <div className="pdf-viewer">
           <PdfJsViewer url="/build/123/output.pdf" />
@@ -53,13 +52,13 @@ describe('<PdfJSViewer/>', function () {
       </EditorProviders>
     )
 
-    unmount()
+    cy.unmount()
   })
 
   it('can be unmounted after loading a document', function () {
     const scope = mockScope()
 
-    mount(
+    cy.mount(
       <EditorProviders scope={scope}>
         <div className="pdf-viewer">
           <PdfJsViewer url="/build/123/output.pdf" />
@@ -69,6 +68,6 @@ describe('<PdfJSViewer/>', function () {
 
     cy.findByLabelText('Page 1')
 
-    unmount()
+    cy.unmount()
   })
 })

+ 4 - 5
services/web/test/frontend/components/pdf-preview/pdf-logs-entries.spec.tsx

@@ -1,4 +1,3 @@
-import { mount } from '@cypress/react'
 import sysendTestHelper from '../../helpers/sysend'
 import { EditorProviders } from '../../helpers/editor-providers'
 import PdfLogsEntries from '../../../../frontend/js/features/pdf-preview/components/pdf-logs-entries'
@@ -43,7 +42,7 @@ describe('<PdfLogsEntries/>', function () {
   })
 
   it('displays human readable hint', function () {
-    mount(
+    cy.mount(
       <EditorProviders {...props}>
         <PdfLogsEntries entries={logEntries} />
       </EditorProviders>
@@ -53,7 +52,7 @@ describe('<PdfLogsEntries/>', function () {
   })
 
   it('opens doc on click', function () {
-    mount(
+    cy.mount(
       <EditorProviders {...props}>
         <PdfLogsEntries entries={logEntries} />
       </EditorProviders>
@@ -78,7 +77,7 @@ describe('<PdfLogsEntries/>', function () {
       win.metaAttributesCache = new Map([['ol-detachRole', 'detacher']])
     })
 
-    mount(
+    cy.mount(
       <EditorProviders {...props}>
         <PdfLogsEntries entries={logEntries} />
       </EditorProviders>
@@ -111,7 +110,7 @@ describe('<PdfLogsEntries/>', function () {
       win.metaAttributesCache = new Map([['ol-detachRole', 'detached']])
     })
 
-    mount(
+    cy.mount(
       <EditorProviders {...props}>
         <PdfLogsEntries entries={logEntries} />
       </EditorProviders>

+ 2 - 3
services/web/test/frontend/components/pdf-preview/pdf-preview-detached-root.spec.tsx

@@ -1,4 +1,3 @@
-import { mount } from '@cypress/react'
 import sysendTestHelper from '../../helpers/sysend'
 import PdfPreviewDetachedRoot from '../../../../frontend/js/features/pdf-preview/components/pdf-preview-detached-root'
 import { User } from '../../../../types/user'
@@ -24,7 +23,7 @@ describe('<PdfPreviewDetachedRoot/>', function () {
   })
 
   it('syncs compiling state', function () {
-    mount(<PdfPreviewDetachedRoot />).then(() => {
+    cy.mount(<PdfPreviewDetachedRoot />).then(() => {
       sysendTestHelper.receiveMessage({
         role: 'detacher',
         event: 'connected',
@@ -52,7 +51,7 @@ describe('<PdfPreviewDetachedRoot/>', function () {
   })
 
   it('sends a clear cache request when the button is pressed', function () {
-    mount(<PdfPreviewDetachedRoot />).then(() => {
+    cy.mount(<PdfPreviewDetachedRoot />).then(() => {
       sysendTestHelper.receiveMessage({
         role: 'detacher',
         event: 'state-showLogs',

+ 5 - 6
services/web/test/frontend/components/pdf-preview/pdf-preview-hybrid-toolbar.spec.tsx

@@ -1,4 +1,3 @@
-import { mount } from '@cypress/react'
 import sysendTestHelper from '../../helpers/sysend'
 import { EditorProviders } from '../../helpers/editor-providers'
 import PdfPreviewHybridToolbar from '../../../../frontend/js/features/pdf-preview/components/pdf-preview-hybrid-toolbar'
@@ -15,7 +14,7 @@ describe('<PdfPreviewHybridToolbar/>', function () {
   })
 
   it('shows normal mode', function () {
-    mount(
+    cy.mount(
       <EditorProviders>
         <PdfPreviewHybridToolbar />
       </EditorProviders>
@@ -30,7 +29,7 @@ describe('<PdfPreviewHybridToolbar/>', function () {
         win.metaAttributesCache = new Map([['ol-detachRole', 'detached']])
       })
 
-      mount(
+      cy.mount(
         <EditorProviders>
           <PdfPreviewHybridToolbar />
         </EditorProviders>
@@ -44,7 +43,7 @@ describe('<PdfPreviewHybridToolbar/>', function () {
         win.metaAttributesCache = new Map([['ol-detachRole', 'detached']])
       })
 
-      mount(
+      cy.mount(
         <EditorProviders>
           <PdfPreviewHybridToolbar />
         </EditorProviders>
@@ -63,7 +62,7 @@ describe('<PdfPreviewHybridToolbar/>', function () {
         win.metaAttributesCache = new Map([['ol-detachRole', 'detached']])
       })
 
-      mount(
+      cy.mount(
         <EditorProviders>
           <PdfPreviewHybridToolbar />
         </EditorProviders>
@@ -88,7 +87,7 @@ describe('<PdfPreviewHybridToolbar/>', function () {
 
       cy.clock()
 
-      mount(
+      cy.mount(
         <EditorProviders>
           <PdfPreviewHybridToolbar />
         </EditorProviders>

+ 17 - 18
services/web/test/frontend/components/pdf-preview/pdf-preview.spec.tsx

@@ -1,4 +1,3 @@
-import { mount } from '@cypress/react'
 import localStorage from '../../../../frontend/js/infrastructure/local-storage'
 import PdfPreview from '../../../../frontend/js/features/pdf-preview/components/pdf-preview'
 import { EditorProviders } from '../../helpers/editor-providers'
@@ -18,7 +17,7 @@ describe('<PdfPreview/>', function () {
   it('renders the PDF preview', function () {
     const scope = mockScope()
 
-    mount(
+    cy.mount(
       <EditorProviders scope={scope}>
         <div className="pdf-viewer">
           <PdfPreview />
@@ -36,7 +35,7 @@ describe('<PdfPreview/>', function () {
   it('runs a compile when the Recompile button is pressed', function () {
     const scope = mockScope()
 
-    mount(
+    cy.mount(
       <EditorProviders scope={scope}>
         <div className="pdf-viewer">
           <PdfPreview />
@@ -68,7 +67,7 @@ describe('<PdfPreview/>', function () {
   it('runs a compile on `pdf:recompile` event', function () {
     const scope = mockScope()
 
-    mount(
+    cy.mount(
       <EditorProviders scope={scope}>
         <div className="pdf-viewer">
           <PdfPreview />
@@ -142,7 +141,7 @@ describe('<PdfPreview/>', function () {
 
     const scope = mockScope()
 
-    mount(
+    cy.mount(
       <EditorProviders scope={scope}>
         <div className="pdf-viewer">
           <PdfPreview />
@@ -168,7 +167,7 @@ describe('<PdfPreview/>', function () {
   it('disables compile button while compile is running', function () {
     const scope = mockScope()
 
-    mount(
+    cy.mount(
       <EditorProviders scope={scope}>
         <div className="pdf-viewer">
           <PdfPreview />
@@ -183,7 +182,7 @@ describe('<PdfPreview/>', function () {
   it('runs a compile on doc change if autocompile is enabled', function () {
     const scope = mockScope()
 
-    mount(
+    cy.mount(
       <EditorProviders scope={scope}>
         <div className="pdf-viewer">
           <PdfPreview />
@@ -217,7 +216,7 @@ describe('<PdfPreview/>', function () {
   it('does not run a compile on doc change if autocompile is disabled', function () {
     const scope = mockScope()
 
-    mount(
+    cy.mount(
       <EditorProviders scope={scope}>
         <div className="pdf-viewer">
           <PdfPreview />
@@ -253,7 +252,7 @@ describe('<PdfPreview/>', function () {
     // mock a linting error
     scope.hasLintingError = true
 
-    mount(
+    cy.mount(
       <EditorProviders scope={scope}>
         <div className="pdf-viewer">
           <PdfPreview />
@@ -320,7 +319,7 @@ describe('<PdfPreview/>', function () {
 
         const scope = mockScope()
 
-        mount(
+        cy.mount(
           <EditorProviders scope={scope}>
             <div className="pdf-viewer">
               <PdfPreview />
@@ -339,7 +338,7 @@ describe('<PdfPreview/>', function () {
     it('displays expandable raw logs', function () {
       const scope = mockScope()
 
-      mount(
+      cy.mount(
         <EditorProviders scope={scope}>
           <div className="pdf-viewer">
             <PdfPreview />
@@ -388,7 +387,7 @@ describe('<PdfPreview/>', function () {
 
       const scope = mockScope()
 
-      mount(
+      cy.mount(
         <EditorProviders scope={scope}>
           <div className="pdf-viewer">
             <PdfPreview />
@@ -410,7 +409,7 @@ describe('<PdfPreview/>', function () {
     it('sends a clear cache request when the button is pressed', function () {
       const scope = mockScope()
 
-      mount(
+      cy.mount(
         <EditorProviders scope={scope}>
           <div className="pdf-viewer">
             <PdfPreview />
@@ -446,7 +445,7 @@ describe('<PdfPreview/>', function () {
     it('handle "recompile from scratch"', function () {
       const scope = mockScope()
 
-      mount(
+      cy.mount(
         <EditorProviders scope={scope}>
           <div className="pdf-viewer">
             <PdfPreview />
@@ -501,7 +500,7 @@ describe('<PdfPreview/>', function () {
 
       const scope = mockScope()
 
-      mount(
+      cy.mount(
         <EditorProviders scope={scope}>
           <div className="pdf-viewer">
             <PdfPreview />
@@ -522,7 +521,7 @@ describe('<PdfPreview/>', function () {
 
       const scope = mockScope()
 
-      mount(
+      cy.mount(
         <EditorProviders scope={scope}>
           <div className="pdf-viewer">
             <PdfPreview />
@@ -545,7 +544,7 @@ describe('<PdfPreview/>', function () {
 
       const scope = mockScope()
 
-      mount(
+      cy.mount(
         <EditorProviders scope={scope}>
           <div className="pdf-viewer">
             <PdfPreview />
@@ -576,7 +575,7 @@ describe('<PdfPreview/>', function () {
 
       const scope = mockScope()
 
-      mount(
+      cy.mount(
         <EditorProviders scope={scope}>
           <div className="pdf-viewer">
             <PdfPreview />

+ 12 - 11
services/web/test/frontend/components/pdf-preview/pdf-synctex-controls.spec.tsx

@@ -4,7 +4,7 @@ import { cloneDeep } from 'lodash'
 import { useDetachCompileContext as useCompileContext } from '../../../../frontend/js/shared/context/detach-compile-context'
 import { useFileTreeData } from '../../../../frontend/js/shared/context/file-tree-data-context'
 import { useEffect } from 'react'
-import { mount } from '@cypress/react'
+
 import { EditorProviders } from '../../helpers/editor-providers'
 import { mockScope } from './scope'
 
@@ -92,7 +92,7 @@ describe('<PdfSynctexControls/>', function () {
   it('handles clicks on sync buttons', function () {
     const scope = mockScope()
 
-    mount(
+    cy.mount(
       <EditorProviders scope={scope}>
         <WithPosition mockPosition={mockPosition} />
         <WithSelectedEntities mockSelectedEntities={mockSelectedEntities} />
@@ -133,7 +133,7 @@ describe('<PdfSynctexControls/>', function () {
   it('disables button when multiple entities are selected', function () {
     const scope = mockScope()
 
-    mount(
+    cy.mount(
       <EditorProviders scope={scope}>
         <WithPosition mockPosition={mockPosition} />
         <WithSelectedEntities
@@ -151,7 +151,7 @@ describe('<PdfSynctexControls/>', function () {
   it('disables button when a file is selected', function () {
     const scope = mockScope()
 
-    mount(
+    cy.mount(
       <EditorProviders scope={scope}>
         <WithPosition mockPosition={mockPosition} />
         <WithSelectedEntities mockSelectedEntities={[{ type: 'file' }]} />
@@ -172,7 +172,7 @@ describe('<PdfSynctexControls/>', function () {
     it('does not have go to PDF location button nor arrow icon', function () {
       const scope = mockScope()
 
-      mount(
+      cy.mount(
         <EditorProviders scope={scope}>
           <WithPosition mockPosition={mockPosition} />
           <WithSelectedEntities mockSelectedEntities={mockSelectedEntities} />
@@ -187,10 +187,11 @@ describe('<PdfSynctexControls/>', function () {
       cy.get('.synctex-control-icon').should('not.exist')
     })
 
-    it('send set highlights action', function () {
+    // eslint-disable-next-line mocha/no-skipped-tests
+    it.skip('send set highlights action', function () {
       const scope = mockScope()
 
-      mount(
+      cy.mount(
         <EditorProviders scope={scope}>
           <WithPosition mockPosition={mockPosition} />
           <WithSelectedEntities mockSelectedEntities={mockSelectedEntities} />
@@ -243,7 +244,7 @@ describe('<PdfSynctexControls/>', function () {
     it('reacts to sync to code action', function () {
       const scope = mockScope()
 
-      mount(
+      cy.mount(
         <EditorProviders scope={scope}>
           <WithPosition mockPosition={mockPosition} />
           <WithSelectedEntities mockSelectedEntities={mockSelectedEntities} />
@@ -273,7 +274,7 @@ describe('<PdfSynctexControls/>', function () {
     it('does not have go to code location button nor arrow icon', function () {
       const scope = mockScope()
 
-      mount(
+      cy.mount(
         <EditorProviders scope={scope}>
           <WithPosition mockPosition={mockPosition} />
           <PdfSynctexControls />
@@ -291,7 +292,7 @@ describe('<PdfSynctexControls/>', function () {
     it.skip('send go to code line action', function () {
       const scope = mockScope()
 
-      mount(
+      cy.mount(
         <EditorProviders scope={scope}>
           <WithPosition mockPosition={mockPosition} />
           <PdfSynctexControls />
@@ -337,7 +338,7 @@ describe('<PdfSynctexControls/>', function () {
     it.skip('update inflight state', function () {
       const scope = mockScope()
 
-      mount(
+      cy.mount(
         <EditorProviders scope={scope}>
           <WithPosition mockPosition={mockPosition} />
           <PdfSynctexControls />

+ 1 - 2
services/web/test/frontend/components/shared/beta-badge.spec.tsx

@@ -1,9 +1,8 @@
-import { mount } from '@cypress/react'
 import BetaBadge from '../../../../frontend/js/shared/components/beta-badge'
 
 describe('beta badge', function () {
   it('renders the url and tooltip text', function () {
-    mount(
+    cy.mount(
       <BetaBadge
         url="/foo"
         tooltip={{