vitest-auto-spy 3.14.0 → 3.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +98 -12
- package/README.md +49 -18
- package/dist/angular.d.ts +97 -8
- package/dist/angular.js +87 -4
- package/dist/bun-angular.d.ts +4 -4
- package/dist/bun-angular.js +7 -7
- package/dist/bun.d.ts +4 -4
- package/dist/bun.js +4 -4
- package/dist/{chunk-USCBO2MG.js → chunk-3OX44LME.js} +1 -1
- package/dist/{chunk-Y5KHK2GG.js → chunk-AQSVZK2R.js} +26 -2
- package/dist/{chunk-OF4YYOUI.js → chunk-CR5Q3YMQ.js} +3 -3
- package/dist/{chunk-GVTSBOZ3.js → chunk-DMOJ4NZH.js} +1 -1
- package/dist/{chunk-3JTZD6ME.js → chunk-LIOV4WZK.js} +2 -2
- package/dist/console.d.ts +1 -1
- package/dist/console.js +1 -1
- package/dist/eslint-plugin.cjs +37 -0
- package/dist/eslint-plugin.js +37 -0
- package/dist/{expect-emission-DMx5uXie.d.ts → expect-emission-COcg6YzT.d.ts} +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +26 -2
- package/dist/jasmine-compat.d.ts +1 -1
- package/dist/jasmine.d.ts +2 -2
- package/dist/jasmine.js +2 -2
- package/dist/nestjs.d.ts +2 -2
- package/dist/nestjs.js +3 -3
- package/dist/node.cjs +26 -2
- package/dist/node.d.ts +3 -3
- package/dist/node.js +4 -4
- package/dist/{prop-mock-DyjtZVoA.d.ts → prop-mock-CEBKBA7k.d.ts} +1 -1
- package/dist/react.d.ts +3 -3
- package/dist/react.js +4 -4
- package/dist/rxjs.d.ts +2 -2
- package/dist/rxjs.js +1 -0
- package/dist/setup.d.ts +21 -2
- package/dist/setup.js +40 -5
- package/dist/svelte.d.ts +3 -3
- package/dist/svelte.js +4 -4
- package/dist/{track-injections-BQndbppn.d.ts → track-injections-BU-WSjji.d.ts} +1 -1
- package/dist/{types-Br-Usge9.d.ts → types-W5kEgzND.d.ts} +38 -7
- package/dist/vue.d.ts +4 -4
- package/dist/vue.js +5 -5
- package/dist/{zoneless-CEhs7o9p.d.ts → zoneless-DzUXGIYb.d.ts} +3 -3
- package/package.json +1 -1
- package/skills/vitest-auto-spy/SKILL.md +14 -2
package/AGENTS.md
CHANGED
|
@@ -51,14 +51,14 @@ adapter installed and spies fail at runtime.
|
|
|
51
51
|
|
|
52
52
|
Five add-ons, orthogonal to the runner:
|
|
53
53
|
|
|
54
|
-
| Add-on
|
|
55
|
-
|
|
|
56
|
-
| Observable spies
|
|
57
|
-
| observer-spy shim | `vitest-auto-spy/observer-spy`
|
|
58
|
-
| Console spies
|
|
59
|
-
| Setup helpers
|
|
60
|
-
| Zone patch
|
|
61
|
-
| jasmine compat
|
|
54
|
+
| Add-on | Import | Needed for |
|
|
55
|
+
| ----------------- | ------------------------------- | --------------------------------------------------------------------------------------------------------- |
|
|
56
|
+
| Observable spies | `import 'vitest-auto-spy/rxjs'` | `nextWith` & friends. **Side-effect import, once.** |
|
|
57
|
+
| observer-spy shim | `vitest-auto-spy/observer-spy` | `subscribeSpyTo` — the `@hirez_io/observer-spy` surface (§20). Its own entry so `/rxjs` does not carry it |
|
|
58
|
+
| Console spies | `vitest-auto-spy/console` | silent typed spies over the global `console` |
|
|
59
|
+
| Setup helpers | `vitest-auto-spy/setup` | `setupAutoSpy()`, `setupFakeTimers()` |
|
|
60
|
+
| Zone patch | `import 'vitest-auto-spy/zone'` | `fakeAsync` / `waitForAsync` on Vitest (§14) |
|
|
61
|
+
| jasmine compat | `vitest-auto-spy/jasmine` | `.and` / `.calls` / `.withArgs`, the `jasmine` namespace (§20) |
|
|
62
62
|
|
|
63
63
|
`vitest-auto-spy/jasmine` is Vitest-only, because it registers the Vitest adapter. On `bun test` and
|
|
64
64
|
`node --test` call `enableJasmineCompat()` from `vitest-auto-spy/jasmine-compat` instead.
|
|
@@ -349,7 +349,7 @@ Every spied method is a real runner mock, so `mockReturnValue`, `mockImplementat
|
|
|
349
349
|
|
|
350
350
|
| Return type | Helpers added |
|
|
351
351
|
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
352
|
-
| anything | `calledWith(...args)` → `.mockReturnValue(v)` / `.returnValue(v)`, `mustBeCalledWith(...args)` → same
|
|
352
|
+
| anything | `calledWith(...args)` → `.mockReturnValue(v)` / `.returnValue(v)` / `.failWith(err)`, `mustBeCalledWith(...args)` → same, `failWith(err)` |
|
|
353
353
|
| `Promise<T>` | `resolveWith(v)`, `rejectWith(v)`, `resolveWithPerCall([{ value }, …])` |
|
|
354
354
|
| `Observable<T>` | `nextWith(v)`, `nextOneTimeWith(v)`, `nextWithValues(configs)`, `nextWithPerCall(configs)`, `throwWith(v)`, `complete()`, `returnSubject()` |
|
|
355
355
|
|
|
@@ -379,8 +379,24 @@ feed.items$.nextWithValues([{ value: a }, { value: b, delay: 100 }, { complete:
|
|
|
379
379
|
const [first$, second$] = feed.watch$.nextWithPerCall([{ value: 'a' }, { value: 'b', doNotComplete: true }]);
|
|
380
380
|
feed.items$.throwWith('FAKE ERROR');
|
|
381
381
|
const subject = feed.items$.returnSubject(); // ReplaySubject, for anything the helpers miss
|
|
382
|
+
|
|
383
|
+
// throwing — `failWith`, on a spy of any return type
|
|
384
|
+
cart.checkout.failWith(new HttpErrorResponse({ status: 500 })); // every call throws
|
|
385
|
+
cart.checkout.calledWith(BAD_ID).failWith(new Error('unknown cart')); // only these arguments throw
|
|
382
386
|
```
|
|
383
387
|
|
|
388
|
+
`failWith` is the sync counterpart of `rejectWith`, and it is **not** called `throwWith` — that name
|
|
389
|
+
belongs to the observable helper above, which errors the stream. At runtime every spy carries every
|
|
390
|
+
bundle; only the return type in `Spy<T>` tells them apart, so one name for both would mean whichever
|
|
391
|
+
is attached last silently wins.
|
|
392
|
+
|
|
393
|
+
On Vitest, `mockThrow` / `mockThrowOnce` (4.1) do the spy-level half of this too. `failWith` exists
|
|
394
|
+
because Bun and `node:test` ship neither, and because **no** runtime can make one `calledWith` chain
|
|
395
|
+
throw while its siblings answer normally — `mockImplementation` replaces the whole dispatch, which is
|
|
396
|
+
the opposite of configuring one set of arguments. A `failWith` supersedes a `resolveWith` /
|
|
397
|
+
`nextWith` / per-call batch configured before it, and is superseded by one configured after, so the
|
|
398
|
+
outcome never depends on the order the spec happens to be written in.
|
|
399
|
+
|
|
384
400
|
An exact argument list is matched before the asymmetric configs, and those are tried in
|
|
385
401
|
registration order — a narrow config written first keeps its calls. Two matchers count as the same
|
|
386
402
|
argument when they accept the same values (same matcher class, sample and inversion), which is what
|
|
@@ -922,7 +938,21 @@ setupAutoSpy({ strayTimers: true }); // wrap the schedulers, sweep the survivors
|
|
|
922
938
|
The pieces are exported too — `trackStrayTimers()` (idempotent, returns the undo),
|
|
923
939
|
`cancelStrayTimers()` (returns how many it cancelled) and `countStrayTimers()`, all from
|
|
924
940
|
`vitest-auto-spy/setup`. Use `expect(countStrayTimers()).toBe(0)` in an `afterEach` to make a leak
|
|
925
|
-
fail rather than be tidied away
|
|
941
|
+
fail rather than be tidied away, or take the per-file count from the sweep itself:
|
|
942
|
+
|
|
943
|
+
```ts
|
|
944
|
+
setupAutoSpy({ strayTimers: true, onStrayTimers: ({ cancelled }) => expect(cancelled).toBe(0) });
|
|
945
|
+
```
|
|
946
|
+
|
|
947
|
+
**With Vitest 4.1's `--detect-async-leaks`, run one or the other — not both silently.** The two
|
|
948
|
+
arrive at the same timer from opposite ends and the quiet one wins: the sweep cancels in `afterAll`,
|
|
949
|
+
Vitest collects its leaks afterwards, and a cancelled timeout is no longer referenced, so the run
|
|
950
|
+
reports **no leaks** for a file that leaks. Cancelling is still the right default — a callback firing
|
|
951
|
+
during a later file is the more expensive failure — so when both are on and no `onStrayTimers` is
|
|
952
|
+
given, the sweep prints one line to stderr saying how many it took away. To see _where_ each one was
|
|
953
|
+
scheduled, re-run that file with `strayTimers` off and read Vitest's report; the code frame points
|
|
954
|
+
at the `setTimeout` in the spec, because the library's own scheduler wrappers go through
|
|
955
|
+
`vi.defineHelper` and are dropped from the stack.
|
|
926
956
|
|
|
927
957
|
**The one that keeps a suite green while it is wrong:** zone.js replaces the global `Promise`, and a
|
|
928
958
|
rejection nobody handled is drained into `console.error` and no further — it never reaches
|
|
@@ -944,6 +974,12 @@ undo), `flushStrayRejections()` (takes what was captured and starts again from e
|
|
|
944
974
|
`countStrayRejections()`. The `no-floating-assertion` lint rule catches the commonest shape before
|
|
945
975
|
it ever runs (§16).
|
|
946
976
|
|
|
977
|
+
**`onUnhandledError` is not this.** Vitest 4.0 added a config callback for errors the _runner_ hears
|
|
978
|
+
about, and under zone.js the runner never hears about these at all — zone.js drains the rejection
|
|
979
|
+
into `console.error` before `process.on('unhandledRejection')` would fire, so there is nothing for
|
|
980
|
+
that callback to filter. Use `onUnhandledError` to triage the native failures Vitest already reports;
|
|
981
|
+
use `strayRejections` to find the ones it never sees.
|
|
982
|
+
|
|
947
983
|
A rejection the runner has **already** blamed the finished test for is not reported again. An
|
|
948
984
|
`async` test that fails an assertion leaves its own `AssertionError` in both places, so a red run
|
|
949
985
|
used to print two messages per failure and the second one sent the reader hunting for a defect that
|
|
@@ -1354,6 +1390,44 @@ const myService = injectSpy(MyService); // Spy<MyService>
|
|
|
1354
1390
|
`{ lazySpies: false }` to opt out. The spies never touch `NgZone`, so they work zoneless and with
|
|
1355
1391
|
zone.js alike.
|
|
1356
1392
|
|
|
1393
|
+
### The same thing as fixtures — `extendWithAutoSpies` (Vitest 4.1+)
|
|
1394
|
+
|
|
1395
|
+
The block above, written once instead of once per dependency, with the types inferred rather than
|
|
1396
|
+
declared:
|
|
1397
|
+
|
|
1398
|
+
```ts
|
|
1399
|
+
import { test as base } from 'vitest';
|
|
1400
|
+
import { extendWithAutoSpies } from 'vitest-auto-spy/angular';
|
|
1401
|
+
|
|
1402
|
+
const test = extendWithAutoSpies(base, {
|
|
1403
|
+
cart: CartService,
|
|
1404
|
+
api: [ApiService, { returns: { get: of([]) } }],
|
|
1405
|
+
passcode: PASSCODE_TOKEN,
|
|
1406
|
+
});
|
|
1407
|
+
|
|
1408
|
+
test('checks out', async ({ cart }) => {
|
|
1409
|
+
cart.checkout.resolveWith(true);
|
|
1410
|
+
|
|
1411
|
+
await expect(cart.checkout(1)).resolves.toBe(true);
|
|
1412
|
+
});
|
|
1413
|
+
```
|
|
1414
|
+
|
|
1415
|
+
No `let cart: Spy<CartService>` that is `undefined` between tests, and a test that never destructures
|
|
1416
|
+
`api` never builds it. Entries are a class, `[Class, config]` with whatever `provideAutoSpy` takes,
|
|
1417
|
+
or an `InjectionToken` (built from the token's own type, like `provideAutoSpyForToken`). Extra
|
|
1418
|
+
providers — the component under test, a real service, `provideHttpClient()` — go in the third
|
|
1419
|
+
argument and are registered in the same call, ahead of the generated ones, so a token named there
|
|
1420
|
+
wins.
|
|
1421
|
+
|
|
1422
|
+
**It takes the whole map at once, and that is a `TestBed` constraint rather than a typing one.** The
|
|
1423
|
+
composing form — `base.extend('cart', …).extend('api', …)` — cannot work: fixtures resolve
|
|
1424
|
+
independently, so `cart` would configure the testing module _and_ inject, which instantiates it, and
|
|
1425
|
+
`api` would then reach `configureTestingModule` after instantiation and fail with Angular's own
|
|
1426
|
+
"Cannot configure the test module when the test module has already been instantiated". A `beforeEach`
|
|
1427
|
+
that configures the module further still composes, because it runs before any fixture resolves and
|
|
1428
|
+
repeated `configureTestingModule` calls merge right up until the first injection. A `beforeEach` that
|
|
1429
|
+
**injects** does not, and nothing can repair that from here.
|
|
1430
|
+
|
|
1357
1431
|
The token may be an **abstract class** — `abstract class LocalStorage extends AbstractStorage {}`,
|
|
1358
1432
|
the shape production provides with `useClass`. Its members are erased before they reach a prototype,
|
|
1359
1433
|
so there is nothing to discover; the factory notices and returns the `createAutoMock` proxy, which
|
|
@@ -1958,6 +2032,7 @@ export default [{ files: ['**/*.spec.ts'], ...autoSpy.configs.recommended }];
|
|
|
1958
2032
|
| `prefer-as-spy` | `warn` | `--fix` | `TestBed.inject(X) as Spy<X>` → `asSpy<X>(TestBed.inject(X))`, import and all |
|
|
1959
2033
|
| `no-done-callback` | `error` | — | `it('x', (done) => …)` → `async` + an awaited assertion, and `done.fail(…)` at the call site |
|
|
1960
2034
|
| `no-floating-assertion` | `error` | — | `expect()` in a `.then()` nobody awaits → `expect(await promise)` |
|
|
2035
|
+
| `no-bare-called-with` | `error` | — | `spy.m.calledWith(1);` as a statement — a stub nobody continued, asserting nothing; chai's `expect(fn).to.have.been.calledWith()` exempt |
|
|
1961
2036
|
| `no-overridden-provider` | `error` | suggest | two providers for one token in one array → the earlier one never runs; the exact duplicate can be deleted |
|
|
1962
2037
|
| `no-inject-before-override` | `warn` | — | `TestBed.inject()` in a hook, in a suite that still calls `override*` |
|
|
1963
2038
|
| `no-import-time-spread` | `error` | suggest | `export const x = [...Imported]` at module scope → a `TypeError` while the bundle loads |
|
|
@@ -1967,10 +2042,10 @@ export default [{ files: ['**/*.spec.ts'], ...autoSpy.configs.recommended }];
|
|
|
1967
2042
|
| `no-save-arguments-by-value` | `error` | — | `spy.calls.saveArgumentsByValue()` — a no-op here, so the spec silently asserts on post-mutation state |
|
|
1968
2043
|
| `prefer-native-spy-api` | `off` | `--fix` / suggest | `.and` / `.calls` where the spy's own API says the same thing — turn it on for the last mile off the jasmine shim |
|
|
1969
2044
|
|
|
1970
|
-
|
|
2045
|
+
Nineteen rules; three fix on their own, seven offer suggestions. The last four are for a suite
|
|
1971
2046
|
mid-migration off `jasmine-auto-spies` (§20); `prefer-native-spy-api` is **off** in the recommended
|
|
1972
2047
|
config because it reports working code — the compatibility layer is what a suite runs on while it is
|
|
1973
|
-
being migrated. `no-mocked-for-spy` only ever touches a
|
|
2048
|
+
being migrated. `no-mocked-for-spy` only ever touches a
|
|
1974
2049
|
**type position**, where a wrong rewrite is a compile error rather than a test that quietly changed
|
|
1975
2050
|
meaning — so `--fix` renames the type, adds `import type { Spy } from 'vitest-auto-spy'` and drops
|
|
1976
2051
|
the orphaned `Mocked` import. Every type position, not only a `let`: a factory's return type, a
|
|
@@ -2096,6 +2171,7 @@ packages, which a subpath export can never be.
|
|
|
2096
2171
|
| a `.withContext('…')` message that never appears in the failure output | Vitest's chai layer has an `@internal` `withContext(flags)`; handed a string it walks the character indices, sets nonsense flags and returns `this` | `expect(actual, 'message').toBe(expected)` — the second argument of `expect` is the label. Nothing throws, so nothing warns (§20) |
|
|
2097
2172
|
| `requested method(s) not found on the class prototype` | typo, or an instance-field callable | fix the name, or move it to `instanceMethodsToSpyOn` |
|
|
2098
2173
|
| `was configured with 'mustBeCalledWith'` | the code called the spy with other arguments | that is the assertion firing — fix the code, or relax to `calledWith` |
|
|
2174
|
+
| `extendWithAutoSpies needs Vitest 4.1 or newer` | the `test` handed in has only the object-form `extend` (Vitest ≤ 4.0); the builder form the helper is written against arrived in 4.1 | upgrade Vitest, or keep `provideAutoSpy` + `injectSpy` in a `beforeEach` until then |
|
|
2099
2175
|
| `advanceTimers() requires fake timers` | no fake timers installed | `setupFakeTimers()` or `vi.useFakeTimers()` first |
|
|
2100
2176
|
| `Nothing configured X.method, and strict mode is on` | a strict double was asked for a method no line configured | configure it (`mockReturnValue` / `resolveWith` / `nextWith` / `calledWith`), or `{ strict: false }` on that double (§5) |
|
|
2101
2177
|
| `Cannot redefine property: …` from a library accessor spy | the target is an ES module namespace a bundler inlined | no spy library can win this — give the code a real seam (inject it, pass it in) and spy on that |
|
|
@@ -2159,6 +2235,8 @@ packages, which a subpath export can never be.
|
|
|
2159
2235
|
| two runs with the same totals, one of them missing a suite | a lost `describe` and a fixed flake cancel out in the counters | `compareTestRuns(before, after)` — compare the set of names, not the numbers |
|
|
2160
2236
|
| a 30 s timeout, in a different file each run | module-level `vi.fn()` in a fixture shared by files | make the fixture a factory (§10) |
|
|
2161
2237
|
| a component's `afterNextRender` state is empty | `detectChanges()` does not run the after-render phase | `await stable(fixture)` (§11) |
|
|
2238
|
+
| a green test whose only line about a call is `spy.m.calledWith(1);` | that is a **stub**, not an assertion — chai's `expect(fn).to.have.been.calledWith(x)` is the one that checks | continue the chain, or `expect(spy.m).toHaveBeenCalledWith(1)` — `no-bare-called-with` (§16) |
|
|
2239
|
+
| `--detect-async-leaks` reporting no leaks in a suite that visibly leaks timers | `setupAutoSpy({ strayTimers: true })` cancelled them before Vitest collected | re-run that file with `strayTimers` off; the warning on stderr says how many were taken (§10) |
|
|
2162
2240
|
|
|
2163
2241
|
**Seven of these are library defects, not spec ones.** On anything below 3.8.0, upgrade and change
|
|
2164
2242
|
nothing in the spec: `of(double)` never emitting; `accessorSpies.setters.X` still `undefined` after
|
|
@@ -2242,6 +2320,14 @@ npx tsc --noEmit # Spy<T> mistakes are compile errors, not
|
|
|
2242
2320
|
npx vitest-auto-spy doctor # suite-level defects that never fail a run
|
|
2243
2321
|
```
|
|
2244
2322
|
|
|
2323
|
+
**If you are an agent, add `--reporter=agent`** (Vitest 4.1). It is Vitest's own reporter, added for
|
|
2324
|
+
exactly this: the same failures, without the passing-test roll call and the repeated banners that
|
|
2325
|
+
make a run's output expensive to read and expensive to carry.
|
|
2326
|
+
|
|
2327
|
+
```bash
|
|
2328
|
+
npx vitest run --reporter=agent path/to/file.spec.ts
|
|
2329
|
+
```
|
|
2330
|
+
|
|
2245
2331
|
Type errors matter here more than usual: most of this library's guarantees are type-level, so a
|
|
2246
2332
|
suite that runs green but does not type-check is not done.
|
|
2247
2333
|
|
package/README.md
CHANGED
|
@@ -63,7 +63,7 @@ identical API, with **RxJS** spies and **Angular / NestJS / React / Vue·Pinia /
|
|
|
63
63
|
- 🧩 Module mocks that prove they applied — `assertMocked`, `moduleNamespace`, for a `vi.mock()` a bundler quietly ignored
|
|
64
64
|
- 🧾 Fixtures without casts — deep-partial `createMock`, `createFixture` / `createFixtureFactory`, `narrow()`, `withOverrides()`, `asInstances()`, `captureArg()`
|
|
65
65
|
- 🚚 A migration you can verify — `compareTestRuns` on the two JSON reports, `diffByField` for the assertion the reporter collapses
|
|
66
|
-
- 📏 Lint rules and one-line test-run hygiene —
|
|
66
|
+
- 📏 Lint rules and one-line test-run hygiene — nineteen rules in `vitest-auto-spy/eslint-plugin` (three `--fix`, seven suggestions, four of them for a suite mid-migration off jasmine), `setupAutoSpy()`
|
|
67
67
|
- 🩺 [Editor diagnostics](#editor-diagnostics--webstorm--vs-code) — the same anti-patterns underlined while you type: native ESLint inspections in **WebStorm** and the other JetBrains IDEs, the ESLint extension in **VS Code**, no extra plugin either way
|
|
68
68
|
- 🔎 [`npx vitest-auto-spy doctor`](#the-cli--doctor-codemod-and-init) — suite-level defects **that never fail a run**: a `tsconfig` `include` matching no file, a production module importing a spec, a `@jest-environment` pragma the runner never reads, config left behind for a runner that is gone. Read-only, no config, exits 1 in CI
|
|
69
69
|
- 🚚 [`npx vitest-auto-spy codemod`](#codemod--migrating-a-suite-off-jest-auto-spies) — thirteen transforms that move a suite off `jest-auto-spies` and Jest, or off `jasmine-auto-spies` and jasmine (`--from jasmine`), dry-run by default, with a `--verify` pass that also checks a file somebody edited by hand
|
|
@@ -604,6 +604,23 @@ cart.total.mockReturnValue(42);
|
|
|
604
604
|
`CartService` and the spy has it. A hand-written `{ provide: CartService, useValue: { total:
|
|
605
605
|
vi.fn() } }` silently keeps mocking yesterday's class.
|
|
606
606
|
|
|
607
|
+
On **Vitest 4.1+**, the same thing as fixtures — one statement, types inferred, and a test that
|
|
608
|
+
never names a dependency never builds it:
|
|
609
|
+
|
|
610
|
+
```ts
|
|
611
|
+
import { test as base } from 'vitest';
|
|
612
|
+
import { extendWithAutoSpies } from 'vitest-auto-spy/angular';
|
|
613
|
+
|
|
614
|
+
const test = extendWithAutoSpies(base, { cart: CartService, api: [ApiService, { returns: { get: of([]) } }] });
|
|
615
|
+
|
|
616
|
+
test('checks out', ({ cart }) => cart.total.mockReturnValue(42));
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
It takes the whole map at once because every provider has to be known before the first injection —
|
|
620
|
+
[why, in full](https://asdalexey.github.io/vitest-auto-spy/adapters/angular#fixtures-instead-of-let-beforeeach-extendwithautospies).
|
|
621
|
+
On an older Vitest it throws `needs Vitest 4.1 or newer` up front, instead of letting the object-form
|
|
622
|
+
`extend` register nonsense and every test die on `undefined`.
|
|
623
|
+
|
|
607
624
|
### How to mock: a service without DI
|
|
608
625
|
|
|
609
626
|
```ts
|
|
@@ -668,6 +685,18 @@ Not `source$.subscribe(value => expect(value).toEqual(…))`: if the stream neve
|
|
|
668
685
|
never runs, nothing is asserted, and the test is green and empty. `expectEmission` **is** the
|
|
669
686
|
assertion — a silent stream fails it, with the stream's name and the timeout in the message.
|
|
670
687
|
|
|
688
|
+
### How to mock: a call that has to throw
|
|
689
|
+
|
|
690
|
+
```ts
|
|
691
|
+
cart.checkout.failWith(new HttpErrorResponse({ status: 500 })); // every call throws
|
|
692
|
+
cart.checkout.calledWith(BAD_ID).failWith(new Error('unknown cart')); // only these arguments
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
`failWith` works on a spy of any return type. Vitest 4.1's `mockThrow` covers the first line; Bun
|
|
696
|
+
and `node:test` have no equivalent, and **no** runtime has one for the second — `mockImplementation`
|
|
697
|
+
replaces the whole dispatch, which is the opposite of configuring one set of arguments. It is not
|
|
698
|
+
called `throwWith` because that name already means _error the stream_ on an observable spy.
|
|
699
|
+
|
|
671
700
|
### How to mock: a promise a test forgets to await
|
|
672
701
|
|
|
673
702
|
```ts
|
|
@@ -2235,20 +2264,21 @@ expensive to diagnose when it is missing. The first three are on by default:
|
|
|
2235
2264
|
timer in sight: a request matching no Express route is ended by `finalhandler` on `setImmediate`,
|
|
2236
2265
|
so the 404 is never written and a routing mistake is reported as a slow test.
|
|
2237
2266
|
|
|
2238
|
-
| Option | Default | Notes
|
|
2239
|
-
| --------------------- | --------- |
|
|
2240
|
-
| `duplicateCopies` | `'throw'` | `'warn'` to report without failing, `'off'` to skip the check
|
|
2241
|
-
| `restoreProps` | `true` | `restoreMockedProps()` in a global `afterEach`
|
|
2242
|
-
| `restoreMocks` | `false` | `vi.restoreAllMocks()` in a global `afterEach` — turn on for `isolate: false`
|
|
2243
|
-
| `strayTimers` | `false` | Cancel timeouts, intervals and frames that outlive their file
|
|
2244
|
-
| `
|
|
2245
|
-
| `
|
|
2246
|
-
| `
|
|
2247
|
-
| `
|
|
2248
|
-
| `
|
|
2249
|
-
| `
|
|
2250
|
-
| `
|
|
2251
|
-
| `
|
|
2267
|
+
| Option | Default | Notes |
|
|
2268
|
+
| --------------------- | --------- | ------------------------------------------------------------------------------------- |
|
|
2269
|
+
| `duplicateCopies` | `'throw'` | `'warn'` to report without failing, `'off'` to skip the check |
|
|
2270
|
+
| `restoreProps` | `true` | `restoreMockedProps()` in a global `afterEach` |
|
|
2271
|
+
| `restoreMocks` | `false` | `vi.restoreAllMocks()` in a global `afterEach` — turn on for `isolate: false` |
|
|
2272
|
+
| `strayTimers` | `false` | Cancel timeouts, intervals and frames that outlive their file |
|
|
2273
|
+
| `onStrayTimers` | — | Takes the per-file count the sweep cancelled — see the note on `--detect-async-leaks` |
|
|
2274
|
+
| `strayRejections` | `false` | Fail the test a rejection zone.js swallowed surfaced in — needs zone.js |
|
|
2275
|
+
| `blockNetwork` | `false` | Close every network channel the environment has — `true`, or a narrowing object |
|
|
2276
|
+
| `guardGlobals` | `'off'` | Report a test that redefines a global property as non-configurable |
|
|
2277
|
+
| `globalFakeTimers` | `false` | Fake timers for every test **and between them** — Jest's `enableGlobally` |
|
|
2278
|
+
| `restoreTimerGlobals` | `true` | Put back timer globals that uninstalling the fakes deleted |
|
|
2279
|
+
| `pruneMockRegistry` | `false` | Keep @vitest/spy's ever-growing mock registry to the mocks that outlive a file |
|
|
2280
|
+
| `hookTimeoutHint` | `true` | Explain a hook that ran out of `hookTimeout` while `testTimeout` is larger |
|
|
2281
|
+
| `frozenClockHint` | `true` | Explain a timeout that happened because nothing advanced the fake clock |
|
|
2252
2282
|
|
|
2253
2283
|
`restoreMocks` is off by default because it also drops `vi.spyOn` stubs a suite installed in
|
|
2254
2284
|
`beforeAll`; it is the knob to reach for when the run shares one environment across files.
|
|
@@ -2395,6 +2425,7 @@ export can never be.
|
|
|
2395
2425
|
| `prefer-as-spy` | `warn` | `--fix` | `TestBed.inject(X) as Spy<X>` → `asSpy<X>(TestBed.inject(X))`, import and all |
|
|
2396
2426
|
| `no-done-callback` | `error` | — | `it('x', (done) => …)` → `async` + an awaited assertion, and `done.fail(…)` at the call site |
|
|
2397
2427
|
| `no-floating-assertion` | `error` | — | `expect()` in a `.then()` nobody awaits → `expect(await promise)` |
|
|
2428
|
+
| `no-bare-called-with` | `error` | — | `spy.m.calledWith(1);` as a statement of its own — a stub nobody continued, asserting nothing |
|
|
2398
2429
|
| `no-overridden-provider` | `error` | suggest | two providers for one token in one array → the earlier one never runs; the exact duplicate can be deleted |
|
|
2399
2430
|
| `no-inject-before-override` | `warn` | — | `TestBed.inject()` in a hook, in a suite that still calls `override*` |
|
|
2400
2431
|
| `no-import-time-spread` | `error` | suggest | `export const x = [...Imported]` at module scope → a `TypeError` while the bundle loads |
|
|
@@ -2408,7 +2439,7 @@ Every message ends with a link to the matching [recipe](#how-to-mock): a rule th
|
|
|
2408
2439
|
"don't" moves the problem rather than solving it. Rules travel with the API they recommend, so they
|
|
2409
2440
|
are versioned together and stop being re-written in every project that installs the package.
|
|
2410
2441
|
|
|
2411
|
-
**Three of the
|
|
2442
|
+
**Three of the nineteen fix on their own, seven offer suggestions**, and the split is not about how hard
|
|
2412
2443
|
the rewrite is. `no-mocked-for-spy` touches a _declaration_: get it wrong and the file stops
|
|
2413
2444
|
compiling, which is the loudest, cheapest failure there is — so `--fix` rewrites the type, adds
|
|
2414
2445
|
`import type { Spy } from 'vitest-auto-spy'` and drops the `Mocked` import once nothing else uses
|
|
@@ -2510,7 +2541,7 @@ package's own — it needs its ESLint integration switched on.
|
|
|
2510
2541
|
### WebStorm and the other JetBrains IDEs
|
|
2511
2542
|
|
|
2512
2543
|
No plugin to install: WebStorm, IntelliJ IDEA Ultimate, PhpStorm, PyCharm Professional and RubyMine
|
|
2513
|
-
all run ESLint natively, so the
|
|
2544
|
+
all run ESLint natively, so the nineteen rules appear inline, in the **Problems** tool window, and
|
|
2514
2545
|
under **Code → Inspect Code** for the whole project.
|
|
2515
2546
|
|
|
2516
2547
|
```js
|
|
@@ -2527,7 +2558,7 @@ has supported flat config since 2023.3); scope the block to spec files yourself;
|
|
|
2527
2558
|
the fixes and suggestions live.
|
|
2528
2559
|
|
|
2529
2560
|
A native JetBrains plugin is **not** planned — it would duplicate an integration the IDE already has
|
|
2530
|
-
and then keep a second copy of
|
|
2561
|
+
and then keep a second copy of nineteen rules, in Kotlin, in step with the TypeScript ones.
|
|
2531
2562
|
|
|
2532
2563
|
### VS Code, Cursor, Windsurf, VSCodium
|
|
2533
2564
|
|
package/dist/angular.d.ts
CHANGED
|
@@ -1,12 +1,101 @@
|
|
|
1
|
-
export { l as AngularTokenProvider, A as AngularValueProvider, a as AutoSpiedInstance, C as ComponentInputs, b as CreateWithAutoSpiesOptions, R as RenderShallowOptions, c as ResourceStatusLike, S as SettleResourceOptions, d as ShallowRender, e as SpyRegistry, f as StableOptions, g as createWithAutoSpies, h as flushEffects, i as injectSpy, p as provideAutoSpy, m as provideAutoSpyForToken, r as renderShallow, j as runEffect, s as settleResource, k as stable } from './zoneless-
|
|
2
|
-
import { Type, Signal, WritableSignal } from '@angular/core';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
export {
|
|
6
|
-
export {
|
|
1
|
+
export { l as AngularTokenProvider, A as AngularValueProvider, a as AutoSpiedInstance, C as ComponentInputs, b as CreateWithAutoSpiesOptions, R as RenderShallowOptions, c as ResourceStatusLike, S as SettleResourceOptions, d as ShallowRender, e as SpyRegistry, f as StableOptions, g as createWithAutoSpies, h as flushEffects, i as injectSpy, p as provideAutoSpy, m as provideAutoSpyForToken, r as renderShallow, j as runEffect, s as settleResource, k as stable } from './zoneless-DzUXGIYb.js';
|
|
2
|
+
import { InjectionToken, Provider, Type, Signal, WritableSignal } from '@angular/core';
|
|
3
|
+
import { TestAPI } from 'vitest';
|
|
4
|
+
import { C as ClassType, S as Spy, a as ClassSpyConfiguration, O as OnlyMethodKeysOf, j as AddSpyMethodsByReturnTypes } from './types-W5kEgzND.js';
|
|
5
|
+
export { I as InjectionLog, T as TrackInjectionsOptions, a as TrackedProvider, t as trackInjections } from './track-injections-BU-WSjji.js';
|
|
6
|
+
export { A as AccessorImplementations, R as RestoreProp, c as countMockedProps, m as mockAccessorsProp, a as mockReadonlyProp, b as mockReadonlyPropGetter, d as mockValueProp, r as restoreMockedProps } from './prop-mock-CEBKBA7k.js';
|
|
7
|
+
export { C as CallbackSubscribable, E as EmissionObserver, a as EmissionOptions, b as EmissionSource, S as SubscribableLike, e as expectCompletion, f as expectEmission, g as expectEmissions, h as expectError, i as expectNoEmission, s as setEmissionTimeout } from './expect-emission-COcg6YzT.js';
|
|
7
8
|
import '@angular/core/testing';
|
|
8
9
|
import 'rxjs';
|
|
9
|
-
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* `extendWithAutoSpies` — the `TestBed` half of a spec, moved into Vitest fixtures.
|
|
13
|
+
*
|
|
14
|
+
* The shape it replaces is in every Angular suite ever migrated:
|
|
15
|
+
*
|
|
16
|
+
* ```ts
|
|
17
|
+
* let cart: Spy<CartService>;
|
|
18
|
+
* let api: Spy<ApiService>;
|
|
19
|
+
*
|
|
20
|
+
* beforeEach(() => {
|
|
21
|
+
* TestBed.configureTestingModule({ providers: [provideAutoSpy(CartService), provideAutoSpy(ApiService)] });
|
|
22
|
+
* cart = injectSpy(CartService);
|
|
23
|
+
* api = injectSpy(ApiService);
|
|
24
|
+
* });
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* Five lines of ceremony per dependency, a `let` that is `undefined` between tests and a
|
|
28
|
+
* declaration whose type has to be repeated by hand. Vitest 4.1's builder form of `test.extend`
|
|
29
|
+
* infers the type from the factory, so the whole block becomes one statement — and a test that does
|
|
30
|
+
* not destructure `api` never builds it.
|
|
31
|
+
*
|
|
32
|
+
* **Why one call rather than a chain of `.extend`s.** The obvious composing form —
|
|
33
|
+
* `base.extend('cart', autoSpy(CartService)).extend('api', autoSpy(ApiService))` — cannot work, and
|
|
34
|
+
* the reason is `TestBed`, not typing. Fixtures resolve lazily and independently, so `cart` would
|
|
35
|
+
* configure the testing module and inject, which *instantiates* it; `api` would then reach
|
|
36
|
+
* `configureTestingModule` after instantiation and fail with Angular's own
|
|
37
|
+
* "Cannot configure the test module when the test module has already been instantiated". Every
|
|
38
|
+
* provider has to be known before the first injection, so the helper has to see them all at once.
|
|
39
|
+
*
|
|
40
|
+
* A `beforeEach` that configures the module further still composes, because it runs before any
|
|
41
|
+
* fixture resolves and `configureTestingModule` may be called repeatedly right up until the first
|
|
42
|
+
* injection. A `beforeEach` that *injects* does not — and that is the one case this cannot paper
|
|
43
|
+
* over, since by then Angular has already made the decision.
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* One entry of the map: a class, a class with the configuration {@link provideAutoSpy} takes, or an
|
|
48
|
+
* `InjectionToken` whose type argument is what the double is built from.
|
|
49
|
+
*/
|
|
50
|
+
type AutoSpyFixture = ClassType<any> | InjectionToken<unknown> | readonly [ClassType<any>, ...unknown[]];
|
|
51
|
+
/** What each entry of the map becomes in the test's context. */
|
|
52
|
+
type SpiedFixtures<Spec> = {
|
|
53
|
+
[Name in keyof Spec]: Spec[Name] extends InjectionToken<infer T> ? Spy<T> : Spec[Name] extends readonly [ClassType<infer T>, ...unknown[]] ? Spy<T> : Spec[Name] extends ClassType<infer T> ? Spy<T> : never;
|
|
54
|
+
};
|
|
55
|
+
/** Options for {@link extendWithAutoSpies}. */
|
|
56
|
+
interface ExtendWithAutoSpiesOptions {
|
|
57
|
+
/**
|
|
58
|
+
* Providers registered alongside the spies, in the same `configureTestingModule` call — the
|
|
59
|
+
* component under test, a real service the spec deliberately keeps, `provideHttpClient()`.
|
|
60
|
+
*
|
|
61
|
+
* They go in *before* the generated ones, so a provider named here wins over the auto-spy that
|
|
62
|
+
* would otherwise be made for the same token.
|
|
63
|
+
*/
|
|
64
|
+
providers?: Provider[];
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Turn a map of dependencies into typed `TestBed` fixtures.
|
|
68
|
+
*
|
|
69
|
+
* ```ts
|
|
70
|
+
* import { test as base } from 'vitest';
|
|
71
|
+
* import { extendWithAutoSpies } from 'vitest-auto-spy/angular';
|
|
72
|
+
*
|
|
73
|
+
* const test = extendWithAutoSpies(base, {
|
|
74
|
+
* cart: CartService,
|
|
75
|
+
* api: [ApiService, { methodsToSpyOn: ['get'] }],
|
|
76
|
+
* passcode: PASSCODE_TOKEN,
|
|
77
|
+
* });
|
|
78
|
+
*
|
|
79
|
+
* test('checks out', async ({ cart }) => {
|
|
80
|
+
* cart.checkout.resolveWith(true);
|
|
81
|
+
*
|
|
82
|
+
* await expect(cart.checkout(1)).resolves.toBe(true);
|
|
83
|
+
* });
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* The testing module is configured **once per test**, the first time any of the fixtures is
|
|
87
|
+
* touched, and the flag that remembers it is released on cleanup — a fixture object outlives the
|
|
88
|
+
* test that used it, and a module configured for the previous one is the shape that makes an
|
|
89
|
+
* Angular suite fail depending on order.
|
|
90
|
+
*
|
|
91
|
+
* Needs **Vitest 4.1 or newer**: the builder form of `test.extend` it is written against is what
|
|
92
|
+
* infers a fixture's type from its factory, and older versions have only the object form.
|
|
93
|
+
*
|
|
94
|
+
* @param base The `test` to extend — Vitest's own, or one already carrying fixtures of yours.
|
|
95
|
+
* @param spec Fixture name to dependency. A bare class, `[Class, config]` with what
|
|
96
|
+
* {@link provideAutoSpy} accepts, or an `InjectionToken`.
|
|
97
|
+
*/
|
|
98
|
+
declare function extendWithAutoSpies<Context, const Spec extends Record<string, AutoSpyFixture>>(base: TestAPI<Context>, spec: Spec, { providers }?: ExtendWithAutoSpiesOptions): TestAPI<Context & SpiedFixtures<Spec>>;
|
|
10
99
|
|
|
11
100
|
/**
|
|
12
101
|
* Overriding what a *component* provides, and the diagnostic for the bundle that makes it necessary.
|
|
@@ -615,4 +704,4 @@ declare function reportSpecTiming(timing: SpecTiming): void;
|
|
|
615
704
|
*/
|
|
616
705
|
declare function enableTestBedDiagnostics(options?: TestBedDiagnosticsOptions): void;
|
|
617
706
|
|
|
618
|
-
export { type AngularDiagnosticsOptions, type AngularTestEnvMode, type AngularTestEnvOptions, type AutoSpyOverride, type DirectiveHostOptions, type MockedResource, type ResourceDouble, type ResourceDoubleStatus, type ResourceLike, type SignalLike, type SpecTiming, type TestBedDiagnosticsOptions, assertComponentDefIntact, assertNgModuleScopes, assertNoPendingRequests, createDirectiveHost, disableAngularDiagnostics, disableTestBedDiagnostics, enableAngularDiagnostics, enableTestBedDiagnostics, formatSpecTiming, getTestBedTiming, instrumentTestBed, mockResourceProp, mockSignalProp, overrideAutoSpy, overrideComponentProvider, registerDirectiveMatchers, registerResourceMatchers, registerSignalMatchers, reportSpecTiming, setupAngularTestEnv };
|
|
707
|
+
export { type AngularDiagnosticsOptions, type AngularTestEnvMode, type AngularTestEnvOptions, type AutoSpyFixture, type AutoSpyOverride, type DirectiveHostOptions, type ExtendWithAutoSpiesOptions, type MockedResource, type ResourceDouble, type ResourceDoubleStatus, type ResourceLike, type SignalLike, type SpecTiming, type SpiedFixtures, type TestBedDiagnosticsOptions, assertComponentDefIntact, assertNgModuleScopes, assertNoPendingRequests, createDirectiveHost, disableAngularDiagnostics, disableTestBedDiagnostics, enableAngularDiagnostics, enableTestBedDiagnostics, extendWithAutoSpies, formatSpecTiming, getTestBedTiming, instrumentTestBed, mockResourceProp, mockSignalProp, overrideAutoSpy, overrideComponentProvider, registerDirectiveMatchers, registerResourceMatchers, registerSignalMatchers, reportSpecTiming, setupAngularTestEnv };
|
package/dist/angular.js
CHANGED
|
@@ -2,7 +2,7 @@ import { guardAccessorSpies, registerMockAdapter, getMockAdapter, getObservableS
|
|
|
2
2
|
export { expectCompletion, expectEmission, expectEmissions, expectError, expectNoEmission, setEmissionTimeout } from './shared-state.js';
|
|
3
3
|
import { vi, expect, beforeAll, afterAll, beforeEach, afterEach } from 'vitest';
|
|
4
4
|
import { TestBed, getTestBed } from '@angular/core/testing';
|
|
5
|
-
import { isStandalone, Component, Injector, runInInjectionContext, NO_ERRORS_SCHEMA, ApplicationRef, signal, computed, ɵSIGNAL as _SIGNAL } from '@angular/core';
|
|
5
|
+
import { isStandalone, Component, Injector, runInInjectionContext, NO_ERRORS_SCHEMA, ApplicationRef, signal, computed, ɵSIGNAL as _SIGNAL, InjectionToken } from '@angular/core';
|
|
6
6
|
import { By } from '@angular/platform-browser';
|
|
7
7
|
|
|
8
8
|
// src/lib/use-vitest-adapter.ts
|
|
@@ -410,6 +410,7 @@ function addPromiseHelpersToFunctionSpy(spyFunction, valueContainer) {
|
|
|
410
410
|
addPromiseHelpers(spyFunction, (container) => {
|
|
411
411
|
valueContainer.value = container.value;
|
|
412
412
|
valueContainer._isRejectedPromise = container._isRejectedPromise ?? false;
|
|
413
|
+
valueContainer._isThrown = false;
|
|
413
414
|
valueContainer.valuesPerCalls = container.valuesPerCalls ?? [];
|
|
414
415
|
});
|
|
415
416
|
}
|
|
@@ -522,6 +523,9 @@ function isReturnValueContainer(value) {
|
|
|
522
523
|
return typeof value === "object" && value !== null && "value" in value;
|
|
523
524
|
}
|
|
524
525
|
function unwrapContainer(container) {
|
|
526
|
+
if (container._isThrown) {
|
|
527
|
+
throw container.value;
|
|
528
|
+
}
|
|
525
529
|
if (container._isRejectedPromise) {
|
|
526
530
|
return Promise.reject(container.value);
|
|
527
531
|
}
|
|
@@ -556,7 +560,7 @@ function resolveUnstubbedGuard(className2, config) {
|
|
|
556
560
|
}
|
|
557
561
|
function isUnconfigured(state) {
|
|
558
562
|
const container = state.valueContainer;
|
|
559
|
-
return state.calledWith === void 0 && state.mustBeCalledWith === void 0 && container.value === void 0 && !container._isRejectedPromise && !container.valuesPerCalls?.length;
|
|
563
|
+
return state.calledWith === void 0 && state.mustBeCalledWith === void 0 && container.value === void 0 && !container._isRejectedPromise && !container._isThrown && !container.valuesPerCalls?.length;
|
|
560
564
|
}
|
|
561
565
|
function lookupConfigured(calledWithObject, actualArgs) {
|
|
562
566
|
const configured = calledWithObject.argsToValuesMap.get(actualArgs);
|
|
@@ -588,7 +592,10 @@ function addMethodsToCalledWith(calledWith, calledWithArgs) {
|
|
|
588
592
|
decorate(calledWith, {
|
|
589
593
|
mockReturnValue: setReturnValue,
|
|
590
594
|
// `returnValue` is the `jest-auto-spies` name — aliased so migrating tests need no rewrite.
|
|
591
|
-
returnValue: setReturnValue
|
|
595
|
+
returnValue: setReturnValue,
|
|
596
|
+
failWith: (error) => {
|
|
597
|
+
calledWith.argsToValuesMap.set(calledWithArgs, { value: error, _isThrown: true });
|
|
598
|
+
}
|
|
592
599
|
});
|
|
593
600
|
addPromiseHelpersToCalledWithObject(calledWith, calledWithArgs);
|
|
594
601
|
getObservableSupport()?.addToCalledWithObject(calledWith, calledWithArgs);
|
|
@@ -617,6 +624,22 @@ function createFunctionSpy(name, unstubbed) {
|
|
|
617
624
|
addPromiseHelpersToFunctionSpy(functionSpy, valueContainer);
|
|
618
625
|
const resetObservableStream = getObservableSupport()?.addToFunctionSpy(functionSpy, valueContainer);
|
|
619
626
|
const spy = decorate(functionSpy, {
|
|
627
|
+
// The sync twin of `resolveWith` / `nextWith`, and the reason it is here rather than left to
|
|
628
|
+
// the runner: Vitest 4.1 grew `mockThrow`, but Bun and `node:test` have nothing like it, and
|
|
629
|
+
// no runtime has a way to make a *`calledWith` chain* throw — `mockImplementation` replaces the
|
|
630
|
+
// whole dispatch, which is the opposite of configuring one set of arguments.
|
|
631
|
+
//
|
|
632
|
+
// `failWith` and not `throwWith`, which is the name the shape asks for: `throwWith` is already
|
|
633
|
+
// the observable helper that *errors the stream*, it is attached to every spy at runtime (the
|
|
634
|
+
// return type that tells the two apart exists only in the types), and whichever is installed
|
|
635
|
+
// last wins. Sharing the name therefore breaks one of them on every spy in the run — which it
|
|
636
|
+
// did, loudly, the first time this was written that way.
|
|
637
|
+
failWith: (error) => {
|
|
638
|
+
valueContainer.value = error;
|
|
639
|
+
valueContainer._isThrown = true;
|
|
640
|
+
valueContainer._isRejectedPromise = false;
|
|
641
|
+
valueContainer.valuesPerCalls = [];
|
|
642
|
+
},
|
|
620
643
|
calledWith: (...calledWithArgs) => addMethodsToCalledWith(ensureCalledWithObject(state, "calledWith"), calledWithArgs),
|
|
621
644
|
mustBeCalledWith: (...calledWithArgs) => addMethodsToCalledWith(ensureCalledWithObject(state, "mustBeCalledWith"), calledWithArgs)
|
|
622
645
|
});
|
|
@@ -631,6 +654,7 @@ function createFunctionSpy(name, unstubbed) {
|
|
|
631
654
|
delete state.mustBeCalledWith;
|
|
632
655
|
valueContainer.value = void 0;
|
|
633
656
|
delete valueContainer._isRejectedPromise;
|
|
657
|
+
delete valueContainer._isThrown;
|
|
634
658
|
delete valueContainer.valuesPerCalls;
|
|
635
659
|
resetObservableStream?.();
|
|
636
660
|
getMockAdapter().restoreImplementation(functionSpy, dispatch);
|
|
@@ -1288,6 +1312,65 @@ function reportWhenNotASpy(token, injected) {
|
|
|
1288
1312
|
reportedTokens.add(token);
|
|
1289
1313
|
console.warn(message);
|
|
1290
1314
|
}
|
|
1315
|
+
function toBuilder(api) {
|
|
1316
|
+
return api;
|
|
1317
|
+
}
|
|
1318
|
+
function fromBuilder(builder) {
|
|
1319
|
+
return builder;
|
|
1320
|
+
}
|
|
1321
|
+
function supportsBuilderExtend(api) {
|
|
1322
|
+
const extend = Reflect.get(api, "extend");
|
|
1323
|
+
return typeof extend === "function" && extend.length >= 2;
|
|
1324
|
+
}
|
|
1325
|
+
function isToken(fixture) {
|
|
1326
|
+
return fixture instanceof InjectionToken;
|
|
1327
|
+
}
|
|
1328
|
+
function providerFor(fixture) {
|
|
1329
|
+
if (isToken(fixture)) {
|
|
1330
|
+
return provideAutoSpyForToken(fixture);
|
|
1331
|
+
}
|
|
1332
|
+
if (Array.isArray(fixture)) {
|
|
1333
|
+
const [ObjectClass, config] = fixture;
|
|
1334
|
+
return provideAutoSpy(ObjectClass, config);
|
|
1335
|
+
}
|
|
1336
|
+
return provideAutoSpy(fixture);
|
|
1337
|
+
}
|
|
1338
|
+
function tokenFor(fixture) {
|
|
1339
|
+
if (isToken(fixture)) {
|
|
1340
|
+
return fixture;
|
|
1341
|
+
}
|
|
1342
|
+
return Array.isArray(fixture) ? fixture[0] : fixture;
|
|
1343
|
+
}
|
|
1344
|
+
function extendWithAutoSpies(base, spec, { providers = [] } = {}) {
|
|
1345
|
+
if (!supportsBuilderExtend(base)) {
|
|
1346
|
+
throw new Error(
|
|
1347
|
+
withDocs(
|
|
1348
|
+
'[vitest-auto-spy] extendWithAutoSpies needs Vitest 4.1 or newer: the `test` handed in has only the object form of `extend` (Vitest 4.0 and below), which would register fixtures named "0", "1", \u2026 and hand every test `undefined`. Upgrade Vitest, or keep `provideAutoSpy` + `injectSpy` in a `beforeEach` until then.',
|
|
1349
|
+
DOCS_LINKS.angular
|
|
1350
|
+
)
|
|
1351
|
+
);
|
|
1352
|
+
}
|
|
1353
|
+
const entries = Object.entries(spec);
|
|
1354
|
+
let configured = false;
|
|
1355
|
+
const configureOnce = (onCleanup) => {
|
|
1356
|
+
if (configured) {
|
|
1357
|
+
return;
|
|
1358
|
+
}
|
|
1359
|
+
configured = true;
|
|
1360
|
+
onCleanup(() => {
|
|
1361
|
+
configured = false;
|
|
1362
|
+
});
|
|
1363
|
+
TestBed.configureTestingModule({ providers: [...providers, ...entries.map(([, fixture]) => providerFor(fixture))] });
|
|
1364
|
+
};
|
|
1365
|
+
let builder = toBuilder(base);
|
|
1366
|
+
for (const [name, fixture] of entries) {
|
|
1367
|
+
builder = builder.extend(name, ({}, { onCleanup }) => {
|
|
1368
|
+
configureOnce(onCleanup);
|
|
1369
|
+
return injectSpy(tokenFor(fixture));
|
|
1370
|
+
});
|
|
1371
|
+
}
|
|
1372
|
+
return fromBuilder(builder);
|
|
1373
|
+
}
|
|
1291
1374
|
var INSTRUMENTED = [
|
|
1292
1375
|
{ method: "configureTestingModule", counter: "configurations" },
|
|
1293
1376
|
{ method: "createComponent", counter: "components" },
|
|
@@ -2154,4 +2237,4 @@ function registerSignalMatchers() {
|
|
|
2154
2237
|
}
|
|
2155
2238
|
useVitestAdapter();
|
|
2156
2239
|
|
|
2157
|
-
export { assertComponentDefIntact, assertNgModuleScopes, assertNoPendingRequests, countMockedProps, createDirectiveHost, createWithAutoSpies, disableAngularDiagnostics, disableTestBedDiagnostics, enableAngularDiagnostics, enableTestBedDiagnostics, flushEffects, formatSpecTiming, getTestBedTiming, injectSpy, instrumentTestBed, mockAccessorsProp, mockReadonlyProp, mockReadonlyPropGetter, mockResourceProp, mockSignalProp, mockValueProp, overrideAutoSpy, overrideComponentProvider, provideAutoSpy, provideAutoSpyForToken, registerDirectiveMatchers, registerResourceMatchers, registerSignalMatchers, renderShallow, reportSpecTiming, restoreMockedProps, runEffect, settleResource, setupAngularTestEnv, stable, trackInjections };
|
|
2240
|
+
export { assertComponentDefIntact, assertNgModuleScopes, assertNoPendingRequests, countMockedProps, createDirectiveHost, createWithAutoSpies, disableAngularDiagnostics, disableTestBedDiagnostics, enableAngularDiagnostics, enableTestBedDiagnostics, extendWithAutoSpies, flushEffects, formatSpecTiming, getTestBedTiming, injectSpy, instrumentTestBed, mockAccessorsProp, mockReadonlyProp, mockReadonlyPropGetter, mockResourceProp, mockSignalProp, mockValueProp, overrideAutoSpy, overrideComponentProvider, provideAutoSpy, provideAutoSpyForToken, registerDirectiveMatchers, registerResourceMatchers, registerSignalMatchers, renderShallow, reportSpecTiming, restoreMockedProps, runEffect, settleResource, setupAngularTestEnv, stable, trackInjections };
|
package/dist/bun-angular.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export { d as AccessorKeysOf, e as AddAccessorsSpies, f as AddCalledWithObservable, g as AddCalledWithPromise, h as AddCalledWithSpyMethods, A as AddObservableSpyMethods, i as AddPromiseSpyMethods, j as AddSpyMethodsByReturnTypes, k as AddVoidReturnHelpers, a as ClassSpyConfiguration, C as ClassType, b as CompleteValueConfig, D as DeepMockProxy,
|
|
1
|
+
export { d as AccessorKeysOf, e as AddAccessorsSpies, f as AddCalledWithObservable, g as AddCalledWithPromise, h as AddCalledWithSpyMethods, A as AddObservableSpyMethods, i as AddPromiseSpyMethods, j as AddSpyMethodsByReturnTypes, k as AddThrowHelper, l as AddVoidReturnHelpers, a as ClassSpyConfiguration, C as ClassType, b as CompleteValueConfig, D as DeepMockProxy, m as DeepPartial, E as ErrorValueConfig, F as Func, M as MethodReturns, n as Mutable, N as NextValueConfig, O as OnlyMethodKeysOf, o as OnlyObservablePropsOf, p as OnlyPropsOf, q as Overload, r as Overloads, P as PropStubValue, S as Spy, s as SpyDisposable, t as SpyOptions, u as StrictSpyConfiguration, U as UnstubbedCall, v as UnstubbedCallHandler, V as ValueConfig, c as ValueConfigPerCall, W as WithMockReturnValue } from './types-W5kEgzND.js';
|
|
2
2
|
export { ArgCaptor, AsInstances, AssertMockedOptions, ConstructorMock, ConstructorSpy, FixtureFactory, FlushUntilOptions, IntersectionObserverStubOptions, MediaElementState, MediaElementStub, MediaElementStubOptions, MockDeepOptions, ModuleNamespace, ModuleNamespaceOptions, MutationRecordInit, ObserverGlobal, ObserverInstance, ObserverStub, ObserverStubOptions, ResizeEntryRect, TestRunComparison, TestRunReport, TestRunSummary, asInstance, asInstances, asSpy, assertMocked, captureArg, clearAutoSpy, compareTestRuns, createFixture, createFixtureFactory, createFunctionSpy, createMock, createSpyClass, createSpyFromClass, diffByField, errorHandler, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resetAutoSpy, resizeEntry, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides } from './bun.js';
|
|
3
|
-
export { A as AutoMockConfiguration, C as CallbackSubscribable, E as EmissionObserver, a as EmissionOptions, b as EmissionSource, S as SubscribableLike, c as autoMocked, d as createAutoMock, e as expectCompletion, f as expectEmission, g as expectEmissions, h as expectError, i as expectNoEmission, s as setEmissionTimeout } from './expect-emission-
|
|
4
|
-
export { A as AccessorImplementations, R as RestoreProp, c as countMockedProps, m as mockAccessorsProp, a as mockReadonlyProp, b as mockReadonlyPropGetter, d as mockValueProp, r as restoreMockedProps } from './prop-mock-
|
|
3
|
+
export { A as AutoMockConfiguration, C as CallbackSubscribable, E as EmissionObserver, a as EmissionOptions, b as EmissionSource, S as SubscribableLike, c as autoMocked, d as createAutoMock, e as expectCompletion, f as expectEmission, g as expectEmissions, h as expectError, i as expectNoEmission, s as setEmissionTimeout } from './expect-emission-COcg6YzT.js';
|
|
4
|
+
export { A as AccessorImplementations, R as RestoreProp, c as countMockedProps, m as mockAccessorsProp, a as mockReadonlyProp, b as mockReadonlyPropGetter, d as mockValueProp, r as restoreMockedProps } from './prop-mock-CEBKBA7k.js';
|
|
5
5
|
export { d as describeDuplicateCopies, g as getPackageCopies } from './package-identity-B1pqa-Sh.js';
|
|
6
|
-
export { A as AngularValueProvider, a as AutoSpiedInstance, C as ComponentInputs, b as CreateWithAutoSpiesOptions, R as RenderShallowOptions, c as ResourceStatusLike, S as SettleResourceOptions, d as ShallowRender, e as SpyRegistry, f as StableOptions, g as createWithAutoSpies, h as flushEffects, i as injectSpy, p as provideAutoSpy, r as renderShallow, j as runEffect, s as settleResource, k as stable } from './zoneless-
|
|
6
|
+
export { A as AngularValueProvider, a as AutoSpiedInstance, C as ComponentInputs, b as CreateWithAutoSpiesOptions, R as RenderShallowOptions, c as ResourceStatusLike, S as SettleResourceOptions, d as ShallowRender, e as SpyRegistry, f as StableOptions, g as createWithAutoSpies, h as flushEffects, i as injectSpy, p as provideAutoSpy, r as renderShallow, j as runEffect, s as settleResource, k as stable } from './zoneless-DzUXGIYb.js';
|
|
7
7
|
import 'rxjs';
|
|
8
8
|
import 'vitest';
|
|
9
9
|
import '@angular/core';
|