Совместимость
Эта страница объясняет, откуда взялись минимальные версии со страницы Установка. Она пригодится, когда обновление или закреплённая версия спорит с диапазонами ниже. Чтобы просто узнать, что ставить, хватит раздела Что нужно проекту.
| Зависимость | Минимум | Почему, в одну строку |
|---|---|---|
| Vitest | 2.1 | типы спаев берут тип Mock из самого Vitest, а settledResults в нём появился в 2.x |
| rxjs | 7.2 | первая версия, где все нужные пакету операторы экспортируются из корневого пути rxjs |
| Angular | 20 | первая версия с provideZonelessChangeDetection и самая старая, которую Angular ещё поддерживает |
| Node.js | 22 | у 18 и 20 кончилась поддержка, а всем поддерживаемым версиям Vitest нужно больше |
| TypeScript | 4.7 | он нужен типизированным хелперам; чистый JavaScript работает без типов |
Верхней границы нет ни у одного диапазона.
Vitest 2.1
Типизированный spy.method.mock.settledResults берётся из типа Mock самого Vitest. В @vitest/spy поле settledResults появилось в 2.0, а устоялась линейка 2.x на 2.1.
Сами хелперы работают и на более старом Vitest, а на bun:test и node:test библиотека добавляет settledResults сама. Больше нужно только типам: на Vitest ниже 2.1 они уже не сходятся, поэтому диапазон начинается с 2.1.
vitest — необязательная peer-зависимость. Проекту, который импортирует только vitest-auto-spy/bun или vitest-auto-spy/node, ставить раннер Vitest не нужно. А проект, где Vitest есть, по-прежнему должен держать >=2.1.
Типы этих точек входа не упоминают vitest: /node, /bun, /bun-angular, /rstest, /jasmine-compat, /angular-router, /console, /nestjs, /observer-spy и /rxjs. Проект без Vitest проходит с ними проверку типов даже при skipLibCheck: false.
Spy<T> — один тип во всех точках входа, но спаи методов бывают двух видов:
- Собственный
MockInstanceиз Vitest — если любой файл, который проверяетtsconfig.json, импортирует точку входа, загружающую Vitest:vitest-auto-spy,/angular,/angular/doubles,/react,/vue,/svelte,/setup,/jasmineили/dom-stubs. - Тип мока без раннера — во всех остальных случаях. У него те же члены, кроме
mockThrowиз Vitest. Чтобы спай бросал ошибку на любом раннере, используйтеfailWith(error)из библиотеки.
Частая ошибка: набор тестов на Vitest, который импортирует только /nestjs, /observer-spy или /rxjs, получает тип без раннера: mockThrow нет, и спай не подходит под аннотацию MockInstance. Добавьте эту строку в любой файл, который включает tsconfig.json, например в спеку или .d.ts:
import type {} from 'vitest-auto-spy';rxjs 7.2
Слой Observable собирает свои Subject из шести операторов: concatMap, delay, switchMap, take, takeUntil и takeWhile. Раньше они импортировались из rxjs/operators — старого глубокого пути, который rxjs 8 убирает. Теперь пакет берёт их из корневого пути rxjs. Там они появились в 7.2 — это сверено с объявлениями типов самого rxjs 7.2.0.
firstValueFrom есть с 7.0, с ним ничего не менялось. Angular с 16 по 22 принимает rxjs ^6.5.3 || ^7.4.0, поэтому у Angular-проекта на rxjs 7 уже стоит 7.4 или новее. Обновить rxjs до 7.2 или новее придётся только проекту на rxjs 6, 7.0 или 7.1.
Angular 20
Если нет функции, которую пакет импортирует по имени, это ошибка связывания: не загружается вся точка входа, а не один хелпер. Поэтому минимум задают функции Angular, которые пакет импортирует по имени.
provideZonelessChangeDetectionесть с Angular 20. В 18 и 19 она называласьprovideExperimentalZonelessChangeDetection, в 16 и 17 её не было. Preloadvitest-auto-spy/bun-angularимпортирует её по имени. Ниже 20bun testпадает ещё при загрузке preload, до первого файла тестов.- Ничего приватного по имени не импортируется.
runEffect(),mockSignalPropи матчеры сигналов раньше импортировали приватный символ AngularɵSIGNAL. Теперь они находят его во время выполнения, так что Angular без этого экспорта не сломает точку входа/angular.
Angular 20 — ещё и самая старая версия, которую сам Angular поддерживает. У Angular 19 поддержка закончилась 2026-05-19, у 18, 17 и 16 — раньше. Так что минимум не отрезает ничего, что ещё получает исправления. Верхней границы нет намеренно: иначе на каждую мажорную версию Angular нужен был бы релиз, а тот, кто обновился первым, получал бы ERESOLVE.
@angular/platform-browser объявлен как peer-зависимость. Матчеры директив из vitest-auto-spy/angular/matchers импортируют из него By, а preload для Bun импортирует platformBrowserTesting и BrowserTestingModule. В плоском node_modules у npm пакет и так находился: он есть в каждом Angular-проекте. В изолированной раскладке pnpm он не находился вовсе, поэтому теперь объявлен. Оба этих импорта есть с Angular 16, так что минимум они не поднимают. В 20 изменилось только одно: путь @angular/platform-browser-dynamic/testing перестал быть рекомендуемым.
Сигнальным формам (vitest-auto-spy/signal-forms) нужен Angular 22: в нём @angular/forms их и выпускает. При этом @angular/forms объявлен с Angular 20 (>=20.0.0), как и @angular/core.
Необязательные peer-зависимости
Все peer-зависимости необязательные. Ставить нужно только те, что нужны импортированным точкам входа:
| Пакет | Диапазон | Кому нужен |
|---|---|---|
vitest | >=2.1.0 | корневой точке входа и всем, что работают на Vitest |
rxjs | >=7.2.0 | vitest-auto-spy/rxjs, /angular-router, /angular/doubles |
@angular/core | >=20.0.0 | всем точкам входа для Angular |
@angular/common | >=20.0.0 | vitest-auto-spy/angular-http, /angular-router |
@angular/platform-browser | >=20.0.0 | vitest-auto-spy/angular/matchers, /angular/doubles, /bun-angular |
@angular/compiler | >=20.0.0 | vitest-auto-spy/angular/matchers, /bun-angular |
@angular/router | >=20.0.0 | vitest-auto-spy/angular-router |
@angular/forms | >=20.0.0 | vitest-auto-spy/signal-forms, которой для работы нужен ещё и Angular 22 |
@rstest/core | >=0.11.0 | vitest-auto-spy/rstest |
Строгий установщик вроде pnpm отказывается разрешать импорт, который никто не объявил. Поэтому объявлен каждый пакет, который импортирует код. Необязательные они потому, что каждый нужен только точкам входа из своей строки. Точке входа, которой нет в таблице (например, /bun, /node или /nestjs), пакеты из этого списка не нужны.
У @angular/common есть своя причина. vitest-auto-spy/angular должна загружаться и в проекте, где есть @angular/core, но нет @angular/common. Статический импорт @angular/common внутри /angular сломал бы это всем, включая множество наборов тестов, которые вообще не проверяют HTTP. Поэтому хелперы HTTP вынесены в отдельную точку входа vitest-auto-spy/angular-http, и @angular/common импортируют только те точки входа, которым он нужен. rxjs держится вне ядра так же: хелперы для Observable лежат за vitest-auto-spy/rxjs.
Node.js 22
У Node 18 и 20 кончилась поддержка, и всем поддерживаемым раннерам нужно больше:
- Vitest 4 объявляет
^20.0.0 || ^22.0.0 || >=24.0.0. Vite 7, который он ставит, требует^20.19.0 || >=22.12.0. На Node 18 прогон падает сTypeError: crypto.hash is not a functionещё до загрузки первой спеки. - Vitest 5 требует
^22.12.0 || ^24.0.0 || >=26.0.0. Ещё он объявляет@types/nodeкак^22.0.0 || >=24.0.0. Эта зависимость необязательная, но npm проверяет её, если она установлена. Поэтому проект на@types/node20 получитERESOLVE.
У билдера Angular CLI свой диапазон: @angular/build 22 требует Node ^22.22.3 || ^24.15.0 || >=26.0.0.
CI гоняет Node 22, 24 и 26. Опубликованный код собран под ES2022. На какой версии Node тесты идут быстрее, измерено на странице Производительность.
using на Node 22
using spy = createSpyFromClass(UserService) сбрасывает спай, когда блок заканчивается. Метод [Symbol.dispose]() даёт библиотека, а синтаксис using — ваш инструментарий сборки.
- Код после транспиляции работает на любой поддерживаемой Node. esbuild и
tscпереписываютusingв обычные вызовы, и именно так Vitest, Bun и Rstest запускают ваши спеки. - Код без транспиляции требует Node 24. Файл
.jsсusingбез транспиляции на Node 22 — этоSyntaxError. Если ваша сборка не транспилирует код, вызывайтеspy[Symbol.dispose]()илиresetAutoSpy(spy)сами;resetAutoSpyберётся из той же точки входа, что иcreateSpyFromClass. - На Node 22 пакет сам добавляет
Symbol.dispose. Речь оusingпосле транспиляции, а не о синтаксисе. ПереписанныйusingчитаетSymbol.disposeиз глобальногоSymbol. В Node 24 он есть в каждом realm (realm — отдельный набор глобальных объектов). Node 22 добавляет его только в главный realm, какSymbol.for('nodejs.dispose'). Окруженияjsdomиhappy-domв Vitest запускают спеки в отдельном realmvm, где его нет, иusingбросил быTypeError: Symbol.dispose is not defined.
Импорт пакета определяет Symbol.dispose в этом realm. Он берёт тот же символ из реестра, что и Node, поэтому ключ одинаков во всех realm процесса. Символ определяется только там, где его нет, неперечисляемым и настраиваемым (configurable); realm, где Symbol.dispose уже есть, остаётся как был.
ESM и CommonJS
Пакет выходит как ESM с типами .d.ts в комплекте. У двух точек входа есть ещё и сборка CommonJS:
vitest-auto-spy/node— для тестовnode --test, написанных на CommonJS;vitest-auto-spy/eslint-plugin— для CommonJS-конфигаeslint.config.cjs.
Всё остальное — только ESM. require() точки входа поверх Vitest всё равно не мог бы сработать: Vitest не даёт себя подключить так и пишет Vitest cannot be imported in a CommonJS module using require(). Раннеры тестов загружают ESM сами, так что ничего не потеряно. Без этой бесполезной сборки опубликованный пакет стал примерно вдвое меньше. Текущий размер пакета и стоимость импорта — на странице Производительность.
В CommonJS-конфиге ESLint require — как раз правильный вызов:
// eslint.config.cjs
const autoSpy = require('vitest-auto-spy/eslint-plugin');
module.exports = [{ files: ['**/*.spec.ts'], ...autoSpy.configs.recommended }];require('vitest-auto-spy/eslint-plugin') возвращает сам объект плагина, и типы .d.cts говорят ровно это (export =). Поэтому в eslint.config.cts запись autoSpy.default.rules — ошибка типов, а не код, который компилируется и падает при запуске.
TypeScript без rxjs
Ни один тип, который выпускает пакет, не ссылается на типы rxjs. Проект без rxjs не ставит его и не загружает его объявления в TypeScript. До 4.0.0 каждый import { createSpyFromClass } тянул за собой 189 файлов .d.ts из rxjs, и rxjs приходилось ставить даже для тестов без Observable. См. Переход на 4.0.
vitest-auto-spy/package.json
Манифест пакета есть в карте экспортов, поэтому vitest-auto-spy/package.json разрешается. Инструменты, которые читают package.json зависимости через резолвер Node (Storybook, Nx, помощник Renovate), получают файл, а не ERR_PACKAGE_PATH_NOT_EXPORTED.
Алиас во множественном числе vitest-auto-spies
vitest-auto-spies — тонкий пакет-алиас. Он реэкспортирует этот пакет, точку входа за точкой входа, так что опечатка ставит тот же код. Лучше пишите имя в единственном числе: алиас собирается из него и только повторяет его.
Как CI проверяет самые старые версии
Минимальные версии проверяются, а не только объявлены. Кроме обычной матрицы тестов, CI собирает tarball и ставит его в чистый проект с четырьмя парами раннера и rxjs:
- нижняя граница обоих: Vitest 2.1 с rxjs 7.2;
- Vitest 3 с rxjs 7.8;
- Vitest 4 с rxjs 7.8;
- текущие версии обоих.
В каждой паре запускается спека на опубликованной сборке и проверяются типы пробного файла на опубликованных объявлениях.