diff --git a/docs/api/mock.md b/docs/api/mock.md index cbdf294fcb47..40777340294a 100644 --- a/docs/api/mock.md +++ b/docs/api/mock.md @@ -91,6 +91,43 @@ You should use spy assertions (e.g., [`toHaveBeenCalled`](/api/expect#tohavebeen console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn()) ``` +## withImplementation + +- **Type:** `(fn: Function, callback: () => void) => MockInstance` +- **Type:** `(fn: Function, callback: () => Promise) => Promise` + + Overrides the original mock implementation temporarily while the callback is being executed. + + ```js + const myMockFn = vi.fn(() => 'original') + + myMockFn.withImplementation(() => 'temp', () => { + myMockFn() // 'temp' + }) + + myMockFn() // 'original' + ``` + + Can be used with an asynchronous callback. The method has to be awaited to use the original implementation afterward. + + ```ts + test('async callback', () => { + const myMockFn = vi.fn(() => 'original') + + // We await this call since the callback is async + await myMockFn.withImplementation( + () => 'temp', + async () => { + myMockFn() // 'temp' + }, + ) + + myMockFn() // 'original' + }) + ``` + + Also, it takes precedence over the [`mockImplementationOnce`](https://vitest.dev/api/mock.html#mockimplementationonce). + ## mockRejectedValue - **Type:** `(value: any) => MockInstance` diff --git a/packages/spy/src/index.ts b/packages/spy/src/index.ts index 6a57cf60a357..b855f8c7b73e 100644 --- a/packages/spy/src/index.ts +++ b/packages/spy/src/index.ts @@ -46,6 +46,7 @@ export interface SpyInstance { getMockImplementation(): ((...args: TArgs) => TReturns) | undefined mockImplementation(fn: ((...args: TArgs) => TReturns) | (() => Promise)): this mockImplementationOnce(fn: ((...args: TArgs) => TReturns) | (() => Promise)): this + withImplementation(fn: ((...args: TArgs) => TReturns), cb: () => T): T extends Promise ? Promise : this mockReturnThis(): this mockReturnValue(obj: TReturns): this mockReturnValueOnce(obj: TReturns): this @@ -208,6 +209,7 @@ function enhanceSpy( } let onceImplementations: ((...args: TArgs) => TReturns)[] = [] + let implementationChangedTemporarily = false let name: string = (stub as any).name @@ -248,6 +250,35 @@ function enhanceSpy( return stub } + function withImplementation(fn: (...args: TArgs) => TReturns, cb: () => void): EnhancedSpy + function withImplementation(fn: (...args: TArgs) => TReturns, cb: () => Promise): Promise> + function withImplementation(fn: (...args: TArgs) => TReturns, cb: () => void | Promise): EnhancedSpy | Promise> { + const originalImplementation = implementation + + implementation = fn + implementationChangedTemporarily = true + + const reset = () => { + implementation = originalImplementation + implementationChangedTemporarily = false + } + + const result = cb() + + if (result instanceof Promise) { + return result.then(() => { + reset() + return stub + }) + } + + reset() + + return stub + } + + stub.withImplementation = withImplementation + stub.mockReturnThis = () => stub.mockImplementation(function (this: TReturns) { return this @@ -275,7 +306,7 @@ function enhanceSpy( stub.willCall(function (this: unknown, ...args) { instances.push(this) invocations.push(++callOrder) - const impl = onceImplementations.shift() || implementation || stub.getOriginal() || (() => {}) + const impl = implementationChangedTemporarily ? implementation! : onceImplementations.shift() || implementation || stub.getOriginal() || (() => {}) return impl.apply(this, args) }) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 706f3e638c33..6f6247897dfa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -240,7 +240,7 @@ importers: react-dom: 18.0.0_react@18.0.0 devDependencies: '@testing-library/react': 13.3.0_zpnidt7m3osuk7shl3s4oenomq - '@types/node': 18.14.0 + '@types/node': 18.14.1 '@types/react': 18.0.28 '@vitejs/plugin-react': 3.1.0 jsdom: 21.1.0 @@ -292,7 +292,7 @@ importers: '@types/react-test-renderer': 17.0.2 '@vitejs/plugin-react': 3.1.0_vite@4.0.0 '@vitest/ui': link:../../packages/ui - happy-dom: 8.7.1 + happy-dom: 8.7.2 jsdom: 21.1.0 react-test-renderer: 17.0.2_react@17.0.2 vite: 4.0.0 @@ -1068,7 +1068,7 @@ importers: devDependencies: '@vitejs/plugin-vue': 4.0.0_vite@4.0.0+vue@3.2.47 '@vue/test-utils': 2.3.0_vue@3.2.47 - happy-dom: 8.7.1 + happy-dom: 8.7.2 vite: 4.0.0 vitest: link:../../packages/vitest vue: 3.2.47 @@ -1123,7 +1123,7 @@ importers: vitest: workspace:* devDependencies: execa: 6.1.0 - jsdom: 21.1.0 + jsdom: 21.0.0 vitest: link:../../packages/vitest test/global-setup: @@ -1253,7 +1253,7 @@ importers: devDependencies: execa: 6.1.0 fs-extra: 10.1.0 - playwright-chromium: 1.29.2 + playwright-chromium: 1.30.0 vitest: link:../../packages/vitest test/vite-config: @@ -2122,13 +2122,6 @@ packages: dependencies: '@babel/types': 7.20.7 - /@babel/parser/7.20.5: - resolution: {integrity: sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==} - engines: {node: '>=6.0.0'} - hasBin: true - dependencies: - '@babel/types': 7.20.7 - /@babel/parser/7.20.7: resolution: {integrity: sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==} engines: {node: '>=6.0.0'} @@ -3661,7 +3654,7 @@ packages: '@babel/helper-module-imports': 7.18.6 '@babel/helper-plugin-utils': 7.20.2 '@babel/plugin-syntax-jsx': 7.18.6_@babel+core@7.18.13 - '@babel/types': 7.20.5 + '@babel/types': 7.20.7 dev: true /@babel/plugin-transform-react-jsx/7.19.0_@babel+core@7.18.13: @@ -4288,15 +4281,6 @@ packages: '@babel/helper-validator-identifier': 7.19.1 to-fast-properties: 2.0.0 - /@babel/types/7.20.5: - resolution: {integrity: sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-string-parser': 7.19.4 - '@babel/helper-validator-identifier': 7.19.1 - to-fast-properties: 2.0.0 - dev: true - /@babel/types/7.20.7: resolution: {integrity: sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==} engines: {node: '>=6.9.0'} @@ -5007,7 +4991,7 @@ packages: dependencies: '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 18.14.0 + '@types/node': 18.14.1 '@types/yargs': 15.0.14 chalk: 4.1.2 dev: true @@ -5019,7 +5003,7 @@ packages: '@jest/schemas': 29.0.0 '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 18.14.0 + '@types/node': 18.14.1 '@types/yargs': 17.0.12 chalk: 4.1.2 dev: true @@ -5531,7 +5515,7 @@ packages: engines: {node: '>=14'} hasBin: true dependencies: - '@types/node': 18.13.0 + '@types/node': 18.14.1 playwright-core: 1.28.0 dev: true @@ -5707,8 +5691,8 @@ packages: rollup: 2.79.1 dev: true - /@rollup/plugin-replace/5.0.1_rollup@2.79.1: - resolution: {integrity: sha512-Z3MfsJ4CK17BfGrZgvrcp/l6WXoKb0kokULO+zt/7bmcyayokDaQ2K3eDJcRLCTAlp5FPI4/gz9MHAsosz4Rag==} + /@rollup/plugin-replace/5.0.2_rollup@2.79.1: + resolution: {integrity: sha512-M9YXNekv/C/iHHK+cvORzfRYfPbq0RDD8r0G+bMiTXjNGKulPnCT9O3Ss46WfhI6ZOCgApOP7xAdmCQJ+U2LAA==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^1.20.0||^2.0.0||^3.0.0 @@ -5717,7 +5701,7 @@ packages: optional: true dependencies: '@rollup/pluginutils': 5.0.2_rollup@2.79.1 - magic-string: 0.26.7 + magic-string: 0.27.0 rollup: 2.79.1 dev: true @@ -7357,7 +7341,7 @@ packages: /@types/cheerio/0.22.31: resolution: {integrity: sha512-Kt7Cdjjdi2XWSfrZ53v4Of0wG3ZcmaegFXjMmz9tfNrZSkzzo36G0AL1YqSdcIA78Etjt6E609pt5h1xnQkPUw==} dependencies: - '@types/node': 18.14.0 + '@types/node': 18.14.1 dev: true /@types/codemirror/5.60.6: @@ -7424,33 +7408,33 @@ packages: resolution: {integrity: sha512-zdV5odfHf95B4qr6bdpshG4VMm/3xgnPhSJLa3xh75CYr35e34k+4FQli82Q48sPqwHazJGy+6+jl4T+Vw1AMg==} dependencies: '@types/jsonfile': 6.1.1 - '@types/node': 18.14.0 + '@types/node': 18.14.1 dev: true /@types/fs-extra/9.0.13: resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} dependencies: - '@types/node': 18.14.0 + '@types/node': 18.14.1 dev: true /@types/glob/7.2.0: resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} dependencies: '@types/minimatch': 5.1.1 - '@types/node': 18.14.0 + '@types/node': 18.14.1 dev: true /@types/glob/8.0.0: resolution: {integrity: sha512-l6NQsDDyQUVeoTynNpC9uRvCUint/gSUXQA2euwmTuWGvPY5LSDUu6tkCtJB2SvGQlJQzLaKqcGZP4//7EDveA==} dependencies: '@types/minimatch': 5.1.1 - '@types/node': 18.14.0 + '@types/node': 18.14.1 dev: true /@types/graceful-fs/4.1.5: resolution: {integrity: sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==} dependencies: - '@types/node': 18.14.0 + '@types/node': 18.14.1 dev: true /@types/hast/2.3.4: @@ -7511,7 +7495,7 @@ packages: /@types/jsdom/21.1.0: resolution: {integrity: sha512-leWreJOdnuIxq9Y70tBVm/bvTuh31DSlF/r4l7Cfi4uhVQqLHD0Q4v301GMisEMwwbMgF7ZKxuZ+Jbd4NcdmRw==} dependencies: - '@types/node': 18.14.0 + '@types/node': 18.14.1 '@types/tough-cookie': 4.0.2 parse5: 7.1.1 dev: true @@ -7527,7 +7511,7 @@ packages: /@types/jsonfile/6.1.1: resolution: {integrity: sha512-GSgiRCVeapDN+3pqA35IkQwasaCh/0YFH5dEF6S88iDvEn901DjOeH3/QPY+XYP1DFzDZPvIvfeEgk+7br5png==} dependencies: - '@types/node': 18.14.0 + '@types/node': 18.14.1 dev: true /@types/lodash/4.14.191: @@ -7561,7 +7545,7 @@ packages: /@types/node-fetch/2.6.2: resolution: {integrity: sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==} dependencies: - '@types/node': 18.14.0 + '@types/node': 18.14.1 form-data: 3.0.1 dev: true @@ -7577,12 +7561,8 @@ packages: resolution: {integrity: sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==} dev: true - /@types/node/18.13.0: - resolution: {integrity: sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==} - dev: true - - /@types/node/18.14.0: - resolution: {integrity: sha512-5EWrvLmglK+imbCJY0+INViFWUHg1AHel1sq4ZVSfdcNqGy9Edv3UB9IIzzg+xPaUcAgZYcfVs2fBcwDeZzU0A==} + /@types/node/18.14.1: + resolution: {integrity: sha512-QH+37Qds3E0eDlReeboBxfHbX9omAcBCXEzswCu6jySP642jiM3cYSIkU/REqwhCUqXdonHFuBfJDiAJxMNhaQ==} dev: true /@types/node/18.7.13: @@ -7615,7 +7595,7 @@ packages: /@types/prompts/2.4.2: resolution: {integrity: sha512-TwNx7qsjvRIUv/BCx583tqF5IINEVjCNqg9ofKHRlSoUHE62WBHrem4B1HGXcIrG511v29d1kJ9a/t2Esz7MIg==} dependencies: - '@types/node': 18.14.0 + '@types/node': 18.14.1 kleur: 3.0.3 dev: true @@ -7688,7 +7668,7 @@ packages: /@types/resolve/1.17.1: resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} dependencies: - '@types/node': 18.14.0 + '@types/node': 18.14.1 dev: true /@types/resolve/1.20.2: @@ -7705,7 +7685,7 @@ packages: /@types/set-cookie-parser/2.4.2: resolution: {integrity: sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==} dependencies: - '@types/node': 18.14.0 + '@types/node': 18.14.1 dev: true /@types/sinonjs__fake-timers/8.1.1: @@ -7779,7 +7759,7 @@ packages: /@types/webpack-sources/3.2.0: resolution: {integrity: sha512-Ft7YH3lEVRQ6ls8k4Ff1oB4jN6oy/XmU6tQISKdhfh+1mR+viZFphS6WL0IrtDOzvefmJg5a0s7ZQoRXwqTEFg==} dependencies: - '@types/node': 18.14.0 + '@types/node': 18.14.1 '@types/source-list-map': 0.1.2 source-map: 0.7.4 dev: true @@ -7787,7 +7767,7 @@ packages: /@types/webpack/4.41.32: resolution: {integrity: sha512-cb+0ioil/7oz5//7tZUSwbrSAN/NWHrQylz5cW8G0dWTcF/g+/dSdMlKVZspBYuMAN1+WnwHrkxiRrLcwd0Heg==} dependencies: - '@types/node': 18.14.0 + '@types/node': 18.14.1 '@types/tapable': 1.0.8 '@types/uglify-js': 3.17.0 '@types/webpack-sources': 3.2.0 @@ -7798,7 +7778,7 @@ packages: /@types/ws/8.5.4: resolution: {integrity: sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==} dependencies: - '@types/node': 18.14.0 + '@types/node': 18.14.1 dev: true /@types/yargs-parser/21.0.0: @@ -7821,7 +7801,7 @@ packages: resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==} requiresBuild: true dependencies: - '@types/node': 18.14.0 + '@types/node': 18.14.1 dev: true optional: true @@ -8252,9 +8232,9 @@ packages: vite: ^4.0.0 vue: ^3.0.0 dependencies: - '@babel/core': 7.20.5 - '@babel/plugin-transform-typescript': 7.20.2_@babel+core@7.20.5 - '@vue/babel-plugin-jsx': 1.1.1_@babel+core@7.20.5 + '@babel/core': 7.20.12 + '@babel/plugin-transform-typescript': 7.20.2_@babel+core@7.20.12 + '@vue/babel-plugin-jsx': 1.1.1_@babel+core@7.20.12 vite: 4.0.0 vue: 3.2.45 transitivePeerDependencies: @@ -8268,9 +8248,9 @@ packages: vite: ^4.0.0 vue: ^3.0.0 dependencies: - '@babel/core': 7.20.5 - '@babel/plugin-transform-typescript': 7.20.2_@babel+core@7.20.5 - '@vue/babel-plugin-jsx': 1.1.1_@babel+core@7.20.5 + '@babel/core': 7.20.12 + '@babel/plugin-transform-typescript': 7.20.2_@babel+core@7.20.12 + '@vue/babel-plugin-jsx': 1.1.1_@babel+core@7.20.12 vite: 4.0.0 vue: 3.2.47 transitivePeerDependencies: @@ -8359,11 +8339,11 @@ packages: resolution: {integrity: sha512-hz4R8tS5jMn8lDq6iD+yWL6XNB699pGIVLk7WSJnn1dbpjaazsjZQkieJoRX6gW5zpYSCFqQ7jUquPNY65tQYA==} dev: true - /@vue/babel-plugin-jsx/1.1.1_@babel+core@7.20.5: + /@vue/babel-plugin-jsx/1.1.1_@babel+core@7.20.12: resolution: {integrity: sha512-j2uVfZjnB5+zkcbc/zsOc0fSNGCMMjaEXP52wdwdIfn0qjFfEYpYZBFKFg+HHnQeJCVrjOeO0YxgaL7DMrym9w==} dependencies: '@babel/helper-module-imports': 7.18.6 - '@babel/plugin-syntax-jsx': 7.18.6_@babel+core@7.20.5 + '@babel/plugin-syntax-jsx': 7.18.6_@babel+core@7.20.12 '@babel/template': 7.20.7 '@babel/traverse': 7.20.12 '@babel/types': 7.20.7 @@ -8430,7 +8410,7 @@ packages: /@vue/compiler-sfc/3.2.39: resolution: {integrity: sha512-fqAQgFs1/BxTUZkd0Vakn3teKUt//J3c420BgnYgEOoVdTwYpBTSXCMJ88GOBCylmUBbtquGPli9tVs7LzsWIA==} dependencies: - '@babel/parser': 7.20.5 + '@babel/parser': 7.20.7 '@vue/compiler-core': 3.2.39 '@vue/compiler-dom': 3.2.39 '@vue/compiler-ssr': 3.2.39 @@ -10451,7 +10431,7 @@ packages: check-error: 1.0.2 deep-eql: 4.1.3 get-func-name: 2.0.0 - loupe: 2.3.6 + loupe: 2.3.4 pathval: 1.1.1 type-detect: 4.0.8 dev: false @@ -13789,8 +13769,8 @@ packages: - encoding dev: true - /happy-dom/8.7.1: - resolution: {integrity: sha512-/z+B/LUEETO9qGbUw80TTCjyhibmczB7OF1XxJ+UU1LlFOBkqO+GCVM+lDaQKVH62HxvX4sbu/EL2KlUtmyyZw==} + /happy-dom/8.7.2: + resolution: {integrity: sha512-lkm1l7SLNtI9svaU3PflbM8zahYahLrUZf0fZTUkQ8W6bo5gtXjC/2utOkcjpv9rhWTkHFUuDVjAvBWg4ClAxA==} dependencies: css.escape: 1.5.1 he: 1.2.0 @@ -14208,8 +14188,8 @@ packages: postcss: 7.0.39 dev: true - /idb/7.0.2: - resolution: {integrity: sha512-jjKrT1EnyZewQ/gCBb/eyiYrhGzws2FeY92Yx8qT9S9GeQAmo4JFVIiWRIfKW/6Ob9A+UDAOW9j9jn58fy2HIg==} + /idb/7.1.1: + resolution: {integrity: sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==} dev: true /ieee754/1.2.1: @@ -14928,7 +14908,7 @@ packages: dependencies: '@jest/types': 26.6.2 '@types/graceful-fs': 4.1.5 - '@types/node': 18.14.0 + '@types/node': 18.14.1 anymatch: 3.1.2 fb-watchman: 2.0.1 graceful-fs: 4.2.10 @@ -14996,7 +14976,7 @@ packages: resolution: {integrity: sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==} engines: {node: '>= 10.14.2'} dependencies: - '@types/node': 18.14.0 + '@types/node': 18.14.1 graceful-fs: 4.2.10 dev: true @@ -15005,7 +14985,7 @@ packages: engines: {node: '>= 10.14.2'} dependencies: '@jest/types': 26.6.2 - '@types/node': 18.14.0 + '@types/node': 18.14.1 chalk: 4.1.2 graceful-fs: 4.2.10 is-ci: 2.0.0 @@ -15017,7 +14997,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.0.1 - '@types/node': 18.14.0 + '@types/node': 18.14.1 chalk: 4.1.2 ci-info: 3.7.0 graceful-fs: 4.2.10 @@ -15028,7 +15008,7 @@ packages: resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==} engines: {node: '>= 10.13.0'} dependencies: - '@types/node': 18.14.0 + '@types/node': 18.14.1 merge-stream: 2.0.0 supports-color: 7.2.0 dev: true @@ -15037,7 +15017,7 @@ packages: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} dependencies: - '@types/node': 18.14.0 + '@types/node': 18.14.1 merge-stream: 2.0.0 supports-color: 8.1.1 dev: true @@ -15185,6 +15165,47 @@ packages: - utf-8-validate dev: true + /jsdom/21.0.0: + resolution: {integrity: sha512-AIw+3ZakSUtDYvhwPwWHiZsUi3zHugpMEKlNPaurviseYoBqo0zBd3zqoUi3LPCNtPFlEP8FiW9MqCZdjb2IYA==} + engines: {node: '>=14'} + peerDependencies: + canvas: ^2.5.0 + peerDependenciesMeta: + canvas: + optional: true + dependencies: + abab: 2.0.6 + acorn: 8.8.1 + acorn-globals: 7.0.1 + cssom: 0.5.0 + cssstyle: 2.3.0 + data-urls: 3.0.2 + decimal.js: 10.4.2 + domexception: 4.0.0 + escodegen: 2.0.0 + form-data: 4.0.0 + html-encoding-sniffer: 3.0.0 + http-proxy-agent: 5.0.0 + https-proxy-agent: 5.0.1 + is-potential-custom-element-name: 1.0.1 + nwsapi: 2.2.2 + parse5: 7.1.1 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 4.1.2 + w3c-xmlserializer: 4.0.0 + webidl-conversions: 7.0.0 + whatwg-encoding: 2.0.0 + whatwg-mimetype: 3.0.0 + whatwg-url: 11.0.0 + ws: 8.12.0 + xml-name-validator: 4.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: true + /jsdom/21.1.0: resolution: {integrity: sha512-m0lzlP7qOtthD918nenK3hdItSd2I+V3W9IrBcB36sqDwG+KnUs66IF5GY7laGWUnlM9vTsD0W1QwSEBYWWcJg==} engines: {node: '>=14'} @@ -15559,7 +15580,7 @@ packages: dependencies: big.js: 5.2.2 emojis-list: 3.0.0 - json5: 2.2.1 + json5: 2.2.3 dev: true /local-pkg/0.4.2: @@ -15673,6 +15694,12 @@ packages: dev: true optional: true + /loupe/2.3.4: + resolution: {integrity: sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==} + dependencies: + get-func-name: 2.0.0 + dev: false + /loupe/2.3.6: resolution: {integrity: sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==} dependencies: @@ -16152,7 +16179,7 @@ packages: resolution: {integrity: sha512-cwzBrBfwGC1gYJyfcy8TcZU1f+dbH/T+TuOhtYP2wLv/Fb51/uV7HJQfBPtEupZ2ORLRU1EKFS/QfS3eo9+kBQ==} dependencies: acorn: 8.8.1 - pathe: 1.1.0 + pathe: 1.0.0 pkg-types: 1.0.1 ufo: 1.0.1 @@ -17153,6 +17180,9 @@ packages: resolution: {integrity: sha512-6Y6s0vT112P3jD8dGfuS6r+lpa0qqNrLyHPOwvXMnyNTQaYiwgau2DP3aNDsR13xqtGj7rrPo+jFUATpU6/s+g==} dev: true + /pathe/1.0.0: + resolution: {integrity: sha512-nPdMG0Pd09HuSsr7QOKUXO2Jr9eqaDiZvDwdyIhNG5SHYujkQHYKDfGQkulBxvbDHz8oHLsTgKN86LSwYzSHAg==} + /pathe/1.1.0: resolution: {integrity: sha512-ODbEPR0KKHqECXW1GoxdDb+AZvULmXjVPy4rt+pGo2+TnjJTIPJQSVS6N63n8T2Ip+syHhbn52OewKicV0373w==} @@ -17311,13 +17341,13 @@ packages: mlly: 1.1.0 pathe: 1.1.0 - /playwright-chromium/1.29.2: - resolution: {integrity: sha512-iylIZpI8pD2ukBY5fQhluCx530bi2w4oUUM0PAfsxBnAYKntdj4bkTlcHuvS23EvabUS++YYi6KCI5uC517nxQ==} + /playwright-chromium/1.30.0: + resolution: {integrity: sha512-ZfqjYdFuxnZxK02mDZtHFK/Mi0+cjCVn51RmwLwLLHA8PkCExk0odmZH2REx+LjqX8tDLGnmf6vDnPAirdSY0g==} engines: {node: '>=14'} hasBin: true requiresBuild: true dependencies: - playwright-core: 1.29.2 + playwright-core: 1.30.0 dev: true /playwright-core/1.28.0: @@ -17326,8 +17356,8 @@ packages: hasBin: true dev: true - /playwright-core/1.29.2: - resolution: {integrity: sha512-94QXm4PMgFoHAhlCuoWyaBYKb92yOcGVHdQLoxQ7Wjlc7Flg4aC/jbFW7xMR52OfXMVkWicue4WXE7QEegbIRA==} + /playwright-core/1.30.0: + resolution: {integrity: sha512-7AnRmTCf+GVYhHbLJsGUtskWTE33SwMZkybJ0v6rqR1boxq2x36U7p1vDRV7HO2IwTZgmycracLxPEJI49wu4g==} engines: {node: '>=14'} hasBin: true dev: true @@ -21044,7 +21074,7 @@ packages: vite: ^3.1.0 || ^4.0.0 workbox-window: ^6.5.4 dependencies: - '@rollup/plugin-replace': 5.0.1_rollup@2.79.1 + '@rollup/plugin-replace': 5.0.2_rollup@2.79.1 debug: 4.3.4 fast-glob: 3.2.12 pretty-bytes: 6.0.0 @@ -21731,7 +21761,7 @@ packages: /workbox-background-sync/6.5.4: resolution: {integrity: sha512-0r4INQZMyPky/lj4Ou98qxcThrETucOde+7mRGJl13MPJugQNKeZQOdIJe/1AchOP23cTqHcN/YVpD6r8E6I8g==} dependencies: - idb: 7.0.2 + idb: 7.1.1 workbox-core: 6.5.4 dev: true @@ -21800,7 +21830,7 @@ packages: /workbox-expiration/6.5.4: resolution: {integrity: sha512-jUP5qPOpH1nXtjGGh1fRBa1wJL2QlIb5mGpct3NzepjGG2uFFBn4iiEBiI9GUmfAFR2ApuRhDydjcRmYXddiEQ==} dependencies: - idb: 7.0.2 + idb: 7.1.1 workbox-core: 6.5.4 dev: true diff --git a/test/core/test/mocked.test.ts b/test/core/test/mocked.test.ts index f6824991d730..cb32fdc26737 100644 --- a/test/core/test/mocked.test.ts +++ b/test/core/test/mocked.test.ts @@ -169,3 +169,88 @@ describe('mocked function which fails on toReturnWith', () => { test('streams', () => { expect(exportedStream).toBeDefined() }) + +describe('temporary mock implementation', () => { + test('temporary mock implementation works as expected', () => { + const mock = vi.fn(() => 1) + + expect.assertions(3) + + mock.withImplementation(() => 2, () => { + expect(mock()).toBe(2) + expect(mock()).toBe(2) + }) + + expect(mock()).toBe(1) + }) + + test('original implementation restored as undefined, when there is none', () => { + const mock = vi.fn() + + expect.assertions(5) + + mock.withImplementation(() => 2, () => { + expect(mock.getMockImplementation()).toBeTypeOf('function') + expect(mock()).toBe(2) + expect(mock()).toBe(2) + }) + + expect(mock()).toBe(undefined) + expect(mock.getMockImplementation()).toBe(undefined) + }) + + test('temporary mock implementation return value can be of different type than the original', async () => { + const mock = vi.fn(() => 1) + + expect.assertions(3) + + mock.withImplementation(() => 2, () => { + expect(mock()).toBe(2) + expect(mock()).toBe(2) + }) + + expect(mock()).toBe(1) + }) + + test('temporary mock implementation with async callback works as expecetd', async () => { + const mock = vi.fn(() => 1) + + expect.assertions(3) + + await mock.withImplementation(() => 2, async () => { + await Promise.resolve() + + expect(mock()).toBe(2) + expect(mock()).toBe(2) + }) + + expect(mock()).toBe(1) + }) + + test('temporary mock implementation can be async', async () => { + const mock = vi.fn(async () => 1) + + expect.assertions(3) + + await mock.withImplementation(async () => 2, async () => { + expect(await mock()).toBe(2) + expect(await mock()).toBe(2) + }) + + expect(await mock()).toBe(1) + }) + + test('temporary mock implementation takes precedence over mockImplementationOnce', () => { + const mock = vi.fn(() => 1) + + expect.assertions(3) + + mock.mockImplementationOnce(() => 2) + mock.withImplementation(() => 3, () => { + expect(mock()).toBe(3) + expect(mock()).toBe(3) + }) + + expect(mock()).toBe(2) + }) +})