vitest-auto-spy 3.7.0 → 3.8.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 +69 -19
- package/README.md +103 -5
- package/dist/angular.d.ts +150 -8
- package/dist/angular.js +118 -3
- package/dist/bun-angular.d.ts +5 -5
- package/dist/bun-angular.js +1 -1
- package/dist/bun.d.ts +58 -12
- package/dist/bun.js +1 -1
- package/dist/{chunk-R5MFTE64.js → chunk-ISSGEVLO.js} +46 -1
- package/dist/cli.js +1150 -0
- package/dist/console.d.ts +1 -1
- package/dist/{expect-emission-RtR1iYgI.d.ts → expect-emission-Cpj2GGcD.d.ts} +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1 -1
- package/dist/nestjs.d.ts +1 -1
- package/dist/node.cjs +46 -0
- package/dist/node.d.cts +60 -1828
- package/dist/node.d.ts +4 -4
- package/dist/node.js +1 -1
- package/dist/{prop-mock-CKFksCvA.d.ts → prop-mock-CeHqAeIG.d.ts} +1 -1
- package/dist/react.d.ts +4 -4
- package/dist/react.js +1 -1
- package/dist/rxjs.d.ts +2 -2
- package/dist/setup.d.ts +2 -2
- package/dist/svelte.d.ts +4 -4
- package/dist/svelte.js +1 -1
- package/dist/{types-dZUFYsox.d.ts → types-W3lPrwC7.d.ts} +3 -3
- package/dist/vue.d.ts +5 -5
- package/dist/vue.js +1 -1
- package/dist/{zoneless-DbVZ96iR.d.ts → zoneless-Ch2Ym_6z.d.ts} +7 -7
- package/package.json +7 -3
- package/skills/vitest-auto-spy/SKILL.md +19 -3
package/AGENTS.md
CHANGED
|
@@ -269,7 +269,7 @@ import { type Spy, injectSpy, mockReadonlyProp, provideAutoSpy } from 'vitest-au
|
|
|
269
269
|
|
|
270
270
|
describe('TaskService', () => {
|
|
271
271
|
let projects: Spy<ProjectStore>;
|
|
272
|
-
let feed: Spy<
|
|
272
|
+
let feed: Spy<NewsFeedService>;
|
|
273
273
|
let service: TaskService;
|
|
274
274
|
|
|
275
275
|
beforeEach(() => {
|
|
@@ -277,12 +277,12 @@ describe('TaskService', () => {
|
|
|
277
277
|
providers: [
|
|
278
278
|
provideAutoSpy(NotificationService), // plain service — nothing to configure
|
|
279
279
|
provideAutoSpy(ProjectStore, { instanceMethodsToSpyOn: ['current', 'isEmpty'] }), // signals
|
|
280
|
-
provideAutoSpy(
|
|
280
|
+
provideAutoSpy(NewsFeedService, { observablePropsToSpyOn: ['connected$'] }), // Observable props
|
|
281
281
|
],
|
|
282
282
|
});
|
|
283
283
|
|
|
284
284
|
projects = injectSpy(ProjectStore);
|
|
285
|
-
feed = injectSpy(
|
|
285
|
+
feed = injectSpy(NewsFeedService);
|
|
286
286
|
|
|
287
287
|
feed.connected$.nextWith(true); // seed the defaults every test needs, once
|
|
288
288
|
projects.save.mockReturnValue(of(true));
|
|
@@ -369,6 +369,27 @@ const subject = feed.items$.returnSubject(); // ReplaySubject, for anything the
|
|
|
369
369
|
`mock.settledResults` is native on Vitest and polyfilled on Bun / `node:test`, so it is identical on
|
|
370
370
|
all three. Entries are `{ type: 'fulfilled' | 'incomplete' | 'rejected', value }`.
|
|
371
371
|
|
|
372
|
+
When the argument worth asserting on is one the **code under test built** — a callback, a config
|
|
373
|
+
object, an `AbortSignal` — describing its shape is the wrong tool. `expect.any(Function)` says a
|
|
374
|
+
function was passed; `captureArg` hands it to you so the test can call it:
|
|
375
|
+
|
|
376
|
+
```ts
|
|
377
|
+
import { captureArg } from 'vitest-auto-spy';
|
|
378
|
+
|
|
379
|
+
const onDone = captureArg<() => void>();
|
|
380
|
+
|
|
381
|
+
expect(notifier.subscribe).toHaveBeenCalledWith('ready', onDone);
|
|
382
|
+
|
|
383
|
+
onDone.value(); // and now exercise what was passed
|
|
384
|
+
expect(component.finished()).toBe(true);
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
`.values` holds every match, oldest first; `.captured` asks without triggering the "nothing was
|
|
388
|
+
captured" throw; `.reset()` lets one captor serve two phases. **Assertions only** — a captor matches
|
|
389
|
+
every value, so putting one in `calledWith` would configure a return for every call, which is
|
|
390
|
+
`mockReturnValue` spelled less clearly, and `calledWith` is typed to the method's own parameters so
|
|
391
|
+
it will not compile anyway.
|
|
392
|
+
|
|
372
393
|
**The observable helpers are backed by a `ReplaySubject(1)` that belongs to the spy, and it is
|
|
373
394
|
configuration — so it must be reset with the rest of it.** Two failures used to come out of that
|
|
374
395
|
buffer outliving the test that filled it, and both were silent:
|
|
@@ -569,8 +590,8 @@ constructor and produces `Service<any>`, and the `any` surfaces much later as a
|
|
|
569
590
|
it says "type parameter":
|
|
570
591
|
|
|
571
592
|
```ts
|
|
572
|
-
const config = asSpy<
|
|
573
|
-
const config = injectSpy<
|
|
593
|
+
const config = asSpy<FeatureFlagService>(TestBed.inject(FeatureFlagService)); // ✅
|
|
594
|
+
const config = injectSpy<FeatureFlagService>(FeatureFlagService); // ✅
|
|
574
595
|
```
|
|
575
596
|
|
|
576
597
|
---
|
|
@@ -1166,10 +1187,10 @@ inlined when the mock would be installed, so the real implementation runs and th
|
|
|
1166
1187
|
for the wrong reason or fails somewhere unrelated.
|
|
1167
1188
|
|
|
1168
1189
|
```ts
|
|
1169
|
-
import * as engine from '@app/
|
|
1190
|
+
import * as engine from '@app/pricing-engine';
|
|
1170
1191
|
|
|
1171
|
-
vi.mock('@app/
|
|
1172
|
-
beforeEach(() => assertMocked(engine, { specifier: '@app/
|
|
1192
|
+
vi.mock('@app/pricing-engine');
|
|
1193
|
+
beforeEach(() => assertMocked(engine, { specifier: '@app/pricing-engine', exports: ['createEngine'] }));
|
|
1173
1194
|
```
|
|
1174
1195
|
|
|
1175
1196
|
And when a mocked dependency probes itself with `mod.default ?? mod` — every package that ships both
|
|
@@ -1215,7 +1236,7 @@ result:
|
|
|
1215
1236
|
```ts
|
|
1216
1237
|
provideAutoSpy(FavoritesService, {
|
|
1217
1238
|
returns: { load: of([]) },
|
|
1218
|
-
overrides: { favoritesCacheUpdated$: of(undefined),
|
|
1239
|
+
overrides: { favoritesCacheUpdated$: of(undefined), favoriteItems: [] },
|
|
1219
1240
|
});
|
|
1220
1241
|
|
|
1221
1242
|
provideAutoSpyForToken(PRODUCTS, undefined, { returns: { getProducts: of([]), getById: of(null) } });
|
|
@@ -1338,8 +1359,8 @@ nodes, so the helper silently rips the element out of the fixture it was just as
|
|
|
1338
1359
|
Worth reading before the rest of this section: it has now come up twice in one migration wave, and
|
|
1339
1360
|
both times the failure landed in a different file from its cause.
|
|
1340
1361
|
|
|
1341
|
-
`@Component({ providers: [
|
|
1342
|
-
injector, and a module-level `provideAutoSpy(
|
|
1362
|
+
`@Component({ providers: [DeleteAccountService] })` declares the provider on the **element**
|
|
1363
|
+
injector, and a module-level `provideAutoSpy(DeleteAccountService)` in `configureTestingModule`
|
|
1343
1364
|
loses to it — so the component builds the **real** service. Nothing warns. What fails is whatever
|
|
1344
1365
|
the real service touches first: in the observed case a logger, with
|
|
1345
1366
|
`TypeError: Cannot read properties of undefined (reading 'pipe')`, which names neither the component
|
|
@@ -1349,10 +1370,10 @@ Two things fix it, and which one depends on whether the double is wanted:
|
|
|
1349
1370
|
|
|
1350
1371
|
```ts
|
|
1351
1372
|
// keep a double, but put it where the component will look
|
|
1352
|
-
const menu = overrideComponentProvider(
|
|
1373
|
+
const menu = overrideComponentProvider(CatalogPageComponent, NavigationBuilderService);
|
|
1353
1374
|
|
|
1354
1375
|
// or take the component's own provider away, so the module-level one is reached again
|
|
1355
|
-
TestBed.overrideComponent(ProfileComponent, { remove: { providers: [
|
|
1376
|
+
TestBed.overrideComponent(ProfileComponent, { remove: { providers: [DeleteAccountService] } });
|
|
1356
1377
|
```
|
|
1357
1378
|
|
|
1358
1379
|
`overrideComponentProvider` is the one to reach for by default — it also queues the component with
|
|
@@ -1377,10 +1398,10 @@ do that, because a testing-module provider loses to one the component declares:
|
|
|
1377
1398
|
```ts
|
|
1378
1399
|
import { overrideAutoSpy, overrideComponentProvider } from 'vitest-auto-spy/angular';
|
|
1379
1400
|
|
|
1380
|
-
const menu = overrideComponentProvider(
|
|
1401
|
+
const menu = overrideComponentProvider(CatalogPageComponent, NavigationBuilderService); // → Spy<NavigationBuilderService>
|
|
1381
1402
|
|
|
1382
1403
|
// or, when the component is already in the testing module:
|
|
1383
|
-
TestBed.configureTestingModule({ … }).overrideProvider(
|
|
1404
|
+
TestBed.configureTestingModule({ … }).overrideProvider(PaymentMethodService, overrideAutoSpy(PaymentMethodService));
|
|
1384
1405
|
```
|
|
1385
1406
|
|
|
1386
1407
|
`overrideProvider(X, provideAutoSpy(X))` is **not** broken, contrary to what this section used to
|
|
@@ -1489,9 +1510,20 @@ flushEffects(); // an httpResource issues NO request until something ticks
|
|
|
1489
1510
|
httpTesting.expectOne('/api/products').flush([product]);
|
|
1490
1511
|
await settleResource(products, { label: 'the product resource' });
|
|
1491
1512
|
|
|
1513
|
+
// ...or skip the request entirely when it is not what the spec is about
|
|
1514
|
+
const products = mockResourceProp(service, 'products', []);
|
|
1515
|
+
products.set([product]); // 'resolved' products.loading() products.fail('offline')
|
|
1516
|
+
expect(products.reload).toHaveBeenCalled(); // reload is spied, and re-issues nothing
|
|
1517
|
+
|
|
1492
1518
|
// signal assertions
|
|
1493
1519
|
registerSignalMatchers(); // once, in the setup file
|
|
1494
1520
|
expect(component.total).toHaveSignalValue(3);
|
|
1521
|
+
|
|
1522
|
+
// resource assertions — value AND status, which is the whole point
|
|
1523
|
+
registerResourceMatchers(); // once, in the setup file
|
|
1524
|
+
expect(component.products).toBeLoading();
|
|
1525
|
+
expect(component.products).toHaveResourceValue([product]);
|
|
1526
|
+
expect(component.products).toHaveResourceError(/503/);
|
|
1495
1527
|
```
|
|
1496
1528
|
|
|
1497
1529
|
Two zoneless traps:
|
|
@@ -1507,6 +1539,13 @@ that asserts too early asserts the default and passes. `settleResource` fails in
|
|
|
1507
1539
|
emptily. Note the order — `flushEffects()` first (the request is issued there, not on creation),
|
|
1508
1540
|
then the flush, then the wait.
|
|
1509
1541
|
|
|
1542
|
+
`toHaveResourceValue` is the matcher form of that trap and the reason to prefer it over
|
|
1543
|
+
`expect(products.value()).toEqual(...)`: it **fails an unresolved resource even when the default
|
|
1544
|
+
value matches**, and names the status it was in. And when the request is not what the spec is about
|
|
1545
|
+
at all, do not arrange one — `mockResourceProp(service, 'products', [])` replaces the property with
|
|
1546
|
+
a double whose `set` / `fail` / `loading` move it directly, built from real `signal()`s so a
|
|
1547
|
+
`computed()` downstream still recomputes. Nothing is in flight, so there is nothing to await.
|
|
1548
|
+
|
|
1510
1549
|
Per-file timing, to find which specs actually pay for `TestBed`:
|
|
1511
1550
|
|
|
1512
1551
|
```ts
|
|
@@ -1528,8 +1567,10 @@ if (process.env['SPEC_TIMING']) {
|
|
|
1528
1567
|
preload = ["vitest-auto-spy/bun-angular"]
|
|
1529
1568
|
```
|
|
1530
1569
|
|
|
1531
|
-
It re-exports everything in this section except `registerSignalMatchers
|
|
1532
|
-
|
|
1570
|
+
It re-exports everything in this section except `registerSignalMatchers`,
|
|
1571
|
+
`registerResourceMatchers`, `mockSignalProp` / `mockResourceProp` and the TestBed diagnostics — the
|
|
1572
|
+
matchers and diagnostics need the runner's `expect.extend` and suite-level hooks, and the `mock*Prop`
|
|
1573
|
+
family is not re-exported there either.
|
|
1533
1574
|
|
|
1534
1575
|
---
|
|
1535
1576
|
|
|
@@ -1557,8 +1598,8 @@ which platform and which providers is not this library's decision.
|
|
|
1557
1598
|
### A dependency behind an `InjectionToken`
|
|
1558
1599
|
|
|
1559
1600
|
```ts
|
|
1560
|
-
providers: [provideAutoSpyForToken(
|
|
1561
|
-
const
|
|
1601
|
+
providers: [provideAutoSpyForToken(PASSCODE_SERVICE_TOKEN)];
|
|
1602
|
+
const passcode = injectSpy(PASSCODE_SERVICE_TOKEN); // Spy<PasscodeService>
|
|
1562
1603
|
```
|
|
1563
1604
|
|
|
1564
1605
|
A token typed with an interface has no class to read, so the habit is a `…Mock` class written in the
|
|
@@ -1918,11 +1959,20 @@ Run what the project actually has — check its `package.json` first.
|
|
|
1918
1959
|
```bash
|
|
1919
1960
|
npx vitest run path/to/file.spec.ts # or: bun test path/to/file.test.ts
|
|
1920
1961
|
npx tsc --noEmit # Spy<T> mistakes are compile errors, not runtime ones
|
|
1962
|
+
npx vitest-auto-spy doctor # suite-level defects that never fail a run
|
|
1921
1963
|
```
|
|
1922
1964
|
|
|
1923
1965
|
Type errors matter here more than usual: most of this library's guarantees are type-level, so a
|
|
1924
1966
|
suite that runs green but does not type-check is not done.
|
|
1925
1967
|
|
|
1968
|
+
`doctor` is read-only and finds what a green run cannot: a `tsconfig` `include` pattern that
|
|
1969
|
+
matches no file (so it type-checks nothing while `tsc --noEmit` still reports success), a
|
|
1970
|
+
production module importing a `*.spec.ts`, a spec importing another spec, a `@jest-environment`
|
|
1971
|
+
pragma the runner never reads, and configuration left behind for a runner that is gone. It is
|
|
1972
|
+
worth one run after any large edit to a test suite — especially after a codemod, which is where
|
|
1973
|
+
the eaten glob below came from. Full reference:
|
|
1974
|
+
<https://asdalexey.github.io/vitest-auto-spy/utilities/cli>.
|
|
1975
|
+
|
|
1926
1976
|
### If you are writing a codemod over specs
|
|
1927
1977
|
|
|
1928
1978
|
Two traps, both found the hard way on rxjs-heavy code.
|
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ identical API, with **RxJS** spies and **Angular / NestJS / React / Vue·Pinia /
|
|
|
16
16
|
[](https://www.npmjs.com/package/vitest-auto-spy)
|
|
17
17
|
[](https://www.npmjs.com/package/vitest-auto-spy)
|
|
18
18
|
[](https://github.com/ASDAlexey/vitest-auto-spy/actions/workflows/ci.yml)
|
|
19
|
-
[](#install)
|
|
20
20
|
[](https://www.npmjs.com/package/vitest-auto-spy)
|
|
21
21
|
[](https://github.com/ASDAlexey/vitest-auto-spy/actions/workflows/ci.yml)
|
|
22
22
|
[](./LICENSE)
|
|
@@ -55,13 +55,14 @@ identical API, with **RxJS** spies and **Angular / NestJS / React / Vue·Pinia /
|
|
|
55
55
|
- ⏳ Waiting that is not a guess — `flushEventLoop`, `settleDynamicImport`, `flushEventLoopUntil`, and a clock that survives fake timers (`mockSystemTime`, `useCountingClock`)
|
|
56
56
|
- 🌀 `fakeAsync` / `waitForAsync` on Vitest — one import of `vitest-auto-spy/zone`; zone.js stays out of every other entry
|
|
57
57
|
- 🧩 Module mocks that prove they applied — `assertMocked`, `moduleNamespace`, for a `vi.mock()` a bundler quietly ignored
|
|
58
|
-
- 🧾 Fixtures without casts — deep-partial `createMock`, `narrow()`, `withOverrides()`, `asInstances()`
|
|
58
|
+
- 🧾 Fixtures without casts — deep-partial `createMock`, `narrow()`, `withOverrides()`, `asInstances()`, `captureArg()`
|
|
59
59
|
- 🚚 A migration you can verify — `compareTestRuns` on the two JSON reports, `diffByField` for the assertion the reporter collapses
|
|
60
60
|
- 📏 Lint rules and one-line test-run hygiene — twelve rules in `vitest-auto-spy/eslint-plugin` (two `--fix`, three suggestions), `setupAutoSpy()`
|
|
61
61
|
- 🩺 [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
|
|
62
|
+
- 🔎 [`npx vitest-auto-spy doctor`](#the-cli--doctor-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
|
|
62
63
|
- 🔇 Console spies — `import { consoleInfoSpy } from 'vitest-auto-spy/console'` silences `console` and asserts its calls
|
|
63
64
|
- 🧭 [**Spec patterns**](https://asdalexey.github.io/vitest-auto-spy/recipes) — the shapes a ~370-file Angular suite converged on, and the traps that only surface at scale
|
|
64
|
-
- 🤖 Built for AI agents too — an offline [`AGENTS.md`](#using-this-library-with-an-ai-agent) inside the package, a [per-agent map](#which-file-your-agent-reads) for **Claude Code**, **OpenAI Codex**, **GLM/z.ai**, **Cursor**, **Copilot**, **Gemini CLI** and the rest, `llms.txt` on the docs site, a Claude Code skill, and errors that name their own fix
|
|
65
|
+
- 🤖 Built for AI agents too — one `npx vitest-auto-spy init` writes the pointer into the files your agents actually read and specialises it for this repository, backed by an offline [`AGENTS.md`](#using-this-library-with-an-ai-agent) inside the package, a [per-agent map](#which-file-your-agent-reads) for **Claude Code**, **OpenAI Codex**, **GLM/z.ai**, **Cursor**, **Copilot**, **Gemini CLI** and the rest, `llms.txt` on the docs site, a Claude Code skill, and errors that name their own fix
|
|
65
66
|
- 🟢 100% test coverage, **zero runtime dependencies** (in-tree arg serializer, no `javascript-stringify`)
|
|
66
67
|
|
|
67
68
|
## Table of contents
|
|
@@ -69,6 +70,9 @@ identical API, with **RxJS** spies and **Angular / NestJS / React / Vue·Pinia /
|
|
|
69
70
|
- [Install](#install)
|
|
70
71
|
- [Requirements](#requirements)
|
|
71
72
|
- [Peer dependencies](#peer-dependencies)
|
|
73
|
+
- [The CLI — `doctor` and `init`](#the-cli--doctor-and-init)
|
|
74
|
+
- [`doctor` — defects that never fail](#doctor--defects-that-never-fail)
|
|
75
|
+
- [`init` — the pointer an agent reads](#init--the-pointer-an-agent-reads)
|
|
72
76
|
- [Using this library with an AI agent](#using-this-library-with-an-ai-agent)
|
|
73
77
|
- [Point your agent at it once](#point-your-agent-at-it-once)
|
|
74
78
|
- [Which file your agent reads](#which-file-your-agent-reads)
|
|
@@ -190,6 +194,65 @@ them only for the matching entry point. The package itself has **zero runtime de
|
|
|
190
194
|
| `rxjs` | `vitest-auto-spy/rxjs` observable spies (and `Spy<T>` type-checking) — `>=7`, **no upper bound** (the rxjs 8 line included) | yes |
|
|
191
195
|
| `@angular/core` | `vitest-auto-spy/angular` helpers | yes |
|
|
192
196
|
|
|
197
|
+
## The CLI — `doctor` and `init`
|
|
198
|
+
|
|
199
|
+
The package ships one executable, with no dependencies and nothing to configure:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
npx vitest-auto-spy doctor # read-only. Exits 1 when it finds something
|
|
203
|
+
npx vitest-auto-spy init # writes the agent instructions pointer
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### `doctor` — defects that never fail
|
|
207
|
+
|
|
208
|
+
Every check shares one property: **nothing consumes the result**. The suite is green,
|
|
209
|
+
`tsc --noEmit` reports zero errors, and the only reader of the stale thing is whoever opens the
|
|
210
|
+
file. That is why they survive for years, and why a per-file linter cannot find most of them — the
|
|
211
|
+
evidence is spread across files.
|
|
212
|
+
|
|
213
|
+
```
|
|
214
|
+
$ npx vitest-auto-spy doctor
|
|
215
|
+
vitest-auto-spy doctor — /work/app
|
|
216
|
+
1284 files, runner: vitest, entry: vitest-auto-spy/angular
|
|
217
|
+
|
|
218
|
+
error tsconfig-glob-matches-nothing libs/users/tsconfig.spec.json
|
|
219
|
+
The "include" pattern "src*.spec.ts" matches no file.
|
|
220
|
+
→ A pattern that matches nothing type-checks nothing, and `tsc --noEmit` still reports
|
|
221
|
+
zero errors. Fix the glob or delete the entry.
|
|
222
|
+
|
|
223
|
+
3 errors, 4 warnings, 1 note
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
| Check | What it finds |
|
|
227
|
+
| ------------------------------ | -------------------------------------------------------------------- |
|
|
228
|
+
| `tsconfig-glob-matches-nothing` | An `include` pattern that matches no file — so it type-checks nothing |
|
|
229
|
+
| `tsconfig-file-missing` | A `files` entry naming a file that is gone |
|
|
230
|
+
| `spec-imported-by-non-spec` | A production module importing a `*.spec.ts` |
|
|
231
|
+
| `spec-exports-fixture` | A spec importing another spec, whose hooks then run in a foreign file |
|
|
232
|
+
| `foreign-runner-pragma` | `@jest-environment` left in a spec, which Vitest never reads |
|
|
233
|
+
| `dead-runner-config` | `jest.config.*` / `karma.conf.*` for a runner that is not installed |
|
|
234
|
+
| `orphan-runner-file` | A setup file only that dead config referenced |
|
|
235
|
+
| `angular-build-splitting-off` | `@angular/build` in `[22.1.5, 22.1.7)` — the OOM under `--coverage` |
|
|
236
|
+
| `no-agent-instructions` | No instruction file names the package. A note, not an error |
|
|
237
|
+
|
|
238
|
+
The check that motivated the tool: a spec showing `Cannot find name 'vi'` in the editor while
|
|
239
|
+
`tsc --noEmit` reported zero errors. A migration codemod editing `include` had eaten a `/**`,
|
|
240
|
+
turning `src/**/*.spec.ts` into `src*.spec.ts` — a valid glob that matches nothing. Nine of 152
|
|
241
|
+
spec tsconfigs still covered their specs.
|
|
242
|
+
|
|
243
|
+
`doctor` never writes. There is no `--fix`.
|
|
244
|
+
|
|
245
|
+
### `init` — the pointer an agent reads
|
|
246
|
+
|
|
247
|
+
No coding agent scans dependencies for instructions, so the `AGENTS.md` and the skill shipped
|
|
248
|
+
inside this package's tarball are never discovered on their own. `init` writes the pointer into
|
|
249
|
+
the files that *are* read — `AGENTS.md`, `CLAUDE.md`, `GEMINI.md`, a Claude Code skill stub, and a
|
|
250
|
+
glob-scoped rule file for each tool whose directory already exists — and specialises it for this
|
|
251
|
+
repository's runner, framework and setup file. Everything sits between markers, so a re-run is a
|
|
252
|
+
no-op and `--uninstall` puts the files back.
|
|
253
|
+
|
|
254
|
+
Full reference, including the flags and the CI form: **[The CLI](https://asdalexey.github.io/vitest-auto-spy/utilities/cli)**.
|
|
255
|
+
|
|
193
256
|
## Using this library with an AI agent
|
|
194
257
|
|
|
195
258
|
Most tests are now written with an assistant in the loop, so this package ships documentation
|
|
@@ -245,7 +308,14 @@ already exists.
|
|
|
245
308
|
|
|
246
309
|
### Install it in your agent
|
|
247
310
|
|
|
248
|
-
|
|
311
|
+
One command covers every tool in that table, and specialises the text for this repository:
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
npx vitest-auto-spy init # write it
|
|
315
|
+
npx vitest-auto-spy init --check # CI: fail when it is missing or out of date
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
By hand, the same thing is two commands at the repository root:
|
|
249
319
|
|
|
250
320
|
```bash
|
|
251
321
|
# 1 — AGENTS.md: Codex, Cursor, Copilot, Cline, Windsurf, Zed, OpenCode, Qwen, Roo, Junie, Aider…
|
|
@@ -712,7 +782,7 @@ Node / Bun / React / Vue project pulls **neither rxjs nor Angular into its runti
|
|
|
712
782
|
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- | :----: |
|
|
713
783
|
| `vitest-auto-spy` | `createSpyFromClass`, `createAutoMock`, `createFunctionSpy`, sync + promise + accessor spies, `errorHandler`, types | `vitest` | ✅ |
|
|
714
784
|
| `vitest-auto-spy/rxjs` | observable spies (`nextWith`, `nextWithValues`, `observablePropsToSpyOn`, …) + `createObservableWithValues` | `rxjs` | ✅ |
|
|
715
|
-
| `vitest-auto-spy/angular` | `provideAutoSpy`, `injectSpy`, `renderShallow`, `createWithAutoSpies`, `stable`/`flushEffects`, `settleResource`, the `mock*Prop` helpers, signal matchers, TestBed diagnostics | `@angular/core` | ✅ |
|
|
785
|
+
| `vitest-auto-spy/angular` | `provideAutoSpy`, `injectSpy`, `renderShallow`, `createWithAutoSpies`, `stable`/`flushEffects`, `settleResource`, `mockResourceProp`, the `mock*Prop` helpers, signal & resource matchers, TestBed diagnostics | `@angular/core` | ✅ |
|
|
716
786
|
| `vitest-auto-spy/bun` | the same core, driven by Bun's `bun:test` mocks | `bun:test` | ✅ |
|
|
717
787
|
| `vitest-auto-spy/bun-angular` | Angular's `TestBed` under `bun test` — DOM, JIT `templateUrl` resolution and a zoneless environment, from one preload | `bun:test`, `@angular/core` | ✅ |
|
|
718
788
|
| `vitest-auto-spy/node` | the same core, driven by `node:test`'s `mock.fn()` | `node:test` | ✅ |
|
|
@@ -1285,6 +1355,31 @@ resource and the flush it is missing.
|
|
|
1285
1355
|
`flushEventLoopUntil` cannot do this: it takes real event-loop turns and never ticks, so a resource
|
|
1286
1356
|
awaited through it finishes the budget having issued zero requests.
|
|
1287
1357
|
|
|
1358
|
+
#### Driving a resource with no HTTP at all
|
|
1359
|
+
|
|
1360
|
+
```ts
|
|
1361
|
+
import { mockResourceProp, registerResourceMatchers } from 'vitest-auto-spy/angular';
|
|
1362
|
+
|
|
1363
|
+
const products = mockResourceProp(service, 'products', []);
|
|
1364
|
+
|
|
1365
|
+
products.set([product]); // 'resolved'
|
|
1366
|
+
products.loading(); // back in flight
|
|
1367
|
+
products.fail('offline'); // 'error', error() is Error('offline')
|
|
1368
|
+
|
|
1369
|
+
expect(products.reload).toHaveBeenCalled(); // reload is spied and re-issues nothing
|
|
1370
|
+
```
|
|
1371
|
+
|
|
1372
|
+
Everything above is the answer when the request _is_ the point. Often it is not — the spec is about
|
|
1373
|
+
the component's own logic and the value was chosen in advance. `mockResourceProp` replaces the
|
|
1374
|
+
property with a double the spec moves directly, so nothing is ever in flight: no tick, no
|
|
1375
|
+
`HttpTestingController`, no budget. It is built from real `signal()`s, so a `computed()` reading
|
|
1376
|
+
`products.value()` still recomputes and an `effect()` still runs. Undone by `restoreMockedProps()`.
|
|
1377
|
+
|
|
1378
|
+
And `registerResourceMatchers()` adds `toBeLoading` / `toHaveResourceValue` / `toHaveResourceError`,
|
|
1379
|
+
which read the value **and** the status. `toHaveResourceValue` is the one that earns its place: it
|
|
1380
|
+
fails an unresolved resource **even when its default value matches**, which is exactly the assertion
|
|
1381
|
+
`expect(products.value()).toEqual([])` lets through.
|
|
1382
|
+
|
|
1288
1383
|
#### Asserting a signal's value
|
|
1289
1384
|
|
|
1290
1385
|
```ts
|
|
@@ -1498,12 +1593,15 @@ single-purpose utility you can pick up independently — they all ride on the sa
|
|
|
1498
1593
|
| `assertMocked(namespace, opts?)` | core | Fail when the `vi.mock()` a spec relies on silently did not apply (a bundled alias, `isolate: false`) |
|
|
1499
1594
|
| `moduleNamespace(exports, opts?)` | core | The `vi.mock` factory result an interop probe recognises — `default` + `__esModule` in place |
|
|
1500
1595
|
| `diffByField(actual, expected)` | core | Which field of an array of records moved, and in how many elements — the diff the reporter collapses |
|
|
1596
|
+
| `captureArg<T>()` | core | Take hold of a callback or config the code under test built, instead of describing its shape — assertions only, never `calledWith` |
|
|
1501
1597
|
| `asInstances(...spies)` | core | `asInstance` for a whole argument list — one edit against one compiler error, not five |
|
|
1502
1598
|
| `narrow(value, guard)` / `narrow.byKey` / `narrow.observable` | core | The branch of a union a test knows it got, failing with the shape the value actually had |
|
|
1503
1599
|
| `withOverrides(model, overrides?)` | core | A fixture from a model instance: its getters read once, as data — a spread drops them |
|
|
1504
1600
|
| `compareTestRuns(a, b, root?)` | core | Whether a migration lost a test — the set of `file::name`, which matching counters cannot answer |
|
|
1505
1601
|
| `provideAutoSpyForToken(TOKEN, overrides?)` | `/angular` | The provider for a dependency behind an `InjectionToken` — no stand-in class to write |
|
|
1506
1602
|
| `createDirectiveHost({ template, scope, props })` | `/angular` | A standalone host for a directive under test, with its scope where the compiler reads it |
|
|
1603
|
+
| `mockResourceProp(obj, prop, initial)` | `/angular` | Drive a resource with no HTTP — `set` / `fail` / `loading`, plus a spied `reload` |
|
|
1604
|
+
| `registerResourceMatchers()` | `/angular` | Adds `toBeLoading` / `toHaveResourceValue` / `toHaveResourceError`; the value matcher fails an unresolved resource |
|
|
1507
1605
|
| `registerDirectiveMatchers()` | `/angular` | Adds `expect(fixture).toHaveDirectiveApplied(Directive, selector?)` |
|
|
1508
1606
|
| `installProxyZonePatch(opts?)` | `/zone` | `fakeAsync` / `waitForAsync` on Vitest — the patch `zone.js/testing` does not ship; `scope: 'callback'` per callback |
|
|
1509
1607
|
| `autoMocked<T>(overrides?)` | core | `createAutoMock` typed as `T & Spy<T>`, for a collaborator passed as an argument rather than injected |
|
package/dist/angular.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
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-
|
|
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-Ch2Ym_6z.js';
|
|
2
2
|
import { Type, Signal, WritableSignal } from '@angular/core';
|
|
3
|
-
import { S as Spy, C as ClassType, a as ClassSpyConfiguration, O as OnlyMethodKeysOf } from './types-
|
|
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-
|
|
5
|
-
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-
|
|
3
|
+
import { S as Spy, C as ClassType, a as ClassSpyConfiguration, O as OnlyMethodKeysOf, j as AddSpyMethodsByReturnTypes } from './types-W3lPrwC7.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-CeHqAeIG.js';
|
|
5
|
+
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-Cpj2GGcD.js';
|
|
6
6
|
import '@angular/core/testing';
|
|
7
7
|
import 'rxjs';
|
|
8
8
|
import 'vitest';
|
|
@@ -39,9 +39,9 @@ interface AutoSpyOverride<T> {
|
|
|
39
39
|
* An auto-spy wrapped as a `TestBed.overrideProvider` value.
|
|
40
40
|
*
|
|
41
41
|
* ```ts
|
|
42
|
-
* const payments = overrideAutoSpy(
|
|
42
|
+
* const payments = overrideAutoSpy(PaymentMethodService);
|
|
43
43
|
*
|
|
44
|
-
* TestBed.configureTestingModule({ imports: [CheckoutComponent] }).overrideProvider(
|
|
44
|
+
* TestBed.configureTestingModule({ imports: [CheckoutComponent] }).overrideProvider(PaymentMethodService, payments);
|
|
45
45
|
* payments.useValue.charge.resolveWith({ ok: true });
|
|
46
46
|
* ```
|
|
47
47
|
*
|
|
@@ -58,7 +58,7 @@ declare function overrideAutoSpy<T>(ObjectClass: ClassType<T>, methodsToSpyOnOrC
|
|
|
58
58
|
* a component the testing module never mentions is never compiled by it.
|
|
59
59
|
*
|
|
60
60
|
* ```ts
|
|
61
|
-
* const menu = overrideComponentProvider(
|
|
61
|
+
* const menu = overrideComponentProvider(CatalogPageComponent, NavigationBuilderService);
|
|
62
62
|
*
|
|
63
63
|
* menu.build.mockReturnValue([]); // the component's own provider is now the spy
|
|
64
64
|
* const fixture = TestBed.createComponent(HostComponent);
|
|
@@ -212,6 +212,112 @@ declare module 'vitest' {
|
|
|
212
212
|
*/
|
|
213
213
|
declare function registerDirectiveMatchers(): void;
|
|
214
214
|
|
|
215
|
+
/**
|
|
216
|
+
* Driving an Angular resource from a spec, without any HTTP at all.
|
|
217
|
+
*
|
|
218
|
+
* `httpResource()` and `resource()` are the primitives a modern Angular service exposes, and a spec
|
|
219
|
+
* that wants to assert "the component shows the empty state while products are loading" has, until
|
|
220
|
+
* now, had to produce that state the long way: configure `provideHttpClientTesting`, tick so the
|
|
221
|
+
* request is issued, find it on the `HttpTestingController`, flush it, then settle. Six steps and a
|
|
222
|
+
* real request, to arrive at a value the spec picked in advance.
|
|
223
|
+
*
|
|
224
|
+
* {@link settleResource} is the answer when the request is the point. This is the answer when it is
|
|
225
|
+
* not — the shallow one, for a suite that tests business logic and never wanted a request in the
|
|
226
|
+
* first place. The property is replaced by a hand-built double whose statuses the spec sets
|
|
227
|
+
* directly, so nothing is ever in flight and there is nothing to wait for: no tick, no flush, no
|
|
228
|
+
* budget, and no way for the test to pass against a resource's default value by accident.
|
|
229
|
+
*
|
|
230
|
+
* Reactivity is genuine, exactly as in {@link mockSignalProp}: the double is built out of real
|
|
231
|
+
* `signal()`s from `@angular/core`, so a `computed()` reading `products.value()` recomputes and an
|
|
232
|
+
* `effect()` watching `products.status()` runs. A plain object with the same keys would satisfy
|
|
233
|
+
* every read and notify nothing.
|
|
234
|
+
*
|
|
235
|
+
* `@angular/core` stays an optional peer the same way the rest of this surface does: `ResourceRef`
|
|
236
|
+
* is only ever a *type* here, and the value handed to the property is assembled from `signal()`.
|
|
237
|
+
*/
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* The resource statuses Angular defines, as a string union.
|
|
241
|
+
*
|
|
242
|
+
* Declared here rather than imported so this module keeps `@angular/core` to a type-only
|
|
243
|
+
* dependency in spirit as well as in fact — Angular moved this from an enum to a union in v20, and
|
|
244
|
+
* a local union works against both without a version guard.
|
|
245
|
+
*/
|
|
246
|
+
type ResourceDoubleStatus = 'error' | 'idle' | 'loading' | 'local' | 'reloading' | 'resolved';
|
|
247
|
+
/**
|
|
248
|
+
* The double installed on the property — the slice of `ResourceRef` a component actually reads.
|
|
249
|
+
*
|
|
250
|
+
* Structural on purpose: a component typed against `ResourceRef<T>` reads `value`, `status`,
|
|
251
|
+
* `error`, `isLoading`, `hasValue` and `reload`, and this provides all six with the same shapes.
|
|
252
|
+
* The members `ResourceRef` has that a *consumer* never calls — `asReadonly`, `destroy`, `update` —
|
|
253
|
+
* are deliberately absent, because a double that answers a call nobody should be making is how a
|
|
254
|
+
* typo survives a test run.
|
|
255
|
+
*/
|
|
256
|
+
interface ResourceDouble<TValue> {
|
|
257
|
+
/** The current value. Writable through the returned handle, readonly to the code under test. */
|
|
258
|
+
value: Signal<TValue>;
|
|
259
|
+
/** `'resolved'` unless the spec moved it — see {@link MockedResource.loading} / `fail`. */
|
|
260
|
+
status: Signal<ResourceDoubleStatus>;
|
|
261
|
+
/** The error behind an `'error'` status, `undefined` otherwise. */
|
|
262
|
+
error: Signal<Error | undefined>;
|
|
263
|
+
/** `true` while the status is `'loading'` or `'reloading'`, matching Angular's own derivation. */
|
|
264
|
+
isLoading: Signal<boolean>;
|
|
265
|
+
/** `true` when the status is `'resolved'` or `'local'` — that is, when `value()` means anything. */
|
|
266
|
+
hasValue(): boolean;
|
|
267
|
+
/** Spied, and inert: a double has no request to re-issue, so the spec asserts the call instead. */
|
|
268
|
+
reload: AddSpyMethodsByReturnTypes<() => boolean>;
|
|
269
|
+
}
|
|
270
|
+
/** The spec's handle on a resource installed by {@link mockResourceProp}. */
|
|
271
|
+
interface MockedResource<TValue> {
|
|
272
|
+
/** Resolve the resource with a value — status `'resolved'`, error cleared. */
|
|
273
|
+
set(value: TValue): void;
|
|
274
|
+
/** Fail the resource — status `'error'`, `error()` set, `hasValue()` false. */
|
|
275
|
+
fail(error: Error | string): void;
|
|
276
|
+
/** Put the resource back in flight — status `'loading'`, `hasValue()` false. */
|
|
277
|
+
loading(): void;
|
|
278
|
+
/** The spied `reload()`; `expect(products.reload).toHaveBeenCalled()`. */
|
|
279
|
+
reload: AddSpyMethodsByReturnTypes<() => boolean>;
|
|
280
|
+
/** The double now behind the property, for asserting on it directly. */
|
|
281
|
+
resource: ResourceDouble<TValue>;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Replace a resource-valued property with a double the spec drives directly.
|
|
285
|
+
*
|
|
286
|
+
* ```ts
|
|
287
|
+
* const service = injectSpy(ProductService);
|
|
288
|
+
* const products = mockResourceProp(service, 'products', []);
|
|
289
|
+
*
|
|
290
|
+
* expect(component.emptyState()).toBe(true);
|
|
291
|
+
*
|
|
292
|
+
* products.set([product]);
|
|
293
|
+
* await stable(fixture);
|
|
294
|
+
*
|
|
295
|
+
* expect(component.emptyState()).toBe(false);
|
|
296
|
+
*
|
|
297
|
+
* products.fail('offline');
|
|
298
|
+
* expect(component.errorMessage()).toBe('offline');
|
|
299
|
+
* ```
|
|
300
|
+
*
|
|
301
|
+
* The resource starts `'resolved'` at `initialValue`, because that is the state a spec asserts
|
|
302
|
+
* against most and the one it would otherwise have to arrange. `loading()` and `fail()` are how the
|
|
303
|
+
* other two states are reached, and each is a single synchronous call — the point of this helper is
|
|
304
|
+
* that there is no asynchrony to get wrong. When a spec *does* want the real request path, that is
|
|
305
|
+
* `settleResource` over a real `httpResource`, not this.
|
|
306
|
+
*
|
|
307
|
+
* Undone by `restoreMockedProps()` like every other property patch, so a suite running
|
|
308
|
+
* `setupAutoSpy()` needs no teardown of its own.
|
|
309
|
+
*
|
|
310
|
+
* @param object The spy (or real instance) whose property to replace.
|
|
311
|
+
* @param property The resource-valued property.
|
|
312
|
+
* @param initialValue The value the resource starts resolved at.
|
|
313
|
+
* @returns The handle driving that resource — `set` / `fail` / `loading`, plus the spied `reload`.
|
|
314
|
+
*/
|
|
315
|
+
declare function mockResourceProp<T, K extends keyof T>(object: T, property: K, initialValue: T[K] extends {
|
|
316
|
+
value: Signal<infer TValue>;
|
|
317
|
+
} ? TValue : never): MockedResource<T[K] extends {
|
|
318
|
+
value: Signal<infer TValue>;
|
|
319
|
+
} ? TValue : never>;
|
|
320
|
+
|
|
215
321
|
/**
|
|
216
322
|
* Driving a service's signal from a spec.
|
|
217
323
|
*
|
|
@@ -264,6 +370,42 @@ declare function registerDirectiveMatchers(): void;
|
|
|
264
370
|
*/
|
|
265
371
|
declare function mockSignalProp<T, K extends keyof T>(object: T, property: K, initialValue: T[K] extends Signal<infer TValue> ? TValue : never): WritableSignal<T[K] extends Signal<infer TValue> ? TValue : never>;
|
|
266
372
|
|
|
373
|
+
/** The slice of a resource these matchers read. `error` is absent on some hand-built doubles. */
|
|
374
|
+
interface ResourceLike<TValue = unknown> {
|
|
375
|
+
status(): string;
|
|
376
|
+
value(): TValue;
|
|
377
|
+
error?(): Error | undefined;
|
|
378
|
+
}
|
|
379
|
+
declare module 'vitest' {
|
|
380
|
+
interface Matchers<T = any> {
|
|
381
|
+
/** The resource is still in flight — `status()` is `'loading'` or `'reloading'`. */
|
|
382
|
+
toBeLoading(): T;
|
|
383
|
+
/** The resource has resolved *and* its value deep-equals the expected one. */
|
|
384
|
+
toHaveResourceValue(expected: unknown): T;
|
|
385
|
+
/** The resource has failed; with an argument, its error message matches too. */
|
|
386
|
+
toHaveResourceError(expected?: RegExp | string): T;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Register the resource matchers with the runner. Call once, from your setup file.
|
|
391
|
+
*
|
|
392
|
+
* @example
|
|
393
|
+
* ```ts
|
|
394
|
+
* registerResourceMatchers(); // once, in the setup file
|
|
395
|
+
*
|
|
396
|
+
* expect(component.products).toBeLoading();
|
|
397
|
+
*
|
|
398
|
+
* httpTesting.expectOne('/api/products').flush([product]);
|
|
399
|
+
* await settleResource(component.products);
|
|
400
|
+
*
|
|
401
|
+
* expect(component.products).toHaveResourceValue([product]);
|
|
402
|
+
* ```
|
|
403
|
+
*
|
|
404
|
+
* `toHaveResourceValue` deliberately fails a resource that is still loading even when its default
|
|
405
|
+
* value happens to match, because that is the assertion this whole family exists to stop passing.
|
|
406
|
+
*/
|
|
407
|
+
declare function registerResourceMatchers(): void;
|
|
408
|
+
|
|
267
409
|
/** Anything readable like a signal: `signal()`, `computed()`, `input()`, or a plain getter. */
|
|
268
410
|
type SignalLike<T> = () => T;
|
|
269
411
|
declare module 'vitest' {
|
|
@@ -378,4 +520,4 @@ declare function reportSpecTiming(timing: SpecTiming): void;
|
|
|
378
520
|
*/
|
|
379
521
|
declare function enableTestBedDiagnostics(options?: TestBedDiagnosticsOptions): void;
|
|
380
522
|
|
|
381
|
-
export { type AngularTestEnvMode, type AngularTestEnvOptions, type AutoSpyOverride, type DirectiveHostOptions, type SignalLike, type SpecTiming, type TestBedDiagnosticsOptions, assertNgModuleScopes, createDirectiveHost, disableTestBedDiagnostics, enableTestBedDiagnostics, formatSpecTiming, getTestBedTiming, instrumentTestBed, mockSignalProp, overrideAutoSpy, overrideComponentProvider, registerDirectiveMatchers, registerSignalMatchers, reportSpecTiming, setupAngularTestEnv };
|
|
523
|
+
export { type AngularTestEnvMode, type AngularTestEnvOptions, type AutoSpyOverride, type DirectiveHostOptions, type MockedResource, type ResourceDouble, type ResourceDoubleStatus, type ResourceLike, type SignalLike, type SpecTiming, type TestBedDiagnosticsOptions, assertNgModuleScopes, createDirectiveHost, disableTestBedDiagnostics, enableTestBedDiagnostics, formatSpecTiming, getTestBedTiming, instrumentTestBed, mockResourceProp, mockSignalProp, overrideAutoSpy, overrideComponentProvider, registerDirectiveMatchers, registerResourceMatchers, registerSignalMatchers, reportSpecTiming, setupAngularTestEnv };
|