Переглянути джерело

test: migrate to Vitest for Uppy core and Uppy plugins (#4700)

Antoine du Hamel 1 рік тому
батько
коміт
2c432b12cd
78 змінених файлів з 670 додано та 544 видалено
  1. 0 25
      .yarn/patches/jest-environment-jsdom-npm-29.5.0-fc600add1e.patch
  2. 4 19
      package.json
  3. 1 1
      packages/@uppy/audio/package.json
  4. 1 1
      packages/@uppy/audio/src/formatSeconds.test.js
  5. 1 1
      packages/@uppy/audio/src/supportsMediaRecorder.test.js
  6. 1 1
      packages/@uppy/aws-s3-multipart/package.json
  7. 1 1
      packages/@uppy/aws-s3-multipart/src/createSignedURL.test.js
  8. 35 35
      packages/@uppy/aws-s3-multipart/src/index.test.js
  9. 1 1
      packages/@uppy/aws-s3/package.json
  10. 1 1
      packages/@uppy/aws-s3/src/index.test.js
  11. 1 1
      packages/@uppy/aws-s3/src/isXml.test.js
  12. 1 1
      packages/@uppy/companion-client/package.json
  13. 1 1
      packages/@uppy/companion-client/src/RequestClient.test.js
  14. 7 7
      packages/@uppy/companion-client/src/Socket.test.js
  15. 1 1
      packages/@uppy/compressor/package.json
  16. 4 2
      packages/@uppy/compressor/src/index.test.js
  17. 1 1
      packages/@uppy/core/package.json
  18. 1 1
      packages/@uppy/core/src/UIPlugin.test.js
  19. 130 128
      packages/@uppy/core/src/Uppy.test.js
  20. 67 1
      packages/@uppy/core/src/__snapshots__/Uppy.test.js.snap
  21. 4 4
      packages/@uppy/core/src/mocks/acquirerPlugin1.js
  22. 4 4
      packages/@uppy/core/src/mocks/acquirerPlugin2.js
  23. 1 1
      packages/@uppy/core/src/supportsUploadProgress.test.js
  24. 2 2
      packages/@uppy/dashboard/package.json
  25. 1 1
      packages/@uppy/dashboard/src/index.test.js
  26. 2 2
      packages/@uppy/dashboard/src/utils/copyToClipboard.test.js
  27. 1 1
      packages/@uppy/dashboard/src/utils/createSuperFocus.test.js
  28. 2 2
      packages/@uppy/remote-sources/package.json
  29. 1 1
      packages/@uppy/remote-sources/src/index.test.js
  30. 1 1
      packages/@uppy/store-default/package.json
  31. 1 1
      packages/@uppy/store-default/src/index.test.js
  32. 2 2
      packages/@uppy/store-redux/package.json
  33. 1 1
      packages/@uppy/store-redux/src/index.test.js
  34. 2 2
      packages/@uppy/thumbnail-generator/package.json
  35. 34 34
      packages/@uppy/thumbnail-generator/src/index.test.js
  36. 1 1
      packages/@uppy/transloadit/package.json
  37. 2 2
      packages/@uppy/transloadit/src/Assembly.test.js
  38. 1 1
      packages/@uppy/transloadit/src/AssemblyOptions.test.js
  39. 1 1
      packages/@uppy/transloadit/src/index.test.js
  40. 1 1
      packages/@uppy/tus/package.json
  41. 1 1
      packages/@uppy/tus/src/index.test.js
  42. 1 1
      packages/@uppy/utils/package.json
  43. 4 4
      packages/@uppy/utils/src/AbortController.test.js
  44. 1 1
      packages/@uppy/utils/src/ErrorWithCause.test.js
  45. 1 1
      packages/@uppy/utils/src/RateLimitedQueue.test.js
  46. 1 1
      packages/@uppy/utils/src/Translator.test.js
  47. 1 1
      packages/@uppy/utils/src/dataURItoBlob.test.js
  48. 1 1
      packages/@uppy/utils/src/dataURItoFile.test.js
  49. 1 1
      packages/@uppy/utils/src/delay.test.js
  50. 1 1
      packages/@uppy/utils/src/emaFilter.test.js
  51. 1 1
      packages/@uppy/utils/src/findIndex.test.js
  52. 1 1
      packages/@uppy/utils/src/generateFileID.test.js
  53. 1 1
      packages/@uppy/utils/src/getBytesRemaining.test.js
  54. 1 1
      packages/@uppy/utils/src/getETA.test.js
  55. 1 1
      packages/@uppy/utils/src/getFileNameAndExtension.test.js
  56. 1 1
      packages/@uppy/utils/src/getFileType.test.js
  57. 1 1
      packages/@uppy/utils/src/getFileTypeExtension.test.js
  58. 1 1
      packages/@uppy/utils/src/getSocketHost.test.js
  59. 1 1
      packages/@uppy/utils/src/getSpeed.test.js
  60. 1 1
      packages/@uppy/utils/src/isMobileDevice.test.js
  61. 1 1
      packages/@uppy/utils/src/isNetworkError.test.js
  62. 1 1
      packages/@uppy/utils/src/isObjectURL.test.js
  63. 1 1
      packages/@uppy/utils/src/isPreviewSupported.test.js
  64. 2 2
      packages/@uppy/utils/src/isTouchDevice.test.js
  65. 1 1
      packages/@uppy/utils/src/prettyETA.test.js
  66. 1 1
      packages/@uppy/utils/src/secondsToTime.test.js
  67. 1 1
      packages/@uppy/utils/src/settle.test.js
  68. 1 1
      packages/@uppy/utils/src/toArray.test.js
  69. 1 1
      packages/@uppy/utils/src/truncateString.test.js
  70. 1 1
      packages/@uppy/webcam/package.json
  71. 1 1
      packages/@uppy/webcam/src/Webcam.test.js
  72. 1 1
      packages/@uppy/webcam/src/formatSeconds.test.js
  73. 1 1
      packages/@uppy/webcam/src/supportsMediaRecorder.test.js
  74. 2 2
      packages/@uppy/xhr-upload/package.json
  75. 3 3
      packages/@uppy/xhr-upload/src/index.test.js
  76. 4 0
      private/test/globalSetup.mjs
  77. 14 0
      vitest.config.ts
  78. 285 207
      yarn.lock

+ 0 - 25
.yarn/patches/jest-environment-jsdom-npm-29.5.0-fc600add1e.patch

@@ -1,25 +0,0 @@
-diff --git a/build/index.js b/build/index.js
-index ec8a133f3fbea56f4b395c96ca2b27bd4903c62e..dfd3852248f5008f82794ce61e3dca10ee8f8389 100644
---- a/build/index.js
-+++ b/build/index.js
-@@ -49,7 +49,7 @@ class JSDOMEnvironment {
-   global;
-   errorEventListener;
-   moduleMocker;
--  customExportConditions = ['browser'];
-+  customExportConditions = ['jest','browser'];
-   constructor(config, context) {
-     const {projectConfig} = config;
-     const virtualConsole = new (_jsdom().VirtualConsole)();
-@@ -93,6 +93,11 @@ class JSDOMEnvironment {
-     // TODO: remove this ASAP, but it currently causes tests to run really slow
-     global.Buffer = Buffer;
- 
-+    // JSDOM does not provide the following, thankfully Node.js ships with spec-compliant equivalent:
-+    global.TextDecoder = TextDecoder;
-+    global.TextEncoder = TextEncoder;
-+    Object.defineProperty(global, 'crypto', {__proto__:null, value:require('node:crypto').webcrypto});
-+
-     // Report uncaught errors.
-     this.errorEventListener = event => {
-       if (userErrorListenerCount === 0 && event.error != null) {

+ 4 - 19
package.json

@@ -53,7 +53,6 @@
     "adm-zip": "^0.5.5",
     "autoprefixer": "^10.2.6",
     "aws-sdk": "^2.1038.0",
-    "babel-jest": "^29.0.0",
     "babel-plugin-inline-package-json": "^2.0.0",
     "chalk": "^5.0.0",
     "concat-stream": "^2.0.0",
@@ -80,8 +79,7 @@
     "eslint-plugin-unicorn": "^46.0.0",
     "github-contributors-list": "^1.2.4",
     "glob": "^8.0.0",
-    "jest": "^29.0.0",
-    "jest-environment-jsdom": "^29.0.0",
+    "jsdom": "^22.1.0",
     "lint-staged": "^13.0.0",
     "mime-types": "^2.1.26",
     "nodemon": "^2.0.8",
@@ -104,6 +102,7 @@
     "tar": "^6.1.0",
     "tsd": "^0.22.0",
     "typescript": "~4.8",
+    "vitest": "^0.34.5",
     "vue-template-compiler": "workspace:*"
   },
   "scripts": {
@@ -143,8 +142,8 @@
     "test:locale-packs:unused": "yarn workspace @uppy-dev/locale-pack test unused",
     "test:locale-packs:warnings": "yarn workspace @uppy-dev/locale-pack test warnings",
     "test:type": "yarn workspaces foreach -piv --include '@uppy/*' --exclude '@uppy/{angular,react-native,locales,companion,provider-views,robodog,svelte}' exec tsd",
-    "test:unit": "yarn run build:lib && NODE_OPTIONS=--experimental-vm-modules jest --env jsdom",
-    "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --env jsdom --watch --no-coverage",
+    "test:unit": "yarn run build:lib && yarn test:watch",
+    "test:watch": "vitest --environment jsdom --dir packages/@uppy",
     "test": "npm-run-all lint test:locale-packs:unused test:unit test:type test:companion",
     "uploadcdn": "yarn node ./bin/upload-to-cdn.js",
     "version": "yarn node ./bin/after-version-bump.js",
@@ -154,24 +153,10 @@
     "watch:js": "npm-run-all --parallel watch:js:bundle watch:js:lib",
     "watch": "npm-run-all --parallel watch:css watch:js"
   },
-  "jest": {
-    "automock": false,
-    "collectCoverage": true,
-    "collectCoverageFrom": [
-      "packages/**/src/**/*.js"
-    ],
-    "testMatch": [
-      "**/packages/**/*.test.js"
-    ],
-    "testPathIgnorePatterns": [
-      "/packages/@uppy/companion/"
-    ]
-  },
   "resolutions": {
     "@types/eslint@^7.2.13": "^8.2.0",
     "@types/react": "^17",
     "@types/webpack-dev-server": "^4",
-    "jest-environment-jsdom": "patch:jest-environment-jsdom@npm:29.5.0#.yarn/patches/jest-environment-jsdom-npm-29.5.0-fc600add1e.patch",
     "pre-commit": "patch:pre-commit@npm:1.2.2#.yarn/patches/pre-commit-npm-1.2.2-f30af83877.patch",
     "preact": "patch:preact@npm:10.10.0#.yarn/patches/preact-npm-10.10.0-dd04de05e8.patch",
     "start-server-and-test": "patch:start-server-and-test@npm:1.14.0#.yarn/patches/start-server-and-test-npm-1.14.0-841aa34fdf.patch",

+ 1 - 1
packages/@uppy/audio/package.json

@@ -30,7 +30,7 @@
     "preact": "^10.5.13"
   },
   "devDependencies": {
-    "@jest/globals": "^29.0.0"
+    "vitest": "^0.34.5"
   },
   "peerDependencies": {
     "@uppy/core": "workspace:^"

+ 1 - 1
packages/@uppy/audio/src/formatSeconds.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import formatSeconds from './formatSeconds.js'
 
 describe('formatSeconds', () => {

+ 1 - 1
packages/@uppy/audio/src/supportsMediaRecorder.test.js

@@ -1,5 +1,5 @@
 /* eslint-disable max-classes-per-file */
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import supportsMediaRecorder from './supportsMediaRecorder.js'
 
 describe('supportsMediaRecorder', () => {

+ 1 - 1
packages/@uppy/aws-s3-multipart/package.json

@@ -30,8 +30,8 @@
   "devDependencies": {
     "@aws-sdk/client-s3": "^3.362.0",
     "@aws-sdk/s3-request-presigner": "^3.362.0",
-    "@jest/globals": "^29.0.0",
     "nock": "^13.1.0",
+    "vitest": "^0.34.5",
     "whatwg-fetch": "3.6.2"
   },
   "peerDependencies": {

+ 1 - 1
packages/@uppy/aws-s3-multipart/src/createSignedURL.test.js

@@ -1,4 +1,4 @@
-import { describe, it, beforeEach, afterEach } from '@jest/globals'
+import { describe, it, beforeEach, afterEach } from 'vitest'
 import assert from 'node:assert'
 import { S3Client, UploadPartCommand, PutObjectCommand } from '@aws-sdk/client-s3'
 import { getSignedUrl } from '@aws-sdk/s3-request-presigner'

+ 35 - 35
packages/@uppy/aws-s3-multipart/src/index.test.js

@@ -1,4 +1,4 @@
-import { afterEach, beforeEach, describe, expect, it, jest } from '@jest/globals'
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
 
 import 'whatwg-fetch'
 import nock from 'nock'
@@ -68,7 +68,7 @@ describe('AwsS3Multipart', () => {
       const fileSize = 1
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'multitest.dat',
         type: 'application/octet-stream',
         data: new File([new Uint8Array(fileSize)], {
@@ -76,7 +76,7 @@ describe('AwsS3Multipart', () => {
         }),
       })
 
-      const uploadSuccessHandler = jest.fn()
+      const uploadSuccessHandler = vi.fn()
       core.on('upload-success', uploadSuccessHandler)
 
       await core.upload()
@@ -102,15 +102,15 @@ describe('AwsS3Multipart', () => {
       core = new Core()
       core.use(AwsS3Multipart, {
         limit: 0,
-        createMultipartUpload: jest.fn(() => {
+        createMultipartUpload: vi.fn(() => {
           return {
             uploadId: '6aeb1980f3fc7ce0b5454d25b71992',
             key: 'test/upload/multitest.dat',
           }
         }),
-        completeMultipartUpload: jest.fn(async () => ({ location: 'test' })),
-        abortMultipartUpload: jest.fn(),
-        prepareUploadParts: jest.fn(async (file, { parts }) => {
+        completeMultipartUpload: vi.fn(async () => ({ location: 'test' })),
+        abortMultipartUpload: vi.fn(),
+        prepareUploadParts: vi.fn(async (file, { parts }) => {
           const presignedUrls = {}
           parts.forEach(({ number }) => {
             presignedUrls[
@@ -156,7 +156,7 @@ describe('AwsS3Multipart', () => {
         .reply(200, '', { ETag: 'test2' })
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'multitest.dat',
         type: 'application/octet-stream',
         data: new File([new Uint8Array(fileSize)], {
@@ -198,7 +198,7 @@ describe('AwsS3Multipart', () => {
       scope.persist()
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'multitest.dat',
         type: 'application/octet-stream',
         data: new File([new Uint8Array(fileSize)], {
@@ -270,13 +270,13 @@ describe('AwsS3Multipart', () => {
       let doneSpy
       awsS3Multipart.setOptions({
         retryDelays: [10],
-        createMultipartUpload: jest.fn((file) => {
+        createMultipartUpload: vi.fn((file) => {
           const multipartUploader = awsS3Multipart.uploaders[file.id]
           const testChunkState = multipartUploader.chunkState[6]
           let busy = false
           let done = false
-          busySpy = jest.fn((value) => { busy = value })
-          doneSpy = jest.fn((value) => { done = value })
+          busySpy = vi.fn((value) => { busy = value })
+          doneSpy = vi.fn((value) => { done = value })
           Object.defineProperty(testChunkState, 'busy', { get: () => busy, set: busySpy })
           Object.defineProperty(testChunkState, 'done', { get: () => done, set: doneSpy })
 
@@ -288,7 +288,7 @@ describe('AwsS3Multipart', () => {
       })
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'multitest.dat',
         type: 'application/octet-stream',
         data: new File([new Uint8Array(fileSize)], {
@@ -316,29 +316,29 @@ describe('AwsS3Multipart', () => {
   })
 
   describe('MultipartUploader', () => {
-    const createMultipartUpload = jest.fn(() => {
+    const createMultipartUpload = vi.fn(() => {
       return {
         uploadId: '6aeb1980f3fc7ce0b5454d25b71992',
         key: 'test/upload/multitest.dat',
       }
     })
 
-    const signPart = jest
+    const signPart = vi
       .fn(async (file, { partNumber }) => {
         return { url: `https://bucket.s3.us-east-2.amazonaws.com/test/upload/multitest.dat?partNumber=${partNumber}&uploadId=6aeb1980f3fc7ce0b5454d25b71992&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIATEST%2F20210729%2Fus-east-2%2Fs3%2Faws4_request&X-Amz-Date=20210729T014044Z&X-Amz-Expires=600&X-Amz-SignedHeaders=host&X-Amz-Signature=test` }
       })
 
-    const uploadPartBytes = jest.fn()
+    const uploadPartBytes = vi.fn()
 
-    afterEach(() => jest.clearAllMocks())
+    afterEach(() => vi.clearAllMocks())
 
     it('retries uploadPartBytes when it fails once', async () => {
       const core = new Core()
         .use(AwsS3Multipart, {
           createMultipartUpload,
-          completeMultipartUpload: jest.fn(async () => ({ location: 'test' })),
+          completeMultipartUpload: vi.fn(async () => ({ location: 'test' })),
           // eslint-disable-next-line no-throw-literal
-          abortMultipartUpload: jest.fn(() => { throw 'should ignore' }),
+          abortMultipartUpload: vi.fn(() => { throw 'should ignore' }),
           signPart,
           uploadPartBytes:
             uploadPartBytes
@@ -349,7 +349,7 @@ describe('AwsS3Multipart', () => {
       const fileSize = 5 * MB + 1 * MB
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'multitest.dat',
         type: 'application/octet-stream',
         data: new File([new Uint8Array(fileSize)], {
@@ -367,8 +367,8 @@ describe('AwsS3Multipart', () => {
         .use(AwsS3Multipart, {
           retryDelays: [10],
           createMultipartUpload,
-          completeMultipartUpload: jest.fn(async () => ({ location: 'test' })),
-          abortMultipartUpload: jest.fn(),
+          completeMultipartUpload: vi.fn(async () => ({ location: 'test' })),
+          abortMultipartUpload: vi.fn(),
           signPart,
           uploadPartBytes: uploadPartBytes
             // eslint-disable-next-line prefer-promise-reject-errors
@@ -376,11 +376,11 @@ describe('AwsS3Multipart', () => {
         })
       const awsS3Multipart = core.getPlugin('AwsS3Multipart')
       const fileSize = 5 * MB + 1 * MB
-      const mock = jest.fn()
+      const mock = vi.fn()
       core.on('upload-error', mock)
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'multitest.dat',
         type: 'application/octet-stream',
         data: new File([new Uint8Array(fileSize)], {
@@ -454,7 +454,7 @@ describe('AwsS3Multipart', () => {
 
   describe('file metadata across custom main functions', () => {
     let core
-    const createMultipartUpload = jest.fn(file => {
+    const createMultipartUpload = vi.fn(file => {
       core.setFileMeta(file.id, {
         ...file.meta,
         createMultipartUpload: true,
@@ -466,7 +466,7 @@ describe('AwsS3Multipart', () => {
       }
     })
 
-    const signPart = jest.fn((file, partData) => {
+    const signPart = vi.fn((file, partData) => {
       expect(file.meta.createMultipartUpload).toBe(true)
 
       core.setFileMeta(file.id, {
@@ -480,7 +480,7 @@ describe('AwsS3Multipart', () => {
       }
     })
 
-    const listParts = jest.fn((file) => {
+    const listParts = vi.fn((file) => {
       expect(file.meta.createMultipartUpload).toBe(true)
       core.setFileMeta(file.id, {
         ...file.meta,
@@ -495,7 +495,7 @@ describe('AwsS3Multipart', () => {
       }))
     })
 
-    const completeMultipartUpload = jest.fn((file) => {
+    const completeMultipartUpload = vi.fn((file) => {
       expect(file.meta.createMultipartUpload).toBe(true)
       expect(file.meta.signPart).toBe(true)
       for (let i = 1; i <= 10; i++) {
@@ -504,7 +504,7 @@ describe('AwsS3Multipart', () => {
       return {}
     })
 
-    const abortMultipartUpload = jest.fn((file) => {
+    const abortMultipartUpload = vi.fn((file) => {
       expect(file.meta.createMultipartUpload).toBe(true)
       expect(file.meta.signPart).toBe(true)
       expect(file.meta.abortingPart).toBe(5)
@@ -542,7 +542,7 @@ describe('AwsS3Multipart', () => {
 
       const fileSize = 50 * MB
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'multitest.dat',
         type: 'application/octet-stream',
         data: new File([new Uint8Array(fileSize)], {
@@ -557,7 +557,7 @@ describe('AwsS3Multipart', () => {
     })
 
     it('preserves file metadata if upload is aborted', async () => {
-      const signPartWithAbort = jest.fn((file, partData) => {
+      const signPartWithAbort = vi.fn((file, partData) => {
         expect(file.meta.createMultipartUpload).toBe(true)
         if (partData.partNumber === 5) {
           core.setFileMeta(file.id, {
@@ -601,7 +601,7 @@ describe('AwsS3Multipart', () => {
 
       const fileSize = 50 * MB
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'multitest.dat',
         type: 'application/octet-stream',
         data: new File([new Uint8Array(fileSize)], {
@@ -616,7 +616,7 @@ describe('AwsS3Multipart', () => {
     })
 
     it('preserves file metadata if upload is paused and resumed', async () => {
-      const completeMultipartUploadAfterPause = jest.fn((file) => {
+      const completeMultipartUploadAfterPause = vi.fn((file) => {
         expect(file.meta.createMultipartUpload).toBe(true)
         expect(file.meta.signPart).toBe(true)
         for (let i = 1; i <= 10; i++) {
@@ -627,7 +627,7 @@ describe('AwsS3Multipart', () => {
         return {}
       })
 
-      const signPartWithPause = jest.fn((file, partData) => {
+      const signPartWithPause = vi.fn((file, partData) => {
         expect(file.meta.createMultipartUpload).toBe(true)
         if (partData.partNumber === 3) {
           core.setFileMeta(file.id, {
@@ -671,7 +671,7 @@ describe('AwsS3Multipart', () => {
 
       const fileSize = 50 * MB
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'multitest.dat',
         type: 'application/octet-stream',
         data: new File([new Uint8Array(fileSize)], {

+ 1 - 1
packages/@uppy/aws-s3/package.json

@@ -30,7 +30,7 @@
     "nanoid": "^4.0.0"
   },
   "devDependencies": {
-    "@jest/globals": "^29.0.0",
+    "vitest": "^0.34.5",
     "whatwg-fetch": "3.6.2"
   },
   "peerDependencies": {

+ 1 - 1
packages/@uppy/aws-s3/src/index.test.js

@@ -1,4 +1,4 @@
-import { beforeEach, describe, expect, it } from '@jest/globals'
+import { beforeEach, describe, expect, it } from 'vitest'
 import 'whatwg-fetch'
 import Core from '@uppy/core'
 import AwsS3 from './index.js'

+ 1 - 1
packages/@uppy/aws-s3/src/isXml.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import isXml from './isXml.js'
 
 describe('AwsS3', () => {

+ 1 - 1
packages/@uppy/companion-client/package.json

@@ -26,6 +26,6 @@
     "namespace-emitter": "^2.0.1"
   },
   "devDependencies": {
-    "@jest/globals": "^29.0.0"
+    "vitest": "^0.34.5"
   }
 }

+ 1 - 1
packages/@uppy/companion-client/src/RequestClient.test.js

@@ -1,4 +1,4 @@
-import { describe, it, expect } from '@jest/globals'
+import { describe, it, expect } from 'vitest'
 import RequestClient from './RequestClient.js'
 
 describe('RequestClient', () => {

+ 7 - 7
packages/@uppy/companion-client/src/Socket.test.js

@@ -1,4 +1,4 @@
-import { afterEach, beforeEach, jest, describe, it, expect } from '@jest/globals'
+import { afterEach, beforeEach, vi, describe, it, expect } from 'vitest'
 import UppySocket from './Socket.js'
 
 describe('Socket', () => {
@@ -7,9 +7,9 @@ describe('Socket', () => {
   let webSocketSendSpy
 
   beforeEach(() => {
-    webSocketConstructorSpy = jest.fn()
-    webSocketCloseSpy = jest.fn()
-    webSocketSendSpy = jest.fn()
+    webSocketConstructorSpy = vi.fn()
+    webSocketCloseSpy = vi.fn()
+    webSocketSendSpy = vi.fn()
 
     globalThis.WebSocket = class WebSocket {
       constructor (target) {
@@ -122,7 +122,7 @@ describe('Socket', () => {
     const uppySocket = new UppySocket({ target: 'foo' })
     const webSocketInstance = uppySocket[Symbol.for('uppy test: getSocket')]()
 
-    const emitterListenerMock = jest.fn()
+    const emitterListenerMock = vi.fn()
     uppySocket.on('hi', emitterListenerMock)
 
     webSocketInstance.triggerOpen()
@@ -137,7 +137,7 @@ describe('Socket', () => {
   it('should be able to emit messages and subscribe to them', () => {
     const uppySocket = new UppySocket({ target: 'foo' })
 
-    const emitterListenerMock = jest.fn()
+    const emitterListenerMock = vi.fn()
     uppySocket.on('hi', emitterListenerMock)
 
     uppySocket.emit('hi', 'ho')
@@ -161,7 +161,7 @@ describe('Socket', () => {
   it('should be able to subscribe to the first event for a particular action', () => {
     const uppySocket = new UppySocket({ target: 'foo' })
 
-    const emitterListenerMock = jest.fn()
+    const emitterListenerMock = vi.fn()
     uppySocket.once('hi', emitterListenerMock)
 
     uppySocket.emit('hi', 'ho')

+ 1 - 1
packages/@uppy/compressor/package.json

@@ -36,6 +36,6 @@
     "access": "public"
   },
   "devDependencies": {
-    "@jest/globals": "^29.0.0"
+    "vitest": "^0.34.5"
   }
 }

+ 4 - 2
packages/@uppy/compressor/src/index.test.js

@@ -1,7 +1,8 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import Core from '@uppy/core'
 import getFileNameAndExtension from '@uppy/utils/lib/getFileNameAndExtension'
 import fs from 'node:fs'
+import path from 'node:path'
 import CompressorPlugin from './index.js'
 
 // Compressor uses browser canvas API, so need to mock compress()
@@ -14,7 +15,8 @@ CompressorPlugin.prototype.compress = (blob) => {
   }
 }
 
-const sampleImage = fs.readFileSync(new URL('../../../../e2e/cypress/fixtures/images/image.jpg', import.meta.url))
+// eslint-disable-next-line no-restricted-globals
+const sampleImage = fs.readFileSync(path.join(__dirname, '../../../../e2e/cypress/fixtures/images/image.jpg'))
 
 const file1 = { source: 'jest', name: 'image-1.jpeg', type: 'image/jpeg', data: new File([sampleImage], 'image-1.jpeg', { type: 'image/jpeg' }) }
 const file2 = { source: 'jest', name: 'yolo', type: 'image/jpeg', data: new File([sampleImage], 'yolo', { type: 'image/jpeg' }) }

+ 1 - 1
packages/@uppy/core/package.json

@@ -31,6 +31,6 @@
     "preact": "^10.5.13"
   },
   "devDependencies": {
-    "@jest/globals": "^29.0.0"
+    "vitest": "^0.34.5"
   }
 }

+ 1 - 1
packages/@uppy/core/src/UIPlugin.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import UIPlugin from './UIPlugin.js'
 import Core from './index.js'
 

+ 130 - 128
packages/@uppy/core/src/Uppy.test.js

@@ -1,8 +1,9 @@
 /* eslint no-console: "off", no-restricted-syntax: "off" */
-import { afterEach, beforeEach, describe, expect, it, jest, xit } from '@jest/globals'
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
 
 import assert from 'node:assert'
 import fs from 'node:fs'
+import path from 'node:path'
 import prettierBytes from '@transloadit/prettier-bytes'
 import Core from '../lib/index.js'
 import UIPlugin from '../lib/UIPlugin.js'
@@ -14,12 +15,13 @@ import InvalidPluginWithoutId from './mocks/invalidPluginWithoutId.js'
 import InvalidPluginWithoutType from './mocks/invalidPluginWithoutType.js'
 import DeepFrozenStore from '../../../../e2e/cypress/fixtures/DeepFrozenStore.mjs'
 
-const sampleImage = fs.readFileSync(new URL('../../../../e2e/cypress/fixtures/images/image.jpg', import.meta.url))
+// eslint-disable-next-line no-restricted-globals
+const sampleImage = fs.readFileSync(path.join(__dirname, '../../../../e2e/cypress/fixtures/images/image.jpg'))
 
 describe('src/Core', () => {
   const RealCreateObjectUrl = globalThis.URL.createObjectURL
   beforeEach(() => {
-    globalThis.URL.createObjectURL = jest.fn().mockReturnValue('newUrl')
+    globalThis.URL.createObjectURL = vi.fn().mockReturnValue('newUrl')
   })
 
   afterEach(() => {
@@ -134,7 +136,7 @@ describe('src/Core', () => {
 
     it('should update the state', () => {
       const core = new Core()
-      const stateUpdateEventMock = jest.fn()
+      const stateUpdateEventMock = vi.fn()
       core.on('state-update', stateUpdateEventMock)
       core.use(AcquirerPlugin1)
       core.use(AcquirerPlugin2)
@@ -210,9 +212,9 @@ describe('src/Core', () => {
     const core = new Core({
       store: DeepFrozenStore(),
     })
-    // const corePauseEventMock = jest.fn()
-    const coreCancelEventMock = jest.fn()
-    const coreStateUpdateEventMock = jest.fn()
+    // const corePauseEventMock = vi.fn()
+    const coreCancelEventMock = vi.fn()
+    const coreStateUpdateEventMock = vi.fn()
     core.on('cancel-all', coreCancelEventMock)
     core.on('state-update', coreStateUpdateEventMock)
     core.setState({ foo: 'bar', totalProgress: 30 })
@@ -240,14 +242,14 @@ describe('src/Core', () => {
     const core = new Core()
 
     core.addFile({
-      source: 'jest',
+      source: 'vi',
       name: 'foo1.jpg',
       type: 'image/jpeg',
       data: new File([sampleImage], { type: 'image/jpeg' }),
     })
 
     core.addFile({
-      source: 'jest',
+      source: 'vi',
       name: 'foo2.jpg',
       type: 'image/jpeg',
       data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -277,14 +279,14 @@ describe('src/Core', () => {
     })
 
     core.addFile({
-      source: 'jest',
+      source: 'vi',
       name: 'foo1.jpg',
       type: 'image/jpeg',
       data: new File([sampleImage], { type: 'image/jpeg' }),
     })
 
     core.addFile({
-      source: 'jest',
+      source: 'vi',
       name: 'foo2.jpg',
       type: 'image/jpeg',
       data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -314,14 +316,14 @@ describe('src/Core', () => {
     })
 
     core.addFile({
-      source: 'jest',
+      source: 'vi',
       name: 'foo1.jpg',
       type: 'image/jpeg',
       data: new File([sampleImage], { type: 'image/jpeg' }),
     })
 
     core.addFile({
-      source: 'jest',
+      source: 'vi',
       name: 'foo2.jpg',
       type: 'image/jpeg',
       data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -351,14 +353,14 @@ describe('src/Core', () => {
     })
 
     core.addFile({
-      source: 'jest',
+      source: 'vi',
       name: 'foo1.jpg',
       type: 'image/jpeg',
       data: new File([sampleImage], { type: 'image/jpeg' }),
     })
 
     core.addFile({
-      source: 'jest',
+      source: 'vi',
       name: 'foo2.jpg',
       type: 'image/jpeg',
       data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -383,8 +385,8 @@ describe('src/Core', () => {
     })
     core.use(AcquirerPlugin1)
 
-    const coreCancelEventMock = jest.fn()
-    const coreStateUpdateEventMock = jest.fn()
+    const coreCancelEventMock = vi.fn()
+    const coreStateUpdateEventMock = vi.fn()
     const plugin = core[Symbol.for('uppy test: getPlugins')]('acquirer')[0]
 
     core.on('cancel-all', coreCancelEventMock)
@@ -408,7 +410,7 @@ describe('src/Core', () => {
     })
     expect(plugin.mocks.uninstall.mock.calls.length).toEqual(1)
 
-    const pluginIteration = jest.fn()
+    const pluginIteration = vi.fn()
     core.iteratePlugins(pluginIteration)
     expect(pluginIteration.mock.calls.length).toEqual(0)
   })
@@ -445,13 +447,13 @@ describe('src/Core', () => {
 
     it('should execute all the preprocessors when uploading a file', () => {
       const core = new Core()
-      const preprocessor1 = jest.fn()
-      const preprocessor2 = jest.fn()
+      const preprocessor1 = vi.fn()
+      const preprocessor2 = vi.fn()
       core.addPreProcessor(preprocessor1)
       core.addPreProcessor(preprocessor2)
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -472,20 +474,20 @@ describe('src/Core', () => {
 
     it('should not pass removed file IDs to next step', async () => {
       const core = new Core()
-      const uploader = jest.fn()
+      const uploader = vi.fn()
       core.addPreProcessor((fileIDs) => {
         core.removeFile(fileIDs[0])
       })
       core.addUploader(uploader)
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'rmd.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
       })
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'kept.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -501,7 +503,7 @@ describe('src/Core', () => {
     it('should update the file progress state when preprocess-progress event is fired', () => {
       const core = new Core()
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -528,7 +530,7 @@ describe('src/Core', () => {
       const core = new Core()
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -563,13 +565,13 @@ describe('src/Core', () => {
 
     it('should execute all the postprocessors when uploading a file', () => {
       const core = new Core()
-      const postprocessor1 = jest.fn()
-      const postprocessor2 = jest.fn()
+      const postprocessor1 = vi.fn()
+      const postprocessor2 = vi.fn()
       core.addPostProcessor(postprocessor1)
       core.addPostProcessor(postprocessor2)
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -597,7 +599,7 @@ describe('src/Core', () => {
       const core = new Core()
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -624,7 +626,7 @@ describe('src/Core', () => {
       const core = new Core()
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -650,7 +652,7 @@ describe('src/Core', () => {
       const core = new Core()
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -683,7 +685,7 @@ describe('src/Core', () => {
 
   describe('adding a file', () => {
     it('should call onBeforeFileAdded if it was specified in the options when initialising the class', () => {
-      const onBeforeFileAdded = jest.fn()
+      const onBeforeFileAdded = vi.fn()
 
       const core = new Core({
         // need to capture a snapshot of files, because files will change in the next tick, thus failing the expect below
@@ -691,7 +693,7 @@ describe('src/Core', () => {
       })
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -707,14 +709,14 @@ describe('src/Core', () => {
       const sameFileBlob = new File([sampleImage], { type: 'image/jpeg' })
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data: sameFileBlob,
       })
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data: sameFileBlob,
@@ -723,12 +725,12 @@ describe('src/Core', () => {
 
     it('should add a file', () => {
       const fileData = new File([sampleImage], { type: 'image/jpeg' })
-      const fileAddedEventMock = jest.fn()
+      const fileAddedEventMock = vi.fn()
       const core = new Core()
       core.on('file-added', fileAddedEventMock)
 
       const fileId = core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data: fileData,
@@ -750,7 +752,7 @@ describe('src/Core', () => {
         },
         remote: '',
         size: 17175,
-        source: 'jest',
+        source: 'vi',
         type: 'image/jpeg',
       }
       expect(core.getFile(fileId)).toEqual(newFile)
@@ -774,7 +776,7 @@ describe('src/Core', () => {
 
       expect(() => {
         core.addFile({
-          source: 'jest',
+          source: 'vi',
           name: 'foo.jpg',
           type: 'image/jpeg',
           data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -783,7 +785,7 @@ describe('src/Core', () => {
 
       expect(() => {
         core.addFile({
-          source: 'jest',
+          source: 'vi',
           name: 'foo.webm',
           type: 'video/webm; codecs="vp8, opus"',
           data: new File([sampleImage], { type: 'video/webm; codecs="vp8, opus"' }),
@@ -795,14 +797,14 @@ describe('src/Core', () => {
       const core = new Core()
       const sameFileBlob = new File([sampleImage], { type: 'image/jpeg' })
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data: sameFileBlob,
       })
       expect(() => {
         core.addFile({
-          source: 'jest',
+          source: 'vi',
           name: 'foo.jpg',
           type: 'image/jpeg',
           data: sameFileBlob,
@@ -819,13 +821,13 @@ describe('src/Core', () => {
     it('should allow a duplicate file if its relativePath is different, thus the id is different', () => {
       const core = new Core()
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
       })
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -839,7 +841,7 @@ describe('src/Core', () => {
     it('should not allow a file if onBeforeFileAdded returned false', () => {
       const core = new Core({
         onBeforeFileAdded: (file) => {
-          if (file.source === 'jest') {
+          if (file.source === 'vi') {
             return false
           }
           return undefined
@@ -847,7 +849,7 @@ describe('src/Core', () => {
       })
       expect(() => {
         core.addFile({
-          source: 'jest',
+          source: 'vi',
           name: 'foo.jpg',
           type: 'image/jpeg',
           data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -862,7 +864,7 @@ describe('src/Core', () => {
       it('allows no new files after upload', async () => {
         const core = new Core({ allowMultipleUploadBatches: false })
         core.addFile({
-          source: 'jest',
+          source: 'vi',
           name: 'foo.jpg',
           type: 'image/jpeg',
           data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -872,7 +874,7 @@ describe('src/Core', () => {
 
         expect(() => {
           core.addFile({
-            source: 'jest',
+            source: 'vi',
             name: '123.foo',
             type: 'image/jpeg',
             data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -885,7 +887,7 @@ describe('src/Core', () => {
       it('allows no new files after upload with legacy allowMultipleUploads option', async () => {
         const core = new Core({ allowMultipleUploads: false })
         core.addFile({
-          source: 'jest',
+          source: 'vi',
           name: 'foo.jpg',
           type: 'image/jpeg',
           data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -895,7 +897,7 @@ describe('src/Core', () => {
 
         expect(() => {
           core.addFile({
-            source: 'jest',
+            source: 'vi',
             name: '123.foo',
             type: 'image/jpeg',
             data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -910,13 +912,13 @@ describe('src/Core', () => {
 
         // adding 2 files
         const fileId1 = core.addFile({
-          source: 'jest',
+          source: 'vi',
           name: '1.jpg',
           type: 'image/jpeg',
           data: new File([sampleImage], { type: 'image/jpeg' }),
         })
         core.addFile({
-          source: 'jest',
+          source: 'vi',
           name: '2.jpg',
           type: 'image/jpeg',
           data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -933,13 +935,13 @@ describe('src/Core', () => {
 
         // adding 2 files
         const fileId1 = core.addFile({
-          source: 'jest',
+          source: 'vi',
           name: '1.jpg',
           type: 'image/jpeg',
           data: new File([sampleImage], { type: 'image/jpeg' }),
         })
         const fileId2 = core.addFile({
-          source: 'jest',
+          source: 'vi',
           name: '2.jpg',
           type: 'image/jpeg',
           data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -959,13 +961,13 @@ describe('src/Core', () => {
       data.lastModified = 1562770350937
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data,
       })
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo푸.jpg',
         type: 'image/jpeg',
         data,
@@ -982,8 +984,8 @@ describe('src/Core', () => {
       const core = new Core()
       core.addUploader(() => Promise.resolve())
 
-      core.addFile({ source: 'jest', name: 'foo.jpg', type: 'image/jpeg', data: new Uint8Array() })
-      core.addFile({ source: 'jest', name: 'bar.jpg', type: 'image/jpeg', data: new Uint8Array() })
+      core.addFile({ source: 'vi', name: 'foo.jpg', type: 'image/jpeg', data: new Uint8Array() })
+      core.addFile({ source: 'vi', name: 'bar.jpg', type: 'image/jpeg', data: new Uint8Array() })
 
       return expect(core.upload()).resolves.toMatchObject({
         successful: [
@@ -1009,8 +1011,8 @@ describe('src/Core', () => {
         return Promise.resolve()
       })
 
-      core.addFile({ source: 'jest', name: 'foo.jpg', type: 'image/jpeg', data: new Uint8Array() })
-      core.addFile({ source: 'jest', name: 'bar.jpg', type: 'image/jpeg', data: new Uint8Array() })
+      core.addFile({ source: 'vi', name: 'foo.jpg', type: 'image/jpeg', data: new Uint8Array() })
+      core.addFile({ source: 'vi', name: 'bar.jpg', type: 'image/jpeg', data: new Uint8Array() })
 
       return expect(core.upload()).resolves.toMatchObject({
         successful: [
@@ -1034,8 +1036,8 @@ describe('src/Core', () => {
       }
       core.addUploader(() => Promise.resolve())
 
-      core.addFile({ source: 'jest', name: 'foo.jpg', type: 'image/jpeg', data: new Uint8Array() })
-      core.addFile({ source: 'jest', name: 'bar.jpg', type: 'image/jpeg', data: new Uint8Array() })
+      core.addFile({ source: 'vi', name: 'foo.jpg', type: 'image/jpeg', data: new Uint8Array() })
+      core.addFile({ source: 'vi', name: 'bar.jpg', type: 'image/jpeg', data: new Uint8Array() })
       core.addFile({ source: 'file3', name: 'file3.jpg', type: 'image/jpeg', data: new Uint8Array() })
 
       // uploadID is random, we don't want randomness in the snapshot
@@ -1058,19 +1060,19 @@ describe('src/Core', () => {
         },
       })
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
       })
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'bar.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
       })
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: '123.foo',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -1083,13 +1085,13 @@ describe('src/Core', () => {
     it('only allows a single upload() batch when allowMultipleUploadBatches: false', async () => {
       const core = new Core({ allowMultipleUploadBatches: false })
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
       })
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'bar.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -1105,7 +1107,7 @@ describe('src/Core', () => {
       const core = new Core({ allowMultipleUploadBatches: false })
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'bar.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -1115,7 +1117,7 @@ describe('src/Core', () => {
       core.cancelAll()
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: '123.foo',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -1126,13 +1128,13 @@ describe('src/Core', () => {
 
   describe('removing a file', () => {
     it('should remove the file', () => {
-      const fileRemovedEventMock = jest.fn()
+      const fileRemovedEventMock = vi.fn()
 
       const core = new Core()
       core.on('file-removed', fileRemovedEventMock)
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -1155,15 +1157,15 @@ describe('src/Core', () => {
 
   describe('retries', () => {
     it('should start a new upload with failed files', async () => {
-      const onUpload = jest.fn()
-      const onRetryAll = jest.fn()
+      const onUpload = vi.fn()
+      const onRetryAll = vi.fn()
 
       const core = new Core()
       core.on('upload', onUpload)
       core.on('retry-all', onRetryAll)
 
       const id = core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -1178,13 +1180,13 @@ describe('src/Core', () => {
     })
 
     it('should not start a new upload if there are no failed files', async () => {
-      const onUpload = jest.fn()
+      const onUpload = vi.fn()
 
       const core = new Core()
       core.on('upload', onUpload)
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -1196,9 +1198,9 @@ describe('src/Core', () => {
   })
 
   describe('restoring a file', () => {
-    xit('should restore a file', () => { })
+    it.skip('should restore a file', () => { })
 
-    xit("should fail to restore a file if it doesn't exist", () => { })
+    it.skip("should fail to restore a file if it doesn't exist", () => { })
   })
 
   describe('get a file', () => {
@@ -1206,7 +1208,7 @@ describe('src/Core', () => {
       const core = new Core()
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -1230,13 +1232,13 @@ describe('src/Core', () => {
       const core = new Core()
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
       })
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'empty.dat',
         type: 'application/octet-stream',
         data: new File([new Uint8Array(1000)], { type: 'application/octet-stream' }),
@@ -1309,7 +1311,7 @@ describe('src/Core', () => {
 
       try {
         core.addFile({
-          source: 'jest',
+          source: 'vi',
           name: 'foo1.png',
           type: 'image/png',
           data: new File([sampleImage], { type: 'image/png' }),
@@ -1328,7 +1330,7 @@ describe('src/Core', () => {
 
       expect(() => {
         core.addFile({
-          source: 'jest',
+          source: 'vi',
           name: 'foo1.png',
           type: 'image/png',
           data: new File([sampleImage], { type: 'image/png' }),
@@ -1360,7 +1362,7 @@ describe('src/Core', () => {
       const core = new Core()
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -1383,7 +1385,7 @@ describe('src/Core', () => {
         meta: { foo2: 'bar2' },
       })
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         meta: {
@@ -1406,7 +1408,7 @@ describe('src/Core', () => {
       const core = new Core()
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -1558,13 +1560,13 @@ describe('src/Core', () => {
       })
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
       })
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo2.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -1591,18 +1593,18 @@ describe('src/Core', () => {
     })
 
     it('should reset the progress', () => {
-      const resetProgressEvent = jest.fn()
+      const resetProgressEvent = vi.fn()
       const core = new Core()
       core.on('reset-progress', resetProgressEvent)
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
       })
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo2.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -1662,14 +1664,14 @@ describe('src/Core', () => {
 
       // add 2 files
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo1.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
       })
       try {
         core.addFile({
-          source: 'jest',
+          source: 'vi',
           name: 'foo2.jpg',
           type: 'image/jpeg',
           data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -1691,7 +1693,7 @@ describe('src/Core', () => {
       expect(() => {
         // add 1 ghost file
         const fileId1 = core.addFile({
-          source: 'jest',
+          source: 'vi',
           name: 'foo1.jpg',
           type: 'image/jpeg',
           data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -1700,7 +1702,7 @@ describe('src/Core', () => {
 
         // add another file
         core.addFile({
-          source: 'jest',
+          source: 'vi',
           name: 'foo2.jpg',
           type: 'image/jpeg',
           data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -1708,7 +1710,7 @@ describe('src/Core', () => {
       }).not.toThrowError()
     })
 
-    xit('should enforce the minNumberOfFiles rule', () => { })
+    it.skip('should enforce the minNumberOfFiles rule', () => { })
 
     it('should enforce the allowedFileTypes rule', () => {
       const core = new Core({
@@ -1719,7 +1721,7 @@ describe('src/Core', () => {
 
       try {
         core.addFile({
-          source: 'jest',
+          source: 'vi',
           name: 'foo2.jpg',
           type: 'image/jpeg',
           data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -1753,7 +1755,7 @@ describe('src/Core', () => {
 
       try {
         core.addFile({
-          source: 'jest',
+          source: 'vi',
           name: 'foo2.png',
           type: '',
           data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -1765,7 +1767,7 @@ describe('src/Core', () => {
       }
 
       expect(() => core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo2.JPG',
         type: '',
         data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -1781,7 +1783,7 @@ describe('src/Core', () => {
 
       try {
         core.addFile({
-          source: 'jest',
+          source: 'vi',
           name: 'foo.jpg',
           type: 'image/jpeg',
           data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -1802,7 +1804,7 @@ describe('src/Core', () => {
 
       try {
         core.addFile({
-          source: 'jest',
+          source: 'vi',
           name: 'foo.jpg',
           type: 'image/jpeg',
           data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -1822,7 +1824,7 @@ describe('src/Core', () => {
       })
 
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -1830,7 +1832,7 @@ describe('src/Core', () => {
 
       expect(() => {
         core.addFile({
-          source: 'jest',
+          source: 'vi',
           name: 'foo1.jpg',
           type: 'image/jpeg',
           data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -1854,7 +1856,7 @@ describe('src/Core', () => {
       })
 
       const newFile = {
-        source: 'jest',
+        source: 'vi',
         name: 'foo1.jpg',
         extension: 'jpg',
         type: 'image/jpeg',
@@ -1879,7 +1881,7 @@ describe('src/Core', () => {
           maxFileSize,
         },
       })
-      const restrictionsViolatedEventMock = jest.fn()
+      const restrictionsViolatedEventMock = vi.fn()
       const file = {
         name: 'test.jpg',
         data: new Blob([new Uint8Array(2 * maxFileSize)]),
@@ -1950,9 +1952,9 @@ describe('src/Core', () => {
     })
 
     it('should emit the correct event based on whether there is a network connection', () => {
-      const onlineEventMock = jest.fn()
-      const offlineEventMock = jest.fn()
-      const backOnlineEventMock = jest.fn()
+      const onlineEventMock = vi.fn()
+      const offlineEventMock = vi.fn()
+      const backOnlineEventMock = vi.fn()
       const core = new Core()
       core.on('is-offline', offlineEventMock)
       core.on('is-online', onlineEventMock)
@@ -1980,7 +1982,7 @@ describe('src/Core', () => {
 
   describe('info', () => {
     it('should set a string based message to be displayed infinitely', () => {
-      const infoVisibleEvent = jest.fn()
+      const infoVisibleEvent = vi.fn()
       const core = new Core()
       core.on('info-visible', infoVisibleEvent)
 
@@ -1994,7 +1996,7 @@ describe('src/Core', () => {
     })
 
     it('should set a object based message to be displayed infinitely', () => {
-      const infoVisibleEvent = jest.fn()
+      const infoVisibleEvent = vi.fn()
       const core = new Core()
       core.on('info-visible', infoVisibleEvent)
 
@@ -2015,8 +2017,8 @@ describe('src/Core', () => {
     })
 
     it('should set an info message to be displayed for a period of time before hiding', (done) => {
-      const infoVisibleEvent = jest.fn()
-      const infoHiddenEvent = jest.fn()
+      const infoVisibleEvent = vi.fn()
+      const infoHiddenEvent = vi.fn()
       const core = new Core()
       core.on('info-visible', infoVisibleEvent)
       core.on('info-hidden', infoHiddenEvent)
@@ -2031,8 +2033,8 @@ describe('src/Core', () => {
     })
 
     it('should hide an info message', () => {
-      const infoVisibleEvent = jest.fn()
-      const infoHiddenEvent = jest.fn()
+      const infoVisibleEvent = vi.fn()
+      const infoHiddenEvent = vi.fn()
       const core = new Core()
       core.on('info-visible', infoVisibleEvent)
       core.on('info-hidden', infoHiddenEvent)
@@ -2045,8 +2047,8 @@ describe('src/Core', () => {
     })
 
     it('should support multiple messages', () => {
-      const infoVisibleEvent = jest.fn()
-      const infoHiddenEvent = jest.fn()
+      const infoVisibleEvent = vi.fn()
+      const infoHiddenEvent = vi.fn()
       const core = new Core()
 
       core.on('info-visible', infoVisibleEvent)
@@ -2089,7 +2091,7 @@ describe('src/Core', () => {
     it('should assign the specified files to a new upload', () => {
       const core = new Core()
       core.addFile({
-        source: 'jest',
+        source: 'vi',
         name: 'foo.jpg',
         type: 'image/jpeg',
         data: new File([sampleImage], { type: 'image/jpeg' }),
@@ -2138,9 +2140,9 @@ describe('src/Core', () => {
   describe('log', () => {
     it('should log via provided logger function', () => {
       const myTestLogger = {
-        debug: jest.fn(),
-        warn: jest.fn(),
-        error: jest.fn(),
+        debug: vi.fn(),
+        warn: vi.fn(),
+        error: vi.fn(),
       }
 
       const core = new Core({
@@ -2161,9 +2163,9 @@ describe('src/Core', () => {
 
     it('should log via provided logger function, even if debug: true', () => {
       const myTestLogger = {
-        debug: jest.fn(),
-        warn: jest.fn(),
-        error: jest.fn(),
+        debug: vi.fn(),
+        warn: vi.fn(),
+        error: vi.fn(),
       }
 
       const core = new Core({
@@ -2186,8 +2188,8 @@ describe('src/Core', () => {
     })
 
     it('should log to console when logger: Uppy.debugLogger or debug: true is set', () => {
-      console.debug = jest.fn()
-      console.error = jest.fn()
+      console.debug = vi.fn()
+      console.error = vi.fn()
 
       const core = new Core({
         logger: debugLogger,
@@ -2220,8 +2222,8 @@ describe('src/Core', () => {
     })
 
     it('should only log errors to console when logger is not set', () => {
-      console.debug = jest.fn()
-      console.error = jest.fn()
+      console.debug = vi.fn()
+      console.error = vi.fn()
 
       const core = new Core()
 

+ 67 - 1
packages/@uppy/core/src/__snapshots__/Uppy.test.js.snap

@@ -1,4 +1,70 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`src/Core > plugins > should not be able to add a plugin that has no id 1`] = `"Your plugin must have an id"`;
+
+exports[`src/Core > plugins > should not be able to add a plugin that has no type 1`] = `"Your plugin must have a type"`;
+
+exports[`src/Core > plugins > should not be able to add an invalid plugin 1`] = `"Expected a plugin class, but got object. Please verify that the plugin was imported and spelled correctly."`;
+
+exports[`src/Core > plugins > should prevent the same plugin from being added more than once 1`] = `
+"Already found a plugin named 'TestSelector1'. Tried to use: 'TestSelector1'.
+Uppy plugins must have unique \`id\` options. See https://uppy.io/docs/plugins/#id."
+`;
+
+exports[`src/Core > uploading a file > should only upload files that are not already assigned to another upload id 1`] = `
+{
+  "failed": [],
+  "successful": [
+    {
+      "data": Uint8Array [],
+      "extension": "jpg",
+      "id": "uppy-foo/jpg-1e-image/jpeg",
+      "isRemote": false,
+      "meta": {
+        "name": "foo.jpg",
+        "type": "image/jpeg",
+      },
+      "name": "foo.jpg",
+      "preview": undefined,
+      "progress": {
+        "bytesTotal": null,
+        "bytesUploaded": 0,
+        "percentage": 0,
+        "uploadComplete": false,
+        "uploadStarted": null,
+      },
+      "remote": "",
+      "size": null,
+      "source": "vi",
+      "type": "image/jpeg",
+    },
+    {
+      "data": Uint8Array [],
+      "extension": "jpg",
+      "id": "uppy-bar/jpg-1e-image/jpeg",
+      "isRemote": false,
+      "meta": {
+        "name": "bar.jpg",
+        "type": "image/jpeg",
+      },
+      "name": "bar.jpg",
+      "preview": undefined,
+      "progress": {
+        "bytesTotal": null,
+        "bytesUploaded": 0,
+        "percentage": 0,
+        "uploadComplete": false,
+        "uploadStarted": null,
+      },
+      "remote": "",
+      "size": null,
+      "source": "vi",
+      "type": "image/jpeg",
+    },
+  ],
+  "uploadID": "cjd09qwxb000dlql4tp4doz8h",
+}
+`;
 
 exports[`src/Core plugins should not be able to add a plugin that has no id 1`] = `"Your plugin must have an id"`;
 

+ 4 - 4
packages/@uppy/core/src/mocks/acquirerPlugin1.js

@@ -1,4 +1,4 @@
-import { jest } from '@jest/globals' // eslint-disable-line import/no-extraneous-dependencies
+import { vi } from 'vitest' // eslint-disable-line import/no-extraneous-dependencies
 import UIPlugin from '../UIPlugin.js'
 
 export default class TestSelector1 extends UIPlugin {
@@ -9,9 +9,9 @@ export default class TestSelector1 extends UIPlugin {
     this.name = this.constructor.name
 
     this.mocks = {
-      run: jest.fn(),
-      update: jest.fn(),
-      uninstall: jest.fn(),
+      run: vi.fn(),
+      update: vi.fn(),
+      uninstall: vi.fn(),
     }
   }
 

+ 4 - 4
packages/@uppy/core/src/mocks/acquirerPlugin2.js

@@ -1,4 +1,4 @@
-import { jest } from '@jest/globals' // eslint-disable-line import/no-extraneous-dependencies
+import { vi } from 'vitest' // eslint-disable-line import/no-extraneous-dependencies
 import UIPlugin from '../UIPlugin.js'
 
 export default class TestSelector2 extends UIPlugin {
@@ -9,9 +9,9 @@ export default class TestSelector2 extends UIPlugin {
     this.name = this.constructor.name
 
     this.mocks = {
-      run: jest.fn(),
-      update: jest.fn(),
-      uninstall: jest.fn(),
+      run: vi.fn(),
+      update: vi.fn(),
+      uninstall: vi.fn(),
     }
   }
 

+ 1 - 1
packages/@uppy/core/src/supportsUploadProgress.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import supportsUploadProgress from './supportsUploadProgress.js'
 
 describe('supportsUploadProgress', () => {

+ 2 - 2
packages/@uppy/dashboard/package.json

@@ -37,10 +37,10 @@
     "preact": "^10.5.13"
   },
   "devDependencies": {
-    "@jest/globals": "^29.0.0",
     "@uppy/google-drive": "workspace:^",
     "@uppy/status-bar": "workspace:^",
-    "resize-observer-polyfill": "^1.5.0"
+    "resize-observer-polyfill": "^1.5.0",
+    "vitest": "^0.34.5"
   },
   "peerDependencies": {
     "@uppy/core": "workspace:^"

+ 1 - 1
packages/@uppy/dashboard/src/index.test.js

@@ -1,4 +1,4 @@
-import { afterAll, beforeAll, describe, it, expect } from '@jest/globals'
+import { afterAll, beforeAll, describe, it, expect } from 'vitest'
 
 import Core from '@uppy/core'
 import StatusBarPlugin from '@uppy/status-bar'

+ 2 - 2
packages/@uppy/dashboard/src/utils/copyToClipboard.test.js

@@ -1,8 +1,8 @@
-import { describe, xit, expect } from '@jest/globals'
+import { describe, it, expect } from 'vitest'
 import copyToClipboard from './copyToClipboard.js'
 
 describe('copyToClipboard', () => {
-  xit('should copy the specified text to the clipboard', () => {
+  it.skip('should copy the specified text to the clipboard', () => {
     expect(typeof copyToClipboard).toBe('function')
   })
 })

+ 1 - 1
packages/@uppy/dashboard/src/utils/createSuperFocus.test.js

@@ -1,4 +1,4 @@
-import { describe, it, expect } from '@jest/globals'
+import { describe, it, expect } from 'vitest'
 import createSuperFocus from './createSuperFocus.js'
 
 describe('createSuperFocus', () => {

+ 2 - 2
packages/@uppy/remote-sources/package.json

@@ -45,7 +45,7 @@
     "access": "public"
   },
   "devDependencies": {
-    "@jest/globals": "^29.0.0",
-    "resize-observer-polyfill": "^1.5.1"
+    "resize-observer-polyfill": "^1.5.1",
+    "vitest": "^0.34.5"
   }
 }

+ 1 - 1
packages/@uppy/remote-sources/src/index.test.js

@@ -1,4 +1,4 @@
-import { afterAll, beforeAll, describe, expect, it } from '@jest/globals'
+import { afterAll, beforeAll, describe, expect, it } from 'vitest'
 import resizeObserverPolyfill from 'resize-observer-polyfill'
 import Core from '@uppy/core'
 import Dashboard from '@uppy/dashboard'

+ 1 - 1
packages/@uppy/store-default/package.json

@@ -16,7 +16,7 @@
     "url": "https://github.com/transloadit/uppy/issues"
   },
   "devDependencies": {
-    "@jest/globals": "^29.0.0"
+    "vitest": "^0.34.5"
   },
   "repository": {
     "type": "git",

+ 1 - 1
packages/@uppy/store-default/src/index.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import assert from 'node:assert'
 import DefaultStore from './index.js'
 

+ 2 - 2
packages/@uppy/store-redux/package.json

@@ -24,7 +24,7 @@
     "nanoid": "^4.0.0"
   },
   "devDependencies": {
-    "@jest/globals": "^29.0.0",
-    "redux": "^4.0.0"
+    "redux": "^4.0.0",
+    "vitest": "^0.34.5"
   }
 }

+ 1 - 1
packages/@uppy/store-redux/src/index.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import Redux from 'redux'
 import { ReduxStore, reducer } from './index.js'
 

+ 2 - 2
packages/@uppy/thumbnail-generator/package.json

@@ -27,8 +27,8 @@
     "exifr": "^7.0.0"
   },
   "devDependencies": {
-    "@jest/globals": "^29.0.0",
-    "namespace-emitter": "2.0.1"
+    "namespace-emitter": "2.0.1",
+    "vitest": "^0.34.5"
   },
   "peerDependencies": {
     "@uppy/core": "workspace:^"

+ 34 - 34
packages/@uppy/thumbnail-generator/src/index.test.js

@@ -1,4 +1,4 @@
-import { afterEach, beforeEach, describe, it, expect, jest, xit } from '@jest/globals'
+import { afterEach, beforeEach, describe, it, expect, vi } from 'vitest'
 import { UIPlugin } from '@uppy/core'
 import emitter from 'namespace-emitter'
 import ThumbnailGeneratorPlugin from './index.js'
@@ -45,11 +45,11 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
   describe('install', () => {
     it('should subscribe to uppy file-added event', () => {
       const core = Object.assign(new MockCore(), {
-        on: jest.fn(),
+        on: vi.fn(),
       })
 
       const plugin = new ThumbnailGeneratorPlugin(core)
-      plugin.addToQueue = jest.fn()
+      plugin.addToQueue = vi.fn()
       plugin.install()
 
       expect(core.on).toHaveBeenCalledTimes(4)
@@ -60,12 +60,12 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
   describe('uninstall', () => {
     it('should unsubscribe from uppy file-added event', () => {
       const core = Object.assign(new MockCore(), {
-        on: jest.fn(),
-        off: jest.fn(),
+        on: vi.fn(),
+        off: vi.fn(),
       })
 
       const plugin = new ThumbnailGeneratorPlugin(core)
-      plugin.addToQueue = jest.fn()
+      plugin.addToQueue = vi.fn()
       plugin.install()
 
       expect(core.on).toHaveBeenCalledTimes(4)
@@ -81,7 +81,7 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
     it('should add a new file to the queue and start processing the queue when queueProcessing is false', () => {
       const core = new MockCore()
       const plugin = new ThumbnailGeneratorPlugin(core)
-      plugin.processQueue = jest.fn()
+      plugin.processQueue = vi.fn()
 
       const file = { id: 'bar', type: 'image/jpeg' }
       plugin.queueProcessing = false
@@ -99,7 +99,7 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
     it('should process items in the queue one by one', () => {
       const core = new MockCore()
       const plugin = new ThumbnailGeneratorPlugin(core)
-      plugin.requestThumbnail = jest.fn(() => delay(100))
+      plugin.requestThumbnail = vi.fn(() => delay(100))
       plugin.install()
 
       const file1 = { id: 'bar', type: 'image/jpeg', data: new Blob() }
@@ -137,17 +137,17 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
       const plugin = new ThumbnailGeneratorPlugin(core)
       plugin.install()
 
-      URL.revokeObjectURL = jest.fn(() => null)
+      URL.revokeObjectURL = vi.fn(() => null)
 
       try {
         const file1 = { id: 1, name: 'bar.jpg', type: 'image/jpeg', data: new Blob() }
         const file2 = { id: 2, name: 'bar2.jpg', type: 'image/jpeg', data: new Blob() }
 
-        plugin.createThumbnail = jest.fn(async () => {
+        plugin.createThumbnail = vi.fn(async () => {
           await delay(50)
           return 'blob:http://uppy.io/fake-thumbnail'
         })
-        plugin.setPreviewURL = jest.fn((id, preview) => {
+        plugin.setPreviewURL = vi.fn((id, preview) => {
           if (id === 1) file1.preview = preview
           if (id === 2) file2.preview = preview
         })
@@ -177,8 +177,8 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
   describe('events', () => {
     const core = new MockCore()
     const plugin = new ThumbnailGeneratorPlugin(core)
-    plugin.createThumbnail = jest.fn((file) => delay(100).then(() => `blob:${file.id}.png`))
-    plugin.setPreviewURL = jest.fn()
+    plugin.createThumbnail = vi.fn((file) => delay(100).then(() => `blob:${file.id}.png`))
+    plugin.setPreviewURL = vi.fn()
     plugin.install()
 
     function add (file) {
@@ -219,10 +219,10 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
       const core = new MockCore()
       const plugin = new ThumbnailGeneratorPlugin(core)
 
-      plugin.createThumbnail = jest
+      plugin.createThumbnail = vi
         .fn()
         .mockReturnValue(Promise.resolve('preview'))
-      plugin.setPreviewURL = jest.fn()
+      plugin.setPreviewURL = vi.fn()
 
       const file = { id: 'file1', type: 'image/png', isRemote: false }
       return plugin.requestThumbnail(file).then(() => {
@@ -239,10 +239,10 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
       const core = new MockCore()
       const plugin = new ThumbnailGeneratorPlugin(core)
 
-      plugin.createThumbnail = jest
+      plugin.createThumbnail = vi
         .fn()
         .mockReturnValue(Promise.resolve('preview'))
-      plugin.setPreviewURL = jest.fn()
+      plugin.setPreviewURL = vi.fn()
 
       const file = { id: 'file1', type: 'text/html', isRemote: false }
       return plugin.requestThumbnail(file).then(() => {
@@ -254,10 +254,10 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
       const core = new MockCore()
       const plugin = new ThumbnailGeneratorPlugin(core)
 
-      plugin.createThumbnail = jest
+      plugin.createThumbnail = vi
         .fn()
         .mockReturnValue(Promise.resolve('preview'))
-      plugin.setPreviewURL = jest.fn()
+      plugin.setPreviewURL = vi.fn()
 
       const file = { id: 'file1', type: 'image/png', isRemote: true }
       return plugin.requestThumbnail(file).then(() => {
@@ -269,10 +269,10 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
       const core = new MockCore()
       const plugin = new ThumbnailGeneratorPlugin(core)
 
-      plugin.createThumbnail = jest
+      plugin.createThumbnail = vi
         .fn()
         .mockReturnValue(Promise.resolve('preview'))
-      plugin.setPreviewURL = jest.fn()
+      plugin.setPreviewURL = vi.fn()
 
       const file = { id: 'file1', type: 'image/png', isRemote: false }
       return plugin.requestThumbnail(file).then(() => {
@@ -295,7 +295,7 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
             },
           },
         },
-        setFileState: jest.fn(),
+        setFileState: vi.fn(),
         plugins: {},
       }
       core.state = {
@@ -362,7 +362,7 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
       URL.createObjectURL = originalURLCreateObjectURL
     })
 
-    xit('should scale down the image by the specified number of steps', () => {
+    it.skip('should scale down the image by the specified number of steps', () => {
       const core = new MockCore()
       const plugin = new ThumbnailGeneratorPlugin(core)
       const image = {
@@ -370,14 +370,14 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
         height: 800,
       }
       const context = {
-        drawImage: jest.fn(),
+        drawImage: vi.fn(),
       }
       const canvas = {
         width: 0,
         height: 0,
-        getContext: jest.fn().mockReturnValue(context),
+        getContext: vi.fn().mockReturnValue(context),
       }
-      document.createElement = jest.fn().mockReturnValue(canvas)
+      document.createElement = vi.fn().mockReturnValue(canvas)
       const result = plugin.downScaleInSteps(image, 3)
       const newImage = {
         getContext: canvas.getContext,
@@ -427,14 +427,14 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
         height: 800,
       }
       const context = {
-        drawImage: jest.fn(),
+        drawImage: vi.fn(),
       }
       const canvas = {
         width: 0,
         height: 0,
-        getContext: jest.fn().mockReturnValue(context),
+        getContext: vi.fn().mockReturnValue(context),
       }
-      document.createElement = jest.fn().mockReturnValue(canvas)
+      document.createElement = vi.fn().mockReturnValue(canvas)
 
       const result = plugin.resizeImage(image, 200, 160)
       expect(result).toEqual({
@@ -452,14 +452,14 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
         height: 80,
       }
       const context = {
-        drawImage: jest.fn(),
+        drawImage: vi.fn(),
       }
       const canvas = {
         width: 0,
         height: 0,
-        getContext: jest.fn().mockReturnValue(context),
+        getContext: vi.fn().mockReturnValue(context),
       }
-      document.createElement = jest.fn().mockReturnValue(canvas)
+      document.createElement = vi.fn().mockReturnValue(canvas)
 
       const result = plugin.resizeImage(image, 200, 160)
       expect(result).toEqual({
@@ -490,7 +490,7 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
       })
 
       const plugin = new ThumbnailGeneratorPlugin(core)
-      plugin.addToQueue = jest.fn()
+      plugin.addToQueue = vi.fn()
       plugin.install()
 
       core.emit('restored')
@@ -517,7 +517,7 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
       })
 
       const plugin = new ThumbnailGeneratorPlugin(core)
-      plugin.addToQueue = jest.fn()
+      plugin.addToQueue = vi.fn()
       plugin.install()
 
       core.emit('restored')

+ 1 - 1
packages/@uppy/transloadit/package.json

@@ -38,7 +38,7 @@
     "@uppy/core": "workspace:^"
   },
   "devDependencies": {
-    "@jest/globals": "^29.0.0",
+    "vitest": "^0.34.5",
     "whatwg-fetch": "^3.6.2"
   }
 }

+ 2 - 2
packages/@uppy/transloadit/src/Assembly.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it, jest } from '@jest/globals'
+import { describe, expect, it, vi } from 'vitest'
 import { RateLimitedQueue } from '@uppy/utils/lib/RateLimitedQueue'
 import Assembly from './Assembly.js'
 
@@ -7,7 +7,7 @@ describe('Transloadit/Assembly', () => {
     function attemptDiff (prev, next) {
       const assembly = new Assembly(prev, new RateLimitedQueue())
       const events = []
-      assembly.emit = jest.fn((name, ...args) => {
+      assembly.emit = vi.fn((name, ...args) => {
         events.push([name, ...args])
       })
 

+ 1 - 1
packages/@uppy/transloadit/src/AssemblyOptions.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import AssemblyOptions from './AssemblyOptions.js'
 
 describe('Transloadit/AssemblyOptions', () => {

+ 1 - 1
packages/@uppy/transloadit/src/index.test.js

@@ -1,6 +1,6 @@
 import { createServer } from 'node:http'
 import { once } from 'node:events'
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import Core from '@uppy/core'
 import Transloadit from './index.js'
 import 'whatwg-fetch'

+ 1 - 1
packages/@uppy/tus/package.json

@@ -28,7 +28,7 @@
     "tus-js-client": "^3.0.0"
   },
   "devDependencies": {
-    "@jest/globals": "^29.0.0"
+    "vitest": "^0.34.5"
   },
   "peerDependencies": {
     "@uppy/core": "workspace:^"

+ 1 - 1
packages/@uppy/tus/src/index.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import Core from '@uppy/core'
 import Tus from './index.js'
 

+ 1 - 1
packages/@uppy/utils/package.json

@@ -72,6 +72,6 @@
     "preact": "^10.5.13"
   },
   "devDependencies": {
-    "@jest/globals": "^29.0.0"
+    "vitest": "^0.34.5"
   }
 }

+ 4 - 4
packages/@uppy/utils/src/AbortController.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it, jest } from '@jest/globals'
+import { describe, expect, it, vi } from 'vitest'
 import { AbortController, AbortSignal } from './AbortController.js'
 
 function flushInstantTimeouts () {
@@ -14,7 +14,7 @@ describe('AbortController', () => {
 
   it('emits "abort" when abort() is called', async () => {
     const controller = new AbortController()
-    const callback = jest.fn()
+    const callback = vi.fn()
 
     controller.signal.addEventListener('abort', callback)
     controller.abort()
@@ -27,8 +27,8 @@ describe('AbortController', () => {
 
   it('add and remove events', async () => {
     const controller = new AbortController()
-    const callback = jest.fn()
-    const callback2 = jest.fn()
+    const callback = vi.fn()
+    const callback2 = vi.fn()
 
     controller.signal.addEventListener('abort', callback)
     controller.signal.addEventListener('abort', callback2)

+ 1 - 1
packages/@uppy/utils/src/ErrorWithCause.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import ErrorWithCause from './ErrorWithCause.js'
 import NetworkError from './NetworkError.js'
 import isNetworkError from './isNetworkError.js'

+ 1 - 1
packages/@uppy/utils/src/RateLimitedQueue.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import { RateLimitedQueue } from './RateLimitedQueue.js'
 
 const delay = ms => new Promise(resolve => setTimeout(resolve, ms))

+ 1 - 1
packages/@uppy/utils/src/Translator.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import Translator from './Translator.js'
 
 const english = {

+ 1 - 1
packages/@uppy/utils/src/dataURItoBlob.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import dataURItoBlob from './dataURItoBlob.js'
 import sampleImageDataURI from './sampleImageDataURI.js'
 

+ 1 - 1
packages/@uppy/utils/src/dataURItoFile.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import dataURItoFile from './dataURItoFile.js'
 import sampleImageDataURI from './sampleImageDataURI.js'
 

+ 1 - 1
packages/@uppy/utils/src/delay.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import { AbortController } from './AbortController.js'
 import delay from './delay.js'
 

+ 1 - 1
packages/@uppy/utils/src/emaFilter.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import emaFilter from './emaFilter.js'
 
 describe('emaFilter', () => {

+ 1 - 1
packages/@uppy/utils/src/findIndex.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import findIndex from './findIndex.js'
 
 describe('findIndex', () => {

+ 1 - 1
packages/@uppy/utils/src/generateFileID.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import generateFileID from './generateFileID.js'
 
 describe('generateFileID', () => {

+ 1 - 1
packages/@uppy/utils/src/getBytesRemaining.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import getBytesRemaining from './getBytesRemaining.js'
 
 describe('getBytesRemaining', () => {

+ 1 - 1
packages/@uppy/utils/src/getETA.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import getETA from './getETA.js'
 
 describe('getETA', () => {

+ 1 - 1
packages/@uppy/utils/src/getFileNameAndExtension.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import getFileNameAndExtension from './getFileNameAndExtension.js'
 
 describe('getFileNameAndExtension', () => {

+ 1 - 1
packages/@uppy/utils/src/getFileType.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import getFileType from './getFileType.js'
 
 describe('getFileType', () => {

+ 1 - 1
packages/@uppy/utils/src/getFileTypeExtension.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import getFileTypeExtension from './getFileTypeExtension.js'
 
 describe('getFileTypeExtension', () => {

+ 1 - 1
packages/@uppy/utils/src/getSocketHost.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import getSocketHost from './getSocketHost.js'
 
 describe('getSocketHost', () => {

+ 1 - 1
packages/@uppy/utils/src/getSpeed.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import getSpeed from './getSpeed.js'
 
 describe('getSpeed', () => {

+ 1 - 1
packages/@uppy/utils/src/isMobileDevice.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import isMobileDevice from './isMobileDevice.js'
 
 let fakeUserAgent = null

+ 1 - 1
packages/@uppy/utils/src/isNetworkError.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import isNetworkError from './isNetworkError.js'
 
 describe('isNetworkError', () => {

+ 1 - 1
packages/@uppy/utils/src/isObjectURL.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import isObjectURL from './isObjectURL.js'
 
 describe('isObjectURL', () => {

+ 1 - 1
packages/@uppy/utils/src/isPreviewSupported.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import isPreviewSupported from './isPreviewSupported.js'
 
 describe('isPreviewSupported', () => {

+ 2 - 2
packages/@uppy/utils/src/isTouchDevice.test.js

@@ -1,4 +1,4 @@
-import { afterEach, beforeEach, describe, expect, xit } from '@jest/globals'
+import { afterEach, beforeEach, describe, expect, it } from 'vitest'
 import isTouchDevice from './isTouchDevice.js'
 
 describe('isTouchDevice', () => {
@@ -15,7 +15,7 @@ describe('isTouchDevice', () => {
     globalThis.window.ontouchstart = RealTouchStart
   })
 
-  xit("should return true if it's a touch device", () => {
+  it.skip("should return true if it's a touch device", () => {
     expect(isTouchDevice()).toEqual(true)
     delete globalThis.window.ontouchstart
     globalThis.navigator.maxTouchPoints = false

+ 1 - 1
packages/@uppy/utils/src/prettyETA.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import prettyETA from './prettyETA.js'
 
 describe('prettyETA', () => {

+ 1 - 1
packages/@uppy/utils/src/secondsToTime.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import secondsToTime from './secondsToTime.js'
 
 describe('secondsToTime', () => {

+ 1 - 1
packages/@uppy/utils/src/settle.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import settle from './settle.js'
 
 describe('settle', () => {

+ 1 - 1
packages/@uppy/utils/src/toArray.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import toArray from './toArray.js'
 
 describe('toArray', () => {

+ 1 - 1
packages/@uppy/utils/src/truncateString.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import truncateString from './truncateString.js'
 
 describe('truncateString', () => {

+ 1 - 1
packages/@uppy/webcam/package.json

@@ -32,7 +32,7 @@
     "preact": "^10.5.13"
   },
   "devDependencies": {
-    "@jest/globals": "^29.0.0"
+    "vitest": "^0.34.5"
   },
   "peerDependencies": {
     "@uppy/core": "workspace:^"

+ 1 - 1
packages/@uppy/webcam/src/Webcam.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import Uppy from '@uppy/core'
 import Webcam from '../lib/index.js'
 

+ 1 - 1
packages/@uppy/webcam/src/formatSeconds.test.js

@@ -1,4 +1,4 @@
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import formatSeconds from './formatSeconds.js'
 
 describe('formatSeconds', () => {

+ 1 - 1
packages/@uppy/webcam/src/supportsMediaRecorder.test.js

@@ -1,5 +1,5 @@
 /* eslint-disable max-classes-per-file, class-methods-use-this */
-import { describe, expect, it } from '@jest/globals'
+import { describe, expect, it } from 'vitest'
 import supportsMediaRecorder from './supportsMediaRecorder.js'
 
 describe('supportsMediaRecorder', () => {

+ 2 - 2
packages/@uppy/xhr-upload/package.json

@@ -30,8 +30,8 @@
     "nanoid": "^4.0.0"
   },
   "devDependencies": {
-    "@jest/globals": "^29.0.0",
-    "nock": "^13.1.0"
+    "nock": "^13.1.0",
+    "vitest": "^0.34.5"
   },
   "peerDependencies": {
     "@uppy/core": "workspace:^"

+ 3 - 3
packages/@uppy/xhr-upload/src/index.test.js

@@ -1,4 +1,4 @@
-import { jest, describe, it, expect } from '@jest/globals'
+import { vi, describe, it, expect } from 'vitest'
 import nock from 'nock'
 import Core from '@uppy/core'
 import XHRUpload from './index.js'
@@ -15,7 +15,7 @@ describe('XHRUpload', () => {
         .post('/').reply(200, {})
 
       const core = new Core()
-      const getResponseData = jest.fn(function getResponseData () {
+      const getResponseData = vi.fn(function getResponseData () {
         expect(this.some).toEqual('option')
         return {}
       })
@@ -50,7 +50,7 @@ describe('XHRUpload', () => {
         })
 
       const core = new Core()
-      const validateStatus = jest.fn((status, responseText) => {
+      const validateStatus = vi.fn((status, responseText) => {
         return JSON.parse(responseText).code !== 40000
       })
 

+ 4 - 0
private/test/globalSetup.mjs

@@ -0,0 +1,4 @@
+import { vi } from 'vitest' // eslint-disable-line import/no-extraneous-dependencies
+import { webcrypto } from 'node:crypto'
+
+vi.stubGlobal('crypto', webcrypto)

+ 14 - 0
vitest.config.ts

@@ -0,0 +1,14 @@
+import { configDefaults, defineConfig } from 'vitest/config' // eslint-disable-line import/no-unresolved
+
+export default defineConfig({
+  test: {
+    exclude: [
+      ...configDefaults.exclude,
+      '**/angular/**',
+      'packages/@uppy/companion/*',
+    ],
+    setupFiles: [
+      './private/test/globalSetup.mjs',
+    ],
+  },
+})

Різницю між файлами не показано, бо вона завелика
+ 285 - 207
yarn.lock


Деякі файли не було показано, через те що забагато файлів було змінено