Переход на 5.0
В 5.0 поменялись два диапазона peer-зависимостей: Angular >=20 и rxjs >=7.2. В самой 5.0 хелперы, опции и поведение спаев не изменились. Большинству проектов достаточно поднять версию:
npm install -D vitest-auto-spy@5 # pnpm: pnpm add -D vitest-auto-spy@5Что проверить
Если вы используете точку входа для Angular, а версия Angular ниже 20, сначала обновите Angular.
Если у вас pnpm и
vitest-auto-spy/angularне находит@angular/platform-browser, добавьте его вdevDependencies.Если вы намеренно закрепили
rxjs@7.0или7.1, перейдите на 7.2 или новее. В Angular-проектах она уже стоит.Переходите сразу на более позднюю 5.x (обычный случай)? Тогда ещё:
- запустите
npx vitest-auto-spy doctor: он назовёт каждый импорт, который в 5.21.0 ушёл изvitest-auto-spy/angular(диагностика, подмены диалогов и платформы, матчеры); - запустите проверку типов: с 5.1.0 стабы типизируются по методу;
- запустите тесты: несколько исправленных хелперов теперь роняют спеки, которые проходили случайно.
Подробно — Изменения в следующих релизах 5.x.
- запустите
Зачем обновляться
Хелперы, опции и поведение в рантайме не изменились. Изменились диапазоны peer-зависимостей — то, на чём пакет заявляет, что работает. Оба старых диапазона обещали версии, на которых код работать не мог.
| Что вы получаете | Проверено |
|---|---|
Диапазон Angular говорит правду. >=16.0.0 допускал четыре мажора, на которых точка входа даже не загружается. | Angular 16–22 скачаны, их списки экспортов разобраны: ɵSIGNAL впервые есть в 18, provideZonelessChangeDetection — в 20 |
@angular/platform-browser находится под pnpm. /angular импортирует из него By, но пакет не был объявлен peer-зависимостью. | не объявлен → необязательная peer-зависимость с тем же диапазоном >=20, что у двух других |
Диапазон rxjs больше не обещает rxjs 8. Observable-хелперы импортировали шесть операторов из rxjs/operators, а в rxjs 8 этого пути нет. | все шесть теперь берутся из корня rxjs, который экспортирует их с 7.2 (проверено по декларациям типов самого rxjs 7.2.0) |
flushEffects() стал проще. Запасного пути через ApplicationRef.tick() для старого Angular больше нет. | запасной путь удалён, покрытие по-прежнему 100 % |
Почти для всех цена — одно число в package.json. Все мажоры Angular, которые Angular ещё поддерживает, проходят новую нижнюю границу. Все Angular-проекты уже подходят под границу rxjs.
Что изменилось
Два ломающих изменения, оба в peer-диапазонах:
- ни один хелпер не удалён и не переименован;
- ни одна опция не поменяла смысл;
- ни один спай не ведёт себя иначе.
Если вы переходите с 4.x сразу на более позднюю 5.x, появятся и ошибки типов из 5.1.0: этот релиз проверяет, что возвращает стаб. Раздел Изменения в следующих релизах 5.x разбирает их по тексту ошибки.
| Что делать | |
|---|---|
1. Angular — >=20, и Angular-пакетов в peer-зависимостях теперь три | обновить Angular, если он ниже 20; добавить @angular/platform-browser, если жалуется pnpm |
2. rxjs — >=7.2 | ничего, если вы не закрепили rxjs@7.0 или 7.1 намеренно |
1. Angular — >=20, и Angular-пакетов в peer-зависимостях теперь три
"peerDependencies": {
"@angular/common": ">=20.0.0",
"@angular/core": ">=20.0.0",
"@angular/platform-browser": ">=20.0.0", // новое: раньше не объявлялся
// …
}Все три — необязательные peer-зависимости. Проект, который не импортирует ни одну точку входа для Angular, не ставит ни одного из них.
Почему 20, а не что-нибудь пониже
Пакет импортирует два символа Angular как значения. Если такого импорта нет, не загружается вся точка входа, а не один хелпер.
ɵSIGNALесть с Angular 18. Его читаетrunEffect(), и точка входа/angularимпортирует его при загрузке. На Angular 16 или 17 падает вся точка входа, а с нейprovideAutoSpyиinjectSpy.provideZonelessChangeDetectionесть с Angular 20. В 18 и 19 функция называласьprovideExperimentalZonelessChangeDetection, в 16 и 17 её не было.vitest-auto-spy/bun-angularимпортирует её по имени, поэтому ниже 20bun testпадает при загрузке preload-файла, до запуска спек. Именно этот символ ставит границу на 20. На 18 и 19 точка входа/angularзагружается нормально, не загружается только/bun-angular.
Для таблицы ниже @angular/core, @angular/common и @angular/platform-browser скачаны в версиях 16.2.12, 17.3.12, 18.2.14, 19.2.25, 20.3.30, 21.2.22 и 22.1.5. Разобраны их настоящие списки экспортов; заметкам к релизам не доверяли.
16 17 18 19 20 21 22
ɵSIGNAL . . y y y y y
provideZonelessChangeDetection . . . . y y y
provideExperimentalZonelessCD . . y y . . .
TestBed.tick() . . . . y y y
InputSignal / ModelSignal . y y y y y y
the other 29 symbols this code imports
y y y y y y yНичего из того, что ещё поддерживалось, не отрезано
Angular поддерживает каждый мажор шесть месяцев активно и ещё двенадцать месяцев в режиме LTS. Когда ставили эту границу, LTS Angular 19 закончился 2026-05-19, а 16–18 — ещё раньше. Angular 20 — самый старый мажор, который Angular ещё поддерживает, и он же техническая граница этого пакета. Поэтому изменение не отрезает ничего, что ещё получает исправления.
| мажор | выпуск | конец LTS | статус |
|---|---|---|---|
| 16 | 2023-05-03 | 2024-11-03 | EOL |
| 17 | 2023-11-08 | 2025-05-08 | EOL |
| 18 | 2024-05-22 | 2025-11-22 | EOL |
| 19 | 2024-11-19 | 2026-05-19 | EOL |
| 20 | 2025-05-28 | 2026-11-28 | LTS; новая граница |
| 21 | 2025-11-19 | 2027-05-19 | LTS |
| 22 | 2026-06-03 | 2027-12-03 | активная поддержка |
@angular/platform-browser впервые становится peer-зависимостью
vitest-auto-spy/angular импортирует из него By: на нём построены матчеры директив. Preload для Bun запускается через platformBrowserTesting(). Ни один из этих импортов не был объявлен.
- С npm и его «поднятым»
node_modulesвсё работало случайно: в любом Angular-проекте этот пакет есть. - С изолированной раскладкой pnpm пакет не находился вообще, и
npm lsне подсказывал почему.
Если установка у вас работает, для вас ничего не меняется. Если у вас pnpm и /angular не находил @angular/platform-browser, этот релиз это чинит.
Это не про Angular 20
platformBrowserTesting() и BrowserTestingModule из @angular/platform-browser/testing иногда называют возможностями Angular 20+. Это не так: они экспортируют одни и те же имена во всех мажорах начиная с 16. В 20 изменилось другое: @angular/platform-browser-dynamic/testing перестал быть рекомендуемым путём. Граница bun-angular зависит только от provideZonelessChangeDetection.
Верхней границы нет, и это сознательно
Диапазон вроде >=20.0.0 <23.0.0 выглядит надёжнее, потому что ɵSIGNAL — приватный символ Angular. Но это неверное решение:
- оно требует релиза этого пакета под каждый мажор Angular;
- оно даёт
ERESOLVEвсем, кто обновил Angular первым; - оно ничего не защищает: приватный символ Angular может убрать и в минорной версии.
Настоящая защита — в коде: читать символ в рантайме, а не импортировать по имени. Тогда Angular без ɵSIGNAL сломает один хелпер, а не всю точку входа. Хелперы пакета для zone и zoneless уже так устроены, и runEffect() переходит на тот же подход.
2. rxjs — >=7.2, потому что глубокого пути импорта больше нет
"peerDependencies": {
"rxjs": ">=7.2.0" // было >=7.0.0
}Observable-хелперы используют шесть операторов: concatMap, delay, switchMap, take, takeUntil и takeWhile. Они импортировались из rxjs/operators — старого глубокого пути. В rxjs 8 этого пути нет. Значит, >=7.0.0 обещал мажор, в котором код даже не загрузится.
Теперь импорт идёт из корня rxjs, который экспортирует все шесть операторов с 7.2. Это проверено по декларациям типов самого rxjs 7.2.0, а не по его changelog. firstValueFrom, из-за которого раньше стояла граница 7.0, не изменился. 7.2 — первая версия, где каждый символ, нужный пакету, есть по тому пути, откуда пакет его импортирует.
Кому нужно что-то делать: только проекту, который намеренно закрепил rxjs@7.0 или 7.1. На rxjs 7 Angular 16–22 требуют ^7.4.0, а это выше границы, так что Angular-проекту делать нечего. Верхней границы здесь тоже нет: rxjs 8 теперь действительно достижим.
Как теперь выглядит flushEffects()
Это не ломающее изменение. flushEffects() теперь всегда использует TestBed.tick(), который есть с Angular 20. TestBed.tick() обновляет и представления фикстур, которые не подключены к ApplicationRef. Старый запасной путь через ApplicationRef.tick() был нужен только версиям Angular, которые пакет больше не поддерживает, поэтому его убрали.
import { flushEffects } from 'vitest-auto-spy/angular';
store.filter.set('open');
flushEffects(); // выполняет отложенные эффекты в сервисах и сторах, фикстура не нужнаИзменения в следующих релизах 5.x
Разделы выше описывают саму 5.0. Если вы переходите с 4.x сразу на более позднюю 5.x, вас коснутся и эти изменения.
Стабы проверяются по типу (5.1.0)
С 5.1.0 мок метода-спая — это MockInstance<Method>, а не MockInstance без аргумента типа (то есть (...args: any[]) => any). Теперь по методу типизируются:
mockReturnValue,mockImplementation,mockResolvedValueи их вариантыOnce;- параметры, которые получает реализация;
mock.calls.
В рантайме ничего не меняется.
Замер на переходе 4.6 → 5.24 Angular-приложения с 850 файлами спек: 61 ошибка в 22 файлах, ни одна не меняет поведение в рантайме. 59 из них укладываются в восемь видов; последние два были ошибками самого пакета:
| Текст ошибки | Сколько | Что это | Как исправить |
|---|---|---|---|
… with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' … | 21 | тип стаба отличается от типа метода: ?: T против ?: T | undefined, или записано key: undefined | создать subject из метода (returnSubject()); уберите ключ вместо записи key: undefined |
Argument of type 'Spy<X>' is not assignable to parameter of type 'X' | 9 | спай возвращается из другого спая | mockReturnValue(asInstance(double)) |
Argument of type 'Observable<A>' is not assignable to parameter of type 'Observable<B>' | 8 | фикстура не совпадает с тем, что возвращает метод: DOM-Event вместо Event роутера, null вместо значения | исправить фикстуру — это и есть находка |
Types of parameters 'x' and 'y' are incompatible в mockImplementation | 5 | аннотация параметра в реализации расходится с методом | убрать аннотацию, тип даст метод |
TS4111 или TS2375 внутри тела mockImplementation | 6 | раньше тело получало параметры any, и в нём ничего не проверялось | обычное исправление этой ошибки: тело теперь типизировано |
Argument of type 'Partial<X>', самописный MockXType или базовый класс там, где нужен X | 4 | вручную собранный частичный объект там, где метод возвращает класс | createSpyFromClass(X) или createAutoMock<X>(), затем asInstance |
TS2349: This expression is not callable на значении из mock.calls | 4 | mock.calls типизирован; слушатель из addEventListener имеет тип EventListenerOrEventListenerObject | сузить тип (typeof listener === 'function') перед вызовом |
… is not assignable to parameter of type 'RxMethod<…>' внутри mockReadonlyProp(…, vi.fn(impl)) | 2 | vi.fn(impl) берёт тип у заменяемого члена, а реализация возвращает не то | вернуть то, что возвращает член: Object.assign(vi.fn(), { destroy: vi.fn() }) для rxMethod |
Два самых частых вида — до и после:
// `Subject` инвариантен: аргумент типа должен точно совпадать с методом, `?` к `?`
const events$ = new Subject<EventData<{ params?: EventDataParams }>>(); // ❌ `on` объявляет `params?: EventDataParams | undefined`
remoteRendering.on.mockReturnValue(events$);
const events$ = remoteRendering.on.returnSubject(); // ✅ тип берётся из `on`, что бы он ни объявлялoverlay.create.mockReturnValue(overlayRef); // ❌ у Spy<OverlayRef> нет приватных членов OverlayRef
overlay.create.mockReturnValue(asInstance(overlayRef)); // ✅ тот же объект с типом классаОдин вид был ошибкой пакета, а не спеки. @ngrx/signals типизирует каждый nullable-объект в сторе как объединение сигнатур вызова, например DeepSignal<Angle> | Signal<null>. С 5.1.0 по 5.24.0 такой член не принимал реализацию вообще: mockImplementation(() => angle()) не подходил ни под одну половину. 5.25.0 типизирует стаб как одну сигнатуру, которая возвращает объединение. Обновитесь, а не приводите типы (2 из 61 выше).
Не отвечайте ни на одну из этих ошибок через as any, as unknown as X или @ts-expect-error. Каждый такой приём выключает ту проверку, ради которой строка написана, а 8 из 61 ошибки были фикстурами, не совпадающими с тем, что возвращает метод.
Экспорты ушли из vitest-auto-spy/angular (5.21.0)
В 5.21.0 32 экспорта ушли из vitest-auto-spy/angular в три более узкие точки входа. Спека, которая импортирует provideAutoSpy, больше не загружает диагностику TestBed и подмены диалогов Material, а /angular стал на 14,3 % меньше. Большинство проектов меняют по одной строке импорта на каждую переехавшую группу, в одном setup-файле:
Импорт из vitest-auto-spy/angular | Теперь импортируйте из |
|---|---|
enableAngularDiagnostics, disableAngularDiagnostics, assertNoPendingRequests, assertNoShadowedProviders, AngularDiagnosticsOptions | vitest-auto-spy/angular/diagnostics |
enableTestBedDiagnostics, disableTestBedDiagnostics, instrumentTestBed, getTestBedTiming, formatSpecTiming, reportSpecTiming, SpecTiming, TestBedDiagnosticsOptions | vitest-auto-spy/angular/diagnostics |
createMatDialogRef, injectMatDialogRef, provideMatDialogData, provideMatDialogRef, DialogComponent, DialogRefLike, DialogResult, MatDialogRefDouble, MatDialogRefInit | vitest-auto-spy/angular/doubles |
createWindowDouble, createDocumentDouble, provideWindowDouble, provideDocumentDouble, PlatformOverrides | vitest-auto-spy/angular/doubles |
registerDirectiveMatchers, registerResourceMatchers, registerSignalMatchers, ResourceLike, SignalLike | vitest-auto-spy/angular/matchers |
Как /angular-http и /angular-router, три новые точки входа не реэкспортируют ядро. trackInjections остаётся в vitest-auto-spy/angular. npx vitest-auto-spy doctor сообщает о каждом перенесённом имени, которое ещё импортируется из /angular, как об ошибке helper-from-wrong-entry — в том числе в файлах, до которых не доходит ваш tsconfig. Подробности — в changelog к 5.21.0.
С 5.35.0 vitest-auto-spy/angular экспортирует и тип Spy<T>, так что import { type Spy, injectSpy } from 'vitest-auto-spy/angular' компилируется. Остальное ядро по-прежнему импортируется из vitest-auto-spy.
Исправления диагностики Angular и zone (5.6.0, 5.19.0)
Это исправления ошибок, но проверка, которая молча не работала, после обновления может начать сообщать о проблемах.
- 5.6.0: проверяется каждый файл спеки. Под
isolate: falseenableAngularDiagnostics()иprovideHttpTesting({ verifyOnTeardown })регистрировали хуки один раз на модуль, поэтому проверялся только первый файл спеки в каждом воркере. Теперь проверяется каждый. - 5.6.0: незавершённые HTTP-запросы под
sequence: { hooks: 'list' }. Проверка в конце теста читала пустой модуль и ничего не сообщала. АTestBed.injectна сброшенномTestBedпересобирал модуль, так что каждая спека с HTTP-тестированием падала со второго теста с ошибкой Cannot configure the test module when the test module has already been instantiated. - 5.19.0: диагностика видит и
getTestBed().ngModuleScopes,deadSchemas,shadowedProvidersи проверкаoverrideComponentProviderвидели только статическийTestBedи пропускалиgetTestBed().configureTestingModule(…).TestBed.overrideTemplateтеперь входит в измеряемое времяTestBed. - 5.19.0: упавшая диагностика больше не пропускает сброс. Раньше падал следующий тест с Cannot configure the test module when the test module has already been instantiated — и называлась спека, в которой всё было в порядке.
- 5.19.0:
pendingRequestsнаходит вложенныйHttpTestingController. Чтение только первого уровня импортов не находило токен и молча выключало проверку. - 5.19.0:
installProxyZonePatch()больше не наслаивается. Вызов из setup-файла подisolate: falseоборачивал собственную обёртку: двести файлов оставляли двести слоёв Proxy на каждомitпоследнего файла. Зоны не вкладывались, так что результаты были верными, но каждый слой стоил времени. Повторная установка теперь ничего не делает, как и её откат. - 5.19.0: сторож ожидания эмиссии использует часы zone.js. Внутри
fakeAsyncвызовtick(1_500)при ожиданииdebounceTime(2_000)отклонял ожидание, которое сам же вот-вот должен был выполнить.
Изменения в поведении хелперов Angular (с 5.9.0 по 5.46.0)
Каждое из этих изменений заставляет спеку падать там, где раньше она молча проходила. После обновления ждите несколько красных спек; каждая скрывала настоящую проблему.
- 5.9.0:
stable()иsetInputs()работают в проектах с zone.js. Они выполняют tick внутриTestBed.inject(NgZone). Под zoneless этоNoopNgZone, так что там это ничего не стоит. - 5.9.0:
runEffect()выполняет предыдущую очистку. Раньше каждый вызов оставлял ещё одну функцию очистки, и все они срабатывали разом приfixture.destroy(). Это ломало неидемпотентные очистки:queue.pop(), уменьшение счётчика,unsubscribeна общем subject. - 5.9.0:
hasValue()у подмены ресурса следует правилу Angular (Angular v20 и новее): он сообщает, есть ли значение, а не какой сейчас статус. СdefaultValuehasValue()равенtrueв состоянияхloading,reloadingиidleиfalseтолько приerrorили значенииundefined. Шаблон вида@if (products.hasValue()) { … } @else { <spinner/> }показывает список, пока грузится следующая страница; старая подмена «по статусу» показывала спиннер. - 5.11.0:
inputsвrenderShallowотвергает имена, которых компонент не объявляет. Раньше Angular отвечалNG0303в консоли и не задавал значение. Ключ, который молча ничего не делал, теперь падает — в спеке, которая раньше была зелёной. - 5.11.0:
setInputs()на фикстуре безɵcmpназывает класс. Раньше он падал сCannot read properties of undefined (reading 'inputs'). - 5.19.0:
setInputs()принимает входы, которые открывают host-директивы. Раньше он их отвергал и писал «It declares no inputs at all» про компонент, у которого входы есть. - 5.19.0: упавшая подмена ресурса бросает ошибку из
value(), как Angular. Код компонента, который читаетvalue()без проверкиhasValue(), раньше проходил в спеке и падал в приложении.reload()теперь отвечаетfalse, пока перезапускать нечего; раньше всегда былtrue. - 5.20.0:
injectSpy(GenericClass)больше не выводитnever. Для класса, конструктор которого принимает собственный параметр типа, 5.19.0 выводилnever, и типизированныйaccessorSpiesпревращал это в ошибку присваивания. Теперь такой класс читается по ограничению параметра, напримерSpy<ModalRef<unknown>>. Нужен конкретный тип — укажите его явно:injectSpy<ModalRef<PurchaseOptions>>(ModalRef). - 5.46.0:
toHaveSignalValueиtoHaveResourceValueсравнивают содержимоеSetиMap. Раньше любые два Set были равны, как и любые два Map. Проверка на неверное множество проходила.
Изменения в поведении спаев и проверок (с 5.2.0 по 5.44.0)
Эти исправления могут сделать зелёную спеку красной или сломать проверку типов. Каждая такая спека проходила по неверной причине.
- 5.2.0: тип по умолчанию у параметра generic-класса доходит до спая. Для
class FlagsConfigService<T = FlagsConfigDefaults>createSpyFromClassиinjectSpyраньше выводилиTкакunknown. Тогда каждый член, типизированный черезT, читался какunknown. - 5.2.0:
restoreMocks: trueсохраняет спаи аксессоров у подмены, созданной внеbeforeEach. Раньше восстановление раннера запускалось до теста и возвращало настоящие аксессоры. ЗаписиaccessorSpiesоставались, но их уже никто не читал. - 5.6.0: значение из
overridesдоходит до спая геттера. Для члена изgettersToSpyOnэто значение раньше терялось, и геттер отвечалundefined. Теперь геттер его возвращает. Более позднийaccessorSpies.getters.x.mockReturnValue(…)по-прежнему главнее. - 5.9.0:
returnsиselfReturningпропускают член, заданный вoverrides. Это касаетсяcreateAutoMockиprovideAutoSpyForToken. Обычная функция, заданная там заранее, раньше приводила кTypeError: asVitestMock(...).mockImplementation is not a functionиз провайдера. - 5.15.0: геттер из
overridesвыполняется, только когда спека его читает. Раньше он выполнялся при сборке подмены. Геттер, который должен был бросить ошибку, падал ещё внутриTestBed.configureTestingModule. - 5.19.0:
calledWithбольше не считает разные аргументы одинаковыми. Две функции с одним именем, дваError, различающиеся только сообщением, илиSetв другом порядке раньше получали один и тот же ответ. Спека, которая на это опиралась, теперь падает и печатает оба списка аргументов. - 5.19.0:
resetAutoSpyсбрасывает и отложенныеOnce-значения, и настройку аксессоров. Значение из очередиmockReturnValueOnceраньше отвечало на первый вызов после сброса, уже в другом тесте.accessorSpies.getters.x.mockReturnValue(…)тоже переживал сброс. Спека, которая на это опиралась, теперь получаетundefined. - 5.19.0:
accessorSpies.gettersи.settersтипизированы по члену класса. Стаб геттера значением неверного типа теперь ошибка типов. - 5.19.0: хелперы ожидания эмиссий останавливаются на нужном значении. Спай в
tap,finalizeилиdeferпосле этого значения больше не вызывается. Спека, которая насчитывала пять вызововtap, теперь видит один, как в продакшене.of(1).pipe(repeat())больше не зависает. - 5.19.0:
setupAutoSpy()закрывает ожидание эмиссии, которое тест не дождался черезawait. Раньше оно продолжало работать в следующем тесте и падало там. Теперь оно закрывается в конце своего теста, а предупреждение называет этот тест. - 5.44.0: функция в
overridesдля метода становится спаем этого метода. Это касаетсяcreateSpyFromClassиprovideAutoSpy. Раньше функция сохранялась как есть, поэтомуexpect(sanitizer.sanitize).toHaveBeenCalledOnce()компилировался, а потом бросал[Function sanitize] is not a spy.
Изменения в setup и заглушке сети (с 5.19.0 по 5.22.0)
Это хелперы из vitest-auto-spy/setup. Каждое изменение может поменять результат спеки, которая раньше проходила.
- 5.19.0:
advanceTimers()отказывается работать, когда подменены только часы.mockSystemTime()подменяет одинDate, так что продвигать нечего. Раньше вызов проходил и ничего не делал. Теперь он бросает ошибку и называетsetupFakeTimers(). - 5.19.0:
withSystemTimeиmockSystemTimeвозвращают часы и под фейковыми таймерами набора тестов. Раньше откат там ничего не делал, и часы оставались там, где их бросил блок. - 5.20.0:
blockNetworkбольше не выключает MSW. Еслиserver.listen()стоит вbeforeAll, заглушкаfetchраньше ложилась поверх MSW. Тогда каждый замоканный запросfetchпадал сfetch is stubbed in unit tests, включая запросыHttpClient. - 5.22.0:
stubResponse({ body: null })отправляет JSON-литералnull. Раньшеnullозначал «без тела», и.json()бросалUnexpected end of JSON input. Чтобы тела не было, не указывайтеbodyили напишитеbody: undefined.{ body: null, status: 204 }(или 205, 304) теперь бросает ошибку с понятным текстом.
Изменения в пакете (5.19.0)
Они меняют то, как пакет ставится и загружается, а не то, что делает спай.
vitest— необязательная peer-зависимость. Проект на/bunили/nodeбольше не ставит Vitest. Диапазон прежний:>=2.1.0.vitest-auto-spy/package.jsonнаходится. Инструменты, которые читают манифест зависимости, например Storybook или Nx, раньше получалиERR_PACKAGE_PATH_NOT_EXPORTED.require('vitest-auto-spy/eslint-plugin')типизирован правильно. Его CommonJS-декларация теперьexport =. Раньшеeslint.config.ctsили.cjsпроходил проверку типов на вызове, который падает, и отвергал рабочий.
Изменения в правилах ESLint (с 5.5.0 по 5.25.0)
После обновления ждите новых замечаний. Числа взяты из одного проекта на 1 759 файлов спек.
- 5.5.0: два новых правила, оба
warn.no-stub-class-doubleнаходит класс-заглушку с полямиvi.fn().no-structural-doubleнаходит объект изvi.fn()с типом вида{ m: Mock }. Сначала они дали 12 замечаний в 8 файлах и 115 в 74. После изменения ниже — 10 в 7 и 5 в 4. - 5.5.0:
prefer-provide-auto-spyвидит больше подмен. Правило читаетuseClass:,useExisting:,useValue: new StubMock(),let, который заполняется вbeforeEach, иTestBed.overrideProvider. РаньшеoverrideProviderне читало ни одно правило. В том проекте замечаний стало 154 вместо 18, на уровнеerror. Большинство этих подмен раньше отмечалоno-structural-doubleна уровнеwarn. - 5.5.0: одна подмена — одно замечание.
prefer-create-spy-from-classиno-structural-doubleмолчат, когда объект уходит в DI Angular. Раньше объект вconstмог получить два замечания: одно советовалоcreateSpyFromClass, другоеprovideAutoSpy. - 5.5.0:
no-overridden-providerвидит провайдер, который заменяетTestBed.overrideProvider. ЗаменённыйprovideAutoSpy(X)— спай, которым никто не пользуется. - 5.24.0:
no-redundant-mock-resetотмечает меньше сбросов. 5.23.0 отмечал ещё три случая, где сброс не лишний: восстановление или сброс вafterEachилиafterAll, сброс после другогоbeforeEachи что угодно вbeforeAll. Теперь правило их не отмечает. - 5.25.0:
prefer-create-mockотмечает вложенные приведения фикстуры один раз. Раньше каждое приведение давало своё замечание. После исправления внешнего внутреннее приведение оставалось непроверенным.
Изменения в CLI (с 5.18.0 по 5.20.0)
Задача CI с perf --gate, doctor или init --check после обновления может сменить цвет.
- 5.18.0: порог
perfсудит файл по его тестам, а не по размеру. Бюджет файла теперь считается в медианных тестах прогона.--factorприменяется к каждому тесту;--max-file-ms— только нижняя граница. Старое правило отмечало большие файлы и медленные машины CI. Один и тот же файл был зелёным на ноутбуке и красным в CI. - 5.18.0:
perfпечатает то, что провалит--gate. Вместо двух таблиц «десять самых медленных» теперь файлы и тела тестов сверх бюджета. Старые таблицы показывали самые большие файлы, а они редко бывали медленными. - 5.19.0: неизвестный флаг — ошибка с кодом выхода 2. Раньше
init --dryrunзаписывал файлы, аperf --gatпроходил вообще без порога. - 5.19.0:
init --checkне реагирует на изменение одной только отметки версии. Новый релиз пакета больше не делает проверку красной, если инструкции не изменились. - 5.19.0: отчёты Code Quality сохраняют числа в обратных кавычках.
returns 200иreturns 404теперь две находки. Раньше виджет merge request показывал одну и терял другую. - 5.19.0: codemod правильно читает JSX.
/самозакрывающегося тега принимался за начало регулярного выражения. Часть спеки.tsxтогда пропускали все преобразования и--verify. - 5.20.0:
doctorпредупреждает, когда обход останавливается на лимите. После 50 000 файлов он сообщаетscan-cap-reached. Раньше он писал «No problems found.» про файлы, которые не читал. - 5.20.0: таблицы
perfпечатают путь последним и целиком. Раньше путь обрезался посередине, и скопировать его из лога CI было нельзя.
Общий strict: true начинает действовать (5.6.0)
До 5.6.0 setupAutoSpy({ strict: true }) ни на что не влиял: настройка попадала в копию модуля, которую не читала ни одна спека. 5.6.0 это исправил. Если ваш проект на 5.5 или раньше и эта опция задана, поведение меняется. Каждый ненастроенный вызов спая теперь бросает "… was called; this strict double has nothing configured for it". В одном проекте из-за этого покраснели десять тестов. Настройте вызов, который называет ошибка, или уберите strict для этого спая.
Что не изменилось
- Ни один хелпер не удалён, не переименован и не помечен устаревшим.
provideAutoSpy,injectSpy,renderShallow,createWithAutoSpies,stable,flushEffects, матчеры сигналов и ресурсов и хелперыmock*Propработают как раньше. - В самой 5.0 ни один путь импорта в ваших спеках не меняется. (Позже, в 5.21.0, часть хелперов Angular переехала; см. выше.)
- Angular остаётся необязательным. Проект на React, Vue, Svelte, NestJS или чистом Node не ставит ни одного Angular-пакета и не загружает их в свою программу TypeScript.
- Peer-зависимость
vitestпо-прежнему начинается с 2.1. Одна установка работает с Vitest от 2.1 до 5.x. - Поддерживаются и zoneless, и zone.js. Для
fakeAsyncпо-прежнему нуженvitest-auto-spy/zone.
Если вы идёте издалека
- В Переходе на 4.0 есть настоящая работа: rxjs ушёл из публикуемых деклараций, а две группы хелперов переехали на свои пути импорта.
- Переход на 3.0 — одна строка в
package.json. - Переход на 2.0 важен, только если вы ещё на 1.x.