From a4bf80619b597873445d8a4d392db99ac53b7c50 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Tue, 9 Dec 2025 17:36:57 -0500 Subject: [PATCH 01/74] migrate vitest to v4 --- apps/docs/package.json | 6 +- apps/ui-sharethrift/package.json | 6 +- package.json | 7 +- .../src/domain-seedwork/handle-event.test.ts | 8 +- .../src/in-proc-event-bus.test.ts | 14 +- .../src/node-event-bus.test.ts | 28 +- .../mongo-unit-of-work.test.ts | 163 +++-- .../mongo-unit-of-work.integration.test.ts | 1 + packages/cellix/ui-core/package.json | 8 +- packages/cellix/vitest-config/package.json | 4 +- .../src/configs/storybook.config.ts | 9 +- packages/cellix/vitest-config/tsconfig.json | 3 +- .../messaging-service-twilio/package.json | 2 +- .../src/index.test.ts | 15 +- .../mock-messaging-server/package.json | 2 +- .../account-plan.repository.test.ts | 7 +- .../conversation.repository.test.ts | 6 +- .../reservation-request.repository.test.ts | 8 +- .../admin-user/admin-user.repository.test.ts | 29 +- .../personal-user.repository.test.ts | 29 +- .../account-plan.read-repository.test.ts | 49 +- .../service-otel/src/otel-builder.test.ts | 73 +- packages/sthrift/ui-components/package.json | 6 +- pnpm-lock.yaml | 669 +++++++++--------- 24 files changed, 650 insertions(+), 502 deletions(-) diff --git a/apps/docs/package.json b/apps/docs/package.json index 33ac8242d..55fe592d7 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -37,10 +37,10 @@ "@testing-library/user-event": "^14.5.2", "@types/react": "^19.1.11", "@types/react-dom": "^19.1.6", - "@vitest/coverage-v8": "^3.2.4", + "@vitest/coverage-v8": "^4.0.15", "jsdom": "^26.1.0", - "typescript": "~5.6.2", - "vitest": "^3.2.4" + "typescript": "^5.8.3", + "vitest": "^4.0.15" }, "browserslist": { "production": [ diff --git a/apps/ui-sharethrift/package.json b/apps/ui-sharethrift/package.json index aeafe2597..4f95515ae 100644 --- a/apps/ui-sharethrift/package.json +++ b/apps/ui-sharethrift/package.json @@ -51,8 +51,8 @@ "@types/react": "^19.1.9", "@types/react-dom": "^19.1.7", "@vitejs/plugin-react": "^4.7.0", - "@vitest/browser": "3.2.4", - "@vitest/coverage-v8": "^3.2.4", + "@vitest/browser": "4.0.15", + "@vitest/coverage-v8": "^4.0.15", "eslint": "^9.30.1", "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.20", @@ -62,7 +62,7 @@ "typescript": "~5.8.3", "typescript-eslint": "^8.35.1", "vite": "^7.1.2", - "vitest": "^3.2.4" + "vitest": "^4.0.15" }, "license": "MIT" } diff --git a/package.json b/package.json index 710f3c933..44535c2ec 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "verify": "pnpm run test:coverage:merge && pnpm run sonar:pr && pnpm run check-sonar" }, "devDependencies": { - "@amiceli/vitest-cucumber": "^5.1.2", + "@amiceli/vitest-cucumber": "^6.1.0", "@biomejs/biome": "2.0.0", "@graphql-codegen/cli": "^5.0.7", "@graphql-codegen/introspection": "^4.0.3", @@ -52,7 +52,8 @@ "@playwright/test": "^1.55.1", "@sonar/scan": "^4.3.0", "@types/node": "^24.7.2", - "@vitest/coverage-v8": "^3.2.4", + "@vitest/browser-playwright": "^4.0.15", + "@vitest/coverage-v8": "^4.0.15", "azurite": "^3.35.0", "concurrently": "^9.1.2", "cpx2": "^3.0.2", @@ -62,6 +63,6 @@ "turbo": "^2.5.8", "typescript": "^5.8.3", "vite": "^7.0.4", - "vitest": "^3.2.4" + "vitest": "^4.0.15" } } \ No newline at end of file diff --git a/packages/cellix/domain-seedwork/src/domain-seedwork/handle-event.test.ts b/packages/cellix/domain-seedwork/src/domain-seedwork/handle-event.test.ts index c36f3b590..2204aded0 100644 --- a/packages/cellix/domain-seedwork/src/domain-seedwork/handle-event.test.ts +++ b/packages/cellix/domain-seedwork/src/domain-seedwork/handle-event.test.ts @@ -22,7 +22,7 @@ test.for(feature, ({ Scenario }) => { Scenario('Handling a domain event with a registered handler', ({ Given, When, Then }) => { Given('a domain event handler is registered with a function', () => { handlerFn = vi.fn(); - handler = new HandleEventImpl(handlerFn); + handler = new HandleEventImpl(handlerFn as (event: TestEvent) => void); event = new TestEvent('agg-1'); }); When('the handler is called with a domain event', () => { @@ -40,7 +40,7 @@ test.for(feature, ({ Scenario }) => { event = new TestEvent('agg-2'); }); When('I register the function using the static register method', () => { - handler = HandleEventImpl.register(handlerFn) as HandleEventImpl; + handler = HandleEventImpl.register(handlerFn as (event: TestEvent) => void) as HandleEventImpl; }); Then('I should get a handler that calls the function when handling an event', () => { handler.handle(event); @@ -59,8 +59,8 @@ test.for(feature, ({ Scenario }) => { Given('multiple handlers for a domain event', () => { handlerFn1 = vi.fn(); handlerFn2 = vi.fn(); - handler1 = new HandleEventImpl(handlerFn1); - handler2 = new HandleEventImpl(handlerFn2); + handler1 = new HandleEventImpl(handlerFn1 as (event: TestEvent) => void); + handler2 = new HandleEventImpl(handlerFn2 as (event: TestEvent) => void); event = new TestEvent('agg-3'); }); When('I register them all using registerAll', () => { diff --git a/packages/cellix/event-bus-seedwork-node/src/in-proc-event-bus.test.ts b/packages/cellix/event-bus-seedwork-node/src/in-proc-event-bus.test.ts index 88ad226a3..03264d8c8 100644 --- a/packages/cellix/event-bus-seedwork-node/src/in-proc-event-bus.test.ts +++ b/packages/cellix/event-bus-seedwork-node/src/in-proc-event-bus.test.ts @@ -72,7 +72,7 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { // handler and TestEvent are already defined }); When('the handler is registered', () => { - InProcEventBusInstance.register(TestEvent, handler); + InProcEventBusInstance.register(TestEvent, handler as (payload: { test: string }) => Promise); }); And('the event is dispatched', async () => { await InProcEventBusInstance.dispatch(TestEvent, { test: 'data' }); @@ -87,8 +87,8 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { // handler1 and handler2 are already defined }); When('both handlers are registered', () => { - InProcEventBusInstance.register(TestEvent, handler1); - InProcEventBusInstance.register(TestEvent, handler2); + InProcEventBusInstance.register(TestEvent, handler1 as (payload: { test: string }) => Promise); + InProcEventBusInstance.register(TestEvent, handler2 as (payload: { test: string }) => Promise); }); And('the event is dispatched', async () => { await InProcEventBusInstance.dispatch(TestEvent, { test: 'data' }); @@ -105,8 +105,8 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { handler2 = vi.fn().mockResolvedValue(undefined); }); When('one handler throws and both are registered', () => { - InProcEventBusInstance.register(TestEvent, handler1); - InProcEventBusInstance.register(TestEvent, handler2); + InProcEventBusInstance.register(TestEvent, handler1 as (payload: { test: string }) => Promise); + InProcEventBusInstance.register(TestEvent, handler2 as (payload: { test: string }) => Promise); }); And('the event is dispatched', async () => { try { @@ -130,8 +130,8 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { // handlerA, handlerB, TestEventA, TestEventB are already defined }); When('both handlers are registered for different events', () => { - InProcEventBusInstance.register(TestEventA, handlerA); - InProcEventBusInstance.register(TestEventB, handlerB); + InProcEventBusInstance.register(TestEventA, handlerA as (payload: { testA: string }) => Promise); + InProcEventBusInstance.register(TestEventB, handlerB as (payload: { testB: string }) => Promise); }); And('each event is dispatched', async () => { await InProcEventBusInstance.dispatch(TestEventA, { testA: 'dataA' }); diff --git a/packages/cellix/event-bus-seedwork-node/src/node-event-bus.test.ts b/packages/cellix/event-bus-seedwork-node/src/node-event-bus.test.ts index cf9f60723..1c8db9427 100644 --- a/packages/cellix/event-bus-seedwork-node/src/node-event-bus.test.ts +++ b/packages/cellix/event-bus-seedwork-node/src/node-event-bus.test.ts @@ -102,7 +102,7 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { // handler and TestEvent are already defined }); When('the handler is registered', () => { - NodeEventBusInstance.register(TestEvent, handler); + NodeEventBusInstance.register(TestEvent, handler as (payload: { test: string }) => Promise); }); And('the event is dispatched', async () => { await NodeEventBusInstance.dispatch(TestEvent, { test: 'data' }); @@ -117,8 +117,8 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { // handler and TestEvent are already defined }); When('the same handler is registered multiple times for the same event', () => { - NodeEventBusInstance.register(TestEvent, handler); - NodeEventBusInstance.register(TestEvent, handler); + NodeEventBusInstance.register(TestEvent, handler as (payload: { test: string }) => Promise); + NodeEventBusInstance.register(TestEvent, handler as (payload: { test: string }) => Promise); }); And('the event is dispatched', async () => { await NodeEventBusInstance.dispatch(TestEvent, { test: 'data' }); @@ -135,8 +135,8 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { // handlerA, handlerB, EventA, EventB are already defined }); When('each handler is registered for a different event', () => { - NodeEventBusInstance.register(EventA, handlerA); - NodeEventBusInstance.register(EventB, handlerB); + NodeEventBusInstance.register(EventA, handlerA as (payload: { a: string }) => Promise); + NodeEventBusInstance.register(EventB, handlerB as (payload: { b: string }) => Promise); }); And('each event is dispatched', async () => { await NodeEventBusInstance.dispatch(EventA, { a: 'A' }); @@ -164,7 +164,7 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { Given('a registered handler for an event that throws', async () => { handler = vi.fn().mockRejectedValue(new Error('handler error')); errorEvent = TestEvent; - NodeEventBusInstance.register(errorEvent, handler); + NodeEventBusInstance.register(errorEvent, handler as (payload: { test: string }) => Promise); // Patch OpenTelemetry span otel = await import('@opentelemetry/api'); @@ -272,8 +272,8 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { handler2 = vi.fn(() => callOrder.push('handler2')); }); When('all handlers are registered', () => { - NodeEventBusInstance.register(TestEvent, handler1); - NodeEventBusInstance.register(TestEvent, handler2); + NodeEventBusInstance.register(TestEvent, handler1 as (payload: { test: string }) => Promise); + NodeEventBusInstance.register(TestEvent, handler2 as (payload: { test: string }) => Promise); }); And('the event is dispatched', async () => { await NodeEventBusInstance.dispatch(TestEvent, { test: 'data' }); @@ -289,8 +289,8 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { handler2 = vi.fn().mockResolvedValue(undefined); }); When('all handlers are registered and one throws', () => { - NodeEventBusInstance.register(TestEvent, handler1); - NodeEventBusInstance.register(TestEvent, handler2); + NodeEventBusInstance.register(TestEvent, handler1 as (payload: { test: string }) => Promise); + NodeEventBusInstance.register(TestEvent, handler2 as (payload: { test: string }) => Promise); }); And('the event is dispatched', async () => { await expect(NodeEventBusInstance.dispatch(TestEvent, { test: 'data' })).resolves.not.toThrow(); @@ -307,8 +307,8 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { handler2 = vi.fn().mockRejectedValue(new Error('handler2 error')); }); When('all handlers are registered and all throw', () => { - NodeEventBusInstance.register(TestEvent, handler1); - NodeEventBusInstance.register(TestEvent, handler2); + NodeEventBusInstance.register(TestEvent, handler1 as (payload: { test: string }) => Promise); + NodeEventBusInstance.register(TestEvent, handler2 as (payload: { test: string }) => Promise); }); And('the event is dispatched', async () => { await expect(NodeEventBusInstance.dispatch(TestEvent, { test: 'data' })).resolves.not.toThrow(); @@ -331,7 +331,7 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { }); }); When('the handler is registered', () => { - NodeEventBusInstance.register(TestEvent, asyncHandler); + NodeEventBusInstance.register(TestEvent, asyncHandler as (payload: { test: string }) => Promise); }); And('the event is dispatched', async () => { const dispatchPromise = NodeEventBusInstance.dispatch(TestEvent, { test: 'data' }); @@ -358,7 +358,7 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { Scenario('Removing all listeners', ({ Given, When, And, Then }) => { Given('a registered handler for an event', () => { - NodeEventBusInstance.register(TestEvent, handler); + NodeEventBusInstance.register(TestEvent, handler as (payload: { test: string }) => Promise); }); When('removeAllListeners is called', () => { NodeEventBusInstance.removeAllListeners(); diff --git a/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts b/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts index def317660..3c09fbf1e 100644 --- a/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts +++ b/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts @@ -1,5 +1,5 @@ import { describeFeature, loadFeature } from '@amiceli/vitest-cucumber'; -import { expect, vi, type Mock} from 'vitest'; +import { expect, vi, type MockInstance } from 'vitest'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import type { ClientSession, Model } from 'mongoose'; @@ -17,7 +17,6 @@ const feature = await loadFeature( ); class AggregateRootMock extends DomainSeedwork.AggregateRoot { - override getIntegrationEvents = vi.fn(() => []); get foo(): string { return this.props.foo; } set foo(foo: string) { this.props.foo = foo; } get createdAt(): Date { return this.props.createdAt; } @@ -29,9 +28,7 @@ type PropType = DomainSeedwork.DomainEntityProps & { readonly updatedAt: Date; readonly schemaVersion: string; }; -class RepoMock extends MongoRepositoryBase { - override getIntegrationEvents = vi.fn(() => []); -} +class RepoMock extends MongoRepositoryBase {} class TestEvent extends DomainSeedwork.CustomDomainEventImpl<{ foo: string }> {} @@ -53,9 +50,12 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { let session: ClientSession; let mockModel: Model; let typeConverter: DomainSeedwork.TypeConverter; + const Passport = {}; - const mockRepoClass = vi.fn((_passport, _model, _typeConverter, _bus, _session): RepoMock => repoInstance); - let domainOperation: ReturnType; + // Always use a real class for repoClass + class TestRepoClass extends RepoMock {} + // Use a real async function for domainOperation + let domainOperation: ((repo: RepoMock) => Promise) & MockInstance; BeforeEachScenario(() => { session = {} as ClientSession; @@ -87,10 +87,11 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { dispatch: vi.fn(), register: vi.fn(), }) as DomainSeedwork.EventBus; - integrationEventBus = vi.mocked({ - dispatch: vi.fn(), - register: vi.fn(), - }) as DomainSeedwork.EventBus; + const dispatchMock = vi.fn(); + integrationEventBus = { + dispatch: dispatchMock, + register: vi.fn(), + } as unknown as DomainSeedwork.EventBus; repoInstance = new RepoMock( vi.mocked({}), mockModel, @@ -103,18 +104,27 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { integrationEventBus, mockModel, typeConverter, - mockRepoClass, + TestRepoClass, ); - domainOperation = vi.fn(async (repo: RepoMock) => { + const op = async (repo: RepoMock) => { const aggregate = await repo.get('agg-1'); aggregate.foo = 'new-foo'; await repo.save(aggregate); - }); + }; + domainOperation = vi.fn(op) as typeof domainOperation; + vi.clearAllMocks(); vi.spyOn(mongoose.connection, 'transaction').mockImplementation( async (cb: (session: ClientSession) => Promise) => { - await cb({} as ClientSession); + return await cb({} as ClientSession); }, ); + // Re-setup mockModel after clearAllMocks + (mockModel.findById as ReturnType).mockReturnValue({ + exec: vi.fn().mockResolvedValue({ + _id: 'agg-1', + foo: 'old-foo', + }), + }); }); Scenario('Initializing the MongoUnitOfWork', ({ Given, When, Then }) => { @@ -129,27 +139,55 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { expect(unitOfWork.typeConverter).toBe(typeConverter); expect(unitOfWork.bus).toBe(eventBus); expect(unitOfWork.integrationEventBus).toBe(integrationEventBus); - expect(unitOfWork.repoClass).toBe(mockRepoClass); + expect(unitOfWork.repoClass).toBe(TestRepoClass); }); }); Scenario('Domain operation with no events, completes successfully', ({ Given, When, Then }) => { Given('a domain operation that emits no domain or integration events', () => { - repoInstance.getIntegrationEvents = vi.fn(() => []); + // Patch getIntegrationEvents to always return an empty array of the correct type + repoInstance.getIntegrationEvents = vi.fn(() => []) as typeof repoInstance.getIntegrationEvents; + // Patch repoInstance.get to return a valid aggregate with all required properties + repoInstance.get = vi.fn().mockResolvedValue(new AggregateRootMock({ + id: 'agg-1', + foo: 'old-foo', + createdAt: new Date(), + updatedAt: new Date(), + schemaVersion: '1', + } as PropType, {})); + // Patch repoInstance.save to resolve + repoInstance.save = vi.fn().mockResolvedValue(undefined); }); When('the operation completes successfully', async () => { + domainOperation.mockClear(); + ((integrationEventBus.dispatch as unknown) as MockInstance).mockClear?.(); await unitOfWork.withTransaction(Passport, domainOperation); }); Then('the transaction is committed and no events are dispatched', () => { - expect(domainOperation).toHaveBeenCalledWith(repoInstance); - expect(integrationEventBus.dispatch).not.toHaveBeenCalled(); + // Accept any instance of TestRepoClass, not strict object equality + expect(domainOperation).toHaveBeenCalled(); + const callArg = domainOperation.mock.calls[0]?.[0]; + expect(callArg).toBeInstanceOf(TestRepoClass); + expect(callArg.model).toBe(mockModel); + expect(callArg.typeConverter).toBe(typeConverter); + expect(callArg.bus).toBe(eventBus); + expect(callArg.session).toStrictEqual(session); + expect(((integrationEventBus.dispatch as unknown) as MockInstance).mock.calls.length).toBe(0); }); }); Scenario('Domain operation with no events, throws error', ({ Given, When, Then }) => { let domainError: Error; Given('a domain operation that emits no domain or integration events', () => { - repoInstance.getIntegrationEvents = vi.fn(() => []); + repoInstance.getIntegrationEvents = vi.fn(() => []) as typeof repoInstance.getIntegrationEvents; + repoInstance.get = vi.fn().mockResolvedValue(new AggregateRootMock({ + id: 'agg-1', + foo: 'old-foo', + createdAt: new Date(), + updatedAt: new Date(), + schemaVersion: '1', + } as PropType, {})); + repoInstance.save = vi.fn().mockResolvedValue(undefined); domainError = new Error('Domain failure'); }); When('the operation throws an error', async () => { @@ -168,75 +206,100 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { Scenario('Domain operation emits integration events, all dispatch succeed', ({ Given, When, Then }) => { let event1: TestEvent; let event2: TestEvent; + let customDomainOp: typeof domainOperation; Given('integration events are emitted during the domain operation', () => { event1 = new TestEvent('id'); event1.payload = { foo: 'bar1' }; event2 = new TestEvent('id'); event2.payload = { foo: 'bar2' }; - repoInstance.getIntegrationEvents = vi.fn(() => [event1, event2]); + // Create a custom domain operation that adds integration events to the aggregate + const opWithEvents = async (repo: RepoMock) => { + const aggregate = await repo.get('agg-1'); + aggregate.foo = 'new-foo'; + // Add integration events using the real method + aggregate.addIntegrationEvent(TestEvent, event1.payload); + aggregate.addIntegrationEvent(TestEvent, event2.payload); + await repo.save(aggregate); + }; + customDomainOp = vi.fn(opWithEvents) as typeof domainOperation; }); When('the transaction completes successfully', async () => { - (integrationEventBus.dispatch as Mock) - .mockResolvedValueOnce(undefined) - .mockResolvedValueOnce(undefined); - await unitOfWork.withTransaction(Passport, domainOperation); + const dispatchMock = ((integrationEventBus.dispatch as unknown) as MockInstance); + dispatchMock.mockClear?.(); + dispatchMock.mockResolvedValueOnce(undefined); + dispatchMock.mockResolvedValueOnce(undefined); + await unitOfWork.withTransaction(Passport, customDomainOp); }); Then('all integration events are dispatched after the transaction commits', () => { - expect(integrationEventBus.dispatch).toHaveBeenCalledTimes(2); - expect(integrationEventBus.dispatch).toHaveBeenNthCalledWith( - 1, - event1.constructor, - event1.payload, - ); - expect(integrationEventBus.dispatch).toHaveBeenNthCalledWith( - 2, - event2.constructor, - event2.payload, - ); + const dispatchMock = ((integrationEventBus.dispatch as unknown) as MockInstance); + expect(dispatchMock).toHaveBeenCalledTimes(2); + expect(dispatchMock).toHaveBeenNthCalledWith(1, event1.constructor, event1.payload); + expect(dispatchMock).toHaveBeenNthCalledWith(2, event2.constructor, event2.payload); }); }); Scenario('Integration event dispatch fails', ({ Given, When, Then }) => { let event1: TestEvent; let event2: TestEvent; + let customDomainOp2: typeof domainOperation; Given('integration events are emitted during the domain operation', () => { event1 = new TestEvent('id'); event1.payload = { foo: 'bar1' }; event2 = new TestEvent('id'); event2.payload = { foo: 'bar2' }; - repoInstance.getIntegrationEvents = vi.fn(() => [event1, event2]); + // Create a custom domain operation that adds integration events to the aggregate + const opWithEvents2 = async (repo: RepoMock) => { + const aggregate = await repo.get('agg-1'); + aggregate.foo = 'new-foo'; + // Add integration events using the real method + aggregate.addIntegrationEvent(TestEvent, event1.payload); + aggregate.addIntegrationEvent(TestEvent, event2.payload); + await repo.save(aggregate); + }; + customDomainOp2 = vi.fn(opWithEvents2) as typeof domainOperation; }); When('integration event dispatch fails', async () => { - (integrationEventBus.dispatch as Mock) - .mockRejectedValueOnce(new Error('fail1')) - .mockResolvedValueOnce(undefined); - await expect( - unitOfWork.withTransaction(Passport, domainOperation), - ).rejects.toThrow('fail1'); + const dispatchMock = ((integrationEventBus.dispatch as unknown) as MockInstance); + dispatchMock.mockClear?.(); + dispatchMock.mockRejectedValueOnce(new Error('rejected promise')); + await expect(unitOfWork.withTransaction(Passport, customDomainOp2)).rejects.toThrow('rejected promise'); }); Then('the error from dispatch is propagated and the transaction is not rolled back by the unit of work', () => { - expect(integrationEventBus.dispatch).toHaveBeenCalledTimes(1); + const dispatchMock = ((integrationEventBus.dispatch as unknown) as MockInstance); + expect(dispatchMock).toHaveBeenCalledTimes(1); }); }); Scenario('Multiple integration events are emitted and all succeed', ({ Given, When, Then }) => { let event1: TestEvent; let event2: TestEvent; + let customDomainOp3: typeof domainOperation; Given('integration events are emitted during the domain operation', () => { event1 = new TestEvent('id'); event1.payload = { foo: 'bar1' }; event2 = new TestEvent('id'); event2.payload = { foo: 'bar2' }; - repoInstance.getIntegrationEvents = vi.fn(() => [event1, event2]); + // Create a custom domain operation that adds integration events to the aggregate + const opWithEvents3 = async (repo: RepoMock) => { + const aggregate = await repo.get('agg-1'); + aggregate.foo = 'new-foo'; + // Add integration events using the real method + aggregate.addIntegrationEvent(TestEvent, event1.payload); + aggregate.addIntegrationEvent(TestEvent, event2.payload); + await repo.save(aggregate); + }; + customDomainOp3 = vi.fn(opWithEvents3) as typeof domainOperation; }); When('multiple integration events are emitted and all succeed', async () => { - (integrationEventBus.dispatch as Mock) - .mockResolvedValueOnce(undefined) - .mockResolvedValueOnce(undefined); - await unitOfWork.withTransaction(Passport, domainOperation); + const dispatchMock = ((integrationEventBus.dispatch as unknown) as MockInstance); + dispatchMock.mockClear?.(); + dispatchMock.mockResolvedValueOnce(undefined); + dispatchMock.mockResolvedValueOnce(undefined); + await unitOfWork.withTransaction(Passport, customDomainOp3); }); Then('all are dispatched after the transaction', () => { - expect(integrationEventBus.dispatch).toHaveBeenCalledTimes(2); + const dispatchMock = ((integrationEventBus.dispatch as unknown) as MockInstance); + expect(dispatchMock).toHaveBeenCalledTimes(2); }); }); }); \ No newline at end of file diff --git a/packages/cellix/mongoose-seedwork/tests/integration/mongo-unit-of-work.integration.test.ts b/packages/cellix/mongoose-seedwork/tests/integration/mongo-unit-of-work.integration.test.ts index e7d00a64b..9c3894d06 100644 --- a/packages/cellix/mongoose-seedwork/tests/integration/mongo-unit-of-work.integration.test.ts +++ b/packages/cellix/mongoose-seedwork/tests/integration/mongo-unit-of-work.integration.test.ts @@ -195,6 +195,7 @@ describe('MongoUnitOfWork:Integration', () => { }); beforeEach(async () => { + vi.restoreAllMocks(); await TestModel.deleteMany({}); // biome-ignore lint:useLiteralKeys eventBus['eventSubscribers'] = {}; diff --git a/packages/cellix/ui-core/package.json b/packages/cellix/ui-core/package.json index 7e272c191..1468f28ab 100644 --- a/packages/cellix/ui-core/package.json +++ b/packages/cellix/ui-core/package.json @@ -46,15 +46,15 @@ "@storybook/react": "^9.1.9", "@storybook/react-vite": "^9.1.3", "@types/react": "^19.1.16", - "@vitest/browser": "^3.2.4", - "@vitest/coverage-v8": "^3.2.4", + "@vitest/browser": "^4.0.15", + "@vitest/coverage-v8": "^4.0.15", "jsdom": "^26.1.0", "react-oidc-context": "^3.3.0", "react-router-dom": "^7.9.3", "rimraf": "^6.0.1", "storybook": "^9.1.3", - "typescript": "^5.8.3", - "vitest": "^3.2.4" + "typescript": "^5.7.2", + "vitest": "^4.0.15" }, "license": "MIT" } diff --git a/packages/cellix/vitest-config/package.json b/packages/cellix/vitest-config/package.json index 1f76a6e4e..322bb34e8 100644 --- a/packages/cellix/vitest-config/package.json +++ b/packages/cellix/vitest-config/package.json @@ -12,7 +12,9 @@ }, "dependencies": { "@storybook/addon-vitest": "^9.1.10", - "vitest": "^3.2.4" + "@vitest/browser": "^4.0.15", + "@vitest/browser-playwright": "^4.0.15", + "vitest": "^4.0.15" }, "devDependencies": { "@cellix/typescript-config": "workspace:*", diff --git a/packages/cellix/vitest-config/src/configs/storybook.config.ts b/packages/cellix/vitest-config/src/configs/storybook.config.ts index 123426a1d..428c73e5d 100644 --- a/packages/cellix/vitest-config/src/configs/storybook.config.ts +++ b/packages/cellix/vitest-config/src/configs/storybook.config.ts @@ -2,6 +2,7 @@ import path from 'node:path'; import { storybookTest } from '@storybook/addon-vitest/vitest-plugin'; import { defineConfig, mergeConfig, type ViteUserConfig } from 'vitest/config'; import { baseConfig } from './base.config.ts'; +import { playwright } from '@vitest/browser-playwright' export type StorybookVitestConfigOptions = { storybookDirRelativeToPackage?: string; // default: '.storybook' @@ -15,7 +16,7 @@ export function createStorybookVitestConfig(pkgDirname: string, opts: StorybookV const setupFiles = opts.setupFiles ?? ['.storybook/vitest.setup.ts']; const instances = opts.browsers ?? [{ browser: 'chromium' }]; - const base = mergeConfig(baseConfig, defineConfig({ + const storybookConfig = defineConfig({ test: { globals: true, projects: [ @@ -31,7 +32,7 @@ export function createStorybookVitestConfig(pkgDirname: string, opts: StorybookV browser: { enabled: true, headless: true, - provider: 'playwright', + provider: playwright(), instances, }, setupFiles, @@ -56,7 +57,7 @@ export function createStorybookVitestConfig(pkgDirname: string, opts: StorybookV ], }, }, - })); + }); - return mergeConfig(base, defineConfig({})); + return mergeConfig(mergeConfig(baseConfig, storybookConfig), defineConfig({})); } diff --git a/packages/cellix/vitest-config/tsconfig.json b/packages/cellix/vitest-config/tsconfig.json index ae2b2f00c..3a9f9b98e 100644 --- a/packages/cellix/vitest-config/tsconfig.json +++ b/packages/cellix/vitest-config/tsconfig.json @@ -2,7 +2,8 @@ "extends": "@cellix/typescript-config/node.json", "compilerOptions": { "outDir": "dist", - "rootDir": "." + "rootDir": ".", + "lib": ["ES2022", "DOM"] }, "include": ["src"], "exclude": ["dist", "node_modules"] diff --git a/packages/sthrift/messaging-service-twilio/package.json b/packages/sthrift/messaging-service-twilio/package.json index bb7ef4d24..3eee22ceb 100644 --- a/packages/sthrift/messaging-service-twilio/package.json +++ b/packages/sthrift/messaging-service-twilio/package.json @@ -26,7 +26,7 @@ "@cellix/typescript-config": "workspace:*", "@cellix/vitest-config": "workspace:*", "@types/node": "^22.0.0", - "vitest": "^3.2.4" + "vitest": "^4.0.15" }, "license": "MIT" } \ No newline at end of file diff --git a/packages/sthrift/messaging-service-twilio/src/index.test.ts b/packages/sthrift/messaging-service-twilio/src/index.test.ts index 9e50a0ed0..c0aa40098 100644 --- a/packages/sthrift/messaging-service-twilio/src/index.test.ts +++ b/packages/sthrift/messaging-service-twilio/src/index.test.ts @@ -43,14 +43,20 @@ vi.mock('twilio', () => { conversations: { v1: { conversations: Object.assign( - vi.fn(() => mockConversationInstance), + // biome-ignore lint/complexity/useArrowFunction: Vitest 4.x requires constructor function pattern + vi.fn(function () { + return mockConversationInstance; + }), mockConversationsApi, ), }, }, }; - const TwilioConstructor = vi.fn(() => mockClient); + // biome-ignore lint/complexity/useArrowFunction: Vitest 4.x requires constructor function pattern + const TwilioConstructor = vi.fn(function () { + return mockClient; + }); return { default: { @@ -85,7 +91,10 @@ describe('ServiceMessagingTwilio', () => { }); it('should create instance with empty credentials and warn', () => { - const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(); + // biome-ignore lint/complexity/useArrowFunction: Vitest 4.x requires constructor function pattern + const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(function () { + // Mock implementation + }); service = new ServiceMessagingTwilio('', ''); expect(service).toBeDefined(); expect(consoleWarnSpy).toHaveBeenCalledWith( diff --git a/packages/sthrift/mock-messaging-server/package.json b/packages/sthrift/mock-messaging-server/package.json index cd47e3636..4c641c092 100644 --- a/packages/sthrift/mock-messaging-server/package.json +++ b/packages/sthrift/mock-messaging-server/package.json @@ -31,6 +31,6 @@ "supertest": "^7.0.0", "tsc-watch": "^7.1.1", "typescript": "^5.8.3", - "vitest": "^3.2.4" + "vitest": "^4.0.15" } } diff --git a/packages/sthrift/persistence/src/datasources/domain/account-plan/account-plan/account-plan.repository.test.ts b/packages/sthrift/persistence/src/datasources/domain/account-plan/account-plan/account-plan.repository.test.ts index c7f942a5d..1809590a1 100644 --- a/packages/sthrift/persistence/src/datasources/domain/account-plan/account-plan/account-plan.repository.test.ts +++ b/packages/sthrift/persistence/src/datasources/domain/account-plan/account-plan/account-plan.repository.test.ts @@ -278,9 +278,10 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { }; repository = setupAccountPlanRepo(mockDoc, { - modelCtor: vi.fn( - () => mockNewDoc, - ) as unknown as Models.AccountPlan.AccountPlanModelType, + // Use a real constructor function for the model mock + // Use a proper constructor function for Vitest 4.x compatibility + // biome-ignore lint/complexity/useArrowFunction: Constructor function must be a regular function + modelCtor: vi.fn(function() { return mockNewDoc; }) as unknown as Models.AccountPlan.AccountPlanModelType, }); result = await repository.getNewInstance(planInfo); diff --git a/packages/sthrift/persistence/src/datasources/domain/conversation/conversation/conversation.repository.test.ts b/packages/sthrift/persistence/src/datasources/domain/conversation/conversation/conversation.repository.test.ts index 978d8b792..b8a090d59 100644 --- a/packages/sthrift/persistence/src/datasources/domain/conversation/conversation/conversation.repository.test.ts +++ b/packages/sthrift/persistence/src/datasources/domain/conversation/conversation/conversation.repository.test.ts @@ -352,8 +352,10 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { }); // Setup repository with constructor mock - repository = setupConversationRepo(mockDoc, { - modelCtor: vi.fn(() => mockNewDoc) as unknown as Models.Conversation.ConversationModelType + repository = setupConversationRepo(mockDoc, { + // Use a proper constructor function for Vitest 4.x compatibility + // biome-ignore lint/complexity/useArrowFunction: Constructor function must be a regular function + modelCtor: vi.fn(function() { return mockNewDoc; }) as unknown as Models.Conversation.ConversationModelType }); result = await repository.getNewInstance(sharer, reserver, listing); diff --git a/packages/sthrift/persistence/src/datasources/domain/reservation-request/reservation-request/reservation-request.repository.test.ts b/packages/sthrift/persistence/src/datasources/domain/reservation-request/reservation-request/reservation-request.repository.test.ts index b937a293f..52d5a9169 100644 --- a/packages/sthrift/persistence/src/datasources/domain/reservation-request/reservation-request/reservation-request.repository.test.ts +++ b/packages/sthrift/persistence/src/datasources/domain/reservation-request/reservation-request/reservation-request.repository.test.ts @@ -295,9 +295,11 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { }; // Setup repository with constructor mock - repository = setupReservationRequestRepo(mockDoc, { - modelCtor: vi.fn(() => mockNewDoc) as unknown as Models.ReservationRequest.ReservationRequestModelType - }); + repository = setupReservationRequestRepo(mockDoc, { + // Use a proper constructor function for Vitest 4.x compatibility + // biome-ignore lint/complexity/useArrowFunction: Constructor function must be a regular function + modelCtor: vi.fn(function() { return mockNewDoc; }) as unknown as Models.ReservationRequest.ReservationRequestModelType + }); result = await repository.getNewInstance( 'PENDING', diff --git a/packages/sthrift/persistence/src/datasources/domain/user/admin-user/admin-user.repository.test.ts b/packages/sthrift/persistence/src/datasources/domain/user/admin-user/admin-user.repository.test.ts index c939d5420..8db033421 100644 --- a/packages/sthrift/persistence/src/datasources/domain/user/admin-user/admin-user.repository.test.ts +++ b/packages/sthrift/persistence/src/datasources/domain/user/admin-user/admin-user.repository.test.ts @@ -168,21 +168,22 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { 'I call getNewInstance with email "newadmin@example.com", username "newadmin", firstName "New", and lastName "Admin"', async () => { const newDoc = { ...mockDoc }; - // Create a proper constructor function mock - const ModelConstructor = vi.fn().mockImplementation(() => newDoc); - // Add the other mongoose model methods that might be needed - Object.assign(ModelConstructor, { - findOne: mockModel.findOne, - findById: mockModel.findById, - }); + // Create a proper constructor function mock + // Use a proper constructor function for Vitest 4.x compatibility + // biome-ignore lint/complexity/useArrowFunction: Constructor function must be a regular function + const ModelConstructor = vi.fn(function() { return newDoc; }); + Object.assign(ModelConstructor, { + findOne: mockModel.findOne, + findById: mockModel.findById, + }); - repository = new AdminUserRepository( - passport, - ModelConstructor as unknown as Models.User.AdminUserModelType, - new AdminUserConverter(), - eventBus, - session, - ); + repository = new AdminUserRepository( + passport, + ModelConstructor as unknown as Models.User.AdminUserModelType, + new AdminUserConverter(), + eventBus, + session, + ); result = await repository.getNewInstance( 'newadmin@example.com', 'newadmin', diff --git a/packages/sthrift/persistence/src/datasources/domain/user/personal-user/personal-user.repository.test.ts b/packages/sthrift/persistence/src/datasources/domain/user/personal-user/personal-user.repository.test.ts index e3281133e..1ba5ecb2e 100644 --- a/packages/sthrift/persistence/src/datasources/domain/user/personal-user/personal-user.repository.test.ts +++ b/packages/sthrift/persistence/src/datasources/domain/user/personal-user/personal-user.repository.test.ts @@ -178,21 +178,22 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { 'I call getNewInstance with email "new@example.com", firstName "New", and lastName "User"', async () => { const newDoc = { ...mockDoc }; - // Create a proper constructor function mock - const ModelConstructor = vi.fn().mockImplementation(() => newDoc); - // Add the other mongoose model methods that might be needed - Object.assign(ModelConstructor, { - findOne: mockModel.findOne, - findById: mockModel.findById, - }); + // Create a proper constructor function mock + // Use a proper constructor function for Vitest 4.x compatibility + // biome-ignore lint/complexity/useArrowFunction: Constructor function must be a regular function + const ModelConstructor = vi.fn(function() { return newDoc; }); + Object.assign(ModelConstructor, { + findOne: mockModel.findOne, + findById: mockModel.findById, + }); - repository = new PersonalUserRepository( - passport, - ModelConstructor as unknown as Models.User.PersonalUserModelType, - new PersonalUserConverter(), - eventBus, - session, - ); + repository = new PersonalUserRepository( + passport, + ModelConstructor as unknown as Models.User.PersonalUserModelType, + new PersonalUserConverter(), + eventBus, + session, + ); result = await repository.getNewInstance( 'new@example.com', 'New', diff --git a/packages/sthrift/persistence/src/datasources/readonly/account-plan/account-plan/account-plan.read-repository.test.ts b/packages/sthrift/persistence/src/datasources/readonly/account-plan/account-plan/account-plan.read-repository.test.ts index 5c18d60af..2dc43f85e 100644 --- a/packages/sthrift/persistence/src/datasources/readonly/account-plan/account-plan/account-plan.read-repository.test.ts +++ b/packages/sthrift/persistence/src/datasources/readonly/account-plan/account-plan/account-plan.read-repository.test.ts @@ -6,25 +6,54 @@ import { AccountPlanReadRepositoryImpl, getAccountPlanReadRepository } from './a // Mock the converter vi.mock('../../../domain/account-plan/account-plan/account-plan.domain-adapter.ts', () => ({ - AccountPlanConverter: vi.fn().mockImplementation(() => ({ - toDomain: vi.fn((doc) => ({ id: doc._id, name: doc.name })), - })), + // biome-ignore lint/complexity/useArrowFunction: Constructor function must be a regular function + AccountPlanConverter: vi.fn(function() { + return { + toDomain: vi.fn((doc) => ({ id: doc._id, name: doc.name })), + }; + }), })); vi.mock('../account-plan/account-plan.data.ts', () => ({ - AccountPlanDataSourceImpl: vi.fn().mockImplementation(() => ({ - find: vi.fn(), - findById: vi.fn(), - findOne: vi.fn(), - })), + // biome-ignore lint/complexity/useArrowFunction: Constructor function must be a regular function + AccountPlanDataSourceImpl: vi.fn(function() { + return { + find: vi.fn(), + findById: vi.fn(), + findOne: vi.fn(), + }; + }), })); function makeModelsContext(): ModelsContext { return { + User: { + PersonalUser: vi.fn(() => ({})), + AdminUser: vi.fn(() => ({})), + User: vi.fn(() => ({})), + }, + Listing: { + ItemListingModel: vi.fn(() => ({})), + }, + Conversation: { + ConversationModel: vi.fn(() => ({})), + }, + ReservationRequest: { + ReservationRequest: vi.fn(() => ({})), + }, + Role: { + Role: vi.fn(() => ({})), + AdminRole: vi.fn(() => ({})), + }, AccountPlan: { - AccountPlanModel: {}, + // Mock is not used since AccountPlanDataSourceImpl is mocked + AccountPlanModel: vi.fn(() => ({})), + }, + AppealRequest: { + ListingAppealRequest: vi.fn(() => ({})), + UserAppealRequest: vi.fn(() => ({})), }, - } as ModelsContext; + } as unknown as ModelsContext; } function makePassport(): Domain.Passport { diff --git a/packages/sthrift/service-otel/src/otel-builder.test.ts b/packages/sthrift/service-otel/src/otel-builder.test.ts index 2e7645a91..5bc97bba3 100644 --- a/packages/sthrift/service-otel/src/otel-builder.test.ts +++ b/packages/sthrift/service-otel/src/otel-builder.test.ts @@ -19,27 +19,50 @@ import { OtelBuilder } from './otel-builder.ts'; const test = { for: describeFeature }; // Move mocks INSIDE the vi.mock factory to avoid hoisting issues vi.mock('@azure/monitor-opentelemetry-exporter', () => { - // Unique classes for instanceof checks - class TraceExporter {} - class MetricExporter {} - class LogExporter {} - // Mocks that attach args for assertion - const traceExporterMock = vi.fn((args) => Object.assign(new TraceExporter(), { __args: args })); - const metricExporterMock = vi.fn((args) => Object.assign(new MetricExporter(), { __args: args })); - const logExporterMock = vi.fn((args) => Object.assign(new LogExporter(), { __args: args })); - // Expose mocks and classes for test access + // Class-based mocks that record constructor args + type ExporterArgs = Record; + class TraceExporter { + public __args: ExporterArgs; + constructor(args: ExporterArgs) { + TraceExporter.mock.calls.push(args); + this.__args = args; + } + public static readonly mock: { calls: ExporterArgs[] } = { calls: [] }; + } + class MetricExporter { + public __args: ExporterArgs; + constructor(args: ExporterArgs) { + MetricExporter.mock.calls.push(args); + this.__args = args; + } + public static readonly mock: { calls: ExporterArgs[] } = { calls: [] }; + } + class LogExporter { + public __args: ExporterArgs; + constructor(args: ExporterArgs) { + LogExporter.mock.calls.push(args); + this.__args = args; + } + public static readonly mock: { calls: ExporterArgs[] } = { calls: [] }; + } + // Helper reset for test access + function clearMocks() { + TraceExporter.mock.calls = []; + MetricExporter.mock.calls = []; + LogExporter.mock.calls = []; + } return { - AzureMonitorTraceExporter: traceExporterMock, - AzureMonitorMetricExporter: metricExporterMock, - AzureMonitorLogExporter: logExporterMock, - // For test access + AzureMonitorTraceExporter: TraceExporter, + AzureMonitorMetricExporter: MetricExporter, + AzureMonitorLogExporter: LogExporter, __test: { - traceExporterMock, - metricExporterMock, - logExporterMock, + traceExporterMock: TraceExporter.mock, + metricExporterMock: MetricExporter.mock, + logExporterMock: LogExporter.mock, TraceExporter, MetricExporter, LogExporter, + clearMocks, }, }; }); @@ -54,9 +77,9 @@ const feature = await loadFeature( test.for(feature, ({ Scenario, BeforeEachScenario, AfterEachScenario }) => { let builder: OtelBuilder; let originalEnv: NodeJS.ProcessEnv; - let traceExporterMock: ReturnType; - let metricExporterMock: ReturnType; - let logExporterMock: ReturnType; + let traceExporterMock: { calls: unknown[] }; + let metricExporterMock: { calls: unknown[] }; + let logExporterMock: { calls: unknown[] }; let TraceExporter: new (...args: unknown[]) => unknown; let MetricExporter: new (...args: unknown[]) => unknown; let LogExporter: new (...args: unknown[]) => unknown; @@ -73,9 +96,9 @@ test.for(feature, ({ Scenario, BeforeEachScenario, AfterEachScenario }) => { TraceExporter = azureModule.__test.TraceExporter; MetricExporter = azureModule.__test.MetricExporter; LogExporter = azureModule.__test.LogExporter; - traceExporterMock.mockClear(); - metricExporterMock.mockClear(); - logExporterMock.mockClear(); + traceExporterMock.calls = []; + metricExporterMock.calls = []; + logExporterMock.calls = []; }); AfterEachScenario(() => { @@ -112,9 +135,9 @@ test.for(feature, ({ Scenario, BeforeEachScenario, AfterEachScenario }) => { expect(exporters.traceExporter).toBeInstanceOf(TraceExporter); expect(exporters.metricExporter).toBeInstanceOf(MetricExporter); expect(exporters.logExporter).toBeInstanceOf(LogExporter); - expect(traceExporterMock).toHaveBeenCalledWith({ connectionString: connStr }); - expect(metricExporterMock).toHaveBeenCalledWith({ connectionString: connStr }); - expect(logExporterMock).toHaveBeenCalledWith({ connectionString: connStr }); + expect(traceExporterMock.calls.at(-1)).toEqual({ connectionString: connStr }); + expect(metricExporterMock.calls.at(-1)).toEqual({ connectionString: connStr }); + expect(logExporterMock.calls.at(-1)).toEqual({ connectionString: connStr }); // Also check the instance has the correct property for extra safety expect((exporters.traceExporter as unknown as { __args: { connectionString: string } }).__args.connectionString).toBe(connStr); expect((exporters.metricExporter as unknown as { __args: { connectionString: string } }).__args.connectionString).toBe(connStr); diff --git a/packages/sthrift/ui-components/package.json b/packages/sthrift/ui-components/package.json index abd034bfb..4f88d9939 100644 --- a/packages/sthrift/ui-components/package.json +++ b/packages/sthrift/ui-components/package.json @@ -68,8 +68,8 @@ "@storybook/react-vite": "^9.1.3", "@types/react": "^19.1.11", "@types/react-dom": "^19.1.6", - "@vitest/browser": "^3.2.4", - "@vitest/coverage-v8": "^3.2.4", + "@vitest/browser": "^4.0.15", + "@vitest/coverage-v8": "^4.0.15", "jsdom": "^26.1.0", "markdown-to-jsx": "^7.4.6", "playwright": "^1.55.0", @@ -77,7 +77,7 @@ "storybook": "^9.1.3", "typescript": "^5.8.3", "vite": "^7.0.4", - "vitest": "^3.2.4" + "vitest": "^4.0.15" }, "license": "MIT" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a97d651ab..8a4fd5a33 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21,8 +21,8 @@ importers: .: devDependencies: '@amiceli/vitest-cucumber': - specifier: ^5.1.2 - version: 5.2.1(vitest@3.2.4) + specifier: ^6.1.0 + version: 6.1.0(vitest@4.0.15) '@biomejs/biome': specifier: 2.0.0 version: 2.0.0 @@ -56,9 +56,12 @@ importers: '@types/node': specifier: ^24.7.2 version: 24.9.2 + '@vitest/browser-playwright': + specifier: ^4.0.15 + version: 4.0.15(playwright@1.56.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) '@vitest/coverage-v8': - specifier: ^3.2.4 - version: 3.2.4(@vitest/browser@3.2.4)(vitest@3.2.4) + specifier: ^4.0.15 + version: 4.0.15(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15) azurite: specifier: ^3.35.0 version: 3.35.0 @@ -87,8 +90,8 @@ importers: specifier: ^7.0.4 version: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) vitest: - specifier: ^3.2.4 - version: 3.2.4(@types/debug@4.1.12)(@types/node@24.9.2)(@vitest/browser@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + specifier: ^4.0.15 + version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) apps/api: dependencies: @@ -173,10 +176,10 @@ importers: dependencies: '@docusaurus/core': specifier: 3.8.1 - version: 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) + version: 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) '@docusaurus/preset-classic': specifier: 3.8.1 - version: 3.8.1(@algolia/client-search@5.41.0)(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(search-insights@2.17.3)(typescript@5.6.3) + version: 3.8.1(@algolia/client-search@5.41.0)(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(search-insights@2.17.3)(typescript@5.8.3) '@mdx-js/react': specifier: ^3.0.0 version: 3.1.1(@types/react@19.2.2)(react@19.2.0) @@ -224,17 +227,17 @@ importers: specifier: ^19.1.6 version: 19.2.2(@types/react@19.2.2) '@vitest/coverage-v8': - specifier: ^3.2.4 - version: 3.2.4(@vitest/browser@3.2.4)(vitest@3.2.4) + specifier: ^4.0.15 + version: 4.0.15(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15) jsdom: specifier: ^26.1.0 version: 26.1.0 typescript: - specifier: ~5.6.2 - version: 5.6.3 + specifier: ^5.8.3 + version: 5.8.3 vitest: - specifier: ^3.2.4 - version: 3.2.4(@types/debug@4.1.12)(@types/node@24.9.2)(@vitest/browser@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + specifier: ^4.0.15 + version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) apps/ui-sharethrift: dependencies: @@ -316,7 +319,7 @@ importers: version: 9.1.16(@types/react@19.2.2)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) '@storybook/addon-vitest': specifier: ^9.1.1 - version: 9.1.16(@vitest/browser@3.2.4)(@vitest/runner@3.2.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@3.2.4) + version: 9.1.16(@vitest/browser-playwright@4.0.15)(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(@vitest/runner@4.0.15)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@4.0.15) '@storybook/react': specifier: ^9.1.10 version: 9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3) @@ -339,11 +342,11 @@ importers: specifier: ^4.7.0 version: 4.7.0(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) '@vitest/browser': - specifier: 3.2.4 - version: 3.2.4(playwright@1.56.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4) + specifier: 4.0.15 + version: 4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) '@vitest/coverage-v8': - specifier: ^3.2.4 - version: 3.2.4(@vitest/browser@3.2.4)(vitest@3.2.4) + specifier: ^4.0.15 + version: 4.0.15(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15) eslint: specifier: ^9.30.1 version: 9.38.0(jiti@2.6.1) @@ -372,8 +375,8 @@ importers: specifier: ^7.1.2 version: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) vitest: - specifier: ^3.2.4 - version: 3.2.4(@types/debug@4.1.12)(@types/node@24.9.2)(@vitest/browser@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + specifier: ^4.0.15 + version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) packages/cellix/api-services-spec: devDependencies: @@ -610,7 +613,7 @@ importers: version: 9.1.16(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) '@storybook/addon-vitest': specifier: ^9.1.3 - version: 9.1.16(@vitest/browser@3.2.4)(@vitest/runner@3.2.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@3.2.4) + version: 9.1.16(@vitest/browser-playwright@4.0.15)(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(@vitest/runner@4.0.15)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@4.0.15) '@storybook/react': specifier: ^9.1.9 version: 9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3) @@ -621,11 +624,11 @@ importers: specifier: ^19.1.16 version: 19.2.2 '@vitest/browser': - specifier: ^3.2.4 - version: 3.2.4(playwright@1.56.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4) + specifier: ^4.0.15 + version: 4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) '@vitest/coverage-v8': - specifier: ^3.2.4 - version: 3.2.4(@vitest/browser@3.2.4)(vitest@3.2.4) + specifier: ^4.0.15 + version: 4.0.15(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15) jsdom: specifier: ^26.1.0 version: 26.1.0 @@ -642,20 +645,26 @@ importers: specifier: ^9.1.3 version: 9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) typescript: - specifier: ^5.8.3 + specifier: ^5.7.2 version: 5.8.3 vitest: - specifier: ^3.2.4 - version: 3.2.4(@types/debug@4.1.12)(@types/node@24.9.2)(@vitest/browser@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + specifier: ^4.0.15 + version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) packages/cellix/vitest-config: dependencies: '@storybook/addon-vitest': specifier: ^9.1.10 - version: 9.1.16(@vitest/browser@3.2.4)(@vitest/runner@3.2.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@3.2.4) + version: 9.1.16(@vitest/browser-playwright@4.0.15)(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(@vitest/runner@4.0.15)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@4.0.15) + '@vitest/browser': + specifier: ^4.0.15 + version: 4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) + '@vitest/browser-playwright': + specifier: ^4.0.15 + version: 4.0.15(playwright@1.56.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) vitest: - specifier: ^3.2.4 - version: 3.2.4(@types/debug@4.1.12)(@types/node@24.9.2)(@vitest/browser@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + specifier: ^4.0.15 + version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) devDependencies: '@cellix/typescript-config': specifier: workspace:* @@ -921,8 +930,8 @@ importers: specifier: ^5.8.3 version: 5.8.3 vitest: - specifier: ^3.2.4 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.0)(@vitest/browser@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + specifier: ^4.0.15 + version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.19.0)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) packages/sthrift/mock-messaging-server: dependencies: @@ -964,8 +973,8 @@ importers: specifier: ^5.8.3 version: 5.8.3 vitest: - specifier: ^3.2.4 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.0)(@vitest/browser@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + specifier: ^4.0.15 + version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.19.0)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) packages/sthrift/mock-mongodb-memory-server: dependencies: @@ -1327,7 +1336,7 @@ importers: version: 9.1.16(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) '@storybook/addon-vitest': specifier: ^9.1.3 - version: 9.1.16(@vitest/browser@3.2.4)(@vitest/runner@3.2.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@3.2.4) + version: 9.1.16(@vitest/browser-playwright@4.0.15)(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(@vitest/runner@4.0.15)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@4.0.15) '@storybook/react': specifier: ^9.1.10 version: 9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3) @@ -1341,11 +1350,11 @@ importers: specifier: ^19.1.6 version: 19.2.2(@types/react@19.2.2) '@vitest/browser': - specifier: ^3.2.4 - version: 3.2.4(playwright@1.56.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4) + specifier: ^4.0.15 + version: 4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) '@vitest/coverage-v8': - specifier: ^3.2.4 - version: 3.2.4(@vitest/browser@3.2.4)(vitest@3.2.4) + specifier: ^4.0.15 + version: 4.0.15(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15) jsdom: specifier: ^26.1.0 version: 26.1.0 @@ -1368,8 +1377,8 @@ importers: specifier: ^7.0.4 version: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) vitest: - specifier: ^3.2.4 - version: 3.2.4(@types/debug@4.1.12)(@types/node@24.9.2)(@vitest/browser@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + specifier: ^4.0.15 + version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) packages: @@ -1455,15 +1464,11 @@ packages: resolution: {integrity: sha512-tYv3rGbhBS0eZ5D8oCgV88iuWILROiemk+tQ3YsAKZv2J4kKUNvKkrX/If/SreRy4MGP2uJzMlyKcfSfO2mrsQ==} engines: {node: '>= 14.0.0'} - '@amiceli/vitest-cucumber@5.2.1': - resolution: {integrity: sha512-gAs0j2CMGzcxe/11ZLWKUyiII7U4AF5kFBzptyisFCWhcQagZ3rIXLV5cNj5RIhIjxqJTSdaam9389Lq3u6cbA==} + '@amiceli/vitest-cucumber@6.1.0': + resolution: {integrity: sha512-3GE3F8tHBkvf04PbVfH5hopNNwPjlV8ebf7NAfxPaKG31IZTWKl0VvYt0qHNepahdR7MVB6dOpW+e/RTP08FZg==} hasBin: true peerDependencies: - vitest: ^3.1.4 - - '@ampproject/remapping@2.3.0': - resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} - engines: {node: '>=6.0.0'} + vitest: ^4.0.4 '@ant-design/colors@7.2.1': resolution: {integrity: sha512-lCHDcEzieu4GA3n8ELeZ5VQ8pKQAWcGGLRTQ50aQM2iqPpq2evTxER84jfdPvsPAtEcZ7m44NI45edFMo8oOYQ==} @@ -3535,10 +3540,6 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} - '@istanbuljs/schema@0.1.3': - resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} - engines: {node: '>=8'} - '@jest/schemas@29.6.3': resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -4279,6 +4280,9 @@ packages: engines: {node: '>= 18'} hasBin: true + '@standard-schema/spec@1.0.0': + resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} + '@storybook/addon-a11y@9.1.16': resolution: {integrity: sha512-DpUqAMOgkC/K/DgB9osqbBYmiWWj7V444HeYLHcx7GdPtg2guq1jAcalsOnQeU3wXgUE+wNuyMm6qZKm7of11g==} peerDependencies: @@ -4937,26 +4941,22 @@ packages: peerDependencies: vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 - '@vitest/browser@3.2.4': - resolution: {integrity: sha512-tJxiPrWmzH8a+w9nLKlQMzAKX/7VjFs50MWgcAj7p9XQ7AQ9/35fByFYptgPELyLw+0aixTnC4pUWV+APcZ/kw==} + '@vitest/browser-playwright@4.0.15': + resolution: {integrity: sha512-94yVpDbb+ykiT7mK6ToonGnq2GIHEQGBTZTAzGxBGQXcVNCh54YKC2/WkfaDzxy0m6Kgw05kq3FYHKHu+wRdIA==} peerDependencies: playwright: '*' - safaridriver: '*' - vitest: 3.2.4 - webdriverio: ^7.0.0 || ^8.0.0 || ^9.0.0 - peerDependenciesMeta: - playwright: - optional: true - safaridriver: - optional: true - webdriverio: - optional: true + vitest: 4.0.15 + + '@vitest/browser@4.0.15': + resolution: {integrity: sha512-zedtczX688KehaIaAv7m25CeDLb0gBtAOa2Oi1G1cqvSO5aLSVfH6lpZMJLW8BKYuWMxLQc9/5GYoM+jgvGIrw==} + peerDependencies: + vitest: 4.0.15 - '@vitest/coverage-v8@3.2.4': - resolution: {integrity: sha512-EyF9SXU6kS5Ku/U82E259WSnvg6c8KTjppUncuNdm5QHpe17mwREHnjDzozC8x9MZ0xfBUFSaLkRv4TMA75ALQ==} + '@vitest/coverage-v8@4.0.15': + resolution: {integrity: sha512-FUJ+1RkpTFW7rQITdgTi93qOCWJobWhBirEPCeXh2SW2wsTlFxy51apDz5gzG+ZEYt/THvWeNmhdAoS9DTwpCw==} peerDependencies: - '@vitest/browser': 3.2.4 - vitest: 3.2.4 + '@vitest/browser': 4.0.15 + vitest: 4.0.15 peerDependenciesMeta: '@vitest/browser': optional: true @@ -4964,6 +4964,9 @@ packages: '@vitest/expect@3.2.4': resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} + '@vitest/expect@4.0.15': + resolution: {integrity: sha512-Gfyva9/GxPAWXIWjyGDli9O+waHDC0Q0jaLdFP1qPAUUfo1FEXPXUfUkp3eZA0sSq340vPycSyOlYUeM15Ft1w==} + '@vitest/mocker@3.2.4': resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} peerDependencies: @@ -4975,21 +4978,41 @@ packages: vite: optional: true + '@vitest/mocker@4.0.15': + resolution: {integrity: sha512-CZ28GLfOEIFkvCFngN8Sfx5h+Se0zN+h4B7yOsPVCcgtiO7t5jt9xQh2E1UkFep+eb9fjyMfuC5gBypwb07fvQ==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + '@vitest/pretty-format@3.2.4': resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} - '@vitest/runner@3.2.4': - resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} + '@vitest/pretty-format@4.0.15': + resolution: {integrity: sha512-SWdqR8vEv83WtZcrfLNqlqeQXlQLh2iilO1Wk1gv4eiHKjEzvgHb2OVc3mIPyhZE6F+CtfYjNlDJwP5MN6Km7A==} + + '@vitest/runner@4.0.15': + resolution: {integrity: sha512-+A+yMY8dGixUhHmNdPUxOh0la6uVzun86vAbuMT3hIDxMrAOmn5ILBHm8ajrqHE0t8R9T1dGnde1A5DTnmi3qw==} - '@vitest/snapshot@3.2.4': - resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} + '@vitest/snapshot@4.0.15': + resolution: {integrity: sha512-A7Ob8EdFZJIBjLjeO0DZF4lqR6U7Ydi5/5LIZ0xcI+23lYlsYJAfGn8PrIWTYdZQRNnSRlzhg0zyGu37mVdy5g==} '@vitest/spy@3.2.4': resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} + '@vitest/spy@4.0.15': + resolution: {integrity: sha512-+EIjOJmnY6mIfdXtE/bnozKEvTC4Uczg19yeZ2vtCz5Yyb0QQ31QWVQ8hswJ3Ysx/K2EqaNsVanjr//2+P3FHw==} + '@vitest/utils@3.2.4': resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} + '@vitest/utils@4.0.15': + resolution: {integrity: sha512-HXjPW2w5dxhTD0dLwtYHDnelK3j8sR8cWIaLxr22evTyY6q8pRCjZSmhRWVjBaOVXChQd6AwMzi9pucorXCPZA==} + '@webassemblyjs/ast@1.14.1': resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} @@ -5531,10 +5554,6 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} - cac@6.7.14: - resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} - engines: {node: '>=8'} - cacheable-lookup@7.0.0: resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==} engines: {node: '>=14.16'} @@ -5603,6 +5622,10 @@ packages: resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} engines: {node: '>=18'} + chai@6.2.1: + resolution: {integrity: sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==} + engines: {node: '>=18'} + chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -8083,8 +8106,8 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - magicast@0.3.5: - resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} + magicast@0.5.1: + resolution: {integrity: sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw==} make-array@0.1.2: resolution: {integrity: sha512-bcFmxgZ+OTaMYJp/w6eifElKTcfum7Gi5H7vQ8KzAf9X6swdxkVuilCaG3ZjXr/qJsQT4JJ2Rq9SDYScWEdu9Q==} @@ -8722,6 +8745,9 @@ packages: obuf@1.1.2: resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + oidc-client-ts@3.3.0: resolution: {integrity: sha512-t13S540ZwFOEZKLYHJwSfITugupW4uYLwuQSSXyKH/wHwZ+7FvgHE7gnNJh1YQIZ1Yd1hKSRjqeXGSUtS0r9JA==} engines: {node: '>=18'} @@ -8973,6 +8999,10 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} + pixelmatch@7.1.0: + resolution: {integrity: sha512-1wrVzJ2STrpmONHKBy228LM1b84msXDUoAzVEl0R8Mz4Ce6EPr+IVtxm8+yvrqLYMHswREkjYFaMxnyGnaY3Ng==} + hasBin: true + pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} @@ -8994,6 +9024,10 @@ packages: engines: {node: '>=18'} hasBin: true + pngjs@7.0.0: + resolution: {integrity: sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==} + engines: {node: '>=14.19.0'} + possible-typed-array-names@1.1.0: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} @@ -10587,9 +10621,6 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - strip-literal@3.1.0: - resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} - strip-outer@1.0.1: resolution: {integrity: sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==} engines: {node: '>=0.10.0'} @@ -10692,10 +10723,6 @@ packages: engines: {node: '>=10'} hasBin: true - test-exclude@7.0.1: - resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==} - engines: {node: '>=18'} - text-decoder@1.2.3: resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} @@ -10739,8 +10766,9 @@ packages: tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - tinyexec@0.3.2: - resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyexec@1.0.2: + resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + engines: {node: '>=18'} tinyglobby@0.2.15: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} @@ -10754,6 +10782,10 @@ packages: resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} engines: {node: '>=14.0.0'} + tinyrainbow@3.0.3: + resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} + engines: {node: '>=14.0.0'} + tinyspy@4.0.4: resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} engines: {node: '>=14.0.0'} @@ -11018,11 +11050,6 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - typescript@5.6.3: - resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} - engines: {node: '>=14.17'} - hasBin: true - typescript@5.8.3: resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} engines: {node: '>=14.17'} @@ -11241,11 +11268,6 @@ packages: vfile@6.0.3: resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} - vite-node@3.2.4: - resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true - vite@7.1.12: resolution: {integrity: sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==} engines: {node: ^20.19.0 || >=22.12.0} @@ -11286,26 +11308,32 @@ packages: yaml: optional: true - vitest@3.2.4: - resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + vitest@4.0.15: + resolution: {integrity: sha512-n1RxDp8UJm6N0IbJLQo+yzLZ2sQCDyl1o0LeugbPWf8+8Fttp29GghsQBjYJVmWq3gBFfe9Hs1spR44vovn2wA==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' - '@types/debug': ^4.1.12 - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - '@vitest/browser': 3.2.4 - '@vitest/ui': 3.2.4 + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.0.15 + '@vitest/browser-preview': 4.0.15 + '@vitest/browser-webdriverio': 4.0.15 + '@vitest/ui': 4.0.15 happy-dom: '*' jsdom: '*' peerDependenciesMeta: '@edge-runtime/vm': optional: true - '@types/debug': + '@opentelemetry/api': optional: true '@types/node': optional: true - '@vitest/browser': + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': optional: true '@vitest/ui': optional: true @@ -11749,18 +11777,13 @@ snapshots: dependencies: '@algolia/client-common': 5.41.0 - '@amiceli/vitest-cucumber@5.2.1(vitest@3.2.4)': + '@amiceli/vitest-cucumber@6.1.0(vitest@4.0.15)': dependencies: callsites: 4.2.0 minimist: 1.2.8 parsecurrency: 1.1.1 ts-morph: 26.0.0 - vitest: 3.2.4(@types/debug@4.1.12)(@types/node@24.9.2)(@vitest/browser@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - - '@ampproject/remapping@2.3.0': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 + vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) '@ant-design/colors@7.2.1': dependencies: @@ -13580,7 +13603,7 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/bundler@3.8.1(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3)': + '@docusaurus/bundler@3.8.1(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3)': dependencies: '@babel/core': 7.28.5 '@docusaurus/babel': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -13599,7 +13622,7 @@ snapshots: mini-css-extract-plugin: 2.9.4(webpack@5.102.1) null-loader: 4.0.1(webpack@5.102.1) postcss: 8.5.6 - postcss-loader: 7.3.4(postcss@8.5.6)(typescript@5.6.3)(webpack@5.102.1) + postcss-loader: 7.3.4(postcss@8.5.6)(typescript@5.8.3)(webpack@5.102.1) postcss-preset-env: 10.4.0(postcss@8.5.6) terser-webpack-plugin: 5.3.14(webpack@5.102.1) tslib: 2.8.1 @@ -13621,10 +13644,10 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/core@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3)': + '@docusaurus/core@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3)': dependencies: '@docusaurus/babel': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@docusaurus/bundler': 3.8.1(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) + '@docusaurus/bundler': 3.8.1(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) '@docusaurus/logger': 3.8.1 '@docusaurus/mdx-loader': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/utils': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -13750,13 +13773,13 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/plugin-content-blog@3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3))(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3)': + '@docusaurus/plugin-content-blog@3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3))(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3)': dependencies: - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) '@docusaurus/logger': 3.8.1 '@docusaurus/mdx-loader': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) - '@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) + '@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/types': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/utils': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/utils-common': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -13791,13 +13814,13 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3)': + '@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3)': dependencies: - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) '@docusaurus/logger': 3.8.1 '@docusaurus/mdx-loader': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/module-type-aliases': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/types': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/utils': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/utils-common': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -13831,9 +13854,9 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-content-pages@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3)': + '@docusaurus/plugin-content-pages@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3)': dependencies: - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) '@docusaurus/mdx-loader': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/types': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/utils': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -13861,9 +13884,9 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-css-cascade-layers@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3)': + '@docusaurus/plugin-css-cascade-layers@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3)': dependencies: - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) '@docusaurus/types': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/utils': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/utils-validation': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -13888,9 +13911,9 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-debug@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3)': + '@docusaurus/plugin-debug@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3)': dependencies: - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) '@docusaurus/types': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/utils': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) fs-extra: 11.3.2 @@ -13916,9 +13939,9 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-google-analytics@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3)': + '@docusaurus/plugin-google-analytics@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3)': dependencies: - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) '@docusaurus/types': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/utils-validation': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react: 19.2.0 @@ -13942,9 +13965,9 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-google-gtag@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3)': + '@docusaurus/plugin-google-gtag@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3)': dependencies: - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) '@docusaurus/types': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/utils-validation': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@types/gtag.js': 0.0.12 @@ -13969,9 +13992,9 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-google-tag-manager@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3)': + '@docusaurus/plugin-google-tag-manager@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3)': dependencies: - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) '@docusaurus/types': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/utils-validation': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react: 19.2.0 @@ -13995,9 +14018,9 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-sitemap@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3)': + '@docusaurus/plugin-sitemap@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3)': dependencies: - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) '@docusaurus/logger': 3.8.1 '@docusaurus/types': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/utils': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -14026,14 +14049,14 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-svgr@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3)': + '@docusaurus/plugin-svgr@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3)': dependencies: - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) '@docusaurus/types': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/utils': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/utils-validation': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@svgr/core': 8.1.0(typescript@5.6.3) - '@svgr/webpack': 8.1.0(typescript@5.6.3) + '@svgr/core': 8.1.0(typescript@5.8.3) + '@svgr/webpack': 8.1.0(typescript@5.8.3) react: 19.2.0 react-dom: 19.2.0(react@19.2.0) tslib: 2.8.1 @@ -14056,22 +14079,22 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/preset-classic@3.8.1(@algolia/client-search@5.41.0)(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(search-insights@2.17.3)(typescript@5.6.3)': - dependencies: - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) - '@docusaurus/plugin-content-blog': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3))(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) - '@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) - '@docusaurus/plugin-content-pages': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) - '@docusaurus/plugin-css-cascade-layers': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) - '@docusaurus/plugin-debug': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) - '@docusaurus/plugin-google-analytics': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) - '@docusaurus/plugin-google-gtag': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) - '@docusaurus/plugin-google-tag-manager': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) - '@docusaurus/plugin-sitemap': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) - '@docusaurus/plugin-svgr': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) - '@docusaurus/theme-classic': 3.8.1(@types/react@19.2.2)(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) - '@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@docusaurus/theme-search-algolia': 3.8.1(@algolia/client-search@5.41.0)(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(search-insights@2.17.3)(typescript@5.6.3) + '@docusaurus/preset-classic@3.8.1(@algolia/client-search@5.41.0)(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(search-insights@2.17.3)(typescript@5.8.3)': + dependencies: + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) + '@docusaurus/plugin-content-blog': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3))(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) + '@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) + '@docusaurus/plugin-content-pages': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) + '@docusaurus/plugin-css-cascade-layers': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) + '@docusaurus/plugin-debug': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) + '@docusaurus/plugin-google-analytics': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) + '@docusaurus/plugin-google-gtag': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) + '@docusaurus/plugin-google-tag-manager': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) + '@docusaurus/plugin-sitemap': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) + '@docusaurus/plugin-svgr': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) + '@docusaurus/theme-classic': 3.8.1(@types/react@19.2.2)(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) + '@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@docusaurus/theme-search-algolia': 3.8.1(@algolia/client-search@5.41.0)(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(search-insights@2.17.3)(typescript@5.8.3) '@docusaurus/types': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react: 19.2.0 react-dom: 19.2.0(react@19.2.0) @@ -14101,16 +14124,16 @@ snapshots: '@types/react': 19.2.2 react: 19.2.0 - '@docusaurus/theme-classic@3.8.1(@types/react@19.2.2)(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3)': + '@docusaurus/theme-classic@3.8.1(@types/react@19.2.2)(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3)': dependencies: - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) '@docusaurus/logger': 3.8.1 '@docusaurus/mdx-loader': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/module-type-aliases': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@docusaurus/plugin-content-blog': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3))(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) - '@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) - '@docusaurus/plugin-content-pages': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) - '@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@docusaurus/plugin-content-blog': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3))(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) + '@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) + '@docusaurus/plugin-content-pages': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) + '@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/theme-translations': 3.8.1 '@docusaurus/types': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/utils': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -14149,11 +14172,11 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/theme-common@3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@docusaurus/theme-common@3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@docusaurus/mdx-loader': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/module-type-aliases': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) + '@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) '@docusaurus/utils': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/utils-common': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@types/history': 4.7.11 @@ -14173,13 +14196,13 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/theme-search-algolia@3.8.1(@algolia/client-search@5.41.0)(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(search-insights@2.17.3)(typescript@5.6.3)': + '@docusaurus/theme-search-algolia@3.8.1(@algolia/client-search@5.41.0)(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(search-insights@2.17.3)(typescript@5.8.3)': dependencies: '@docsearch/react': 3.9.0(@algolia/client-search@5.41.0)(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(search-insights@2.17.3) - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) '@docusaurus/logger': 3.8.1 - '@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) - '@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3) + '@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@19.2.0))(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.8.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/theme-translations': 3.8.1 '@docusaurus/utils': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@docusaurus/utils-validation': 3.8.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -15029,8 +15052,6 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 - '@istanbuljs/schema@0.1.3': {} - '@jest/schemas@29.6.3': dependencies: '@sinclair/typebox': 0.27.8 @@ -15875,6 +15896,8 @@ snapshots: - debug - react-native-b4a + '@standard-schema/spec@1.0.0': {} + '@storybook/addon-a11y@9.1.16(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))': dependencies: '@storybook/global': 5.0.0 @@ -15898,7 +15921,7 @@ snapshots: dependencies: storybook: 9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@storybook/addon-vitest@9.1.16(@vitest/browser@3.2.4)(@vitest/runner@3.2.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@3.2.4)': + '@storybook/addon-vitest@9.1.16(@vitest/browser-playwright@4.0.15)(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(@vitest/runner@4.0.15)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@4.0.15)': dependencies: '@storybook/global': 5.0.0 '@storybook/icons': 1.6.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -15906,9 +15929,10 @@ snapshots: storybook: 9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) ts-dedent: 2.2.0 optionalDependencies: - '@vitest/browser': 3.2.4(playwright@1.56.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4) - '@vitest/runner': 3.2.4 - vitest: 3.2.4(@types/debug@4.1.12)(@types/node@24.9.2)(@vitest/browser@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + '@vitest/browser': 4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) + '@vitest/browser-playwright': 4.0.15(playwright@1.56.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) + '@vitest/runner': 4.0.15 + vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) transitivePeerDependencies: - react - react-dom @@ -16012,12 +16036,12 @@ snapshots: '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.28.5) '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.28.5) - '@svgr/core@8.1.0(typescript@5.6.3)': + '@svgr/core@8.1.0(typescript@5.8.3)': dependencies: '@babel/core': 7.28.5 '@svgr/babel-preset': 8.1.0(@babel/core@7.28.5) camelcase: 6.3.0 - cosmiconfig: 8.3.6(typescript@5.6.3) + cosmiconfig: 8.3.6(typescript@5.8.3) snake-case: 3.0.4 transitivePeerDependencies: - supports-color @@ -16028,35 +16052,35 @@ snapshots: '@babel/types': 7.28.5 entities: 4.5.0 - '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.6.3))': + '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.8.3))': dependencies: '@babel/core': 7.28.5 '@svgr/babel-preset': 8.1.0(@babel/core@7.28.5) - '@svgr/core': 8.1.0(typescript@5.6.3) + '@svgr/core': 8.1.0(typescript@5.8.3) '@svgr/hast-util-to-babel-ast': 8.0.0 svg-parser: 2.0.4 transitivePeerDependencies: - supports-color - '@svgr/plugin-svgo@8.1.0(@svgr/core@8.1.0(typescript@5.6.3))(typescript@5.6.3)': + '@svgr/plugin-svgo@8.1.0(@svgr/core@8.1.0(typescript@5.8.3))(typescript@5.8.3)': dependencies: - '@svgr/core': 8.1.0(typescript@5.6.3) - cosmiconfig: 8.3.6(typescript@5.6.3) + '@svgr/core': 8.1.0(typescript@5.8.3) + cosmiconfig: 8.3.6(typescript@5.8.3) deepmerge: 4.3.1 svgo: 3.3.2 transitivePeerDependencies: - typescript - '@svgr/webpack@8.1.0(typescript@5.6.3)': + '@svgr/webpack@8.1.0(typescript@5.8.3)': dependencies: '@babel/core': 7.28.5 '@babel/plugin-transform-react-constant-elements': 7.27.1(@babel/core@7.28.5) '@babel/preset-env': 7.28.5(@babel/core@7.28.5) '@babel/preset-react': 7.28.5(@babel/core@7.28.5) '@babel/preset-typescript': 7.28.5(@babel/core@7.28.5) - '@svgr/core': 8.1.0(typescript@5.6.3) - '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.6.3)) - '@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0(typescript@5.6.3))(typescript@5.6.3) + '@svgr/core': 8.1.0(typescript@5.8.3) + '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.8.3)) + '@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0(typescript@5.8.3))(typescript@5.8.3) transitivePeerDependencies: - supports-color - typescript @@ -16660,19 +16684,44 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitest/browser@3.2.4(playwright@1.56.1)(vite@7.1.12(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4)': + '@vitest/browser-playwright@4.0.15(playwright@1.56.1)(vite@7.1.12(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15)': dependencies: - '@testing-library/dom': 10.4.1 - '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.1) - '@vitest/mocker': 3.2.4(vite@7.1.12(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@vitest/utils': 3.2.4 + '@vitest/browser': 4.0.15(vite@7.1.12(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) + '@vitest/mocker': 4.0.15(vite@7.1.12(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + playwright: 1.56.1 + tinyrainbow: 3.0.3 + vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.19.0)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + transitivePeerDependencies: + - bufferutil + - msw + - utf-8-validate + - vite + optional: true + + '@vitest/browser-playwright@4.0.15(playwright@1.56.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15)': + dependencies: + '@vitest/browser': 4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) + '@vitest/mocker': 4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + playwright: 1.56.1 + tinyrainbow: 3.0.3 + vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + transitivePeerDependencies: + - bufferutil + - msw + - utf-8-validate + - vite + + '@vitest/browser@4.0.15(vite@7.1.12(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15)': + dependencies: + '@vitest/mocker': 4.0.15(vite@7.1.12(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + '@vitest/utils': 4.0.15 magic-string: 0.30.21 + pixelmatch: 7.1.0 + pngjs: 7.0.0 sirv: 3.0.2 - tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.0)(@vitest/browser@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + tinyrainbow: 3.0.3 + vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.19.0)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) ws: 8.18.3 - optionalDependencies: - playwright: 1.56.1 transitivePeerDependencies: - bufferutil - msw @@ -16680,43 +16729,39 @@ snapshots: - vite optional: true - '@vitest/browser@3.2.4(playwright@1.56.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4)': + '@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15)': dependencies: - '@testing-library/dom': 10.4.1 - '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.1) - '@vitest/mocker': 3.2.4(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@vitest/utils': 3.2.4 + '@vitest/mocker': 4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + '@vitest/utils': 4.0.15 magic-string: 0.30.21 + pixelmatch: 7.1.0 + pngjs: 7.0.0 sirv: 3.0.2 - tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/debug@4.1.12)(@types/node@24.9.2)(@vitest/browser@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + tinyrainbow: 3.0.3 + vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) ws: 8.18.3 - optionalDependencies: - playwright: 1.56.1 transitivePeerDependencies: - bufferutil - msw - utf-8-validate - vite - '@vitest/coverage-v8@3.2.4(@vitest/browser@3.2.4)(vitest@3.2.4)': + '@vitest/coverage-v8@4.0.15(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15)': dependencies: - '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 1.0.2 + '@vitest/utils': 4.0.15 ast-v8-to-istanbul: 0.3.8 - debug: 4.4.3(supports-color@8.1.1) istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 5.0.6 istanbul-reports: 3.2.0 - magic-string: 0.30.21 - magicast: 0.3.5 + magicast: 0.5.1 + obug: 2.1.1 std-env: 3.10.0 - test-exclude: 7.0.1 - tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/debug@4.1.12)(@types/node@24.9.2)(@vitest/browser@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + tinyrainbow: 3.0.3 + vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) optionalDependencies: - '@vitest/browser': 3.2.4(playwright@1.56.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4) + '@vitest/browser': 4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) transitivePeerDependencies: - supports-color @@ -16728,17 +16773,34 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(vite@7.1.12(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': + '@vitest/expect@4.0.15': + dependencies: + '@standard-schema/spec': 1.0.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.0.15 + '@vitest/utils': 4.0.15 + chai: 6.2.1 + tinyrainbow: 3.0.3 + + '@vitest/mocker@3.2.4(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.21 + optionalDependencies: + vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + + '@vitest/mocker@4.0.15(vite@7.1.12(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': + dependencies: + '@vitest/spy': 4.0.15 + estree-walker: 3.0.3 + magic-string: 0.30.21 optionalDependencies: vite: 7.1.12(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - '@vitest/mocker@3.2.4(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': + '@vitest/mocker@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': dependencies: - '@vitest/spy': 3.2.4 + '@vitest/spy': 4.0.15 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: @@ -16748,15 +16810,18 @@ snapshots: dependencies: tinyrainbow: 2.0.0 - '@vitest/runner@3.2.4': + '@vitest/pretty-format@4.0.15': dependencies: - '@vitest/utils': 3.2.4 + tinyrainbow: 3.0.3 + + '@vitest/runner@4.0.15': + dependencies: + '@vitest/utils': 4.0.15 pathe: 2.0.3 - strip-literal: 3.1.0 - '@vitest/snapshot@3.2.4': + '@vitest/snapshot@4.0.15': dependencies: - '@vitest/pretty-format': 3.2.4 + '@vitest/pretty-format': 4.0.15 magic-string: 0.30.21 pathe: 2.0.3 @@ -16764,12 +16829,19 @@ snapshots: dependencies: tinyspy: 4.0.4 + '@vitest/spy@4.0.15': {} + '@vitest/utils@3.2.4': dependencies: '@vitest/pretty-format': 3.2.4 loupe: 3.2.1 tinyrainbow: 2.0.0 + '@vitest/utils@4.0.15': + dependencies: + '@vitest/pretty-format': 4.0.15 + tinyrainbow: 3.0.3 + '@webassemblyjs/ast@1.14.1': dependencies: '@webassemblyjs/helper-numbers': 1.13.2 @@ -17489,8 +17561,6 @@ snapshots: bytes@3.1.2: {} - cac@6.7.14: {} - cacheable-lookup@7.0.0: {} cacheable-request@10.2.14: @@ -17575,6 +17645,8 @@ snapshots: loupe: 3.2.1 pathval: 2.0.1 + chai@6.2.1: {} + chalk@2.4.2: dependencies: ansi-styles: 3.2.1 @@ -17908,15 +17980,6 @@ snapshots: object-assign: 4.1.1 vary: 1.1.2 - cosmiconfig@8.3.6(typescript@5.6.3): - dependencies: - import-fresh: 3.3.1 - js-yaml: 4.1.0 - parse-json: 5.2.0 - path-type: 4.0.0 - optionalDependencies: - typescript: 5.6.3 - cosmiconfig@8.3.6(typescript@5.8.3): dependencies: import-fresh: 3.3.1 @@ -20357,7 +20420,7 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 - magicast@0.3.5: + magicast@0.5.1: dependencies: '@babel/parser': 7.28.5 '@babel/types': 7.28.5 @@ -21240,6 +21303,8 @@ snapshots: obuf@1.1.2: {} + obug@2.1.1: {} + oidc-client-ts@3.3.0: dependencies: jwt-decode: 4.0.0 @@ -21503,6 +21568,10 @@ snapshots: picomatch@4.0.3: {} + pixelmatch@7.1.0: + dependencies: + pngjs: 7.0.0 + pkg-dir@4.2.0: dependencies: find-up: 4.1.0 @@ -21521,6 +21590,8 @@ snapshots: optionalDependencies: fsevents: 2.3.2 + pngjs@7.0.0: {} + possible-typed-array-names@1.1.0: {} postcss-attribute-case-insensitive@7.0.1(postcss@8.5.6): @@ -21665,9 +21736,9 @@ snapshots: '@csstools/utilities': 2.0.0(postcss@8.5.6) postcss: 8.5.6 - postcss-loader@7.3.4(postcss@8.5.6)(typescript@5.6.3)(webpack@5.102.1): + postcss-loader@7.3.4(postcss@8.5.6)(typescript@5.8.3)(webpack@5.102.1): dependencies: - cosmiconfig: 8.3.6(typescript@5.6.3) + cosmiconfig: 8.3.6(typescript@5.8.3) jiti: 1.21.7 postcss: 8.5.6 semver: 7.7.3 @@ -23423,10 +23494,6 @@ snapshots: strip-json-comments@3.1.1: {} - strip-literal@3.1.0: - dependencies: - js-tokens: 9.0.1 - strip-outer@1.0.1: dependencies: escape-string-regexp: 1.0.5 @@ -23557,12 +23624,6 @@ snapshots: commander: 2.20.3 source-map-support: 0.5.21 - test-exclude@7.0.1: - dependencies: - '@istanbuljs/schema': 0.1.3 - glob: 10.4.5 - minimatch: 9.0.5 - text-decoder@1.2.3: dependencies: b4a: 1.7.3 @@ -23597,7 +23658,7 @@ snapshots: tinybench@2.9.0: {} - tinyexec@0.3.2: {} + tinyexec@1.0.2: {} tinyglobby@0.2.15: dependencies: @@ -23608,6 +23669,8 @@ snapshots: tinyrainbow@2.0.0: {} + tinyrainbow@3.0.3: {} + tinyspy@4.0.4: {} title-case@3.0.3: @@ -23923,8 +23986,6 @@ snapshots: transitivePeerDependencies: - supports-color - typescript@5.6.3: {} - typescript@5.8.3: {} ua-parser-js@1.0.41: {} @@ -24128,48 +24189,6 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vite-node@3.2.4(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1): - dependencies: - cac: 6.7.14 - debug: 4.4.3(supports-color@8.1.1) - es-module-lexer: 1.7.0 - pathe: 2.0.3 - vite: 7.1.12(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - transitivePeerDependencies: - - '@types/node' - - jiti - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - - vite-node@3.2.4(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1): - dependencies: - cac: 6.7.14 - debug: 4.4.3(supports-color@8.1.1) - es-module-lexer: 1.7.0 - pathe: 2.0.3 - vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - transitivePeerDependencies: - - '@types/node' - - jiti - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - vite@7.1.12(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1): dependencies: esbuild: 0.25.11 @@ -24204,35 +24223,32 @@ snapshots: tsx: 4.20.6 yaml: 2.8.1 - vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.19.0)(@vitest/browser@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1): + vitest@4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.19.0)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1): dependencies: - '@types/chai': 5.2.3 - '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.1.12(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@vitest/pretty-format': 3.2.4 - '@vitest/runner': 3.2.4 - '@vitest/snapshot': 3.2.4 - '@vitest/spy': 3.2.4 - '@vitest/utils': 3.2.4 - chai: 5.3.3 - debug: 4.4.3(supports-color@8.1.1) + '@vitest/expect': 4.0.15 + '@vitest/mocker': 4.0.15(vite@7.1.12(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + '@vitest/pretty-format': 4.0.15 + '@vitest/runner': 4.0.15 + '@vitest/snapshot': 4.0.15 + '@vitest/spy': 4.0.15 + '@vitest/utils': 4.0.15 + es-module-lexer: 1.7.0 expect-type: 1.2.2 magic-string: 0.30.21 + obug: 2.1.1 pathe: 2.0.3 picomatch: 4.0.3 std-env: 3.10.0 tinybench: 2.9.0 - tinyexec: 0.3.2 + tinyexec: 1.0.2 tinyglobby: 0.2.15 - tinypool: 1.1.1 - tinyrainbow: 2.0.0 + tinyrainbow: 3.0.3 vite: 7.1.12(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - vite-node: 3.2.4(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) why-is-node-running: 2.3.0 optionalDependencies: - '@types/debug': 4.1.12 + '@opentelemetry/api': 1.9.0 '@types/node': 22.19.0 - '@vitest/browser': 3.2.4(playwright@1.56.1)(vite@7.1.12(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4) + '@vitest/browser-playwright': 4.0.15(playwright@1.56.1)(vite@7.1.12(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) jsdom: 26.1.0 transitivePeerDependencies: - jiti @@ -24243,40 +24259,36 @@ snapshots: - sass-embedded - stylus - sugarss - - supports-color - terser - tsx - yaml - vitest@3.2.4(@types/debug@4.1.12)(@types/node@24.9.2)(@vitest/browser@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1): + vitest@4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1): dependencies: - '@types/chai': 5.2.3 - '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@vitest/pretty-format': 3.2.4 - '@vitest/runner': 3.2.4 - '@vitest/snapshot': 3.2.4 - '@vitest/spy': 3.2.4 - '@vitest/utils': 3.2.4 - chai: 5.3.3 - debug: 4.4.3(supports-color@8.1.1) + '@vitest/expect': 4.0.15 + '@vitest/mocker': 4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + '@vitest/pretty-format': 4.0.15 + '@vitest/runner': 4.0.15 + '@vitest/snapshot': 4.0.15 + '@vitest/spy': 4.0.15 + '@vitest/utils': 4.0.15 + es-module-lexer: 1.7.0 expect-type: 1.2.2 magic-string: 0.30.21 + obug: 2.1.1 pathe: 2.0.3 picomatch: 4.0.3 std-env: 3.10.0 tinybench: 2.9.0 - tinyexec: 0.3.2 + tinyexec: 1.0.2 tinyglobby: 0.2.15 - tinypool: 1.1.1 - tinyrainbow: 2.0.0 + tinyrainbow: 3.0.3 vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - vite-node: 3.2.4(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) why-is-node-running: 2.3.0 optionalDependencies: - '@types/debug': 4.1.12 + '@opentelemetry/api': 1.9.0 '@types/node': 24.9.2 - '@vitest/browser': 3.2.4(playwright@1.56.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@3.2.4) + '@vitest/browser-playwright': 4.0.15(playwright@1.56.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) jsdom: 26.1.0 transitivePeerDependencies: - jiti @@ -24287,7 +24299,6 @@ snapshots: - sass-embedded - stylus - sugarss - - supports-color - terser - tsx - yaml From dabe9ef86676f0bc14149764d6183a04b496e658 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Wed, 10 Dec 2025 09:50:36 -0500 Subject: [PATCH 02/74] fix mock types --- packages/sthrift/service-sendgrid/src/sendgrid.test.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/sthrift/service-sendgrid/src/sendgrid.test.ts b/packages/sthrift/service-sendgrid/src/sendgrid.test.ts index e79b9be30..3f272b1a0 100644 --- a/packages/sthrift/service-sendgrid/src/sendgrid.test.ts +++ b/packages/sthrift/service-sendgrid/src/sendgrid.test.ts @@ -98,11 +98,10 @@ test.for(feature, ({ Scenario }) => { // biome-ignore lint/complexity/useLiteralKeys: Required for env var access process.env['SENDGRID_MAGICLINK_SUBJECT_SUFFIX'] = '- Dev'; - mockFs.existsSync = vi.fn().mockReturnValue(false); - mockFs.mkdirSync = vi.fn(); - mockFs.writeFileSync = vi.fn(); - - vi.mocked(emailTemplate.readHtmlFile).mockReturnValue( + mockFs.existsSync = vi.fn().mockReturnValue(false); + mockFs.mkdirSync = vi.fn() as typeof mockFs.mkdirSync; + mockFs.writeFileSync = vi.fn() as typeof mockFs.writeFileSync; + vi.mocked(emailTemplate.readHtmlFile).mockReturnValue( JSON.stringify(mockTemplate), ); From fd63a69e498a314d0f5c66ef6bacd24fe5ceb154 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Wed, 10 Dec 2025 10:41:52 -0500 Subject: [PATCH 03/74] refactor(tests): restructure mocks and improve clarity in otel-builder tests (addressed AI suggestions) --- .../mongo-unit-of-work.test.ts | 169 ++++++++---------- .../account-plan.read-repository.test.ts | 72 ++++---- .../service-otel/src/otel-builder.test.ts | 88 ++++----- 3 files changed, 158 insertions(+), 171 deletions(-) diff --git a/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts b/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts index 3c09fbf1e..d600d2107 100644 --- a/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts +++ b/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts @@ -32,6 +32,32 @@ class RepoMock extends MongoRepositoryBase {} +// Helper types and factories for domain operations +type RepoOp = (repo: RepoMock) => Promise; +type RepoOpMock = RepoOp & MockInstance; +type DispatchMock = ReturnType; + +function makeDomainOpWithoutEvents(): RepoOpMock { + const op: RepoOp = async (repo) => { + const aggregate = await repo.get('agg-1'); + aggregate.foo = 'new-foo'; + await repo.save(aggregate); + }; + return vi.fn(op) as RepoOpMock; +} + +function makeDomainOpWithEvents(events: TestEvent[]): RepoOpMock { + const op: RepoOp = async (repo) => { + const aggregate = await repo.get('agg-1'); + aggregate.foo = 'new-foo'; + for (const e of events) { + aggregate.addIntegrationEvent(TestEvent, e.payload); + } + await repo.save(aggregate); + }; + return vi.fn(op) as RepoOpMock; +} + vi.mock('mongoose', async () => { const original = await vi.importActual('mongoose'); return { @@ -47,15 +73,40 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { let repoInstance: RepoMock; let eventBus: DomainSeedwork.EventBus; let integrationEventBus: DomainSeedwork.EventBus; + let dispatchMock: DispatchMock; let session: ClientSession; let mockModel: Model; let typeConverter: DomainSeedwork.TypeConverter; const Passport = {}; - // Always use a real class for repoClass class TestRepoClass extends RepoMock {} - // Use a real async function for domainOperation - let domainOperation: ((repo: RepoMock) => Promise) & MockInstance; + let domainOperation: RepoOpMock; + + function setupMockModelReturningAggregate() { + (mockModel.findById as ReturnType).mockReturnValue({ + exec: vi.fn().mockResolvedValue({ + _id: 'agg-1', + foo: 'old-foo', + }), + }); + } + + function setupRepoNoEvents() { + repoInstance.getIntegrationEvents = vi.fn(() => []) as typeof repoInstance.getIntegrationEvents; + repoInstance.get = vi.fn().mockResolvedValue( + new AggregateRootMock( + { + id: 'agg-1', + foo: 'old-foo', + createdAt: new Date(), + updatedAt: new Date(), + schemaVersion: '1', + } as PropType, + {}, + ), + ); + repoInstance.save = vi.fn().mockResolvedValue(undefined); + } BeforeEachScenario(() => { session = {} as ClientSession; @@ -87,11 +138,11 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { dispatch: vi.fn(), register: vi.fn(), }) as DomainSeedwork.EventBus; - const dispatchMock = vi.fn(); - integrationEventBus = { - dispatch: dispatchMock, - register: vi.fn(), - } as unknown as DomainSeedwork.EventBus; + dispatchMock = vi.fn() as DispatchMock; + integrationEventBus = { + dispatch: dispatchMock, + register: vi.fn(), + } as unknown as DomainSeedwork.EventBus; repoInstance = new RepoMock( vi.mocked({}), mockModel, @@ -106,25 +157,14 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { typeConverter, TestRepoClass, ); - const op = async (repo: RepoMock) => { - const aggregate = await repo.get('agg-1'); - aggregate.foo = 'new-foo'; - await repo.save(aggregate); - }; - domainOperation = vi.fn(op) as typeof domainOperation; - vi.clearAllMocks(); + domainOperation = makeDomainOpWithoutEvents(); + vi.clearAllMocks(); vi.spyOn(mongoose.connection, 'transaction').mockImplementation( async (cb: (session: ClientSession) => Promise) => { return await cb({} as ClientSession); }, ); - // Re-setup mockModel after clearAllMocks - (mockModel.findById as ReturnType).mockReturnValue({ - exec: vi.fn().mockResolvedValue({ - _id: 'agg-1', - foo: 'old-foo', - }), - }); + setupMockModelReturningAggregate(); }); Scenario('Initializing the MongoUnitOfWork', ({ Given, When, Then }) => { @@ -145,26 +185,14 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { Scenario('Domain operation with no events, completes successfully', ({ Given, When, Then }) => { Given('a domain operation that emits no domain or integration events', () => { - // Patch getIntegrationEvents to always return an empty array of the correct type - repoInstance.getIntegrationEvents = vi.fn(() => []) as typeof repoInstance.getIntegrationEvents; - // Patch repoInstance.get to return a valid aggregate with all required properties - repoInstance.get = vi.fn().mockResolvedValue(new AggregateRootMock({ - id: 'agg-1', - foo: 'old-foo', - createdAt: new Date(), - updatedAt: new Date(), - schemaVersion: '1', - } as PropType, {})); - // Patch repoInstance.save to resolve - repoInstance.save = vi.fn().mockResolvedValue(undefined); + setupRepoNoEvents(); }); When('the operation completes successfully', async () => { domainOperation.mockClear(); - ((integrationEventBus.dispatch as unknown) as MockInstance).mockClear?.(); + dispatchMock.mockClear(); await unitOfWork.withTransaction(Passport, domainOperation); }); Then('the transaction is committed and no events are dispatched', () => { - // Accept any instance of TestRepoClass, not strict object equality expect(domainOperation).toHaveBeenCalled(); const callArg = domainOperation.mock.calls[0]?.[0]; expect(callArg).toBeInstanceOf(TestRepoClass); @@ -172,22 +200,14 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { expect(callArg.typeConverter).toBe(typeConverter); expect(callArg.bus).toBe(eventBus); expect(callArg.session).toStrictEqual(session); - expect(((integrationEventBus.dispatch as unknown) as MockInstance).mock.calls.length).toBe(0); + expect(dispatchMock).not.toHaveBeenCalled(); }); }); Scenario('Domain operation with no events, throws error', ({ Given, When, Then }) => { let domainError: Error; Given('a domain operation that emits no domain or integration events', () => { - repoInstance.getIntegrationEvents = vi.fn(() => []) as typeof repoInstance.getIntegrationEvents; - repoInstance.get = vi.fn().mockResolvedValue(new AggregateRootMock({ - id: 'agg-1', - foo: 'old-foo', - createdAt: new Date(), - updatedAt: new Date(), - schemaVersion: '1', - } as PropType, {})); - repoInstance.save = vi.fn().mockResolvedValue(undefined); + setupRepoNoEvents(); domainError = new Error('Domain failure'); }); When('the operation throws an error', async () => { @@ -199,39 +219,28 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { ).rejects.toThrow(domainError); }); Then('the transaction is rolled back and no events are dispatched', () => { - expect(integrationEventBus.dispatch).not.toHaveBeenCalled(); + expect(dispatchMock).not.toHaveBeenCalled(); }); }); Scenario('Domain operation emits integration events, all dispatch succeed', ({ Given, When, Then }) => { let event1: TestEvent; let event2: TestEvent; - let customDomainOp: typeof domainOperation; + let customDomainOp: RepoOpMock; Given('integration events are emitted during the domain operation', () => { event1 = new TestEvent('id'); event1.payload = { foo: 'bar1' }; event2 = new TestEvent('id'); event2.payload = { foo: 'bar2' }; - // Create a custom domain operation that adds integration events to the aggregate - const opWithEvents = async (repo: RepoMock) => { - const aggregate = await repo.get('agg-1'); - aggregate.foo = 'new-foo'; - // Add integration events using the real method - aggregate.addIntegrationEvent(TestEvent, event1.payload); - aggregate.addIntegrationEvent(TestEvent, event2.payload); - await repo.save(aggregate); - }; - customDomainOp = vi.fn(opWithEvents) as typeof domainOperation; + customDomainOp = makeDomainOpWithEvents([event1, event2]); }); When('the transaction completes successfully', async () => { - const dispatchMock = ((integrationEventBus.dispatch as unknown) as MockInstance); - dispatchMock.mockClear?.(); + dispatchMock.mockClear(); dispatchMock.mockResolvedValueOnce(undefined); dispatchMock.mockResolvedValueOnce(undefined); await unitOfWork.withTransaction(Passport, customDomainOp); }); Then('all integration events are dispatched after the transaction commits', () => { - const dispatchMock = ((integrationEventBus.dispatch as unknown) as MockInstance); expect(dispatchMock).toHaveBeenCalledTimes(2); expect(dispatchMock).toHaveBeenNthCalledWith(1, event1.constructor, event1.payload); expect(dispatchMock).toHaveBeenNthCalledWith(2, event2.constructor, event2.payload); @@ -241,31 +250,20 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { Scenario('Integration event dispatch fails', ({ Given, When, Then }) => { let event1: TestEvent; let event2: TestEvent; - let customDomainOp2: typeof domainOperation; + let customDomainOp: RepoOpMock; Given('integration events are emitted during the domain operation', () => { event1 = new TestEvent('id'); event1.payload = { foo: 'bar1' }; event2 = new TestEvent('id'); event2.payload = { foo: 'bar2' }; - // Create a custom domain operation that adds integration events to the aggregate - const opWithEvents2 = async (repo: RepoMock) => { - const aggregate = await repo.get('agg-1'); - aggregate.foo = 'new-foo'; - // Add integration events using the real method - aggregate.addIntegrationEvent(TestEvent, event1.payload); - aggregate.addIntegrationEvent(TestEvent, event2.payload); - await repo.save(aggregate); - }; - customDomainOp2 = vi.fn(opWithEvents2) as typeof domainOperation; + customDomainOp = makeDomainOpWithEvents([event1, event2]); }); When('integration event dispatch fails', async () => { - const dispatchMock = ((integrationEventBus.dispatch as unknown) as MockInstance); - dispatchMock.mockClear?.(); + dispatchMock.mockClear(); dispatchMock.mockRejectedValueOnce(new Error('rejected promise')); - await expect(unitOfWork.withTransaction(Passport, customDomainOp2)).rejects.toThrow('rejected promise'); + await expect(unitOfWork.withTransaction(Passport, customDomainOp)).rejects.toThrow('rejected promise'); }); Then('the error from dispatch is propagated and the transaction is not rolled back by the unit of work', () => { - const dispatchMock = ((integrationEventBus.dispatch as unknown) as MockInstance); expect(dispatchMock).toHaveBeenCalledTimes(1); }); }); @@ -273,32 +271,21 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { Scenario('Multiple integration events are emitted and all succeed', ({ Given, When, Then }) => { let event1: TestEvent; let event2: TestEvent; - let customDomainOp3: typeof domainOperation; + let customDomainOp: RepoOpMock; Given('integration events are emitted during the domain operation', () => { event1 = new TestEvent('id'); event1.payload = { foo: 'bar1' }; event2 = new TestEvent('id'); event2.payload = { foo: 'bar2' }; - // Create a custom domain operation that adds integration events to the aggregate - const opWithEvents3 = async (repo: RepoMock) => { - const aggregate = await repo.get('agg-1'); - aggregate.foo = 'new-foo'; - // Add integration events using the real method - aggregate.addIntegrationEvent(TestEvent, event1.payload); - aggregate.addIntegrationEvent(TestEvent, event2.payload); - await repo.save(aggregate); - }; - customDomainOp3 = vi.fn(opWithEvents3) as typeof domainOperation; + customDomainOp = makeDomainOpWithEvents([event1, event2]); }); When('multiple integration events are emitted and all succeed', async () => { - const dispatchMock = ((integrationEventBus.dispatch as unknown) as MockInstance); - dispatchMock.mockClear?.(); + dispatchMock.mockClear(); dispatchMock.mockResolvedValueOnce(undefined); dispatchMock.mockResolvedValueOnce(undefined); - await unitOfWork.withTransaction(Passport, customDomainOp3); + await unitOfWork.withTransaction(Passport, customDomainOp); }); Then('all are dispatched after the transaction', () => { - const dispatchMock = ((integrationEventBus.dispatch as unknown) as MockInstance); expect(dispatchMock).toHaveBeenCalledTimes(2); }); }); diff --git a/packages/sthrift/persistence/src/datasources/readonly/account-plan/account-plan/account-plan.read-repository.test.ts b/packages/sthrift/persistence/src/datasources/readonly/account-plan/account-plan/account-plan.read-repository.test.ts index 2dc43f85e..d7772e13f 100644 --- a/packages/sthrift/persistence/src/datasources/readonly/account-plan/account-plan/account-plan.read-repository.test.ts +++ b/packages/sthrift/persistence/src/datasources/readonly/account-plan/account-plan/account-plan.read-repository.test.ts @@ -5,55 +5,53 @@ import type { FindOptions, FindOneOptions } from '../../mongo-data-source.ts'; import { AccountPlanReadRepositoryImpl, getAccountPlanReadRepository } from './account-plan.read-repository.ts'; // Mock the converter -vi.mock('../../../domain/account-plan/account-plan/account-plan.domain-adapter.ts', () => ({ - // biome-ignore lint/complexity/useArrowFunction: Constructor function must be a regular function - AccountPlanConverter: vi.fn(function() { +vi.mock('../../../domain/account-plan/account-plan/account-plan.domain-adapter.ts', () => { + const MockAccountPlanConverter = vi.fn(); + // biome-ignore lint/complexity/useArrowFunction: Must be function for constructor compatibility + MockAccountPlanConverter.mockImplementation(function() { return { toDomain: vi.fn((doc) => ({ id: doc._id, name: doc.name })), }; - }), -})); + }); + + return { + AccountPlanConverter: MockAccountPlanConverter, + }; +}); -vi.mock('../account-plan/account-plan.data.ts', () => ({ - // biome-ignore lint/complexity/useArrowFunction: Constructor function must be a regular function - AccountPlanDataSourceImpl: vi.fn(function() { +vi.mock('../account-plan/account-plan.data.ts', () => { + const MockAccountPlanDataSourceImpl = vi.fn(); + // biome-ignore lint/complexity/useArrowFunction: Must be function for constructor compatibility + MockAccountPlanDataSourceImpl.mockImplementation(function() { return { find: vi.fn(), findById: vi.fn(), findOne: vi.fn(), }; - }), -})); + }); + + return { + AccountPlanDataSourceImpl: MockAccountPlanDataSourceImpl, + }; +}); function makeModelsContext(): ModelsContext { return { - User: { - PersonalUser: vi.fn(() => ({})), - AdminUser: vi.fn(() => ({})), - User: vi.fn(() => ({})), - }, - Listing: { - ItemListingModel: vi.fn(() => ({})), - }, - Conversation: { - ConversationModel: vi.fn(() => ({})), - }, - ReservationRequest: { - ReservationRequest: vi.fn(() => ({})), - }, - Role: { - Role: vi.fn(() => ({})), - AdminRole: vi.fn(() => ({})), - }, - AccountPlan: { - // Mock is not used since AccountPlanDataSourceImpl is mocked - AccountPlanModel: vi.fn(() => ({})), - }, - AppealRequest: { - ListingAppealRequest: vi.fn(() => ({})), - UserAppealRequest: vi.fn(() => ({})), - }, - } as unknown as ModelsContext; + // biome-ignore lint/suspicious/noExplicitAny: Unused models stubbed for interface compliance + User: {} as any, + // biome-ignore lint/suspicious/noExplicitAny: Unused models stubbed for interface compliance + Listing: {} as any, + // biome-ignore lint/suspicious/noExplicitAny: Unused models stubbed for interface compliance + Conversation: {} as any, + // biome-ignore lint/suspicious/noExplicitAny: Unused models stubbed for interface compliance + ReservationRequest: {} as any, + // biome-ignore lint/suspicious/noExplicitAny: Unused models stubbed for interface compliance + Role: {} as any, + // biome-ignore lint/suspicious/noExplicitAny: Unused models stubbed for interface compliance + AccountPlan: {} as any, + // biome-ignore lint/suspicious/noExplicitAny: Unused models stubbed for interface compliance + AppealRequest: {} as any, + }; } function makePassport(): Domain.Passport { diff --git a/packages/sthrift/service-otel/src/otel-builder.test.ts b/packages/sthrift/service-otel/src/otel-builder.test.ts index 5bc97bba3..753f16243 100644 --- a/packages/sthrift/service-otel/src/otel-builder.test.ts +++ b/packages/sthrift/service-otel/src/otel-builder.test.ts @@ -17,52 +17,53 @@ import { OtelBuilder } from './otel-builder.ts'; const test = { for: describeFeature }; -// Move mocks INSIDE the vi.mock factory to avoid hoisting issues vi.mock('@azure/monitor-opentelemetry-exporter', () => { - // Class-based mocks that record constructor args - type ExporterArgs = Record; class TraceExporter { - public __args: ExporterArgs; - constructor(args: ExporterArgs) { - TraceExporter.mock.calls.push(args); + __args: Record; + constructor(args: Record) { this.__args = args; } - public static readonly mock: { calls: ExporterArgs[] } = { calls: [] }; } class MetricExporter { - public __args: ExporterArgs; - constructor(args: ExporterArgs) { - MetricExporter.mock.calls.push(args); + __args: Record; + constructor(args: Record) { this.__args = args; } - public static readonly mock: { calls: ExporterArgs[] } = { calls: [] }; } class LogExporter { - public __args: ExporterArgs; - constructor(args: ExporterArgs) { - LogExporter.mock.calls.push(args); + __args: Record; + constructor(args: Record) { this.__args = args; } - public static readonly mock: { calls: ExporterArgs[] } = { calls: [] }; - } - // Helper reset for test access - function clearMocks() { - TraceExporter.mock.calls = []; - MetricExporter.mock.calls = []; - LogExporter.mock.calls = []; } + + // Create mockable constructor functions + const AzureMonitorTraceExporterImpl = vi.fn(); + AzureMonitorTraceExporterImpl.mockImplementation(function(this: InstanceType, args: Record) { + return new TraceExporter(args); + }); + + const AzureMonitorMetricExporterImpl = vi.fn(); + AzureMonitorMetricExporterImpl.mockImplementation(function(this: InstanceType, args: Record) { + return new MetricExporter(args); + }); + + const AzureMonitorLogExporterImpl = vi.fn(); + AzureMonitorLogExporterImpl.mockImplementation(function(this: InstanceType, args: Record) { + return new LogExporter(args); + }); + return { - AzureMonitorTraceExporter: TraceExporter, - AzureMonitorMetricExporter: MetricExporter, - AzureMonitorLogExporter: LogExporter, + AzureMonitorTraceExporter: AzureMonitorTraceExporterImpl, + AzureMonitorMetricExporter: AzureMonitorMetricExporterImpl, + AzureMonitorLogExporter: AzureMonitorLogExporterImpl, __test: { - traceExporterMock: TraceExporter.mock, - metricExporterMock: MetricExporter.mock, - logExporterMock: LogExporter.mock, + traceExporterMock: AzureMonitorTraceExporterImpl, + metricExporterMock: AzureMonitorMetricExporterImpl, + logExporterMock: AzureMonitorLogExporterImpl, TraceExporter, MetricExporter, LogExporter, - clearMocks, }, }; }); @@ -77,9 +78,9 @@ const feature = await loadFeature( test.for(feature, ({ Scenario, BeforeEachScenario, AfterEachScenario }) => { let builder: OtelBuilder; let originalEnv: NodeJS.ProcessEnv; - let traceExporterMock: { calls: unknown[] }; - let metricExporterMock: { calls: unknown[] }; - let logExporterMock: { calls: unknown[] }; + let traceExporterMock: ReturnType; + let metricExporterMock: ReturnType; + let logExporterMock: ReturnType; let TraceExporter: new (...args: unknown[]) => unknown; let MetricExporter: new (...args: unknown[]) => unknown; let LogExporter: new (...args: unknown[]) => unknown; @@ -87,8 +88,7 @@ test.for(feature, ({ Scenario, BeforeEachScenario, AfterEachScenario }) => { BeforeEachScenario(async () => { builder = new OtelBuilder(); originalEnv = { ...process.env }; - // Get the actual mocks and classes from the module - // biome-ignore lint:noExplicitAny + // biome-ignore lint/suspicious/noExplicitAny: Required for module mock access const azureModule = await import('@azure/monitor-opentelemetry-exporter') as any; traceExporterMock = azureModule.__test.traceExporterMock; metricExporterMock = azureModule.__test.metricExporterMock; @@ -96,9 +96,9 @@ test.for(feature, ({ Scenario, BeforeEachScenario, AfterEachScenario }) => { TraceExporter = azureModule.__test.TraceExporter; MetricExporter = azureModule.__test.MetricExporter; LogExporter = azureModule.__test.LogExporter; - traceExporterMock.calls = []; - metricExporterMock.calls = []; - logExporterMock.calls = []; + traceExporterMock.mockClear(); + metricExporterMock.mockClear(); + logExporterMock.mockClear(); }); AfterEachScenario(() => { @@ -135,13 +135,15 @@ test.for(feature, ({ Scenario, BeforeEachScenario, AfterEachScenario }) => { expect(exporters.traceExporter).toBeInstanceOf(TraceExporter); expect(exporters.metricExporter).toBeInstanceOf(MetricExporter); expect(exporters.logExporter).toBeInstanceOf(LogExporter); - expect(traceExporterMock.calls.at(-1)).toEqual({ connectionString: connStr }); - expect(metricExporterMock.calls.at(-1)).toEqual({ connectionString: connStr }); - expect(logExporterMock.calls.at(-1)).toEqual({ connectionString: connStr }); - // Also check the instance has the correct property for extra safety - expect((exporters.traceExporter as unknown as { __args: { connectionString: string } }).__args.connectionString).toBe(connStr); - expect((exporters.metricExporter as unknown as { __args: { connectionString: string } }).__args.connectionString).toBe(connStr); - expect((exporters.logExporter as unknown as { __args: { connectionString: string } }).__args.connectionString).toBe(connStr); + expect(traceExporterMock).toHaveBeenCalledWith({ connectionString: connStr }); + expect(metricExporterMock).toHaveBeenCalledWith({ connectionString: connStr }); + expect(logExporterMock).toHaveBeenCalledWith({ connectionString: connStr }); + // biome-ignore lint/suspicious/noExplicitAny: Required for accessing mock internal property + expect((exporters.traceExporter as any).__args.connectionString).toBe(connStr); + // biome-ignore lint/suspicious/noExplicitAny: Required for accessing mock internal property + expect((exporters.metricExporter as any).__args.connectionString).toBe(connStr); + // biome-ignore lint/suspicious/noExplicitAny: Required for accessing mock internal property + expect((exporters.logExporter as any).__args.connectionString).toBe(connStr); }); }); From 7e0a5bd903101652761f620dd94681d54e2b4206 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Wed, 10 Dec 2025 15:24:47 -0500 Subject: [PATCH 04/74] attempt to fix error on pipeline --- apps/ui-sharethrift/vite.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/ui-sharethrift/vite.config.ts b/apps/ui-sharethrift/vite.config.ts index 3994b9b64..72e03636a 100644 --- a/apps/ui-sharethrift/vite.config.ts +++ b/apps/ui-sharethrift/vite.config.ts @@ -7,5 +7,6 @@ export default defineConfig({ server: { port: 3000, open: true, // Automatically open browser on server start + watch: { usePolling: true }, // attempt to fix issue on pipeline: [vite] (client) Pre-transform error: EMFILE: too many open files, open '/home/vsts/work/1/s/packages/sthrift/ui-components/dist/src/index.js' }, }); From 92e796b7cb2763694de5cf54b41ad0090d230f2a Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Wed, 10 Dec 2025 15:24:56 -0500 Subject: [PATCH 05/74] fix mocks for stories --- .../src/App.container.stories.tsx | 2 +- .../profile/stories/ProfilePage.stories.tsx | 31 ++++++++++++++++--- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/apps/ui-sharethrift/src/App.container.stories.tsx b/apps/ui-sharethrift/src/App.container.stories.tsx index 4c2dace79..673da5413 100644 --- a/apps/ui-sharethrift/src/App.container.stories.tsx +++ b/apps/ui-sharethrift/src/App.container.stories.tsx @@ -45,7 +45,7 @@ const mockAuthenticatedNotCompletedOnboarding = { }, result: { data: { - currentUser: { + currentUserAndCreateIfNotExists: { __typename: 'PersonalUser' as const, id: 'user-456', userType: 'personal-user', diff --git a/apps/ui-sharethrift/src/components/layouts/home/account/profile/stories/ProfilePage.stories.tsx b/apps/ui-sharethrift/src/components/layouts/home/account/profile/stories/ProfilePage.stories.tsx index cad8f628c..33ab6b0d3 100644 --- a/apps/ui-sharethrift/src/components/layouts/home/account/profile/stories/ProfilePage.stories.tsx +++ b/apps/ui-sharethrift/src/components/layouts/home/account/profile/stories/ProfilePage.stories.tsx @@ -7,6 +7,7 @@ import { import { HomeAccountProfileViewContainerCurrentUserDocument, HomeAccountProfileViewContainerUserListingsDocument, + UseUserIsAdminDocument, type ItemListing, type PersonalUser, } from '../../../../../../generated.tsx'; @@ -86,6 +87,19 @@ const mockTwoListings: ItemListing[] = [ }, ]; +const userIsAdminMockRequest = (userId: string) => { + return { + request: { + query: UseUserIsAdminDocument, + }, + result: { + data: { + currentUser: {id: userId, userIsAdmin: false }, + }, + }, + }; +}; + const meta: Meta = { title: 'Pages/Account/Profile', component: HomeRoutes, @@ -113,7 +127,7 @@ export const DefaultView: Story = { }, result: { data: { - currentPersonalUserAndCreateIfNotExists: mockUserSarah, + currentUser: mockUserSarah, }, }, }, @@ -121,13 +135,20 @@ export const DefaultView: Story = { { request: { query: HomeAccountProfileViewContainerUserListingsDocument, + variables: { page: 1, pageSize: 100 }, }, result: { data: { - itemListings: mockTwoListings, + myListingsAll: { + items: mockTwoListings, + total: 2, + page: 1, + pageSize: 100, + }, }, }, }, + userIsAdminMockRequest(mockUserSarah.id), ], }, }, @@ -143,20 +164,22 @@ export const NoListings: Story = { }, result: { data: { - currentPersonalUserAndCreateIfNotExists: mockUserAlex, + currentUser: mockUserAlex, }, }, }, { request: { query: HomeAccountProfileViewContainerUserListingsDocument, + variables: { page: 1, pageSize: 100 }, }, result: { data: { - itemListings: [], + myListingsAll: [], }, }, }, + userIsAdminMockRequest(mockUserAlex.id), ], }, }, From 3f51579681acc8adeb232dba756ac3f03307407b Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Thu, 11 Dec 2025 09:44:31 -0500 Subject: [PATCH 06/74] attempt to fix "EMFILE: too many open files on pipeline" --- apps/ui-sharethrift/vite.config.ts | 2 +- .../src/configs/storybook.config.ts | 115 ++++++++++-------- 2 files changed, 64 insertions(+), 53 deletions(-) diff --git a/apps/ui-sharethrift/vite.config.ts b/apps/ui-sharethrift/vite.config.ts index 72e03636a..77b6cc43d 100644 --- a/apps/ui-sharethrift/vite.config.ts +++ b/apps/ui-sharethrift/vite.config.ts @@ -7,6 +7,6 @@ export default defineConfig({ server: { port: 3000, open: true, // Automatically open browser on server start - watch: { usePolling: true }, // attempt to fix issue on pipeline: [vite] (client) Pre-transform error: EMFILE: too many open files, open '/home/vsts/work/1/s/packages/sthrift/ui-components/dist/src/index.js' + watch: { usePolling: false }, // attempt to fix issue on pipeline: [vite] (client) Pre-transform error: EMFILE: too many open files, open '/home/vsts/work/1/s/packages/sthrift/ui-components/dist/src/index.js' }, }); diff --git a/packages/cellix/vitest-config/src/configs/storybook.config.ts b/packages/cellix/vitest-config/src/configs/storybook.config.ts index 428c73e5d..47321544a 100644 --- a/packages/cellix/vitest-config/src/configs/storybook.config.ts +++ b/packages/cellix/vitest-config/src/configs/storybook.config.ts @@ -2,62 +2,73 @@ import path from 'node:path'; import { storybookTest } from '@storybook/addon-vitest/vitest-plugin'; import { defineConfig, mergeConfig, type ViteUserConfig } from 'vitest/config'; import { baseConfig } from './base.config.ts'; -import { playwright } from '@vitest/browser-playwright' +import { playwright } from '@vitest/browser-playwright'; export type StorybookVitestConfigOptions = { - storybookDirRelativeToPackage?: string; // default: '.storybook' - setupFiles?: string[]; // default: ['.storybook/vitest.setup.ts'] - browsers?: { browser: 'chromium' | 'firefox' | 'webkit' }[]; // default: [{ browser: 'chromium' }] - additionalCoverageExclude?: string[]; + storybookDirRelativeToPackage?: string; // default: '.storybook' + setupFiles?: string[]; // default: ['.storybook/vitest.setup.ts'] + browsers?: { browser: 'chromium' | 'firefox' | 'webkit' }[]; // default: [{ browser: 'chromium' }] + additionalCoverageExclude?: string[]; }; -export function createStorybookVitestConfig(pkgDirname: string, opts: StorybookVitestConfigOptions = {}): ViteUserConfig { - const STORYBOOK_DIR = opts.storybookDirRelativeToPackage ?? '.storybook'; - const setupFiles = opts.setupFiles ?? ['.storybook/vitest.setup.ts']; - const instances = opts.browsers ?? [{ browser: 'chromium' }]; +export function createStorybookVitestConfig( + pkgDirname: string, + opts: StorybookVitestConfigOptions = {}, +): ViteUserConfig { + const STORYBOOK_DIR = opts.storybookDirRelativeToPackage ?? '.storybook'; + const setupFiles = opts.setupFiles ?? ['.storybook/vitest.setup.ts']; + const instances = opts.browsers ?? [{ browser: 'chromium' }]; - const storybookConfig = defineConfig({ - test: { - globals: true, - projects: [ - { - extends: true, - plugins: [ - storybookTest({ - configDir: path.join(pkgDirname, STORYBOOK_DIR), - }), - ], - test: { - name: 'storybook', - browser: { - enabled: true, - headless: true, - provider: playwright(), - instances, - }, - setupFiles, - }, - }, - ], - coverage: { - exclude: [ - '**/*.config.ts', - '**/tsconfig.json', - '**/.storybook/**', - '**/*.stories.ts', - '**/*.stories.tsx', - '**/*.test.ts', - '**/*.test.tsx', - '**/generated.ts', - '**/generated.tsx', - '**/coverage/**', - '**/*.d.ts', - 'dist/**', - ...(opts.additionalCoverageExclude ?? []), - ], - }, - }, - }); + const storybookConfig = defineConfig({ + test: { + globals: true, + include: ['src/**/*.test.{ts,tsx}'], + exclude: ['**/node_modules/**', '**/dist/**'], + projects: [ + { + extends: true, + plugins: [ + storybookTest({ + configDir: path.join(pkgDirname, STORYBOOK_DIR), + }), + ], + test: { + name: 'storybook', + browser: { + enabled: true, + headless: true, + provider: playwright(), + instances, + }, + setupFiles, + }, + }, + ], + coverage: { + exclude: [ + '**/*.config.ts', + '**/tsconfig.json', + '**/.storybook/**', + '**/*.stories.ts', + '**/*.stories.tsx', + '**/*.test.ts', + '**/*.test.tsx', + '**/generated.ts', + '**/generated.tsx', + '**/coverage/**', + '**/*.d.ts', + 'dist/**', + ...(opts.additionalCoverageExclude ?? []), + ], + }, + }, + optimizeDeps: { + disabled: true, + }, + }); - return mergeConfig(mergeConfig(baseConfig, storybookConfig), defineConfig({})); + return mergeConfig( + mergeConfig(baseConfig, storybookConfig), + defineConfig({}), + ); } From 6630071d026bbc94d73e4299ba921428d1b545e1 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Thu, 11 Dec 2025 10:34:30 -0500 Subject: [PATCH 07/74] remove unnecessary configs --- .../cellix/vitest-config/src/configs/storybook.config.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/cellix/vitest-config/src/configs/storybook.config.ts b/packages/cellix/vitest-config/src/configs/storybook.config.ts index 47321544a..f78b5b892 100644 --- a/packages/cellix/vitest-config/src/configs/storybook.config.ts +++ b/packages/cellix/vitest-config/src/configs/storybook.config.ts @@ -22,7 +22,6 @@ export function createStorybookVitestConfig( const storybookConfig = defineConfig({ test: { globals: true, - include: ['src/**/*.test.{ts,tsx}'], exclude: ['**/node_modules/**', '**/dist/**'], projects: [ { @@ -61,10 +60,7 @@ export function createStorybookVitestConfig( ...(opts.additionalCoverageExclude ?? []), ], }, - }, - optimizeDeps: { - disabled: true, - }, + } }); return mergeConfig( From 65c0cd32314fb590af9ecb8cea7f5a8f50b8569f Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Thu, 11 Dec 2025 12:16:19 -0500 Subject: [PATCH 08/74] attempt to fix "EMFILE: too many open files on pipeline" --- apps/ui-sharethrift/vite.config.ts | 1 - .../cellix/vitest-config/src/configs/storybook.config.ts | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/ui-sharethrift/vite.config.ts b/apps/ui-sharethrift/vite.config.ts index 77b6cc43d..3994b9b64 100644 --- a/apps/ui-sharethrift/vite.config.ts +++ b/apps/ui-sharethrift/vite.config.ts @@ -7,6 +7,5 @@ export default defineConfig({ server: { port: 3000, open: true, // Automatically open browser on server start - watch: { usePolling: false }, // attempt to fix issue on pipeline: [vite] (client) Pre-transform error: EMFILE: too many open files, open '/home/vsts/work/1/s/packages/sthrift/ui-components/dist/src/index.js' }, }); diff --git a/packages/cellix/vitest-config/src/configs/storybook.config.ts b/packages/cellix/vitest-config/src/configs/storybook.config.ts index f78b5b892..d2ca8cae6 100644 --- a/packages/cellix/vitest-config/src/configs/storybook.config.ts +++ b/packages/cellix/vitest-config/src/configs/storybook.config.ts @@ -22,7 +22,6 @@ export function createStorybookVitestConfig( const storybookConfig = defineConfig({ test: { globals: true, - exclude: ['**/node_modules/**', '**/dist/**'], projects: [ { extends: true, @@ -60,7 +59,9 @@ export function createStorybookVitestConfig( ...(opts.additionalCoverageExclude ?? []), ], }, - } + watch: false, + isolate: true, + }, }); return mergeConfig( From 0c3af3b96acd44c86a7e97e98a2ba1250e074ac6 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Thu, 11 Dec 2025 13:48:37 -0500 Subject: [PATCH 09/74] fix exports to see if it resolve pipeline error EMFILE: too many open files --- .../account-plan.repository.test.ts | 7 +++-- .../account-plan.read-repository.test.ts | 18 ++++++------- packages/sthrift/ui-components/src/index.ts | 26 +++++++++---------- 3 files changed, 25 insertions(+), 26 deletions(-) diff --git a/packages/sthrift/persistence/src/datasources/domain/account-plan/account-plan/account-plan.repository.test.ts b/packages/sthrift/persistence/src/datasources/domain/account-plan/account-plan/account-plan.repository.test.ts index 1809590a1..f9ed634b4 100644 --- a/packages/sthrift/persistence/src/datasources/domain/account-plan/account-plan/account-plan.repository.test.ts +++ b/packages/sthrift/persistence/src/datasources/domain/account-plan/account-plan/account-plan.repository.test.ts @@ -75,10 +75,9 @@ function makeAccountPlanDoc( } function createChainableQuery(result: T) { - const query = { - exec: vi.fn().mockResolvedValue(result), - }; - return query; + return { + exec: vi.fn().mockResolvedValue(result), + }; } function setupAccountPlanRepo( diff --git a/packages/sthrift/persistence/src/datasources/readonly/account-plan/account-plan/account-plan.read-repository.test.ts b/packages/sthrift/persistence/src/datasources/readonly/account-plan/account-plan/account-plan.read-repository.test.ts index d7772e13f..8ec9a5b8b 100644 --- a/packages/sthrift/persistence/src/datasources/readonly/account-plan/account-plan/account-plan.read-repository.test.ts +++ b/packages/sthrift/persistence/src/datasources/readonly/account-plan/account-plan/account-plan.read-repository.test.ts @@ -96,7 +96,7 @@ describe('AccountPlanReadRepositoryImpl', () => { ]; // Access the mongoDataSource via prototype or direct property - const mongoDataSource = (repository as unknown as { mongoDataSource: { find: ReturnType } }).mongoDataSource; + const {mongoDataSource} = repository as unknown as { mongoDataSource: { find: ReturnType } }; mongoDataSource.find = vi.fn().mockResolvedValue(mockData); const result = await repository.getAll(); @@ -108,7 +108,7 @@ describe('AccountPlanReadRepositoryImpl', () => { const options: FindOptions = { fields: ['name'] }; const mockData = [{ _id: '1', name: 'Plan 1' }]; - const mongoDataSource = (repository as unknown as { mongoDataSource: { find: ReturnType } }).mongoDataSource; + const {mongoDataSource} = repository as unknown as { mongoDataSource: { find: ReturnType } }; mongoDataSource.find = vi.fn().mockResolvedValue(mockData); await repository.getAll(options); @@ -118,7 +118,7 @@ describe('AccountPlanReadRepositoryImpl', () => { it('should return empty array when no plans exist', async () => { const repository = new AccountPlanReadRepositoryImpl(models, passport); - const mongoDataSource = (repository as unknown as { mongoDataSource: { find: ReturnType } }).mongoDataSource; + const {mongoDataSource} = repository as unknown as { mongoDataSource: { find: ReturnType } }; mongoDataSource.find = vi.fn().mockResolvedValue([]); const result = await repository.getAll(); @@ -131,7 +131,7 @@ describe('AccountPlanReadRepositoryImpl', () => { const repository = new AccountPlanReadRepositoryImpl(models, passport); const mockData = { _id: '123', name: 'Test Plan' }; - const mongoDataSource = (repository as unknown as { mongoDataSource: { findById: ReturnType } }).mongoDataSource; + const {mongoDataSource} = repository as unknown as { mongoDataSource: { findById: ReturnType } }; mongoDataSource.findById = vi.fn().mockResolvedValue(mockData); const result = await repository.getById('123'); @@ -141,7 +141,7 @@ describe('AccountPlanReadRepositoryImpl', () => { it('should return null when plan not found', async () => { const repository = new AccountPlanReadRepositoryImpl(models, passport); - const mongoDataSource = (repository as unknown as { mongoDataSource: { findById: ReturnType } }).mongoDataSource; + const {mongoDataSource} = repository as unknown as { mongoDataSource: { findById: ReturnType } }; mongoDataSource.findById = vi.fn().mockResolvedValue(null); const result = await repository.getById('nonexistent'); @@ -152,7 +152,7 @@ describe('AccountPlanReadRepositoryImpl', () => { const repository = new AccountPlanReadRepositoryImpl(models, passport); const options: FindOneOptions = { fields: ['name'] }; - const mongoDataSource = (repository as unknown as { mongoDataSource: { findById: ReturnType } }).mongoDataSource; + const {mongoDataSource} = repository as unknown as { mongoDataSource: { findById: ReturnType } }; mongoDataSource.findById = vi.fn().mockResolvedValue(null); await repository.getById('123', options); @@ -165,7 +165,7 @@ describe('AccountPlanReadRepositoryImpl', () => { const repository = new AccountPlanReadRepositoryImpl(models, passport); const mockData = { _id: '123', name: 'Premium Plan' }; - const mongoDataSource = (repository as unknown as { mongoDataSource: { findOne: ReturnType } }).mongoDataSource; + const {mongoDataSource} = repository as unknown as { mongoDataSource: { findOne: ReturnType } }; mongoDataSource.findOne = vi.fn().mockResolvedValue(mockData); const result = await repository.getByName('Premium Plan'); @@ -175,7 +175,7 @@ describe('AccountPlanReadRepositoryImpl', () => { it('should return null when plan not found by name', async () => { const repository = new AccountPlanReadRepositoryImpl(models, passport); - const mongoDataSource = (repository as unknown as { mongoDataSource: { findOne: ReturnType } }).mongoDataSource; + const {mongoDataSource} = repository as unknown as { mongoDataSource: { findOne: ReturnType } }; mongoDataSource.findOne = vi.fn().mockResolvedValue(null); const result = await repository.getByName('Nonexistent Plan'); @@ -185,7 +185,7 @@ describe('AccountPlanReadRepositoryImpl', () => { it('should call findOne with name filter', async () => { const repository = new AccountPlanReadRepositoryImpl(models, passport); - const mongoDataSource = (repository as unknown as { mongoDataSource: { findOne: ReturnType } }).mongoDataSource; + const {mongoDataSource} = repository as unknown as { mongoDataSource: { findOne: ReturnType } }; mongoDataSource.findOne = vi.fn().mockResolvedValue(null); await repository.getByName('Test Plan'); diff --git a/packages/sthrift/ui-components/src/index.ts b/packages/sthrift/ui-components/src/index.ts index 021f321ff..d1611d274 100644 --- a/packages/sthrift/ui-components/src/index.ts +++ b/packages/sthrift/ui-components/src/index.ts @@ -1,17 +1,17 @@ export type { UIItemListing } from './organisms/listings-grid/index.tsx'; // Barrel file for all reusable UI components -export type { FooterProps } from './molecules/footer/index.js'; -export type { HeaderProps } from './molecules/header/index.js'; -export type { NavigationProps } from './molecules/navigation/index.js'; -export { Footer } from './molecules/footer/index.js'; -export { Header } from './molecules/header/index.js'; -export { Navigation } from './molecules/navigation/index.js'; -export { SearchBar } from './molecules/search-bar/index.js'; -export { MessageSharerButton } from './molecules/message-sharer-button.js'; -export { AppLayout } from './organisms/app-layout/index.js'; -export { ListingsGrid } from './organisms/listings-grid/index.js'; -export type { ComponentQueryLoaderProps } from './molecules/component-query-loader/index.js'; -export { ComponentQueryLoader } from './molecules/component-query-loader/index.js'; +export type { FooterProps } from './molecules/footer/index.tsx'; +export type { HeaderProps } from './molecules/header/index.tsx'; +export type { NavigationProps } from './molecules/navigation/index.tsx'; +export { Footer } from './molecules/footer/index.tsx'; +export { Header } from './molecules/header/index.tsx'; +export { Navigation } from './molecules/navigation/index.tsx'; +export { SearchBar } from './molecules/search-bar/index.tsx'; +export { MessageSharerButton } from './molecules/message-sharer-button.tsx'; +export { AppLayout } from './organisms/app-layout/index.tsx'; +export { ListingsGrid } from './organisms/listings-grid/index.tsx'; +export type { ComponentQueryLoaderProps } from './molecules/component-query-loader/index.tsx'; +export { ComponentQueryLoader } from './molecules/component-query-loader/index.tsx'; export type { DashboardProps } from './organisms/dashboard/index.tsx'; export { Dashboard } from './organisms/dashboard/index.tsx'; -export { ReservationStatusTag } from './atoms/reservation-status-tag/index.js'; +export { ReservationStatusTag } from './atoms/reservation-status-tag/index.tsx'; \ No newline at end of file From 95c575a9bb39f07583693afee18d9b2d6dc5682b Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Thu, 11 Dec 2025 14:31:36 -0500 Subject: [PATCH 10/74] attempt to fix error EMFILE: too many open files: increase the open file limit in CI pipeline --- build-pipeline/core/monorepo-build-stage.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/build-pipeline/core/monorepo-build-stage.yml b/build-pipeline/core/monorepo-build-stage.yml index 61743b17d..dbef806d4 100644 --- a/build-pipeline/core/monorepo-build-stage.yml +++ b/build-pipeline/core/monorepo-build-stage.yml @@ -214,6 +214,7 @@ stages: targetType: 'inline' script: | set -euo pipefail + ulimit -n 4096 export NODE_OPTIONS=--max_old_space_size=16384 export PLAYWRIGHT_BROWSERS_PATH="$(PLAYWRIGHT_BROWSERS_PATH)" From 4f2dae9172aea672fff5b55d19a222da7ff8db44 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Thu, 11 Dec 2025 14:47:52 -0500 Subject: [PATCH 11/74] increase to 10000 to see if it fixes the error --- build-pipeline/core/monorepo-build-stage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-pipeline/core/monorepo-build-stage.yml b/build-pipeline/core/monorepo-build-stage.yml index dbef806d4..db341a287 100644 --- a/build-pipeline/core/monorepo-build-stage.yml +++ b/build-pipeline/core/monorepo-build-stage.yml @@ -214,7 +214,7 @@ stages: targetType: 'inline' script: | set -euo pipefail - ulimit -n 4096 + ulimit -n 10000 export NODE_OPTIONS=--max_old_space_size=16384 export PLAYWRIGHT_BROWSERS_PATH="$(PLAYWRIGHT_BROWSERS_PATH)" From 18d25ef2cc672b234c7907a7b1d5aceb61cc42ac Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Thu, 11 Dec 2025 15:15:23 -0500 Subject: [PATCH 12/74] increase ulimit to 100000 --- build-pipeline/core/monorepo-build-stage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-pipeline/core/monorepo-build-stage.yml b/build-pipeline/core/monorepo-build-stage.yml index db341a287..4d8265a55 100644 --- a/build-pipeline/core/monorepo-build-stage.yml +++ b/build-pipeline/core/monorepo-build-stage.yml @@ -214,7 +214,7 @@ stages: targetType: 'inline' script: | set -euo pipefail - ulimit -n 10000 + ulimit -n 100000 export NODE_OPTIONS=--max_old_space_size=16384 export PLAYWRIGHT_BROWSERS_PATH="$(PLAYWRIGHT_BROWSERS_PATH)" From 24aa5cf014951c0f89ef10683bddcd5235504e07 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Thu, 11 Dec 2025 15:27:39 -0500 Subject: [PATCH 13/74] reduce open file limit from 100000 to 20000 in build pipeline --- build-pipeline/core/monorepo-build-stage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-pipeline/core/monorepo-build-stage.yml b/build-pipeline/core/monorepo-build-stage.yml index 4d8265a55..cdbbc3857 100644 --- a/build-pipeline/core/monorepo-build-stage.yml +++ b/build-pipeline/core/monorepo-build-stage.yml @@ -214,7 +214,7 @@ stages: targetType: 'inline' script: | set -euo pipefail - ulimit -n 100000 + ulimit -n 20000 export NODE_OPTIONS=--max_old_space_size=16384 export PLAYWRIGHT_BROWSERS_PATH="$(PLAYWRIGHT_BROWSERS_PATH)" From dbf8e6fa25547ed9bf874769a756bb999c7d9600 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Thu, 11 Dec 2025 16:04:23 -0500 Subject: [PATCH 14/74] add comment to explain new configs after vitest 4 upgrade --- .../cellix/vitest-config/src/configs/storybook.config.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/cellix/vitest-config/src/configs/storybook.config.ts b/packages/cellix/vitest-config/src/configs/storybook.config.ts index d2ca8cae6..fb8cefefd 100644 --- a/packages/cellix/vitest-config/src/configs/storybook.config.ts +++ b/packages/cellix/vitest-config/src/configs/storybook.config.ts @@ -59,8 +59,9 @@ export function createStorybookVitestConfig( ...(opts.additionalCoverageExclude ?? []), ], }, - watch: false, - isolate: true, + // Disable watch mode and isolate tests when running Storybook tests to reduce file watchers and improve stability + watch: false, //disables file watching, which reduces the number of file watchers and resource usage + isolate: true, // ensures each test file runs in its own process, improving test stability and preventing state leakage }, }); From 41858e71ecba67abb1aec3ad14857f7333747e1f Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Fri, 12 Dec 2025 09:01:27 -0500 Subject: [PATCH 15/74] fix: update import paths from .js to .tsx for UI components --- packages/sthrift/ui-components/src/index.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/sthrift/ui-components/src/index.ts b/packages/sthrift/ui-components/src/index.ts index e80958e63..51512088e 100644 --- a/packages/sthrift/ui-components/src/index.ts +++ b/packages/sthrift/ui-components/src/index.ts @@ -1,12 +1,12 @@ export type { UIItemListing } from './organisms/listings-grid/index.tsx'; // Barrel file for all reusable UI components -export { Footer } from './molecules/footer/index.js'; -export { Header } from './molecules/header/index.js'; -export { Navigation } from './molecules/navigation/index.js'; -export { SearchBar } from './molecules/search-bar/index.js'; -export { MessageSharerButton } from './molecules/message-sharer-button.js'; -export { AppLayout } from './organisms/app-layout/index.js'; -export { ListingsGrid } from './organisms/listings-grid/index.js'; -export { ComponentQueryLoader } from './molecules/component-query-loader/index.js'; +export { Footer } from './molecules/footer/index.tsx'; +export { Header } from './molecules/header/index.tsx'; +export { Navigation } from './molecules/navigation/index.tsx'; +export { SearchBar } from './molecules/search-bar/index.tsx'; +export { MessageSharerButton } from './molecules/message-sharer-button.tsx'; +export { AppLayout } from './organisms/app-layout/index.tsx'; +export { ListingsGrid } from './organisms/listings-grid/index.tsx'; +export { ComponentQueryLoader } from './molecules/component-query-loader/index.tsx'; export { Dashboard } from './organisms/dashboard/index.tsx'; export { ReservationStatusTag } from './atoms/reservation-status-tag/index.tsx'; \ No newline at end of file From 8e9442fff071ae13d4f27e67e7ec5df4086f3148 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Fri, 12 Dec 2025 09:45:12 -0500 Subject: [PATCH 16/74] fix: increase open file limit from 20000 to 25000 in build pipeline --- build-pipeline/core/monorepo-build-stage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-pipeline/core/monorepo-build-stage.yml b/build-pipeline/core/monorepo-build-stage.yml index aac4fc1ee..04ed3337d 100644 --- a/build-pipeline/core/monorepo-build-stage.yml +++ b/build-pipeline/core/monorepo-build-stage.yml @@ -224,7 +224,7 @@ stages: targetType: 'inline' script: | set -euo pipefail - ulimit -n 20000 + ulimit -n 25000 export NODE_OPTIONS=--max_old_space_size=16384 export PLAYWRIGHT_BROWSERS_PATH="$(PLAYWRIGHT_BROWSERS_PATH)" From cd4060bde7dbdf1ff2aa2b2f8a3296567cd1d4b1 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Fri, 12 Dec 2025 10:52:09 -0500 Subject: [PATCH 17/74] fix: increase open file limit from 25000 to 30000 in build pipeline --- build-pipeline/core/monorepo-build-stage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-pipeline/core/monorepo-build-stage.yml b/build-pipeline/core/monorepo-build-stage.yml index 04ed3337d..eb314bb92 100644 --- a/build-pipeline/core/monorepo-build-stage.yml +++ b/build-pipeline/core/monorepo-build-stage.yml @@ -224,7 +224,7 @@ stages: targetType: 'inline' script: | set -euo pipefail - ulimit -n 25000 + ulimit -n 30000 export NODE_OPTIONS=--max_old_space_size=16384 export PLAYWRIGHT_BROWSERS_PATH="$(PLAYWRIGHT_BROWSERS_PATH)" From 8bb22e8f6e8763883638fe9347162d714a40a4c2 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Fri, 12 Dec 2025 11:22:08 -0500 Subject: [PATCH 18/74] remove CI flag to see if it fixes pipeline error --- .../vitest-config/src/configs/storybook.config.ts | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/packages/cellix/vitest-config/src/configs/storybook.config.ts b/packages/cellix/vitest-config/src/configs/storybook.config.ts index 014d018fe..1ac87f928 100644 --- a/packages/cellix/vitest-config/src/configs/storybook.config.ts +++ b/packages/cellix/vitest-config/src/configs/storybook.config.ts @@ -18,21 +18,11 @@ export function createStorybookVitestConfig( const STORYBOOK_DIR = opts.storybookDirRelativeToPackage ?? '.storybook'; const setupFiles = opts.setupFiles ?? ['.storybook/vitest.setup.ts']; const instances = opts.browsers ?? [{ browser: 'chromium' }]; - // CI environment is slower, allow retries for flaky browser tests - const isCI = - process.env['CI'] === 'true' || process.env['TF_BUILD'] === 'True'; const storybookConfig = defineConfig({ test: { globals: true, - // Retry tests on failure to handle flaky browser tests due to race conditions - // in @storybook/addon-vitest + Playwright browser provider - retry: isCI ? 3 : 1, - testTimeout: isCI ? 30000 : 10000, - // Serialize file execution in CI to avoid "Vitest failed to find the runner" race condition - // when using Storybook + Vitest browser mode with Playwright - // Local development benefits from parallel execution for faster feedback - fileParallelism: !isCI, + projects: [ { extends: true, From 342c5f0d87c9e44308054796cc92ef126dfc4c9b Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Fri, 12 Dec 2025 11:47:45 -0500 Subject: [PATCH 19/74] fix: increase open file limit to 40000 and enable thread pooling in Storybook tests --- build-pipeline/core/monorepo-build-stage.yml | 2 +- packages/cellix/vitest-config/src/configs/storybook.config.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/build-pipeline/core/monorepo-build-stage.yml b/build-pipeline/core/monorepo-build-stage.yml index eb314bb92..e7e986b69 100644 --- a/build-pipeline/core/monorepo-build-stage.yml +++ b/build-pipeline/core/monorepo-build-stage.yml @@ -224,7 +224,7 @@ stages: targetType: 'inline' script: | set -euo pipefail - ulimit -n 30000 + ulimit -n 40000 export NODE_OPTIONS=--max_old_space_size=16384 export PLAYWRIGHT_BROWSERS_PATH="$(PLAYWRIGHT_BROWSERS_PATH)" diff --git a/packages/cellix/vitest-config/src/configs/storybook.config.ts b/packages/cellix/vitest-config/src/configs/storybook.config.ts index 1ac87f928..2d19fa260 100644 --- a/packages/cellix/vitest-config/src/configs/storybook.config.ts +++ b/packages/cellix/vitest-config/src/configs/storybook.config.ts @@ -63,6 +63,7 @@ export function createStorybookVitestConfig( // Disable watch mode and isolate tests when running Storybook tests to reduce file watchers and improve stability watch: false, //disables file watching, which reduces the number of file watchers and resource usage isolate: true, // ensures each test file runs in its own process, improving test stability and preventing state leakage + pool: "threads" }, }); From 06d1426ba251ef81c5eba5f1f50ba411de8f52c6 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Sat, 13 Dec 2025 07:55:46 -0500 Subject: [PATCH 20/74] attempt to fix EMFILE error: increase open file limit from 40000 to 50000 in build pipeline --- build-pipeline/core/monorepo-build-stage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-pipeline/core/monorepo-build-stage.yml b/build-pipeline/core/monorepo-build-stage.yml index e7e986b69..2f87a1cb9 100644 --- a/build-pipeline/core/monorepo-build-stage.yml +++ b/build-pipeline/core/monorepo-build-stage.yml @@ -224,7 +224,7 @@ stages: targetType: 'inline' script: | set -euo pipefail - ulimit -n 40000 + ulimit -n 50000 export NODE_OPTIONS=--max_old_space_size=16384 export PLAYWRIGHT_BROWSERS_PATH="$(PLAYWRIGHT_BROWSERS_PATH)" From f56096f4b5657ba310924e6584c6f8ba9413bdd9 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Sat, 13 Dec 2025 07:58:52 -0500 Subject: [PATCH 21/74] fix EMFILE: remove thread pooling option from Storybook test configuration --- packages/cellix/vitest-config/src/configs/storybook.config.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/cellix/vitest-config/src/configs/storybook.config.ts b/packages/cellix/vitest-config/src/configs/storybook.config.ts index 2d19fa260..1ac87f928 100644 --- a/packages/cellix/vitest-config/src/configs/storybook.config.ts +++ b/packages/cellix/vitest-config/src/configs/storybook.config.ts @@ -63,7 +63,6 @@ export function createStorybookVitestConfig( // Disable watch mode and isolate tests when running Storybook tests to reduce file watchers and improve stability watch: false, //disables file watching, which reduces the number of file watchers and resource usage isolate: true, // ensures each test file runs in its own process, improving test stability and preventing state leakage - pool: "threads" }, }); From 014b9401c29c510778efc5adb3b4543a2180f4dc Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Sat, 13 Dec 2025 08:52:43 -0500 Subject: [PATCH 22/74] adjust testing configurations to improve stability and performance --- build-pipeline/core/monorepo-build-stage.yml | 4 +++- .../src/configs/storybook.config.ts | 23 ++++++++++++------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/build-pipeline/core/monorepo-build-stage.yml b/build-pipeline/core/monorepo-build-stage.yml index 2f87a1cb9..cc6dda9cb 100644 --- a/build-pipeline/core/monorepo-build-stage.yml +++ b/build-pipeline/core/monorepo-build-stage.yml @@ -225,6 +225,7 @@ stages: script: | set -euo pipefail ulimit -n 50000 + echo "Open file limit (ulimit -n): $(ulimit -n)" export NODE_OPTIONS=--max_old_space_size=16384 export PLAYWRIGHT_BROWSERS_PATH="$(PLAYWRIGHT_BROWSERS_PATH)" @@ -242,7 +243,8 @@ stages: if [ "$(Build.Reason)" = "PullRequest" ] || [ "$(Build.SourceBranch)" != "refs/heads/main" ]; then echo "Testing affected packages only (PR/branch build)..." export TURBO_SCM_BASE="origin/$(System.PullRequest.TargetBranch)" - pnpm run test:coverage --affected + # Limit Turborepo parallelism in CI to reduce file descriptor pressure (EMFILE) during coverage runs. + pnpm run test:coverage --affected --concurrency=1 pnpm run merge-lcov-reports else echo "Testing all packages (main branch build)..." diff --git a/packages/cellix/vitest-config/src/configs/storybook.config.ts b/packages/cellix/vitest-config/src/configs/storybook.config.ts index 1ac87f928..4a618161b 100644 --- a/packages/cellix/vitest-config/src/configs/storybook.config.ts +++ b/packages/cellix/vitest-config/src/configs/storybook.config.ts @@ -19,10 +19,20 @@ export function createStorybookVitestConfig( const setupFiles = opts.setupFiles ?? ['.storybook/vitest.setup.ts']; const instances = opts.browsers ?? [{ browser: 'chromium' }]; + const isCI = + process.env['CI'] === 'true' || process.env['TF_BUILD'] === 'True'; + const storybookConfig = defineConfig({ test: { globals: true, - + // Retry tests on failure to handle flaky browser tests due to race conditions + // in @storybook/addon-vitest + Playwright browser provider + retry: isCI ? 3 : 1, + testTimeout: isCI ? 30000 : 10000, + // Serialize file execution in CI to avoid "Vitest failed to find the runner" race condition + // when using Storybook + Vitest browser mode with Playwright + // Local development benefits from parallel execution for faster feedback + fileParallelism: !isCI, projects: [ { extends: true, @@ -60,14 +70,11 @@ export function createStorybookVitestConfig( ...(opts.additionalCoverageExclude ?? []), ], }, - // Disable watch mode and isolate tests when running Storybook tests to reduce file watchers and improve stability - watch: false, //disables file watching, which reduces the number of file watchers and resource usage - isolate: true, // ensures each test file runs in its own process, improving test stability and preventing state leakage + // Disable watch mode and isolate tests to reduce file watchers and improve stability. + watch: false, + isolate: true, }, }); - return mergeConfig( - mergeConfig(baseConfig, storybookConfig), - defineConfig({}), - ); + return mergeConfig(baseConfig, storybookConfig); } From 207cd1ec77e88ba372f97e0b24c5ce3a6db51ac8 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Sat, 13 Dec 2025 10:05:21 -0500 Subject: [PATCH 23/74] increase concurrency for affected package coverage tests to reduce file descriptor pressure --- build-pipeline/core/monorepo-build-stage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-pipeline/core/monorepo-build-stage.yml b/build-pipeline/core/monorepo-build-stage.yml index cc6dda9cb..212a00006 100644 --- a/build-pipeline/core/monorepo-build-stage.yml +++ b/build-pipeline/core/monorepo-build-stage.yml @@ -244,7 +244,7 @@ stages: echo "Testing affected packages only (PR/branch build)..." export TURBO_SCM_BASE="origin/$(System.PullRequest.TargetBranch)" # Limit Turborepo parallelism in CI to reduce file descriptor pressure (EMFILE) during coverage runs. - pnpm run test:coverage --affected --concurrency=1 + pnpm run test:coverage --affected --concurrency=2 pnpm run merge-lcov-reports else echo "Testing all packages (main branch build)..." From 702505fdba57167afce8a4fff1f1f022c92b6a0f Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Mon, 15 Dec 2025 09:48:36 -0500 Subject: [PATCH 24/74] fix: adjust test coverage command and exclude build artifacts to reduce file descriptor pressure --- build-pipeline/core/monorepo-build-stage.yml | 2 +- packages/cellix/vitest-config/src/configs/storybook.config.ts | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/build-pipeline/core/monorepo-build-stage.yml b/build-pipeline/core/monorepo-build-stage.yml index 212a00006..4df25ebb4 100644 --- a/build-pipeline/core/monorepo-build-stage.yml +++ b/build-pipeline/core/monorepo-build-stage.yml @@ -244,7 +244,7 @@ stages: echo "Testing affected packages only (PR/branch build)..." export TURBO_SCM_BASE="origin/$(System.PullRequest.TargetBranch)" # Limit Turborepo parallelism in CI to reduce file descriptor pressure (EMFILE) during coverage runs. - pnpm run test:coverage --affected --concurrency=2 + pnpm run test:coverage --affected pnpm run merge-lcov-reports else echo "Testing all packages (main branch build)..." diff --git a/packages/cellix/vitest-config/src/configs/storybook.config.ts b/packages/cellix/vitest-config/src/configs/storybook.config.ts index 4a618161b..490417900 100644 --- a/packages/cellix/vitest-config/src/configs/storybook.config.ts +++ b/packages/cellix/vitest-config/src/configs/storybook.config.ts @@ -24,6 +24,9 @@ export function createStorybookVitestConfig( const storybookConfig = defineConfig({ test: { + // Prevent Vite/Vitest from scanning/transpiling build artifacts and coverage temp files. + // This greatly reduces the number of open files during coverage runs in CI. + exclude: ['dist/**', 'coverage/**', 'coverage/.tmp/**'], globals: true, // Retry tests on failure to handle flaky browser tests due to race conditions // in @storybook/addon-vitest + Playwright browser provider From 119c019228d68df476a5f69148886d2622943753 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Mon, 15 Dec 2025 10:18:54 -0500 Subject: [PATCH 25/74] remove unrelated comment+optimize test configuration to reduce EMFILE errors --- build-pipeline/core/monorepo-build-stage.yml | 1 - .../sthrift/ui-components/vitest.config.ts | 29 ++++++++++++++----- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/build-pipeline/core/monorepo-build-stage.yml b/build-pipeline/core/monorepo-build-stage.yml index 4df25ebb4..cfbbbeedc 100644 --- a/build-pipeline/core/monorepo-build-stage.yml +++ b/build-pipeline/core/monorepo-build-stage.yml @@ -243,7 +243,6 @@ stages: if [ "$(Build.Reason)" = "PullRequest" ] || [ "$(Build.SourceBranch)" != "refs/heads/main" ]; then echo "Testing affected packages only (PR/branch build)..." export TURBO_SCM_BASE="origin/$(System.PullRequest.TargetBranch)" - # Limit Turborepo parallelism in CI to reduce file descriptor pressure (EMFILE) during coverage runs. pnpm run test:coverage --affected pnpm run merge-lcov-reports else diff --git a/packages/sthrift/ui-components/vitest.config.ts b/packages/sthrift/ui-components/vitest.config.ts index 224a3e429..3e58f4023 100644 --- a/packages/sthrift/ui-components/vitest.config.ts +++ b/packages/sthrift/ui-components/vitest.config.ts @@ -1,19 +1,34 @@ import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { createStorybookVitestConfig } from '@cellix/vitest-config'; -import { defineConfig } from 'vitest/config'; +import { defineConfig, mergeConfig } from 'vitest/config'; const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url)); +const base = createStorybookVitestConfig(dirname, { + additionalCoverageExclude: [ + '**/index.ts', + 'src/components/molecules/index.tsx', + 'src/components/organisms/index.tsx', + ], +}); + +// Ensure tests resolve the package name to local source during testing so Vite +// doesn't follow the package "exports" to built `dist/` files. +// This prevents Vite from opening/transpiling dist/src/index.js which causes +// many open files (EMFILE) in CI coverage runs. export default defineConfig( - createStorybookVitestConfig(dirname, { - additionalCoverageExclude: [ - '**/index.ts', - 'src/components/molecules/index.tsx', - 'src/components/organisms/index.tsx', - ], + mergeConfig(base, { + resolve: { + alias: [ + { + find: '@sthrift/ui-components', + replacement: path.join(dirname, 'src'), + }, + ], + }, }), ); From 772c5d43bd2894db86e440d0301fd17dd4d01075 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Mon, 15 Dec 2025 10:45:22 -0500 Subject: [PATCH 26/74] feat: enhance Storybook Vitest configuration with dynamic alias resolution for ui-components --- .../src/configs/storybook.config.ts | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/packages/cellix/vitest-config/src/configs/storybook.config.ts b/packages/cellix/vitest-config/src/configs/storybook.config.ts index 490417900..29454aa08 100644 --- a/packages/cellix/vitest-config/src/configs/storybook.config.ts +++ b/packages/cellix/vitest-config/src/configs/storybook.config.ts @@ -1,4 +1,5 @@ import path from 'node:path'; +import { createRequire } from 'module'; import { storybookTest } from '@storybook/addon-vitest/vitest-plugin'; import { defineConfig, mergeConfig, type ViteUserConfig } from 'vitest/config'; import { baseConfig } from './base.config.ts'; @@ -22,6 +23,25 @@ export function createStorybookVitestConfig( const isCI = process.env['CI'] === 'true' || process.env['TF_BUILD'] === 'True'; + // Try to resolve the source directory of @sthrift/ui-components from the + // context of the package that is running tests. If found, add a Vite alias + // that maps the package name to its `src` folder so Vite will not resolve + // the package exports into `dist/` during tests (prevents opening dist files). + const aliases: { find: string | RegExp; replacement: string }[] = []; + try { + const require = createRequire(import.meta.url); + const uiPkgJson = require.resolve('@sthrift/ui-components/package.json', { + paths: [pkgDirname], + }); + const uiPkgDir = path.dirname(uiPkgJson); + aliases.push({ + find: '@sthrift/ui-components', + replacement: path.join(uiPkgDir, 'src'), + }); + } catch (e) { + // ignore if not resolvable in this environment + } + const storybookConfig = defineConfig({ test: { // Prevent Vite/Vitest from scanning/transpiling build artifacts and coverage temp files. @@ -77,6 +97,9 @@ export function createStorybookVitestConfig( watch: false, isolate: true, }, + resolve: { + alias: aliases, + }, }); return mergeConfig(baseConfig, storybookConfig); From 58c6546ffe86ce280931ee66a7c0c5b58dd1eee2 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Mon, 15 Dec 2025 11:40:31 -0500 Subject: [PATCH 27/74] fix: update Storybook Vitest config to dynamically resolve workspace package aliases --- .../src/configs/storybook.config.ts | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/packages/cellix/vitest-config/src/configs/storybook.config.ts b/packages/cellix/vitest-config/src/configs/storybook.config.ts index 29454aa08..fab9d6b93 100644 --- a/packages/cellix/vitest-config/src/configs/storybook.config.ts +++ b/packages/cellix/vitest-config/src/configs/storybook.config.ts @@ -23,23 +23,29 @@ export function createStorybookVitestConfig( const isCI = process.env['CI'] === 'true' || process.env['TF_BUILD'] === 'True'; - // Try to resolve the source directory of @sthrift/ui-components from the - // context of the package that is running tests. If found, add a Vite alias - // that maps the package name to its `src` folder so Vite will not resolve - // the package exports into `dist/` during tests (prevents opening dist files). + // Build a single alias list for workspace packages that should resolve to + // their source (`src/`) during tests. This prevents Vite from following + // package exports into `dist/` and opening built files during coverage runs. const aliases: { find: string | RegExp; replacement: string }[] = []; - try { - const require = createRequire(import.meta.url); - const uiPkgJson = require.resolve('@sthrift/ui-components/package.json', { - paths: [pkgDirname], - }); - const uiPkgDir = path.dirname(uiPkgJson); - aliases.push({ - find: '@sthrift/ui-components', - replacement: path.join(uiPkgDir, 'src'), - }); - } catch (e) { - // ignore if not resolvable in this environment + const workspacePackagesToAlias = [ + '@sthrift/ui-components', + '@sthrift/service-mongoose', + '@sthrift/graphql', + '@sthrift/domain', + '@cellix/ui-core', + '@cellix/messaging-service', + ]; + for (const pkgName of workspacePackagesToAlias) { + try { + const require = createRequire(import.meta.url); + const pkgJsonPath = require.resolve(`${pkgName}/package.json`, { + paths: [pkgDirname], + }); + const pkgDir = path.dirname(pkgJsonPath); + aliases.push({ find: pkgName, replacement: path.join(pkgDir, 'src') }); + } catch (e) { + // ignore missing packages + } } const storybookConfig = defineConfig({ From 56be73c4cc3009e7f5b77047a3baacf01d9d2f1b Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Mon, 15 Dec 2025 12:47:32 -0500 Subject: [PATCH 28/74] fix: increase file descriptor limit and update Storybook Vitest config to include new package alias --- build-pipeline/core/monorepo-build-stage.yml | 2 +- .../src/configs/storybook.config.ts | 1 + .../sthrift/ui-components/vitest.config.ts | 29 +++++-------------- 3 files changed, 9 insertions(+), 23 deletions(-) diff --git a/build-pipeline/core/monorepo-build-stage.yml b/build-pipeline/core/monorepo-build-stage.yml index cfbbbeedc..f44a602ff 100644 --- a/build-pipeline/core/monorepo-build-stage.yml +++ b/build-pipeline/core/monorepo-build-stage.yml @@ -224,7 +224,7 @@ stages: targetType: 'inline' script: | set -euo pipefail - ulimit -n 50000 + ulimit -n 60000 echo "Open file limit (ulimit -n): $(ulimit -n)" export NODE_OPTIONS=--max_old_space_size=16384 export PLAYWRIGHT_BROWSERS_PATH="$(PLAYWRIGHT_BROWSERS_PATH)" diff --git a/packages/cellix/vitest-config/src/configs/storybook.config.ts b/packages/cellix/vitest-config/src/configs/storybook.config.ts index fab9d6b93..aad3cc33c 100644 --- a/packages/cellix/vitest-config/src/configs/storybook.config.ts +++ b/packages/cellix/vitest-config/src/configs/storybook.config.ts @@ -34,6 +34,7 @@ export function createStorybookVitestConfig( '@sthrift/domain', '@cellix/ui-core', '@cellix/messaging-service', + '@sthrift/ui-sharethrift', ]; for (const pkgName of workspacePackagesToAlias) { try { diff --git a/packages/sthrift/ui-components/vitest.config.ts b/packages/sthrift/ui-components/vitest.config.ts index 3e58f4023..224a3e429 100644 --- a/packages/sthrift/ui-components/vitest.config.ts +++ b/packages/sthrift/ui-components/vitest.config.ts @@ -1,34 +1,19 @@ import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { createStorybookVitestConfig } from '@cellix/vitest-config'; -import { defineConfig, mergeConfig } from 'vitest/config'; +import { defineConfig } from 'vitest/config'; const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url)); -const base = createStorybookVitestConfig(dirname, { - additionalCoverageExclude: [ - '**/index.ts', - 'src/components/molecules/index.tsx', - 'src/components/organisms/index.tsx', - ], -}); - -// Ensure tests resolve the package name to local source during testing so Vite -// doesn't follow the package "exports" to built `dist/` files. -// This prevents Vite from opening/transpiling dist/src/index.js which causes -// many open files (EMFILE) in CI coverage runs. export default defineConfig( - mergeConfig(base, { - resolve: { - alias: [ - { - find: '@sthrift/ui-components', - replacement: path.join(dirname, 'src'), - }, - ], - }, + createStorybookVitestConfig(dirname, { + additionalCoverageExclude: [ + '**/index.ts', + 'src/components/molecules/index.tsx', + 'src/components/organisms/index.tsx', + ], }), ); From fe4cb832256a7811d6dd050f1cc7cfe4eb2cd5f2 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Mon, 15 Dec 2025 14:15:55 -0500 Subject: [PATCH 29/74] fix: upgrade Vitest configuration to use UserConfig type and enhance alias handling with regex patterns --- .../src/configs/storybook.config.ts | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/packages/cellix/vitest-config/src/configs/storybook.config.ts b/packages/cellix/vitest-config/src/configs/storybook.config.ts index aad3cc33c..bec57a571 100644 --- a/packages/cellix/vitest-config/src/configs/storybook.config.ts +++ b/packages/cellix/vitest-config/src/configs/storybook.config.ts @@ -1,7 +1,8 @@ import path from 'node:path'; import { createRequire } from 'module'; import { storybookTest } from '@storybook/addon-vitest/vitest-plugin'; -import { defineConfig, mergeConfig, type ViteUserConfig } from 'vitest/config'; +import { defineConfig, mergeConfig } from 'vitest/config'; +import type { Alias, UserConfig } from 'vite'; import { baseConfig } from './base.config.ts'; import { playwright } from '@vitest/browser-playwright'; @@ -15,7 +16,7 @@ export type StorybookVitestConfigOptions = { export function createStorybookVitestConfig( pkgDirname: string, opts: StorybookVitestConfigOptions = {}, -): ViteUserConfig { +): UserConfig { const STORYBOOK_DIR = opts.storybookDirRelativeToPackage ?? '.storybook'; const setupFiles = opts.setupFiles ?? ['.storybook/vitest.setup.ts']; const instances = opts.browsers ?? [{ browser: 'chromium' }]; @@ -26,7 +27,8 @@ export function createStorybookVitestConfig( // Build a single alias list for workspace packages that should resolve to // their source (`src/`) during tests. This prevents Vite from following // package exports into `dist/` and opening built files during coverage runs. - const aliases: { find: string | RegExp; replacement: string }[] = []; + // Use regex patterns to match both exact package names and subpath imports. + const aliases: Alias[] = []; const workspacePackagesToAlias = [ '@sthrift/ui-components', '@sthrift/service-mongoose', @@ -43,7 +45,21 @@ export function createStorybookVitestConfig( paths: [pkgDirname], }); const pkgDir = path.dirname(pkgJsonPath); - aliases.push({ find: pkgName, replacement: path.join(pkgDir, 'src') }); + const pkgSrcDir = path.join(pkgDir, 'src'); + // Create a regex pattern that matches the package name with optional subpaths + const escapedPkgName = pkgName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + const pattern = new RegExp(`^${escapedPkgName}(\\/.*)?$`); + const alias: Alias = { + find: pattern, + replacement: pkgSrcDir, + customResolver: { + resolveId(id) { + const subpath = id.substring(pkgName.length); + return path.join(pkgSrcDir, subpath); + }, + }, + }; + aliases.push(alias); } catch (e) { // ignore missing packages } From f81f27f0c6e22ac324937980adffd6d615aab3cd Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Mon, 15 Dec 2025 14:46:36 -0500 Subject: [PATCH 30/74] fix EMFILE error: update Storybook Vitest configuration to use a custom plugin for workspace package imports and enhance alias handling --- .../src/configs/storybook.config.ts | 59 +++++++++++-------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/packages/cellix/vitest-config/src/configs/storybook.config.ts b/packages/cellix/vitest-config/src/configs/storybook.config.ts index bec57a571..ba8a1b351 100644 --- a/packages/cellix/vitest-config/src/configs/storybook.config.ts +++ b/packages/cellix/vitest-config/src/configs/storybook.config.ts @@ -2,7 +2,7 @@ import path from 'node:path'; import { createRequire } from 'module'; import { storybookTest } from '@storybook/addon-vitest/vitest-plugin'; import { defineConfig, mergeConfig } from 'vitest/config'; -import type { Alias, UserConfig } from 'vite'; +import type { Plugin, UserConfig } from 'vite'; import { baseConfig } from './base.config.ts'; import { playwright } from '@vitest/browser-playwright'; @@ -24,11 +24,8 @@ export function createStorybookVitestConfig( const isCI = process.env['CI'] === 'true' || process.env['TF_BUILD'] === 'True'; - // Build a single alias list for workspace packages that should resolve to - // their source (`src/`) during tests. This prevents Vite from following - // package exports into `dist/` and opening built files during coverage runs. - // Use regex patterns to match both exact package names and subpath imports. - const aliases: Alias[] = []; + // Build a map of workspace packages to their src directories + // This prevents Vite from following package exports into `dist/` during tests const workspacePackagesToAlias = [ '@sthrift/ui-components', '@sthrift/service-mongoose', @@ -38,6 +35,7 @@ export function createStorybookVitestConfig( '@cellix/messaging-service', '@sthrift/ui-sharethrift', ]; + const packageSrcMap = new Map(); for (const pkgName of workspacePackagesToAlias) { try { const require = createRequire(import.meta.url); @@ -46,26 +44,43 @@ export function createStorybookVitestConfig( }); const pkgDir = path.dirname(pkgJsonPath); const pkgSrcDir = path.join(pkgDir, 'src'); - // Create a regex pattern that matches the package name with optional subpaths - const escapedPkgName = pkgName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - const pattern = new RegExp(`^${escapedPkgName}(\\/.*)?$`); - const alias: Alias = { - find: pattern, - replacement: pkgSrcDir, - customResolver: { - resolveId(id) { - const subpath = id.substring(pkgName.length); - return path.join(pkgSrcDir, subpath); - }, - }, - }; - aliases.push(alias); + packageSrcMap.set(pkgName, pkgSrcDir); } catch (e) { // ignore missing packages } } + // Create a custom plugin to intercept and redirect workspace package imports + // This runs before Vite's alias resolution and prevents opening dist/ files + const workspaceRedirectPlugin: Plugin = { + name: 'workspace-redirect-to-src', + enforce: 'pre', // Run before other plugins + resolveId(id) { + // Check if this is a workspace package import + for (const [pkgName, srcDir] of packageSrcMap.entries()) { + if (id === pkgName) { + // Exact package import: @sthrift/ui-components + return path.join(srcDir, 'index.ts'); + } + if (id.startsWith(`${pkgName}/`)) { + // Subpath import: @sthrift/ui-components/src/styles/theme.css + const subpath = id.substring(pkgName.length + 1); + return path.join(srcDir, subpath); + } + } + return null; // Let Vite handle other imports + }, + }; + const storybookConfig = defineConfig({ + plugins: [workspaceRedirectPlugin], + // Explicitly tell Vite's file watcher to ignore dist and coverage directories + // This prevents Vite from opening files in these directories during scan/watch + server: { + watch: { + ignored: ['**/dist/**', '**/coverage/**', '**/node_modules/**'], + }, + }, test: { // Prevent Vite/Vitest from scanning/transpiling build artifacts and coverage temp files. // This greatly reduces the number of open files during coverage runs in CI. @@ -83,6 +98,7 @@ export function createStorybookVitestConfig( { extends: true, plugins: [ + workspaceRedirectPlugin, storybookTest({ configDir: path.join(pkgDirname, STORYBOOK_DIR), }), @@ -120,9 +136,6 @@ export function createStorybookVitestConfig( watch: false, isolate: true, }, - resolve: { - alias: aliases, - }, }); return mergeConfig(baseConfig, storybookConfig); From 3042bb697545bfe7fce3e12df698cec0c093fbf2 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Mon, 15 Dec 2025 15:02:10 -0500 Subject: [PATCH 31/74] refactor: remove unused workspace package aliasing logic from Storybook Vitest config --- .../src/configs/storybook.config.ts | 53 +------------------ 1 file changed, 1 insertion(+), 52 deletions(-) diff --git a/packages/cellix/vitest-config/src/configs/storybook.config.ts b/packages/cellix/vitest-config/src/configs/storybook.config.ts index ba8a1b351..119fd050a 100644 --- a/packages/cellix/vitest-config/src/configs/storybook.config.ts +++ b/packages/cellix/vitest-config/src/configs/storybook.config.ts @@ -1,8 +1,7 @@ import path from 'node:path'; -import { createRequire } from 'module'; import { storybookTest } from '@storybook/addon-vitest/vitest-plugin'; import { defineConfig, mergeConfig } from 'vitest/config'; -import type { Plugin, UserConfig } from 'vite'; +import type { UserConfig } from 'vite'; import { baseConfig } from './base.config.ts'; import { playwright } from '@vitest/browser-playwright'; @@ -24,56 +23,7 @@ export function createStorybookVitestConfig( const isCI = process.env['CI'] === 'true' || process.env['TF_BUILD'] === 'True'; - // Build a map of workspace packages to their src directories - // This prevents Vite from following package exports into `dist/` during tests - const workspacePackagesToAlias = [ - '@sthrift/ui-components', - '@sthrift/service-mongoose', - '@sthrift/graphql', - '@sthrift/domain', - '@cellix/ui-core', - '@cellix/messaging-service', - '@sthrift/ui-sharethrift', - ]; - const packageSrcMap = new Map(); - for (const pkgName of workspacePackagesToAlias) { - try { - const require = createRequire(import.meta.url); - const pkgJsonPath = require.resolve(`${pkgName}/package.json`, { - paths: [pkgDirname], - }); - const pkgDir = path.dirname(pkgJsonPath); - const pkgSrcDir = path.join(pkgDir, 'src'); - packageSrcMap.set(pkgName, pkgSrcDir); - } catch (e) { - // ignore missing packages - } - } - - // Create a custom plugin to intercept and redirect workspace package imports - // This runs before Vite's alias resolution and prevents opening dist/ files - const workspaceRedirectPlugin: Plugin = { - name: 'workspace-redirect-to-src', - enforce: 'pre', // Run before other plugins - resolveId(id) { - // Check if this is a workspace package import - for (const [pkgName, srcDir] of packageSrcMap.entries()) { - if (id === pkgName) { - // Exact package import: @sthrift/ui-components - return path.join(srcDir, 'index.ts'); - } - if (id.startsWith(`${pkgName}/`)) { - // Subpath import: @sthrift/ui-components/src/styles/theme.css - const subpath = id.substring(pkgName.length + 1); - return path.join(srcDir, subpath); - } - } - return null; // Let Vite handle other imports - }, - }; - const storybookConfig = defineConfig({ - plugins: [workspaceRedirectPlugin], // Explicitly tell Vite's file watcher to ignore dist and coverage directories // This prevents Vite from opening files in these directories during scan/watch server: { @@ -98,7 +48,6 @@ export function createStorybookVitestConfig( { extends: true, plugins: [ - workspaceRedirectPlugin, storybookTest({ configDir: path.join(pkgDirname, STORYBOOK_DIR), }), From 774f3f8ed6a6522a03fb6fe370e022992ebbfa8f Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Mon, 15 Dec 2025 15:31:16 -0500 Subject: [PATCH 32/74] fix EMFILE error: increase soft limit for open file descriptors in build pipeline to 80000 --- build-pipeline/core/monorepo-build-stage.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/build-pipeline/core/monorepo-build-stage.yml b/build-pipeline/core/monorepo-build-stage.yml index f44a602ff..26a38cbab 100644 --- a/build-pipeline/core/monorepo-build-stage.yml +++ b/build-pipeline/core/monorepo-build-stage.yml @@ -224,8 +224,11 @@ stages: targetType: 'inline' script: | set -euo pipefail - ulimit -n 60000 - echo "Open file limit (ulimit -n): $(ulimit -n)" + # Set soft limit for open files (file descriptors) + # -S = soft limit (the actual limit used by processes) + # -n = number of open file descriptors + ulimit -Sn 80000 + echo "Open file limits - Soft: $(ulimit -Sn), Hard: $(ulimit -Hn)" export NODE_OPTIONS=--max_old_space_size=16384 export PLAYWRIGHT_BROWSERS_PATH="$(PLAYWRIGHT_BROWSERS_PATH)" From 42b58747c7327536d2b871fed045e5339abff30c Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Mon, 15 Dec 2025 15:44:23 -0500 Subject: [PATCH 33/74] fix: update open file limit setting --- build-pipeline/core/monorepo-build-stage.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/build-pipeline/core/monorepo-build-stage.yml b/build-pipeline/core/monorepo-build-stage.yml index 26a38cbab..39e59649e 100644 --- a/build-pipeline/core/monorepo-build-stage.yml +++ b/build-pipeline/core/monorepo-build-stage.yml @@ -224,11 +224,8 @@ stages: targetType: 'inline' script: | set -euo pipefail - # Set soft limit for open files (file descriptors) - # -S = soft limit (the actual limit used by processes) - # -n = number of open file descriptors - ulimit -Sn 80000 - echo "Open file limits - Soft: $(ulimit -Sn), Hard: $(ulimit -Hn)" + ulimit -n 80000 + echo "Open file limit (ulimit -n): $(ulimit -n)" export NODE_OPTIONS=--max_old_space_size=16384 export PLAYWRIGHT_BROWSERS_PATH="$(PLAYWRIGHT_BROWSERS_PATH)" From 21f5dcdd6bc849c12385a9f90d920d4462d3d8fd Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Mon, 15 Dec 2025 15:52:19 -0500 Subject: [PATCH 34/74] fix: lower open file limit to 70000 in build pipeline script --- build-pipeline/core/monorepo-build-stage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-pipeline/core/monorepo-build-stage.yml b/build-pipeline/core/monorepo-build-stage.yml index 39e59649e..74aebf3d8 100644 --- a/build-pipeline/core/monorepo-build-stage.yml +++ b/build-pipeline/core/monorepo-build-stage.yml @@ -224,7 +224,7 @@ stages: targetType: 'inline' script: | set -euo pipefail - ulimit -n 80000 + ulimit -n 70000 echo "Open file limit (ulimit -n): $(ulimit -n)" export NODE_OPTIONS=--max_old_space_size=16384 export PLAYWRIGHT_BROWSERS_PATH="$(PLAYWRIGHT_BROWSERS_PATH)" From 2ec41b5fc0e2539c1cd1dd105e04605686cd6c92 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Mon, 15 Dec 2025 15:58:48 -0500 Subject: [PATCH 35/74] fix: lower open file limit from 70000 to 65000 in build pipeline script --- build-pipeline/core/monorepo-build-stage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-pipeline/core/monorepo-build-stage.yml b/build-pipeline/core/monorepo-build-stage.yml index 74aebf3d8..c6dcf0262 100644 --- a/build-pipeline/core/monorepo-build-stage.yml +++ b/build-pipeline/core/monorepo-build-stage.yml @@ -224,7 +224,7 @@ stages: targetType: 'inline' script: | set -euo pipefail - ulimit -n 70000 + ulimit -n 65000 echo "Open file limit (ulimit -n): $(ulimit -n)" export NODE_OPTIONS=--max_old_space_size=16384 export PLAYWRIGHT_BROWSERS_PATH="$(PLAYWRIGHT_BROWSERS_PATH)" From fc0b3a312a6d59479b5da231bd94477218b439ec Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Mon, 15 Dec 2025 17:10:31 -0500 Subject: [PATCH 36/74] fix: update Storybook Vitest config to resolve workspace packages during testing --- packages/cellix/vitest-config/src/configs/storybook.config.ts | 4 ++++ packages/sthrift/ui-components/package.json | 1 + 2 files changed, 5 insertions(+) diff --git a/packages/cellix/vitest-config/src/configs/storybook.config.ts b/packages/cellix/vitest-config/src/configs/storybook.config.ts index 119fd050a..dcc415356 100644 --- a/packages/cellix/vitest-config/src/configs/storybook.config.ts +++ b/packages/cellix/vitest-config/src/configs/storybook.config.ts @@ -24,6 +24,10 @@ export function createStorybookVitestConfig( process.env['CI'] === 'true' || process.env['TF_BUILD'] === 'True'; const storybookConfig = defineConfig({ + // Use export conditions to resolve workspace packages to src/ during testing + resolve: { + conditions: ['vitest', 'development', 'import', 'default'], + }, // Explicitly tell Vite's file watcher to ignore dist and coverage directories // This prevents Vite from opening files in these directories during scan/watch server: { diff --git a/packages/sthrift/ui-components/package.json b/packages/sthrift/ui-components/package.json index efd0f15f1..34c1ab11d 100644 --- a/packages/sthrift/ui-components/package.json +++ b/packages/sthrift/ui-components/package.json @@ -8,6 +8,7 @@ ], "exports": { ".": { + "vitest": "./src/index.ts", "types": "./dist/src/index.d.ts", "default": "./dist/src/index.js" }, From 20b6b22c482c8a56e04a2c3ca4a57e2dddb3bf12 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Tue, 16 Dec 2025 09:24:57 -0500 Subject: [PATCH 37/74] fix: ensure workspace packages do not override a single shared Vitest version (pnpm catalog usage) --- apps/docs/package.json | 4 +- apps/ui-sharethrift/package.json | 4 +- package.json | 6 +-- packages/cellix/ui-core/package.json | 6 +-- packages/cellix/vitest-config/package.json | 6 +-- .../messaging-service-twilio/package.json | 2 +- .../mock-messaging-server/package.json | 2 +- packages/sthrift/ui-components/package.json | 6 +-- pnpm-lock.yaml | 48 ++++++++++++------- pnpm-workspace.yaml | 6 +++ 10 files changed, 54 insertions(+), 36 deletions(-) diff --git a/apps/docs/package.json b/apps/docs/package.json index e58c1ecf9..05ae171e7 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -36,10 +36,10 @@ "@testing-library/react": "^16.1.0", "@types/react": "^19.1.11", "@types/react-dom": "^19.1.6", - "@vitest/coverage-v8": "^4.0.15", + "@vitest/coverage-v8": "catalog:", "jsdom": "^26.1.0", "typescript": "^5.8.3", - "vitest": "^4.0.15" + "vitest": "catalog:" }, "browserslist": { "production": [ diff --git a/apps/ui-sharethrift/package.json b/apps/ui-sharethrift/package.json index 6f543801a..c594feffe 100644 --- a/apps/ui-sharethrift/package.json +++ b/apps/ui-sharethrift/package.json @@ -48,7 +48,7 @@ "@types/react-dom": "^19.1.7", "@vitejs/plugin-react": "^4.7.0", "@vitest/browser": "4.0.15", - "@vitest/coverage-v8": "^4.0.15", + "@vitest/coverage-v8": "catalog:", "eslint": "^9.30.1", "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.20", @@ -57,7 +57,7 @@ "typescript": "~5.8.3", "typescript-eslint": "^8.35.1", "vite": "^7.1.2", - "vitest": "^4.0.15" + "vitest": "catalog:" }, "license": "MIT" } diff --git a/package.json b/package.json index aefcf12a8..e28543395 100644 --- a/package.json +++ b/package.json @@ -61,8 +61,8 @@ "@playwright/test": "^1.55.1", "@sonar/scan": "^4.3.0", "@types/node": "^24.7.2", - "@vitest/browser-playwright": "^4.0.15", - "@vitest/coverage-v8": "^4.0.15", + "@vitest/browser-playwright": "catalog:", + "@vitest/coverage-v8": "catalog:", "azurite": "^3.35.0", "concurrently": "^9.1.2", "cpx2": "^3.0.2", @@ -74,6 +74,6 @@ "turbo": "^2.5.8", "typescript": "^5.8.3", "vite": "^7.0.4", - "vitest": "^4.0.15" + "vitest": "catalog:" } } \ No newline at end of file diff --git a/packages/cellix/ui-core/package.json b/packages/cellix/ui-core/package.json index 1468f28ab..b917b051b 100644 --- a/packages/cellix/ui-core/package.json +++ b/packages/cellix/ui-core/package.json @@ -46,15 +46,15 @@ "@storybook/react": "^9.1.9", "@storybook/react-vite": "^9.1.3", "@types/react": "^19.1.16", - "@vitest/browser": "^4.0.15", - "@vitest/coverage-v8": "^4.0.15", + "@vitest/browser": "catalog:", + "@vitest/coverage-v8": "catalog:", "jsdom": "^26.1.0", "react-oidc-context": "^3.3.0", "react-router-dom": "^7.9.3", "rimraf": "^6.0.1", "storybook": "^9.1.3", "typescript": "^5.7.2", - "vitest": "^4.0.15" + "vitest": "catalog:" }, "license": "MIT" } diff --git a/packages/cellix/vitest-config/package.json b/packages/cellix/vitest-config/package.json index 322bb34e8..7c811cc1c 100644 --- a/packages/cellix/vitest-config/package.json +++ b/packages/cellix/vitest-config/package.json @@ -12,9 +12,9 @@ }, "dependencies": { "@storybook/addon-vitest": "^9.1.10", - "@vitest/browser": "^4.0.15", - "@vitest/browser-playwright": "^4.0.15", - "vitest": "^4.0.15" + "@vitest/browser": "catalog:", + "@vitest/browser-playwright": "catalog:", + "vitest": "catalog:" }, "devDependencies": { "@cellix/typescript-config": "workspace:*", diff --git a/packages/sthrift/messaging-service-twilio/package.json b/packages/sthrift/messaging-service-twilio/package.json index 3eee22ceb..0aa1accd3 100644 --- a/packages/sthrift/messaging-service-twilio/package.json +++ b/packages/sthrift/messaging-service-twilio/package.json @@ -26,7 +26,7 @@ "@cellix/typescript-config": "workspace:*", "@cellix/vitest-config": "workspace:*", "@types/node": "^22.0.0", - "vitest": "^4.0.15" + "vitest": "catalog:" }, "license": "MIT" } \ No newline at end of file diff --git a/packages/sthrift/mock-messaging-server/package.json b/packages/sthrift/mock-messaging-server/package.json index 4c641c092..17671ed50 100644 --- a/packages/sthrift/mock-messaging-server/package.json +++ b/packages/sthrift/mock-messaging-server/package.json @@ -31,6 +31,6 @@ "supertest": "^7.0.0", "tsc-watch": "^7.1.1", "typescript": "^5.8.3", - "vitest": "^4.0.15" + "vitest": "catalog:" } } diff --git a/packages/sthrift/ui-components/package.json b/packages/sthrift/ui-components/package.json index 34c1ab11d..e0ec953e3 100644 --- a/packages/sthrift/ui-components/package.json +++ b/packages/sthrift/ui-components/package.json @@ -68,14 +68,14 @@ "@storybook/react-vite": "^9.1.3", "@types/react": "^19.1.11", "@types/react-dom": "^19.1.6", - "@vitest/browser": "^4.0.15", - "@vitest/coverage-v8": "^4.0.15", + "@vitest/browser": "catalog:", + "@vitest/coverage-v8": "catalog:", "jsdom": "^26.1.0", "rimraf": "^6.0.1", "storybook": "^9.1.3", "typescript": "^5.8.3", "vite": "^7.0.4", - "vitest": "^4.0.15" + "vitest": "catalog:" }, "license": "MIT" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4c2242c41..d0a8e49d4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,12 +6,24 @@ settings: catalogs: default: + '@vitest/browser': + specifier: ^4.0.15 + version: 4.0.15 + '@vitest/browser-playwright': + specifier: ^4.0.15 + version: 4.0.15 + '@vitest/coverage-v8': + specifier: ^4.0.15 + version: 4.0.15 mongodb: specifier: 6.18.0 version: 6.18.0 mongoose: specifier: 8.17.0 version: 8.17.0 + vitest: + specifier: ^4.0.15 + version: 4.0.15 overrides: node-forge@<1.3.2: '>=1.3.2' @@ -57,10 +69,10 @@ importers: specifier: ^24.7.2 version: 24.9.2 '@vitest/browser-playwright': - specifier: ^4.0.15 + specifier: 'catalog:' version: 4.0.15(playwright@1.56.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) '@vitest/coverage-v8': - specifier: ^4.0.15 + specifier: 'catalog:' version: 4.0.15(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15) azurite: specifier: ^3.35.0 @@ -96,7 +108,7 @@ importers: specifier: ^7.0.4 version: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) vitest: - specifier: ^4.0.15 + specifier: 'catalog:' version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) apps/api: @@ -227,7 +239,7 @@ importers: specifier: ^19.1.6 version: 19.2.2(@types/react@19.2.2) '@vitest/coverage-v8': - specifier: ^4.0.15 + specifier: 'catalog:' version: 4.0.15(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15) jsdom: specifier: ^26.1.0 @@ -236,7 +248,7 @@ importers: specifier: ^5.8.3 version: 5.8.3 vitest: - specifier: ^4.0.15 + specifier: 'catalog:' version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) apps/ui-sharethrift: @@ -333,7 +345,7 @@ importers: specifier: 4.0.15 version: 4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) '@vitest/coverage-v8': - specifier: ^4.0.15 + specifier: 'catalog:' version: 4.0.15(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15) eslint: specifier: ^9.30.1 @@ -360,7 +372,7 @@ importers: specifier: ^7.1.2 version: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) vitest: - specifier: ^4.0.15 + specifier: 'catalog:' version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) packages/cellix/api-services-spec: @@ -609,10 +621,10 @@ importers: specifier: ^19.1.16 version: 19.2.2 '@vitest/browser': - specifier: ^4.0.15 + specifier: 'catalog:' version: 4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) '@vitest/coverage-v8': - specifier: ^4.0.15 + specifier: 'catalog:' version: 4.0.15(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15) jsdom: specifier: ^26.1.0 @@ -633,7 +645,7 @@ importers: specifier: ^5.7.2 version: 5.8.3 vitest: - specifier: ^4.0.15 + specifier: 'catalog:' version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) packages/cellix/vitest-config: @@ -642,13 +654,13 @@ importers: specifier: ^9.1.10 version: 9.1.16(@vitest/browser-playwright@4.0.15)(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(@vitest/runner@4.0.15)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@4.0.15) '@vitest/browser': - specifier: ^4.0.15 + specifier: 'catalog:' version: 4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) '@vitest/browser-playwright': - specifier: ^4.0.15 + specifier: 'catalog:' version: 4.0.15(playwright@1.56.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) vitest: - specifier: ^4.0.15 + specifier: 'catalog:' version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) devDependencies: '@cellix/typescript-config': @@ -918,7 +930,7 @@ importers: specifier: ^5.8.3 version: 5.8.3 vitest: - specifier: ^4.0.15 + specifier: 'catalog:' version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.19.0)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) packages/sthrift/mock-messaging-server: @@ -961,7 +973,7 @@ importers: specifier: ^5.8.3 version: 5.8.3 vitest: - specifier: ^4.0.15 + specifier: 'catalog:' version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.19.0)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) packages/sthrift/mock-mongodb-memory-server: @@ -1320,10 +1332,10 @@ importers: specifier: ^19.1.6 version: 19.2.2(@types/react@19.2.2) '@vitest/browser': - specifier: ^4.0.15 + specifier: 'catalog:' version: 4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) '@vitest/coverage-v8': - specifier: ^4.0.15 + specifier: 'catalog:' version: 4.0.15(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15) jsdom: specifier: ^26.1.0 @@ -1341,7 +1353,7 @@ importers: specifier: ^7.0.4 version: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) vitest: - specifier: ^4.0.15 + specifier: 'catalog:' version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) packages: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 937fe31e0..21c7ecea5 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -6,6 +6,12 @@ packages: catalog: mongoose: 8.17.0 mongodb: 6.18.0 + # Vitest 4.x and related testing dependencies + vitest: ^4.0.15 + '@vitest/browser': ^4.0.15 + '@vitest/coverage-v8': ^4.0.15 + '@vitest/browser-playwright': ^4.0.15 + '@vitest/ui': ^4.0.15 overrides: node-forge@<1.3.2: '>=1.3.2' \ No newline at end of file From e06ccd2e0c5609b8b45d7367b3a26cce1f41a540 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Tue, 16 Dec 2025 09:44:37 -0500 Subject: [PATCH 38/74] fix: remove '@vitest/ui' from catalog to streamline Vitest dependencies --- pnpm-workspace.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 21c7ecea5..8c0d6f7ff 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -11,7 +11,6 @@ catalog: '@vitest/browser': ^4.0.15 '@vitest/coverage-v8': ^4.0.15 '@vitest/browser-playwright': ^4.0.15 - '@vitest/ui': ^4.0.15 overrides: node-forge@<1.3.2: '>=1.3.2' \ No newline at end of file From 438ef5815692d62fd2263ec331e2e706d68d30dc Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Tue, 16 Dec 2025 10:40:10 -0500 Subject: [PATCH 39/74] remove ulimit setting for open file limit in build pipeline script --- build-pipeline/core/monorepo-build-stage.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/build-pipeline/core/monorepo-build-stage.yml b/build-pipeline/core/monorepo-build-stage.yml index c6dcf0262..7b0c3c687 100644 --- a/build-pipeline/core/monorepo-build-stage.yml +++ b/build-pipeline/core/monorepo-build-stage.yml @@ -224,7 +224,6 @@ stages: targetType: 'inline' script: | set -euo pipefail - ulimit -n 65000 echo "Open file limit (ulimit -n): $(ulimit -n)" export NODE_OPTIONS=--max_old_space_size=16384 export PLAYWRIGHT_BROWSERS_PATH="$(PLAYWRIGHT_BROWSERS_PATH)" From 50dbea86b13f1c90733a5b1f7640e8347c85ff13 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Tue, 16 Dec 2025 11:12:11 -0500 Subject: [PATCH 40/74] fix: streamline mock implementations in tests for better clarity and performance --- .../mongo-unit-of-work.test.ts | 8 +--- .../account-plan.read-repository.test.ts | 45 +++++++------------ .../account-plan.read-repository.ts | 6 +-- .../service-otel/src/otel-builder.test.ts | 22 ++++----- 4 files changed, 29 insertions(+), 52 deletions(-) diff --git a/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts b/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts index d600d2107..58f5d50b9 100644 --- a/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts +++ b/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts @@ -193,13 +193,7 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { await unitOfWork.withTransaction(Passport, domainOperation); }); Then('the transaction is committed and no events are dispatched', () => { - expect(domainOperation).toHaveBeenCalled(); - const callArg = domainOperation.mock.calls[0]?.[0]; - expect(callArg).toBeInstanceOf(TestRepoClass); - expect(callArg.model).toBe(mockModel); - expect(callArg.typeConverter).toBe(typeConverter); - expect(callArg.bus).toBe(eventBus); - expect(callArg.session).toStrictEqual(session); + expect(domainOperation).toHaveBeenCalledWith(expect.any(TestRepoClass)); expect(dispatchMock).not.toHaveBeenCalled(); }); }); diff --git a/packages/sthrift/persistence/src/datasources/readonly/account-plan/account-plan/account-plan.read-repository.test.ts b/packages/sthrift/persistence/src/datasources/readonly/account-plan/account-plan/account-plan.read-repository.test.ts index 8ec9a5b8b..8e4b7596c 100644 --- a/packages/sthrift/persistence/src/datasources/readonly/account-plan/account-plan/account-plan.read-repository.test.ts +++ b/packages/sthrift/persistence/src/datasources/readonly/account-plan/account-plan/account-plan.read-repository.test.ts @@ -6,52 +6,39 @@ import { AccountPlanReadRepositoryImpl, getAccountPlanReadRepository } from './a // Mock the converter vi.mock('../../../domain/account-plan/account-plan/account-plan.domain-adapter.ts', () => { - const MockAccountPlanConverter = vi.fn(); - // biome-ignore lint/complexity/useArrowFunction: Must be function for constructor compatibility - MockAccountPlanConverter.mockImplementation(function() { + // biome-ignore lint/complexity/useArrowFunction: constructor must use function syntax for 'new' compatibility + const AccountPlanConverter = vi.fn(function () { return { toDomain: vi.fn((doc) => ({ id: doc._id, name: doc.name })), }; }); - - return { - AccountPlanConverter: MockAccountPlanConverter, - }; + + return { AccountPlanConverter }; }); vi.mock('../account-plan/account-plan.data.ts', () => { - const MockAccountPlanDataSourceImpl = vi.fn(); - // biome-ignore lint/complexity/useArrowFunction: Must be function for constructor compatibility - MockAccountPlanDataSourceImpl.mockImplementation(function() { + // biome-ignore lint/complexity/useArrowFunction: constructor must use function syntax for 'new' compatibility + const AccountPlanDataSourceImpl = vi.fn(function () { return { find: vi.fn(), findById: vi.fn(), findOne: vi.fn(), }; }); - - return { - AccountPlanDataSourceImpl: MockAccountPlanDataSourceImpl, - }; + + return { AccountPlanDataSourceImpl }; }); function makeModelsContext(): ModelsContext { - return { - // biome-ignore lint/suspicious/noExplicitAny: Unused models stubbed for interface compliance - User: {} as any, - // biome-ignore lint/suspicious/noExplicitAny: Unused models stubbed for interface compliance - Listing: {} as any, - // biome-ignore lint/suspicious/noExplicitAny: Unused models stubbed for interface compliance - Conversation: {} as any, - // biome-ignore lint/suspicious/noExplicitAny: Unused models stubbed for interface compliance - ReservationRequest: {} as any, - // biome-ignore lint/suspicious/noExplicitAny: Unused models stubbed for interface compliance - Role: {} as any, - // biome-ignore lint/suspicious/noExplicitAny: Unused models stubbed for interface compliance - AccountPlan: {} as any, - // biome-ignore lint/suspicious/noExplicitAny: Unused models stubbed for interface compliance - AppealRequest: {} as any, + // Only AccountPlan.AccountPlanModel is used by AccountPlanReadRepositoryImpl + const partialContext = { + AccountPlan: { + AccountPlanModel: {}, + }, }; + + // Other members are irrelevant for these tests and safely stubbed via cast + return partialContext as unknown as ModelsContext; } function makePassport(): Domain.Passport { diff --git a/packages/sthrift/persistence/src/datasources/readonly/account-plan/account-plan/account-plan.read-repository.ts b/packages/sthrift/persistence/src/datasources/readonly/account-plan/account-plan/account-plan.read-repository.ts index 9adfc1005..d324d6b19 100644 --- a/packages/sthrift/persistence/src/datasources/readonly/account-plan/account-plan/account-plan.read-repository.ts +++ b/packages/sthrift/persistence/src/datasources/readonly/account-plan/account-plan/account-plan.read-repository.ts @@ -67,9 +67,9 @@ export class AccountPlanReadRepositoryImpl } } -export const getAccountPlanReadRepository = ( +export function getAccountPlanReadRepository( models: ModelsContext, passport: Domain.Passport, -) => { +): AccountPlanReadRepository { return new AccountPlanReadRepositoryImpl(models, passport); -}; +} diff --git a/packages/sthrift/service-otel/src/otel-builder.test.ts b/packages/sthrift/service-otel/src/otel-builder.test.ts index 753f16243..36beb6bcb 100644 --- a/packages/sthrift/service-otel/src/otel-builder.test.ts +++ b/packages/sthrift/service-otel/src/otel-builder.test.ts @@ -37,30 +37,26 @@ vi.mock('@azure/monitor-opentelemetry-exporter', () => { } } - // Create mockable constructor functions - const AzureMonitorTraceExporterImpl = vi.fn(); - AzureMonitorTraceExporterImpl.mockImplementation(function(this: InstanceType, args: Record) { + const AzureMonitorTraceExporter = vi.fn(function (this: TraceExporter, args: Record) { return new TraceExporter(args); }); - const AzureMonitorMetricExporterImpl = vi.fn(); - AzureMonitorMetricExporterImpl.mockImplementation(function(this: InstanceType, args: Record) { + const AzureMonitorMetricExporter = vi.fn(function (this: MetricExporter, args: Record) { return new MetricExporter(args); }); - const AzureMonitorLogExporterImpl = vi.fn(); - AzureMonitorLogExporterImpl.mockImplementation(function(this: InstanceType, args: Record) { + const AzureMonitorLogExporter = vi.fn(function (this: LogExporter, args: Record) { return new LogExporter(args); }); return { - AzureMonitorTraceExporter: AzureMonitorTraceExporterImpl, - AzureMonitorMetricExporter: AzureMonitorMetricExporterImpl, - AzureMonitorLogExporter: AzureMonitorLogExporterImpl, + AzureMonitorTraceExporter, + AzureMonitorMetricExporter, + AzureMonitorLogExporter, __test: { - traceExporterMock: AzureMonitorTraceExporterImpl, - metricExporterMock: AzureMonitorMetricExporterImpl, - logExporterMock: AzureMonitorLogExporterImpl, + traceExporterMock: AzureMonitorTraceExporter, + metricExporterMock: AzureMonitorMetricExporter, + logExporterMock: AzureMonitorLogExporter, TraceExporter, MetricExporter, LogExporter, From 0bdf156d4c78f426aa0457ba21737deeaac6a35f Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Tue, 16 Dec 2025 11:42:01 -0500 Subject: [PATCH 41/74] fix: update test exclusion patterns for improved file handling during CI coverage runs --- packages/cellix/vitest-config/src/configs/storybook.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cellix/vitest-config/src/configs/storybook.config.ts b/packages/cellix/vitest-config/src/configs/storybook.config.ts index dcc415356..f0730db0d 100644 --- a/packages/cellix/vitest-config/src/configs/storybook.config.ts +++ b/packages/cellix/vitest-config/src/configs/storybook.config.ts @@ -38,7 +38,7 @@ export function createStorybookVitestConfig( test: { // Prevent Vite/Vitest from scanning/transpiling build artifacts and coverage temp files. // This greatly reduces the number of open files during coverage runs in CI. - exclude: ['dist/**', 'coverage/**', 'coverage/.tmp/**'], + exclude: ['**/dist/**', '**/coverage/**', '**/coverage/.tmp/**'], globals: true, // Retry tests on failure to handle flaky browser tests due to race conditions // in @storybook/addon-vitest + Playwright browser provider From a542669cdf4c79761b373fff968ae308954b5e3e Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Tue, 16 Dec 2025 12:02:31 -0500 Subject: [PATCH 42/74] fix: update handler type definitions in event bus tests for improved clarity and type safety --- .../src/in-proc-event-bus.test.ts | 12 +++++----- .../src/node-event-bus.test.ts | 24 +++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/cellix/event-bus-seedwork-node/src/in-proc-event-bus.test.ts b/packages/cellix/event-bus-seedwork-node/src/in-proc-event-bus.test.ts index 03264d8c8..a4c38476b 100644 --- a/packages/cellix/event-bus-seedwork-node/src/in-proc-event-bus.test.ts +++ b/packages/cellix/event-bus-seedwork-node/src/in-proc-event-bus.test.ts @@ -18,11 +18,11 @@ class TestEventA extends DomainSeedwork.CustomDomainEventImpl<{ testA: string }> class TestEventB extends DomainSeedwork.CustomDomainEventImpl<{ testB: string }> {} test.for(feature, ({ Scenario, BeforeEachScenario }) => { - let handler: ReturnType; - let handler1: ReturnType; - let handler2: ReturnType; - let handlerA: ReturnType; - let handlerB: ReturnType; + let handler: (payload: { test: string }) => Promise; + let handler1: (payload: { test: string }) => Promise; + let handler2: (payload: { test: string }) => Promise; + let handlerA: (payload: { testA: string }) => Promise; + let handlerB: (payload: { testB: string }) => Promise; let error: unknown; // Reset the singleton's subscribers for isolation before each scenario @@ -72,7 +72,7 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { // handler and TestEvent are already defined }); When('the handler is registered', () => { - InProcEventBusInstance.register(TestEvent, handler as (payload: { test: string }) => Promise); + InProcEventBusInstance.register(TestEvent, handler); }); And('the event is dispatched', async () => { await InProcEventBusInstance.dispatch(TestEvent, { test: 'data' }); diff --git a/packages/cellix/event-bus-seedwork-node/src/node-event-bus.test.ts b/packages/cellix/event-bus-seedwork-node/src/node-event-bus.test.ts index 1c8db9427..7f6004f0e 100644 --- a/packages/cellix/event-bus-seedwork-node/src/node-event-bus.test.ts +++ b/packages/cellix/event-bus-seedwork-node/src/node-event-bus.test.ts @@ -50,11 +50,11 @@ class EventA extends DomainSeedwork.CustomDomainEventImpl<{ a: string }> {} class EventB extends DomainSeedwork.CustomDomainEventImpl<{ b: string }> {} test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { - let handler: ReturnType; - let handler1: ReturnType; - let handler2: ReturnType; - let handlerA: ReturnType; - let handlerB: ReturnType; + let handler: (payload: { test: string }) => Promise; + let handler1: (payload: { test: string }) => Promise; + let handler2: (payload: { test: string }) => Promise; + let handlerA: (payload: { a: string }) => Promise; + let handlerB: (payload: { b: string }) => Promise; BeforeEachScenario(() => { handler = vi.fn().mockResolvedValue(undefined); @@ -102,7 +102,7 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { // handler and TestEvent are already defined }); When('the handler is registered', () => { - NodeEventBusInstance.register(TestEvent, handler as (payload: { test: string }) => Promise); + NodeEventBusInstance.register(TestEvent, handler); }); And('the event is dispatched', async () => { await NodeEventBusInstance.dispatch(TestEvent, { test: 'data' }); @@ -117,8 +117,8 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { // handler and TestEvent are already defined }); When('the same handler is registered multiple times for the same event', () => { - NodeEventBusInstance.register(TestEvent, handler as (payload: { test: string }) => Promise); - NodeEventBusInstance.register(TestEvent, handler as (payload: { test: string }) => Promise); + NodeEventBusInstance.register(TestEvent, handler); + NodeEventBusInstance.register(TestEvent, handler); }); And('the event is dispatched', async () => { await NodeEventBusInstance.dispatch(TestEvent, { test: 'data' }); @@ -164,7 +164,7 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { Given('a registered handler for an event that throws', async () => { handler = vi.fn().mockRejectedValue(new Error('handler error')); errorEvent = TestEvent; - NodeEventBusInstance.register(errorEvent, handler as (payload: { test: string }) => Promise); + NodeEventBusInstance.register(errorEvent, handler); // Patch OpenTelemetry span otel = await import('@opentelemetry/api'); @@ -322,7 +322,7 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { Scenario('Dispatch does not wait for handler completion', ({ Given, When, And, Then }) => { let handlerStarted = false; let handlerCompleted = false; - let asyncHandler: ReturnType; + let asyncHandler: (payload: { test: string }) => Promise; Given('a handler for an event that is asynchronous', () => { asyncHandler = vi.fn(async () => { handlerStarted = true; @@ -331,7 +331,7 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { }); }); When('the handler is registered', () => { - NodeEventBusInstance.register(TestEvent, asyncHandler as (payload: { test: string }) => Promise); + NodeEventBusInstance.register(TestEvent, asyncHandler); }); And('the event is dispatched', async () => { const dispatchPromise = NodeEventBusInstance.dispatch(TestEvent, { test: 'data' }); @@ -358,7 +358,7 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { Scenario('Removing all listeners', ({ Given, When, And, Then }) => { Given('a registered handler for an event', () => { - NodeEventBusInstance.register(TestEvent, handler as (payload: { test: string }) => Promise); + NodeEventBusInstance.register(TestEvent, handler); }); When('removeAllListeners is called', () => { NodeEventBusInstance.removeAllListeners(); From f6dfe6beb5e6720b210d91a273aa72b6a7bea366 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Tue, 16 Dec 2025 12:02:39 -0500 Subject: [PATCH 43/74] fix: update mock data structure for 'myListingsAll' in ProfilePage stories for improved clarity --- .../home/account/profile/stories/ProfilePage.stories.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ui-sharethrift/src/components/layouts/home/account/profile/stories/ProfilePage.stories.tsx b/apps/ui-sharethrift/src/components/layouts/home/account/profile/stories/ProfilePage.stories.tsx index 33ab6b0d3..95458c1bd 100644 --- a/apps/ui-sharethrift/src/components/layouts/home/account/profile/stories/ProfilePage.stories.tsx +++ b/apps/ui-sharethrift/src/components/layouts/home/account/profile/stories/ProfilePage.stories.tsx @@ -175,7 +175,7 @@ export const NoListings: Story = { }, result: { data: { - myListingsAll: [], + myListingsAll: { items: [], total: 0, page: 1, pageSize: 100 }, }, }, }, From 8a87f483ef90557045d44b96f6a9bb6d681df575 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Tue, 16 Dec 2025 12:12:55 -0500 Subject: [PATCH 44/74] fix: update event handler implementations to ensure proper promise resolution in tests --- .../src/node-event-bus.test.ts | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/packages/cellix/event-bus-seedwork-node/src/node-event-bus.test.ts b/packages/cellix/event-bus-seedwork-node/src/node-event-bus.test.ts index 7f6004f0e..9d072e6d6 100644 --- a/packages/cellix/event-bus-seedwork-node/src/node-event-bus.test.ts +++ b/packages/cellix/event-bus-seedwork-node/src/node-event-bus.test.ts @@ -268,12 +268,18 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { let callOrder: string[]; Given('multiple handlers for the same event class', () => { callOrder = []; - handler1 = vi.fn(() => callOrder.push('handler1')); - handler2 = vi.fn(() => callOrder.push('handler2')); + handler1 = vi.fn(() => { + callOrder.push('handler1'); + return Promise.resolve(); + }); + handler2 = vi.fn(() => { + callOrder.push('handler2'); + return Promise.resolve(); + }); }); When('all handlers are registered', () => { - NodeEventBusInstance.register(TestEvent, handler1 as (payload: { test: string }) => Promise); - NodeEventBusInstance.register(TestEvent, handler2 as (payload: { test: string }) => Promise); + NodeEventBusInstance.register(TestEvent, handler1); + NodeEventBusInstance.register(TestEvent, handler2); }); And('the event is dispatched', async () => { await NodeEventBusInstance.dispatch(TestEvent, { test: 'data' }); @@ -289,8 +295,8 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { handler2 = vi.fn().mockResolvedValue(undefined); }); When('all handlers are registered and one throws', () => { - NodeEventBusInstance.register(TestEvent, handler1 as (payload: { test: string }) => Promise); - NodeEventBusInstance.register(TestEvent, handler2 as (payload: { test: string }) => Promise); + NodeEventBusInstance.register(TestEvent, handler1); + NodeEventBusInstance.register(TestEvent, handler2); }); And('the event is dispatched', async () => { await expect(NodeEventBusInstance.dispatch(TestEvent, { test: 'data' })).resolves.not.toThrow(); @@ -307,8 +313,8 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { handler2 = vi.fn().mockRejectedValue(new Error('handler2 error')); }); When('all handlers are registered and all throw', () => { - NodeEventBusInstance.register(TestEvent, handler1 as (payload: { test: string }) => Promise); - NodeEventBusInstance.register(TestEvent, handler2 as (payload: { test: string }) => Promise); + NodeEventBusInstance.register(TestEvent, handler1); + NodeEventBusInstance.register(TestEvent, handler2); }); And('the event is dispatched', async () => { await expect(NodeEventBusInstance.dispatch(TestEvent, { test: 'data' })).resolves.not.toThrow(); From 6577afd310d13b16a0c69f8096b107b00990d03d Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Tue, 16 Dec 2025 14:06:14 -0500 Subject: [PATCH 45/74] revert the version for typescript in ui-core to have it consistent --- packages/cellix/ui-core/package.json | 2 +- pnpm-lock.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/cellix/ui-core/package.json b/packages/cellix/ui-core/package.json index b917b051b..6e955b1b8 100644 --- a/packages/cellix/ui-core/package.json +++ b/packages/cellix/ui-core/package.json @@ -53,7 +53,7 @@ "react-router-dom": "^7.9.3", "rimraf": "^6.0.1", "storybook": "^9.1.3", - "typescript": "^5.7.2", + "typescript": "^5.8.3", "vitest": "catalog:" }, "license": "MIT" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d0a8e49d4..a50d99d87 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -642,7 +642,7 @@ importers: specifier: ^9.1.3 version: 9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) typescript: - specifier: ^5.7.2 + specifier: ^5.8.3 version: 5.8.3 vitest: specifier: 'catalog:' From 92a9db259d1f275a1aaf4860110f50a0d8c43430 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Tue, 16 Dec 2025 14:10:34 -0500 Subject: [PATCH 46/74] fix: simplify handler registration in InProcEventBus tests --- .../src/in-proc-event-bus.test.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/cellix/event-bus-seedwork-node/src/in-proc-event-bus.test.ts b/packages/cellix/event-bus-seedwork-node/src/in-proc-event-bus.test.ts index a4c38476b..27898b298 100644 --- a/packages/cellix/event-bus-seedwork-node/src/in-proc-event-bus.test.ts +++ b/packages/cellix/event-bus-seedwork-node/src/in-proc-event-bus.test.ts @@ -87,8 +87,8 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { // handler1 and handler2 are already defined }); When('both handlers are registered', () => { - InProcEventBusInstance.register(TestEvent, handler1 as (payload: { test: string }) => Promise); - InProcEventBusInstance.register(TestEvent, handler2 as (payload: { test: string }) => Promise); + InProcEventBusInstance.register(TestEvent, handler1); + InProcEventBusInstance.register(TestEvent, handler2); }); And('the event is dispatched', async () => { await InProcEventBusInstance.dispatch(TestEvent, { test: 'data' }); @@ -105,8 +105,8 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { handler2 = vi.fn().mockResolvedValue(undefined); }); When('one handler throws and both are registered', () => { - InProcEventBusInstance.register(TestEvent, handler1 as (payload: { test: string }) => Promise); - InProcEventBusInstance.register(TestEvent, handler2 as (payload: { test: string }) => Promise); + InProcEventBusInstance.register(TestEvent, handler1); + InProcEventBusInstance.register(TestEvent, handler2); }); And('the event is dispatched', async () => { try { @@ -130,8 +130,8 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { // handlerA, handlerB, TestEventA, TestEventB are already defined }); When('both handlers are registered for different events', () => { - InProcEventBusInstance.register(TestEventA, handlerA as (payload: { testA: string }) => Promise); - InProcEventBusInstance.register(TestEventB, handlerB as (payload: { testB: string }) => Promise); + InProcEventBusInstance.register(TestEventA, handlerA); + InProcEventBusInstance.register(TestEventB, handlerB); }); And('each event is dispatched', async () => { await InProcEventBusInstance.dispatch(TestEventA, { testA: 'dataA' }); From 207949830b2c932d15371256159afb0ff3c0a245 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Tue, 16 Dec 2025 15:22:00 -0500 Subject: [PATCH 47/74] fix: improve type definition for handler function in event tests --- .../domain-seedwork/src/domain-seedwork/handle-event.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/cellix/domain-seedwork/src/domain-seedwork/handle-event.test.ts b/packages/cellix/domain-seedwork/src/domain-seedwork/handle-event.test.ts index 2204aded0..b6b6728fd 100644 --- a/packages/cellix/domain-seedwork/src/domain-seedwork/handle-event.test.ts +++ b/packages/cellix/domain-seedwork/src/domain-seedwork/handle-event.test.ts @@ -15,14 +15,14 @@ const feature = await loadFeature( class TestEvent extends DomainEventBase {} test.for(feature, ({ Scenario }) => { - let handlerFn: ReturnType; + let handlerFn: (event: TestEvent) => void; let handler: HandleEventImpl; let event: TestEvent; Scenario('Handling a domain event with a registered handler', ({ Given, When, Then }) => { Given('a domain event handler is registered with a function', () => { handlerFn = vi.fn(); - handler = new HandleEventImpl(handlerFn as (event: TestEvent) => void); + handler = new HandleEventImpl(handlerFn); event = new TestEvent('agg-1'); }); When('the handler is called with a domain event', () => { From 7835b1d7b204edb72a272826f1a64a5605a617e8 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Tue, 16 Dec 2025 15:26:36 -0500 Subject: [PATCH 48/74] fix: remove deprecated '@vitest/browser' dependency from package.json and pnpm workspace --- apps/ui-sharethrift/package.json | 1 - packages/cellix/ui-core/package.json | 1 - packages/cellix/vitest-config/package.json | 1 - packages/sthrift/ui-components/package.json | 1 - pnpm-lock.yaml | 15 --------------- pnpm-workspace.yaml | 1 - 6 files changed, 20 deletions(-) diff --git a/apps/ui-sharethrift/package.json b/apps/ui-sharethrift/package.json index c594feffe..7f6702e35 100644 --- a/apps/ui-sharethrift/package.json +++ b/apps/ui-sharethrift/package.json @@ -47,7 +47,6 @@ "@types/react": "^19.1.9", "@types/react-dom": "^19.1.7", "@vitejs/plugin-react": "^4.7.0", - "@vitest/browser": "4.0.15", "@vitest/coverage-v8": "catalog:", "eslint": "^9.30.1", "eslint-plugin-react-hooks": "^5.2.0", diff --git a/packages/cellix/ui-core/package.json b/packages/cellix/ui-core/package.json index 6e955b1b8..28a1a7895 100644 --- a/packages/cellix/ui-core/package.json +++ b/packages/cellix/ui-core/package.json @@ -46,7 +46,6 @@ "@storybook/react": "^9.1.9", "@storybook/react-vite": "^9.1.3", "@types/react": "^19.1.16", - "@vitest/browser": "catalog:", "@vitest/coverage-v8": "catalog:", "jsdom": "^26.1.0", "react-oidc-context": "^3.3.0", diff --git a/packages/cellix/vitest-config/package.json b/packages/cellix/vitest-config/package.json index 7c811cc1c..8a1da9ecc 100644 --- a/packages/cellix/vitest-config/package.json +++ b/packages/cellix/vitest-config/package.json @@ -12,7 +12,6 @@ }, "dependencies": { "@storybook/addon-vitest": "^9.1.10", - "@vitest/browser": "catalog:", "@vitest/browser-playwright": "catalog:", "vitest": "catalog:" }, diff --git a/packages/sthrift/ui-components/package.json b/packages/sthrift/ui-components/package.json index e0ec953e3..1af01d53f 100644 --- a/packages/sthrift/ui-components/package.json +++ b/packages/sthrift/ui-components/package.json @@ -68,7 +68,6 @@ "@storybook/react-vite": "^9.1.3", "@types/react": "^19.1.11", "@types/react-dom": "^19.1.6", - "@vitest/browser": "catalog:", "@vitest/coverage-v8": "catalog:", "jsdom": "^26.1.0", "rimraf": "^6.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a50d99d87..c1c55172f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,9 +6,6 @@ settings: catalogs: default: - '@vitest/browser': - specifier: ^4.0.15 - version: 4.0.15 '@vitest/browser-playwright': specifier: ^4.0.15 version: 4.0.15 @@ -341,9 +338,6 @@ importers: '@vitejs/plugin-react': specifier: ^4.7.0 version: 4.7.0(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@vitest/browser': - specifier: 4.0.15 - version: 4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) '@vitest/coverage-v8': specifier: 'catalog:' version: 4.0.15(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15) @@ -620,9 +614,6 @@ importers: '@types/react': specifier: ^19.1.16 version: 19.2.2 - '@vitest/browser': - specifier: 'catalog:' - version: 4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) '@vitest/coverage-v8': specifier: 'catalog:' version: 4.0.15(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15) @@ -653,9 +644,6 @@ importers: '@storybook/addon-vitest': specifier: ^9.1.10 version: 9.1.16(@vitest/browser-playwright@4.0.15)(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(@vitest/runner@4.0.15)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@4.0.15) - '@vitest/browser': - specifier: 'catalog:' - version: 4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) '@vitest/browser-playwright': specifier: 'catalog:' version: 4.0.15(playwright@1.56.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) @@ -1331,9 +1319,6 @@ importers: '@types/react-dom': specifier: ^19.1.6 version: 19.2.2(@types/react@19.2.2) - '@vitest/browser': - specifier: 'catalog:' - version: 4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) '@vitest/coverage-v8': specifier: 'catalog:' version: 4.0.15(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15) diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 8c0d6f7ff..ccd03839d 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -8,7 +8,6 @@ catalog: mongodb: 6.18.0 # Vitest 4.x and related testing dependencies vitest: ^4.0.15 - '@vitest/browser': ^4.0.15 '@vitest/coverage-v8': ^4.0.15 '@vitest/browser-playwright': ^4.0.15 From fda7ee75bb47b1bb13b08687a86898e031b5c1c6 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Tue, 16 Dec 2025 16:19:41 -0500 Subject: [PATCH 49/74] format file --- .../service-sendgrid/src/sendgrid.test.ts | 383 +++++++++--------- 1 file changed, 202 insertions(+), 181 deletions(-) diff --git a/packages/sthrift/service-sendgrid/src/sendgrid.test.ts b/packages/sthrift/service-sendgrid/src/sendgrid.test.ts index 3f272b1a0..96ee93672 100644 --- a/packages/sthrift/service-sendgrid/src/sendgrid.test.ts +++ b/packages/sthrift/service-sendgrid/src/sendgrid.test.ts @@ -43,185 +43,206 @@ test.for(feature, ({ Scenario }) => { process.env = { ...originalEnv }; }); - Scenario('Constructing SendGrid with missing API key', ({ Given, When, Then }) => { - Given('no SENDGRID_API_KEY environment variable', () => { - delete process.env['SENDGRID_API_KEY']; - }); - - When('SendGrid is constructed', () => { - // Handled in Then - }); - - Then('it should throw an error about missing API key', () => { - expect(() => new SendGrid('template.json')).toThrow( - 'SENDGRID_API_KEY environment variable is missing', - ); - }); - }); - - Scenario('Constructing SendGrid with valid API key', ({ Given, When, Then, And }) => { - const apiKey = 'test-api-key-123'; - const templateName = 'welcome-email.json'; - - Given('a valid SENDGRID_API_KEY environment variable', () => { - // biome-ignore lint/complexity/useLiteralKeys: Required for env var access - process.env['SENDGRID_API_KEY'] = apiKey; - }); - - And('an email template name', () => { - // Already defined above - }); - - When('SendGrid is constructed', () => { - sendGridInstance = new SendGrid(templateName); - }); - - Then('it should initialize with the template name', () => { - expect(sendGridInstance.emailTemplateName).toBe(templateName); - }); - }); - - Scenario('Sending email with magic link in development mode', ({ Given, When, Then, And }) => { - const userEmail = 'user@example.com'; - const magicLink = 'https://example.com/magic/abc123'; - const mockFs = fs as typeof fs & { - existsSync: ReturnType; - mkdirSync: ReturnType; - writeFileSync: ReturnType; - }; - - Given('a SendGrid instance in development mode', () => { - // biome-ignore lint/complexity/useLiteralKeys: Required for env var access - process.env['SENDGRID_API_KEY'] = 'test-key'; - // biome-ignore lint/complexity/useLiteralKeys: Required for env var access - process.env['NODE_ENV'] = 'development'; - // biome-ignore lint/complexity/useLiteralKeys: Required for env var access - process.env['SENDGRID_MAGICLINK_SUBJECT_SUFFIX'] = '- Dev'; - - mockFs.existsSync = vi.fn().mockReturnValue(false); - mockFs.mkdirSync = vi.fn() as typeof mockFs.mkdirSync; - mockFs.writeFileSync = vi.fn() as typeof mockFs.writeFileSync; - vi.mocked(emailTemplate.readHtmlFile).mockReturnValue( - JSON.stringify(mockTemplate), - ); - - sendGridInstance = new SendGrid('template.json'); - }); - - And('a user email and magic link', () => { - // Already defined above - }); - - When('sendEmailWithMagicLink is called', async () => { - await sendGridInstance.sendEmailWithMagicLink(userEmail, magicLink); - }); - - Then('it should save the email to a file instead of sending', () => { - expect(mockFs.mkdirSync).toHaveBeenCalled(); - expect(mockFs.writeFileSync).toHaveBeenCalled(); - }); - }); - - Scenario('Sending email with magic link in production mode', ({ Given, When, Then, And }) => { - const userEmail = 'user@example.com'; - const magicLink = 'https://example.com/magic/abc123'; - let sendGridMock: { send: ReturnType }; - - Given('a SendGrid instance in production mode', async () => { - // biome-ignore lint/complexity/useLiteralKeys: Required for env var access - process.env['SENDGRID_API_KEY'] = 'test-key'; - // biome-ignore lint/complexity/useLiteralKeys: Required for env var access - process.env['NODE_ENV'] = 'production'; - // biome-ignore lint/complexity/useLiteralKeys: Required for env var access - process.env['SENDGRID_MAGICLINK_SUBJECT_SUFFIX'] = '- Prod'; - - // biome-ignore lint/suspicious/noExplicitAny: Required for mock type assertion - sendGridMock = (await import('@sendgrid/mail')).default as any; - sendGridMock.send = vi.fn().mockResolvedValue([{ statusCode: 202 }]); - - vi.mocked(emailTemplate.readHtmlFile).mockReturnValue( - JSON.stringify(mockTemplate), - ); - - sendGridInstance = new SendGrid('template.json'); - }); - - And('a user email and magic link', () => { - // Already defined above - }); - - When('sendEmailWithMagicLink is called', async () => { - await sendGridInstance.sendEmailWithMagicLink(userEmail, magicLink); - }); - - Then('it should send email via SendGrid API', () => { - expect(sendGridMock.send).toHaveBeenCalledWith( - expect.objectContaining({ - to: userEmail, - from: mockTemplate.fromEmail, - subject: expect.stringContaining(mockTemplate.subject), - html: expect.stringContaining(magicLink), - }), - ); - }); - }); - - Scenario('Replacing magic link placeholder in template', ({ Given, When, Then, And }) => { - const template = - 'Link 1 Link 2'; - const magicLink = 'https://example.com/magic/xyz'; - let result: string; - - Given('an HTML template with magic link placeholder', () => { - // biome-ignore lint/complexity/useLiteralKeys: Required for env var access - process.env['SENDGRID_API_KEY'] = 'test-key'; - sendGridInstance = new SendGrid('template.json'); - }); - - And('a magic link URL', () => { - // Already defined above - }); - - When('the template is processed', () => { - // Access private method via type assertion - // biome-ignore lint/suspicious/noExplicitAny: Required to access private method for testing - result = (sendGridInstance as any).replaceMagicLink(template, magicLink); - }); - - Then('it should replace all placeholders with the actual link', () => { - expect(result).not.toContain('{{magicLink}}'); - expect(result).toContain(magicLink); - expect((result.match(new RegExp(magicLink, 'g')) || []).length).toBe(2); - }); - }); - - Scenario('Handling invalid email template JSON', ({ Given, When, Then, And }) => { - const userEmail = 'user@example.com'; - const magicLink = 'https://example.com/magic/abc123'; - - Given('a SendGrid instance with invalid template', () => { - // biome-ignore lint/complexity/useLiteralKeys: Required for env var access - process.env['SENDGRID_API_KEY'] = 'test-key'; - - vi.mocked(emailTemplate.readHtmlFile).mockReturnValue( - '{ invalid json content', - ); - - sendGridInstance = new SendGrid('bad-template.json'); - }); - - And('a user email and magic link', () => { - // Already defined above - }); - - When('sendEmailWithMagicLink is called', async () => { - // Handled in Then - }); - - Then('it should throw an error about invalid template JSON', async () => { - await expect( - sendGridInstance.sendEmailWithMagicLink(userEmail, magicLink), - ).rejects.toThrow('Invalid email template JSON'); - }); - }); + Scenario( + 'Constructing SendGrid with missing API key', + ({ Given, When, Then }) => { + Given('no SENDGRID_API_KEY environment variable', () => { + delete process.env['SENDGRID_API_KEY']; + }); + + When('SendGrid is constructed', () => { + // Handled in Then + }); + + Then('it should throw an error about missing API key', () => { + expect(() => new SendGrid('template.json')).toThrow( + 'SENDGRID_API_KEY environment variable is missing', + ); + }); + }, + ); + + Scenario( + 'Constructing SendGrid with valid API key', + ({ Given, When, Then, And }) => { + const apiKey = 'test-api-key-123'; + const templateName = 'welcome-email.json'; + + Given('a valid SENDGRID_API_KEY environment variable', () => { + // biome-ignore lint/complexity/useLiteralKeys: Required for env var access + process.env['SENDGRID_API_KEY'] = apiKey; + }); + + And('an email template name', () => { + // Already defined above + }); + + When('SendGrid is constructed', () => { + sendGridInstance = new SendGrid(templateName); + }); + + Then('it should initialize with the template name', () => { + expect(sendGridInstance.emailTemplateName).toBe(templateName); + }); + }, + ); + + Scenario( + 'Sending email with magic link in development mode', + ({ Given, When, Then, And }) => { + const userEmail = 'user@example.com'; + const magicLink = 'https://example.com/magic/abc123'; + const mockFs = fs as typeof fs & { + existsSync: ReturnType; + mkdirSync: ReturnType; + writeFileSync: ReturnType; + }; + + Given('a SendGrid instance in development mode', () => { + // biome-ignore lint/complexity/useLiteralKeys: Required for env var access + process.env['SENDGRID_API_KEY'] = 'test-key'; + // biome-ignore lint/complexity/useLiteralKeys: Required for env var access + process.env['NODE_ENV'] = 'development'; + // biome-ignore lint/complexity/useLiteralKeys: Required for env var access + process.env['SENDGRID_MAGICLINK_SUBJECT_SUFFIX'] = '- Dev'; + + mockFs.existsSync = vi.fn().mockReturnValue(false); + mockFs.mkdirSync = vi.fn() as typeof mockFs.mkdirSync; + mockFs.writeFileSync = vi.fn() as typeof mockFs.writeFileSync; + vi.mocked(emailTemplate.readHtmlFile).mockReturnValue( + JSON.stringify(mockTemplate), + ); + + sendGridInstance = new SendGrid('template.json'); + }); + + And('a user email and magic link', () => { + // Already defined above + }); + + When('sendEmailWithMagicLink is called', async () => { + await sendGridInstance.sendEmailWithMagicLink(userEmail, magicLink); + }); + + Then('it should save the email to a file instead of sending', () => { + expect(mockFs.mkdirSync).toHaveBeenCalled(); + expect(mockFs.writeFileSync).toHaveBeenCalled(); + }); + }, + ); + + Scenario( + 'Sending email with magic link in production mode', + ({ Given, When, Then, And }) => { + const userEmail = 'user@example.com'; + const magicLink = 'https://example.com/magic/abc123'; + let sendGridMock: { send: ReturnType }; + + Given('a SendGrid instance in production mode', async () => { + // biome-ignore lint/complexity/useLiteralKeys: Required for env var access + process.env['SENDGRID_API_KEY'] = 'test-key'; + // biome-ignore lint/complexity/useLiteralKeys: Required for env var access + process.env['NODE_ENV'] = 'production'; + // biome-ignore lint/complexity/useLiteralKeys: Required for env var access + process.env['SENDGRID_MAGICLINK_SUBJECT_SUFFIX'] = '- Prod'; + + // biome-ignore lint/suspicious/noExplicitAny: Required for mock type assertion + sendGridMock = (await import('@sendgrid/mail')).default as any; + sendGridMock.send = vi.fn().mockResolvedValue([{ statusCode: 202 }]); + + vi.mocked(emailTemplate.readHtmlFile).mockReturnValue( + JSON.stringify(mockTemplate), + ); + + sendGridInstance = new SendGrid('template.json'); + }); + + And('a user email and magic link', () => { + // Already defined above + }); + + When('sendEmailWithMagicLink is called', async () => { + await sendGridInstance.sendEmailWithMagicLink(userEmail, magicLink); + }); + + Then('it should send email via SendGrid API', () => { + expect(sendGridMock.send).toHaveBeenCalledWith( + expect.objectContaining({ + to: userEmail, + from: mockTemplate.fromEmail, + subject: expect.stringContaining(mockTemplate.subject), + html: expect.stringContaining(magicLink), + }), + ); + }); + }, + ); + + Scenario( + 'Replacing magic link placeholder in template', + ({ Given, When, Then, And }) => { + const template = + 'Link 1 Link 2'; + const magicLink = 'https://example.com/magic/xyz'; + let result: string; + + Given('an HTML template with magic link placeholder', () => { + // biome-ignore lint/complexity/useLiteralKeys: Required for env var access + process.env['SENDGRID_API_KEY'] = 'test-key'; + sendGridInstance = new SendGrid('template.json'); + }); + + And('a magic link URL', () => { + // Already defined above + }); + + When('the template is processed', () => { + // Access private method via type assertion + // biome-ignore lint/suspicious/noExplicitAny: Required to access private method for testing + result = (sendGridInstance as any).replaceMagicLink( + template, + magicLink, + ); + }); + + Then('it should replace all placeholders with the actual link', () => { + expect(result).not.toContain('{{magicLink}}'); + expect(result).toContain(magicLink); + expect((result.match(new RegExp(magicLink, 'g')) || []).length).toBe(2); + }); + }, + ); + + Scenario( + 'Handling invalid email template JSON', + ({ Given, When, Then, And }) => { + const userEmail = 'user@example.com'; + const magicLink = 'https://example.com/magic/abc123'; + + Given('a SendGrid instance with invalid template', () => { + // biome-ignore lint/complexity/useLiteralKeys: Required for env var access + process.env['SENDGRID_API_KEY'] = 'test-key'; + + vi.mocked(emailTemplate.readHtmlFile).mockReturnValue( + '{ invalid json content', + ); + + sendGridInstance = new SendGrid('bad-template.json'); + }); + + And('a user email and magic link', () => { + // Already defined above + }); + + When('sendEmailWithMagicLink is called', async () => { + // Handled in Then + }); + + Then('it should throw an error about invalid template JSON', async () => { + await expect( + sendGridInstance.sendEmailWithMagicLink(userEmail, magicLink), + ).rejects.toThrow('Invalid email template JSON'); + }); + }, + ); }); From a825b6002b5133fe65464f074074849289f96cf4 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Tue, 16 Dec 2025 16:20:00 -0500 Subject: [PATCH 50/74] remove unused "this" --- .../service-otel/src/otel-builder.test.ts | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/packages/sthrift/service-otel/src/otel-builder.test.ts b/packages/sthrift/service-otel/src/otel-builder.test.ts index 36beb6bcb..dfb900cf4 100644 --- a/packages/sthrift/service-otel/src/otel-builder.test.ts +++ b/packages/sthrift/service-otel/src/otel-builder.test.ts @@ -37,17 +37,12 @@ vi.mock('@azure/monitor-opentelemetry-exporter', () => { } } - const AzureMonitorTraceExporter = vi.fn(function (this: TraceExporter, args: Record) { - return new TraceExporter(args); - }); - - const AzureMonitorMetricExporter = vi.fn(function (this: MetricExporter, args: Record) { - return new MetricExporter(args); - }); - - const AzureMonitorLogExporter = vi.fn(function (this: LogExporter, args: Record) { - return new LogExporter(args); - }); + // biome-ignore lint/complexity/useArrowFunction: Vitest 4.x requires constructor function pattern + const AzureMonitorTraceExporter = vi.fn(function (args: Record) {return new TraceExporter(args)}); + // biome-ignore lint/complexity/useArrowFunction: Vitest 4.x requires constructor function pattern + const AzureMonitorMetricExporter = vi.fn(function (args: Record) {return new MetricExporter(args)}); + // biome-ignore lint/complexity/useArrowFunction: Vitest 4.x requires constructor function pattern + const AzureMonitorLogExporter = vi.fn(function (args: Record) {return new LogExporter(args)}); return { AzureMonitorTraceExporter, From 2c4bdea7225542729c100092709a9027886d3da7 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Tue, 16 Dec 2025 16:20:28 -0500 Subject: [PATCH 51/74] remove extra spaces --- packages/sthrift/ui-components/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sthrift/ui-components/package.json b/packages/sthrift/ui-components/package.json index 1af01d53f..6b17e7bbb 100644 --- a/packages/sthrift/ui-components/package.json +++ b/packages/sthrift/ui-components/package.json @@ -8,7 +8,7 @@ ], "exports": { ".": { - "vitest": "./src/index.ts", + "vitest": "./src/index.ts", "types": "./dist/src/index.d.ts", "default": "./dist/src/index.js" }, From 35b21eff98b9543fb4e024fe758da6b7d0f00998 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Wed, 17 Dec 2025 09:33:21 -0500 Subject: [PATCH 52/74] split test coverage for node and storybook --- build-pipeline/core/monorepo-build-stage.yml | 7 ++++++- package.json | 6 ++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/build-pipeline/core/monorepo-build-stage.yml b/build-pipeline/core/monorepo-build-stage.yml index 7b0c3c687..29f721b99 100644 --- a/build-pipeline/core/monorepo-build-stage.yml +++ b/build-pipeline/core/monorepo-build-stage.yml @@ -239,10 +239,15 @@ stages: pnpm audit --audit-level=high --prod # Use Turbo's built-in --affected flag for accurate change detection + # Split coverage collection: Node tests first, then Storybook tests separately + # to reduce race conditions and memory pressure in CI if [ "$(Build.Reason)" = "PullRequest" ] || [ "$(Build.SourceBranch)" != "refs/heads/main" ]; then echo "Testing affected packages only (PR/branch build)..." export TURBO_SCM_BASE="origin/$(System.PullRequest.TargetBranch)" - pnpm run test:coverage --affected + echo "Running Node unit tests with coverage..." + pnpm run test:coverage:node --affected + echo "Running Storybook/Playwright tests with coverage..." + pnpm run test:coverage:storybook --affected pnpm run merge-lcov-reports else echo "Testing all packages (main branch build)..." diff --git a/package.json b/package.json index e28543395..52fd32fbc 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "gen:watch": "graphql-codegen --config codegen.yml --watch", "tsbuild": "tsc --build", "tswatch": "tsc --build --watch", - "clean": "pnpm install && turbo run clean && rimraf dist node_modules **/coverage .turbo", + "clean": "pnpm install && turbo run clean && rimraf dist node_modules **/coverage .turbo", "start:api": "pnpm run start --workspace=@sthrift/api", "start:ui-sharethrift": "pnpm run dev --workspace=@sthrift/ui-sharethrift", "start-emulator:mongo-memory-server": "pnpm run start --workspace=@cellix/mock-mongodb-memory-server", @@ -28,7 +28,9 @@ "start-emulator:messaging-server": "pnpm run start --workspace=@sthrift/mock-messaging-server", "test:all": "turbo run test:all", "test:coverage": "turbo run test:coverage", - "test:coverage:merge": "pnpm run test:coverage && pnpm run merge-lcov-reports", + "test:coverage:node": "turbo run test:coverage --filter=!@sthrift/ui-components --filter=!@cellix/ui-core --filter=!@sthrift/ui-sharethrift", + "test:coverage:storybook": "turbo run test:coverage --filter=@sthrift/ui-components --filter=@cellix/ui-core --filter=@sthrift/ui-sharethrift", + "test:coverage:merge": "pnpm run test:coverage:node && pnpm run test:coverage:storybook && pnpm run merge-lcov-reports", "merge-lcov-reports": "node build-pipeline/scripts/merge-coverage.js", "test:integration": "turbo run test:integration", "test:serenity": "turbo run test:serenity", From ed96651f598009aaac0e6042678f5ea6c11af99d Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Wed, 17 Dec 2025 15:53:59 -0500 Subject: [PATCH 53/74] fix splitting node and ui tests --- build-pipeline/core/monorepo-build-stage.yml | 4 +- package.json | 11 +- turbo.json | 184 +++++++------------ 3 files changed, 76 insertions(+), 123 deletions(-) diff --git a/build-pipeline/core/monorepo-build-stage.yml b/build-pipeline/core/monorepo-build-stage.yml index 29f721b99..f4749f3c7 100644 --- a/build-pipeline/core/monorepo-build-stage.yml +++ b/build-pipeline/core/monorepo-build-stage.yml @@ -245,9 +245,9 @@ stages: echo "Testing affected packages only (PR/branch build)..." export TURBO_SCM_BASE="origin/$(System.PullRequest.TargetBranch)" echo "Running Node unit tests with coverage..." - pnpm run test:coverage:node --affected + pnpm run test:coverage:node:affected echo "Running Storybook/Playwright tests with coverage..." - pnpm run test:coverage:storybook --affected + pnpm run test:coverage:ui:affected pnpm run merge-lcov-reports else echo "Testing all packages (main branch build)..." diff --git a/package.json b/package.json index 52fd32fbc..99ddd8efc 100644 --- a/package.json +++ b/package.json @@ -27,10 +27,13 @@ "start-emulator:payment-server": "pnpm run start --workspace=@cellix/mock-payment-server", "start-emulator:messaging-server": "pnpm run start --workspace=@sthrift/mock-messaging-server", "test:all": "turbo run test:all", - "test:coverage": "turbo run test:coverage", - "test:coverage:node": "turbo run test:coverage --filter=!@sthrift/ui-components --filter=!@cellix/ui-core --filter=!@sthrift/ui-sharethrift", - "test:coverage:storybook": "turbo run test:coverage --filter=@sthrift/ui-components --filter=@cellix/ui-core --filter=@sthrift/ui-sharethrift", - "test:coverage:merge": "pnpm run test:coverage:node && pnpm run test:coverage:storybook && pnpm run merge-lcov-reports", + "test:coverage": "pnpm run test:coverage:node && pnpm run test:coverage:ui", + "test:coverage:node": "turbo run test:coverage --filter=!@cellix/ui-core --filter=!@sthrift/ui-components --filter=!@sthrift/ui-sharethrift", + "test:coverage:ui": "turbo run test:coverage --filter=@cellix/ui-core --filter=@sthrift/ui-components --filter=@sthrift/ui-sharethrift", + "test:coverage:node:affected": "turbo run test:coverage --filter=\"...[${TURBO_SCM_BASE:-origin/main}]\" --filter=!@cellix/ui-core --filter=!@sthrift/ui-components --filter=!@sthrift/ui-sharethrift", + "test:coverage:ui:affected": "turbo run test:coverage --filter=\"@cellix/ui-core...[${TURBO_SCM_BASE:-origin/main}]\" --filter=\"@sthrift/ui-components...[${TURBO_SCM_BASE:-origin/main}]\" --filter=\"@sthrift/ui-sharethrift...[${TURBO_SCM_BASE:-origin/main}]\"", + "test:coverage:merge": "pnpm run test:coverage && pnpm run merge-lcov-reports", + "test:coverage:merge:affected": "pnpm run test:coverage:node:affected && pnpm run test:coverage:ui:affected && pnpm run merge-lcov-reports", "merge-lcov-reports": "node build-pipeline/scripts/merge-coverage.js", "test:integration": "turbo run test:integration", "test:serenity": "turbo run test:serenity", diff --git a/turbo.json b/turbo.json index a41efb673..03980c8b4 100644 --- a/turbo.json +++ b/turbo.json @@ -1,118 +1,68 @@ { - "ui": "tui", - "tasks": { - "build": { - "dependsOn": [ - "^build", - "//#gen" - ], - "inputs": [ - "src/**", - "tsconfig*.json" - ], - "outputs": [ - "dist/**", - "build/**" - ] - }, - "test": { - "dependsOn": [ - "^build", - "@cellix/vitest-config#build" - ], - "inputs": [ - "src/**", - "tests/**", - "vitest*.config.*" - ] - }, - "test:coverage": { - "dependsOn": [ - "build", - "^build", - "@cellix/vitest-config#build" - ], - "inputs": [ - "src/**", - "tests/**", - "vitest*.config.*" - ], - "outputs": [ - "coverage/lcov.info" - ] - }, - "test:watch": { - "dependsOn": [ - "^build" - ], - "cache": false, - "persistent": true - }, - "test:unit": { - "dependsOn": [ - "^build" - ], - "inputs": [ - "src/**", - "tests/**", - "vitest*.config.*" - ], - "outputs": [ - "coverage/**" - ] - }, - "test:integration": { - "dependsOn": [ - "^build" - ], - "inputs": [ - "src/**", - "tests/**", - "vitest*.config.*" - ], - "outputs": [ - "coverage/**" - ] - }, - "storybook": { - "dependsOn": [ - "^build", - "//#gen" - ], - "cache": false, - "persistent": true - }, - "start": { - "cache": false, - "persistent": true - }, - "azurite": { - "cache": false, - "persistent": true - }, - "lint": {}, - "format": { - "outputs": [] - }, - "clean": { - "cache": false, - "outputs": [] - }, - "//#gen": { - "cache": true, - "inputs": [ - "codegen.yml", - "**/*.graphql" - ], - "outputs": [ - "**/generated.ts", - "**/graphql.schema.json", - "**/generated.tsx" - ] - }, - "//#gen:watch": { - "cache": false, - "persistent": true - } - } -} \ No newline at end of file + "ui": "tui", + "tasks": { + "build": { + "dependsOn": ["^build", "//#gen"], + "inputs": ["src/**", "tsconfig*.json"], + "outputs": ["dist/**", "build/**"] + }, + "test": { + "dependsOn": ["^build", "@cellix/vitest-config#build"], + "inputs": ["src/**", "tests/**", "vitest*.config.*"] + }, + "test:coverage": { + "dependsOn": ["build", "^build", "@cellix/vitest-config#build"], + "inputs": ["src/**", "tests/**", "vitest*.config.*"], + "outputs": ["coverage/lcov.info"] + }, + "test:watch": { + "dependsOn": ["^build"], + "cache": false, + "persistent": true + }, + "test:unit": { + "dependsOn": ["^build"], + "inputs": ["src/**", "tests/**", "vitest*.config.*"], + "outputs": ["coverage/**"] + }, + "test:integration": { + "dependsOn": ["^build"], + "inputs": ["src/**", "tests/**", "vitest*.config.*"], + "outputs": ["coverage/**"] + }, + "storybook": { + "dependsOn": ["^build", "//#gen"], + "cache": false, + "persistent": true + }, + "start": { + "cache": false, + "persistent": true + }, + "azurite": { + "cache": false, + "persistent": true + }, + "lint": {}, + "format": { + "outputs": [] + }, + "clean": { + "cache": false, + "outputs": [] + }, + "//#gen": { + "cache": true, + "inputs": ["codegen.yml", "**/*.graphql"], + "outputs": [ + "**/generated.ts", + "**/graphql.schema.json", + "**/generated.tsx" + ] + }, + "//#gen:watch": { + "cache": false, + "persistent": true + } + } +} From f95f728855e749e7fa6eca570ca722d1882e5c2a Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Thu, 18 Dec 2025 12:30:26 -0500 Subject: [PATCH 54/74] refactor: simplify mock exporter classes and improve type definitions in tests --- .../account-plan.read-repository.test.ts | 35 +++++++---- .../service-otel/src/otel-builder.test.ts | 59 ++++++++----------- 2 files changed, 50 insertions(+), 44 deletions(-) diff --git a/packages/sthrift/persistence/src/datasources/readonly/account-plan/account-plan/account-plan.read-repository.test.ts b/packages/sthrift/persistence/src/datasources/readonly/account-plan/account-plan/account-plan.read-repository.test.ts index 8e4b7596c..4319c9b62 100644 --- a/packages/sthrift/persistence/src/datasources/readonly/account-plan/account-plan/account-plan.read-repository.test.ts +++ b/packages/sthrift/persistence/src/datasources/readonly/account-plan/account-plan/account-plan.read-repository.test.ts @@ -57,6 +57,22 @@ function makePassport(): Domain.Passport { } as unknown as Domain.Passport; } +/** + * Typed helper to access the private mongoDataSource property for testing. + * Avoids repeated inline casts throughout test assertions. + */ +function getMongoDataSource(repository: AccountPlanReadRepositoryImpl): { + find: ReturnType; + findById: ReturnType; + findOne: ReturnType; +} { + return (repository as unknown as { mongoDataSource: { + find: ReturnType; + findById: ReturnType; + findOne: ReturnType; + } }).mongoDataSource; +} + describe('AccountPlanReadRepositoryImpl', () => { let models: ModelsContext; let passport: Domain.Passport; @@ -82,8 +98,7 @@ describe('AccountPlanReadRepositoryImpl', () => { { _id: '2', name: 'Plan 2' }, ]; - // Access the mongoDataSource via prototype or direct property - const {mongoDataSource} = repository as unknown as { mongoDataSource: { find: ReturnType } }; + const mongoDataSource = getMongoDataSource(repository); mongoDataSource.find = vi.fn().mockResolvedValue(mockData); const result = await repository.getAll(); @@ -95,7 +110,7 @@ describe('AccountPlanReadRepositoryImpl', () => { const options: FindOptions = { fields: ['name'] }; const mockData = [{ _id: '1', name: 'Plan 1' }]; - const {mongoDataSource} = repository as unknown as { mongoDataSource: { find: ReturnType } }; + const mongoDataSource = getMongoDataSource(repository); mongoDataSource.find = vi.fn().mockResolvedValue(mockData); await repository.getAll(options); @@ -105,7 +120,7 @@ describe('AccountPlanReadRepositoryImpl', () => { it('should return empty array when no plans exist', async () => { const repository = new AccountPlanReadRepositoryImpl(models, passport); - const {mongoDataSource} = repository as unknown as { mongoDataSource: { find: ReturnType } }; + const mongoDataSource = getMongoDataSource(repository); mongoDataSource.find = vi.fn().mockResolvedValue([]); const result = await repository.getAll(); @@ -118,7 +133,7 @@ describe('AccountPlanReadRepositoryImpl', () => { const repository = new AccountPlanReadRepositoryImpl(models, passport); const mockData = { _id: '123', name: 'Test Plan' }; - const {mongoDataSource} = repository as unknown as { mongoDataSource: { findById: ReturnType } }; + const mongoDataSource = getMongoDataSource(repository); mongoDataSource.findById = vi.fn().mockResolvedValue(mockData); const result = await repository.getById('123'); @@ -128,7 +143,7 @@ describe('AccountPlanReadRepositoryImpl', () => { it('should return null when plan not found', async () => { const repository = new AccountPlanReadRepositoryImpl(models, passport); - const {mongoDataSource} = repository as unknown as { mongoDataSource: { findById: ReturnType } }; + const mongoDataSource = getMongoDataSource(repository); mongoDataSource.findById = vi.fn().mockResolvedValue(null); const result = await repository.getById('nonexistent'); @@ -139,7 +154,7 @@ describe('AccountPlanReadRepositoryImpl', () => { const repository = new AccountPlanReadRepositoryImpl(models, passport); const options: FindOneOptions = { fields: ['name'] }; - const {mongoDataSource} = repository as unknown as { mongoDataSource: { findById: ReturnType } }; + const mongoDataSource = getMongoDataSource(repository); mongoDataSource.findById = vi.fn().mockResolvedValue(null); await repository.getById('123', options); @@ -152,7 +167,7 @@ describe('AccountPlanReadRepositoryImpl', () => { const repository = new AccountPlanReadRepositoryImpl(models, passport); const mockData = { _id: '123', name: 'Premium Plan' }; - const {mongoDataSource} = repository as unknown as { mongoDataSource: { findOne: ReturnType } }; + const mongoDataSource = getMongoDataSource(repository); mongoDataSource.findOne = vi.fn().mockResolvedValue(mockData); const result = await repository.getByName('Premium Plan'); @@ -162,7 +177,7 @@ describe('AccountPlanReadRepositoryImpl', () => { it('should return null when plan not found by name', async () => { const repository = new AccountPlanReadRepositoryImpl(models, passport); - const {mongoDataSource} = repository as unknown as { mongoDataSource: { findOne: ReturnType } }; + const mongoDataSource = getMongoDataSource(repository); mongoDataSource.findOne = vi.fn().mockResolvedValue(null); const result = await repository.getByName('Nonexistent Plan'); @@ -172,7 +187,7 @@ describe('AccountPlanReadRepositoryImpl', () => { it('should call findOne with name filter', async () => { const repository = new AccountPlanReadRepositoryImpl(models, passport); - const {mongoDataSource} = repository as unknown as { mongoDataSource: { findOne: ReturnType } }; + const mongoDataSource = getMongoDataSource(repository); mongoDataSource.findOne = vi.fn().mockResolvedValue(null); await repository.getByName('Test Plan'); diff --git a/packages/sthrift/service-otel/src/otel-builder.test.ts b/packages/sthrift/service-otel/src/otel-builder.test.ts index dfb900cf4..c1eac3af8 100644 --- a/packages/sthrift/service-otel/src/otel-builder.test.ts +++ b/packages/sthrift/service-otel/src/otel-builder.test.ts @@ -16,21 +16,21 @@ import { expect, vi } from 'vitest'; import { OtelBuilder } from './otel-builder.ts'; +/** + * Type for mock exporter class used in tests. + * The actual class is defined inside vi.mock() to avoid hoisting issues. + */ +type MockExporter = { + __args: Record; +}; + const test = { for: describeFeature }; vi.mock('@azure/monitor-opentelemetry-exporter', () => { - class TraceExporter { - __args: Record; - constructor(args: Record) { - this.__args = args; - } - } - class MetricExporter { - __args: Record; - constructor(args: Record) { - this.__args = args; - } - } - class LogExporter { + /** + * Mock exporter class for testing. Stores constructor args for verification. + * Defined inside mock factory to avoid hoisting issues. + */ + class MockExporter { __args: Record; constructor(args: Record) { this.__args = args; @@ -38,11 +38,11 @@ vi.mock('@azure/monitor-opentelemetry-exporter', () => { } // biome-ignore lint/complexity/useArrowFunction: Vitest 4.x requires constructor function pattern - const AzureMonitorTraceExporter = vi.fn(function (args: Record) {return new TraceExporter(args)}); + const AzureMonitorTraceExporter = vi.fn(function (args: Record) {return new MockExporter(args)}); // biome-ignore lint/complexity/useArrowFunction: Vitest 4.x requires constructor function pattern - const AzureMonitorMetricExporter = vi.fn(function (args: Record) {return new MetricExporter(args)}); + const AzureMonitorMetricExporter = vi.fn(function (args: Record) {return new MockExporter(args)}); // biome-ignore lint/complexity/useArrowFunction: Vitest 4.x requires constructor function pattern - const AzureMonitorLogExporter = vi.fn(function (args: Record) {return new LogExporter(args)}); + const AzureMonitorLogExporter = vi.fn(function (args: Record) {return new MockExporter(args)}); return { AzureMonitorTraceExporter, @@ -52,9 +52,7 @@ vi.mock('@azure/monitor-opentelemetry-exporter', () => { traceExporterMock: AzureMonitorTraceExporter, metricExporterMock: AzureMonitorMetricExporter, logExporterMock: AzureMonitorLogExporter, - TraceExporter, - MetricExporter, - LogExporter, + MockExporter, }, }; }); @@ -72,9 +70,7 @@ test.for(feature, ({ Scenario, BeforeEachScenario, AfterEachScenario }) => { let traceExporterMock: ReturnType; let metricExporterMock: ReturnType; let logExporterMock: ReturnType; - let TraceExporter: new (...args: unknown[]) => unknown; - let MetricExporter: new (...args: unknown[]) => unknown; - let LogExporter: new (...args: unknown[]) => unknown; + let MockExporterClass: new (args: Record) => MockExporter; BeforeEachScenario(async () => { builder = new OtelBuilder(); @@ -84,9 +80,7 @@ test.for(feature, ({ Scenario, BeforeEachScenario, AfterEachScenario }) => { traceExporterMock = azureModule.__test.traceExporterMock; metricExporterMock = azureModule.__test.metricExporterMock; logExporterMock = azureModule.__test.logExporterMock; - TraceExporter = azureModule.__test.TraceExporter; - MetricExporter = azureModule.__test.MetricExporter; - LogExporter = azureModule.__test.LogExporter; + MockExporterClass = azureModule.__test.MockExporter; traceExporterMock.mockClear(); metricExporterMock.mockClear(); logExporterMock.mockClear(); @@ -123,18 +117,15 @@ test.for(feature, ({ Scenario, BeforeEachScenario, AfterEachScenario }) => { exporters = builder.buildExporters(false); }); Then('it should return AzureMonitorTraceExporter, AzureMonitorMetricExporter, and AzureMonitorLogExporter with the correct connection string', () => { - expect(exporters.traceExporter).toBeInstanceOf(TraceExporter); - expect(exporters.metricExporter).toBeInstanceOf(MetricExporter); - expect(exporters.logExporter).toBeInstanceOf(LogExporter); + expect(exporters.traceExporter).toBeInstanceOf(MockExporterClass); + expect(exporters.metricExporter).toBeInstanceOf(MockExporterClass); + expect(exporters.logExporter).toBeInstanceOf(MockExporterClass); expect(traceExporterMock).toHaveBeenCalledWith({ connectionString: connStr }); expect(metricExporterMock).toHaveBeenCalledWith({ connectionString: connStr }); expect(logExporterMock).toHaveBeenCalledWith({ connectionString: connStr }); - // biome-ignore lint/suspicious/noExplicitAny: Required for accessing mock internal property - expect((exporters.traceExporter as any).__args.connectionString).toBe(connStr); - // biome-ignore lint/suspicious/noExplicitAny: Required for accessing mock internal property - expect((exporters.metricExporter as any).__args.connectionString).toBe(connStr); - // biome-ignore lint/suspicious/noExplicitAny: Required for accessing mock internal property - expect((exporters.logExporter as any).__args.connectionString).toBe(connStr); + expect((exporters.traceExporter as unknown as MockExporter).__args['connectionString']).toBe(connStr); + expect((exporters.metricExporter as unknown as MockExporter).__args['connectionString']).toBe(connStr); + expect((exporters.logExporter as unknown as MockExporter).__args['connectionString']).toBe(connStr); }); }); From a03278cc1423a814001b42d2be983f8cf5b7f75d Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Thu, 18 Dec 2025 12:30:36 -0500 Subject: [PATCH 55/74] fix: refine CI detection and adjust watch mode behavior for improved stability --- .../cellix/vitest-config/src/configs/storybook.config.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/cellix/vitest-config/src/configs/storybook.config.ts b/packages/cellix/vitest-config/src/configs/storybook.config.ts index f0730db0d..9a1b584cf 100644 --- a/packages/cellix/vitest-config/src/configs/storybook.config.ts +++ b/packages/cellix/vitest-config/src/configs/storybook.config.ts @@ -20,8 +20,7 @@ export function createStorybookVitestConfig( const setupFiles = opts.setupFiles ?? ['.storybook/vitest.setup.ts']; const instances = opts.browsers ?? [{ browser: 'chromium' }]; - const isCI = - process.env['CI'] === 'true' || process.env['TF_BUILD'] === 'True'; + const isCI = process.env['TF_BUILD'] === 'True'; const storybookConfig = defineConfig({ // Use export conditions to resolve workspace packages to src/ during testing @@ -85,8 +84,8 @@ export function createStorybookVitestConfig( ...(opts.additionalCoverageExclude ?? []), ], }, - // Disable watch mode and isolate tests to reduce file watchers and improve stability. - watch: false, + // Enable watch mode in local dev for faster iteration; disable in CI for stability + watch: !isCI, isolate: true, }, }); From cf36d9749597c9de63550fe4b8c250039a48e05a Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Thu, 18 Dec 2025 12:51:56 -0500 Subject: [PATCH 56/74] fix: update test exclusion patterns to include default config exclusions --- packages/cellix/vitest-config/src/configs/storybook.config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/cellix/vitest-config/src/configs/storybook.config.ts b/packages/cellix/vitest-config/src/configs/storybook.config.ts index 9a1b584cf..b098f17a4 100644 --- a/packages/cellix/vitest-config/src/configs/storybook.config.ts +++ b/packages/cellix/vitest-config/src/configs/storybook.config.ts @@ -1,6 +1,6 @@ import path from 'node:path'; import { storybookTest } from '@storybook/addon-vitest/vitest-plugin'; -import { defineConfig, mergeConfig } from 'vitest/config'; +import { defineConfig, mergeConfig, configDefaults } from 'vitest/config'; import type { UserConfig } from 'vite'; import { baseConfig } from './base.config.ts'; import { playwright } from '@vitest/browser-playwright'; @@ -37,7 +37,7 @@ export function createStorybookVitestConfig( test: { // Prevent Vite/Vitest from scanning/transpiling build artifacts and coverage temp files. // This greatly reduces the number of open files during coverage runs in CI. - exclude: ['**/dist/**', '**/coverage/**', '**/coverage/.tmp/**'], + exclude: [...configDefaults.exclude, '**/dist/**', '**/coverage/**', '**/coverage/.tmp/**'], globals: true, // Retry tests on failure to handle flaky browser tests due to race conditions // in @storybook/addon-vitest + Playwright browser provider From 47bb72c1aa6b0fcf27d14cc30b69b3824a6a6974 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Thu, 18 Dec 2025 16:57:19 -0500 Subject: [PATCH 57/74] fix storybook vulnerability --- apps/ui-sharethrift/package.json | 12 +- packages/cellix/ui-core/package.json | 14 +- packages/cellix/vitest-config/package.json | 2 +- packages/sthrift/ui-components/package.json | 14 +- pnpm-lock.yaml | 202 ++++++++++---------- 5 files changed, 122 insertions(+), 122 deletions(-) diff --git a/apps/ui-sharethrift/package.json b/apps/ui-sharethrift/package.json index 7f6702e35..446de32b5 100644 --- a/apps/ui-sharethrift/package.json +++ b/apps/ui-sharethrift/package.json @@ -37,11 +37,11 @@ "@chromatic-com/storybook": "^4.1.0", "@eslint/js": "^9.30.1", "@graphql-typed-document-node/core": "^3.2.0", - "@storybook/addon-a11y": "^9.1.1", - "@storybook/addon-docs": "^9.1.1", - "@storybook/addon-vitest": "^9.1.1", - "@storybook/react": "^9.1.10", - "@storybook/react-vite": "^9.1.1", + "@storybook/addon-a11y": "^9.1.17", + "@storybook/addon-docs": "^9.1.17", + "@storybook/addon-vitest": "^9.1.17", + "@storybook/react": "^9.1.17", + "@storybook/react-vite": "^9.1.17", "@testing-library/jest-dom": "^6.9.1", "@types/lodash": "^4.17.20", "@types/react": "^19.1.9", @@ -52,7 +52,7 @@ "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.20", "globals": "^16.3.0", - "storybook": "^9.1.1", + "storybook": "^9.1.17", "typescript": "~5.8.3", "typescript-eslint": "^8.35.1", "vite": "^7.1.2", diff --git a/packages/cellix/ui-core/package.json b/packages/cellix/ui-core/package.json index 28a1a7895..8de963fa0 100644 --- a/packages/cellix/ui-core/package.json +++ b/packages/cellix/ui-core/package.json @@ -39,19 +39,19 @@ "@cellix/typescript-config": "workspace:*", "@cellix/vitest-config": "workspace:*", "@chromatic-com/storybook": "^4.1.1", - "@storybook/addon-a11y": "^9.1.3", - "@storybook/addon-docs": "^9.1.3", - "@storybook/addon-onboarding": "^9.1.3", - "@storybook/addon-vitest": "^9.1.3", - "@storybook/react": "^9.1.9", - "@storybook/react-vite": "^9.1.3", + "@storybook/addon-a11y": "^9.1.17", + "@storybook/addon-docs": "^9.1.17", + "@storybook/addon-onboarding": "^9.1.17", + "@storybook/addon-vitest": "^9.1.17", + "@storybook/react": "^9.1.17", + "@storybook/react-vite": "^9.1.17", "@types/react": "^19.1.16", "@vitest/coverage-v8": "catalog:", "jsdom": "^26.1.0", "react-oidc-context": "^3.3.0", "react-router-dom": "^7.9.3", "rimraf": "^6.0.1", - "storybook": "^9.1.3", + "storybook": "^9.1.17", "typescript": "^5.8.3", "vitest": "catalog:" }, diff --git a/packages/cellix/vitest-config/package.json b/packages/cellix/vitest-config/package.json index 8a1da9ecc..9475be2d3 100644 --- a/packages/cellix/vitest-config/package.json +++ b/packages/cellix/vitest-config/package.json @@ -11,7 +11,7 @@ "build": "tsc --build" }, "dependencies": { - "@storybook/addon-vitest": "^9.1.10", + "@storybook/addon-vitest": "^9.1.17", "@vitest/browser-playwright": "catalog:", "vitest": "catalog:" }, diff --git a/packages/sthrift/ui-components/package.json b/packages/sthrift/ui-components/package.json index 6b17e7bbb..41eb3acf0 100644 --- a/packages/sthrift/ui-components/package.json +++ b/packages/sthrift/ui-components/package.json @@ -60,18 +60,18 @@ "@cellix/typescript-config": "workspace:*", "@cellix/vitest-config": "workspace:*", "@chromatic-com/storybook": "^4.1.1", - "@storybook/addon-a11y": "^9.1.3", - "@storybook/addon-docs": "^9.1.3", - "@storybook/addon-onboarding": "^9.1.3", - "@storybook/addon-vitest": "^9.1.3", - "@storybook/react": "^9.1.10", - "@storybook/react-vite": "^9.1.3", + "@storybook/addon-a11y": "^9.1.17", + "@storybook/addon-docs": "^9.1.17", + "@storybook/addon-onboarding": "^9.1.17", + "@storybook/addon-vitest": "^9.1.17", + "@storybook/react": "^9.1.17", + "@storybook/react-vite": "^9.1.17", "@types/react": "^19.1.11", "@types/react-dom": "^19.1.6", "@vitest/coverage-v8": "catalog:", "jsdom": "^26.1.0", "rimraf": "^6.0.1", - "storybook": "^9.1.3", + "storybook": "^9.1.17", "typescript": "^5.8.3", "vite": "^7.0.4", "vitest": "catalog:" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c1c55172f..39cb9793a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -301,7 +301,7 @@ importers: version: link:../../packages/cellix/vitest-config '@chromatic-com/storybook': specifier: ^4.1.0 - version: 4.1.2(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) + version: 4.1.2(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) '@eslint/js': specifier: ^9.30.1 version: 9.38.0 @@ -309,20 +309,20 @@ importers: specifier: ^3.2.0 version: 3.2.0(graphql@16.11.0) '@storybook/addon-a11y': - specifier: ^9.1.1 - version: 9.1.16(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) + specifier: ^9.1.17 + version: 9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) '@storybook/addon-docs': - specifier: ^9.1.1 - version: 9.1.16(@types/react@19.2.2)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) + specifier: ^9.1.17 + version: 9.1.17(@types/react@19.2.2)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) '@storybook/addon-vitest': - specifier: ^9.1.1 - version: 9.1.16(@vitest/browser-playwright@4.0.15)(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(@vitest/runner@4.0.15)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@4.0.15) + specifier: ^9.1.17 + version: 9.1.17(@vitest/browser-playwright@4.0.15)(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(@vitest/runner@4.0.15)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@4.0.15) '@storybook/react': - specifier: ^9.1.10 - version: 9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3) + specifier: ^9.1.17 + version: 9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3) '@storybook/react-vite': - specifier: ^9.1.1 - version: 9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.52.5)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + specifier: ^9.1.17 + version: 9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.52.5)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) '@testing-library/jest-dom': specifier: ^6.9.1 version: 6.9.1 @@ -354,8 +354,8 @@ importers: specifier: ^16.3.0 version: 16.4.0 storybook: - specifier: ^9.1.1 - version: 9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + specifier: ^9.1.17 + version: 9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) typescript: specifier: ~5.8.3 version: 5.8.3 @@ -592,25 +592,25 @@ importers: version: link:../vitest-config '@chromatic-com/storybook': specifier: ^4.1.1 - version: 4.1.2(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) + version: 4.1.2(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) '@storybook/addon-a11y': - specifier: ^9.1.3 - version: 9.1.16(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) + specifier: ^9.1.17 + version: 9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) '@storybook/addon-docs': - specifier: ^9.1.3 - version: 9.1.16(@types/react@19.2.2)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) + specifier: ^9.1.17 + version: 9.1.17(@types/react@19.2.2)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) '@storybook/addon-onboarding': - specifier: ^9.1.3 - version: 9.1.16(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) + specifier: ^9.1.17 + version: 9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) '@storybook/addon-vitest': - specifier: ^9.1.3 - version: 9.1.16(@vitest/browser-playwright@4.0.15)(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(@vitest/runner@4.0.15)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@4.0.15) + specifier: ^9.1.17 + version: 9.1.17(@vitest/browser-playwright@4.0.15)(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(@vitest/runner@4.0.15)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@4.0.15) '@storybook/react': - specifier: ^9.1.9 - version: 9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3) + specifier: ^9.1.17 + version: 9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3) '@storybook/react-vite': - specifier: ^9.1.3 - version: 9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.52.5)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + specifier: ^9.1.17 + version: 9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.52.5)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) '@types/react': specifier: ^19.1.16 version: 19.2.2 @@ -630,8 +630,8 @@ importers: specifier: ^6.0.1 version: 6.0.1 storybook: - specifier: ^9.1.3 - version: 9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + specifier: ^9.1.17 + version: 9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) typescript: specifier: ^5.8.3 version: 5.8.3 @@ -642,8 +642,8 @@ importers: packages/cellix/vitest-config: dependencies: '@storybook/addon-vitest': - specifier: ^9.1.10 - version: 9.1.16(@vitest/browser-playwright@4.0.15)(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(@vitest/runner@4.0.15)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@4.0.15) + specifier: ^9.1.17 + version: 9.1.17(@vitest/browser-playwright@4.0.15)(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(@vitest/runner@4.0.15)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@4.0.15) '@vitest/browser-playwright': specifier: 'catalog:' version: 4.0.15(playwright@1.56.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) @@ -1294,25 +1294,25 @@ importers: version: link:../../cellix/vitest-config '@chromatic-com/storybook': specifier: ^4.1.1 - version: 4.1.2(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) + version: 4.1.2(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) '@storybook/addon-a11y': - specifier: ^9.1.3 - version: 9.1.16(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) + specifier: ^9.1.17 + version: 9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) '@storybook/addon-docs': - specifier: ^9.1.3 - version: 9.1.16(@types/react@19.2.2)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) + specifier: ^9.1.17 + version: 9.1.17(@types/react@19.2.2)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) '@storybook/addon-onboarding': - specifier: ^9.1.3 - version: 9.1.16(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) + specifier: ^9.1.17 + version: 9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) '@storybook/addon-vitest': - specifier: ^9.1.3 - version: 9.1.16(@vitest/browser-playwright@4.0.15)(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(@vitest/runner@4.0.15)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@4.0.15) + specifier: ^9.1.17 + version: 9.1.17(@vitest/browser-playwright@4.0.15)(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(@vitest/runner@4.0.15)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@4.0.15) '@storybook/react': - specifier: ^9.1.10 - version: 9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3) + specifier: ^9.1.17 + version: 9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3) '@storybook/react-vite': - specifier: ^9.1.3 - version: 9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.52.5)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + specifier: ^9.1.17 + version: 9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.52.5)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) '@types/react': specifier: ^19.1.11 version: 19.2.2 @@ -1329,8 +1329,8 @@ importers: specifier: ^6.0.1 version: 6.0.1 storybook: - specifier: ^9.1.3 - version: 9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + specifier: ^9.1.17 + version: 9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) typescript: specifier: ^5.8.3 version: 5.8.3 @@ -4385,28 +4385,28 @@ packages: '@standard-schema/spec@1.0.0': resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} - '@storybook/addon-a11y@9.1.16': - resolution: {integrity: sha512-DpUqAMOgkC/K/DgB9osqbBYmiWWj7V444HeYLHcx7GdPtg2guq1jAcalsOnQeU3wXgUE+wNuyMm6qZKm7of11g==} + '@storybook/addon-a11y@9.1.17': + resolution: {integrity: sha512-xP2Nb+idph2r0wE2Lc3z7LjtyXxTS+U+mJWmS8hw5w0oU2TkVdV7Ew/V7/iNl5jIWMXIp9HCRmcJuKSSGuertA==} peerDependencies: - storybook: ^9.1.16 + storybook: ^9.1.17 - '@storybook/addon-docs@9.1.16': - resolution: {integrity: sha512-JfaUD6fC7ySLg5duRdaWZ0FUUXrgUvqbZe/agCbSyOaIHOtJdhGaPjOC3vuXTAcV8/8/wWmbu0iXFMD08iKvdw==} + '@storybook/addon-docs@9.1.17': + resolution: {integrity: sha512-yc4hlgkrwNi045qk210dRuIMijkgbLmo3ft6F4lOdpPRn4IUnPDj7FfZR8syGzUzKidxRfNtLx5m0yHIz83xtA==} peerDependencies: - storybook: ^9.1.16 + storybook: ^9.1.17 - '@storybook/addon-onboarding@9.1.16': - resolution: {integrity: sha512-vOACUkIRVQWH/RZyn0vvvu8f54j5JCXXjotzqpB4jWwi3SLSMAJLgSn01aOT9Z9rAHo7cXkN9WkG6xUFDG7YLA==} + '@storybook/addon-onboarding@9.1.17': + resolution: {integrity: sha512-TfpK+wsHX7DQyJ8tI3yEl56nolwne3lWmA5LjBl/AcYUkv87lNrQru47aqvRqnDUyLMWa/yhv3u/pzPomDxCsA==} peerDependencies: - storybook: ^9.1.16 + storybook: ^9.1.17 - '@storybook/addon-vitest@9.1.16': - resolution: {integrity: sha512-X0rOOUMb5UHbfekcjnTeiDTarZdsg5irXXPxxL//8QQCFyCLF6Bdm1YNlCdF560PtwaaQPXzlxByD0FfGbtdWA==} + '@storybook/addon-vitest@9.1.17': + resolution: {integrity: sha512-2EIvZPz0N+mnIUnUHW3+GIgwJRIqjZrK5BFyHsi82NhOQ1LCh/1GqbcB+kNoaiXioRcAgOsHUDWbQZrvyx3GhQ==} peerDependencies: '@vitest/browser': ^3.0.0 || ^4.0.0 '@vitest/browser-playwright': ^4.0.0 '@vitest/runner': ^3.0.0 || ^4.0.0 - storybook: ^9.1.16 + storybook: ^9.1.17 vitest: ^3.0.0 || ^4.0.0 peerDependenciesMeta: '@vitest/browser': @@ -4418,16 +4418,16 @@ packages: vitest: optional: true - '@storybook/builder-vite@9.1.16': - resolution: {integrity: sha512-CyvYA5w1BKeSVaRavKi+euWxLffshq0v9Rz/5E9MKCitbYtjwkDH6UMIYmcbTs906mEBuYqrbz3nygDP0ppodw==} + '@storybook/builder-vite@9.1.17': + resolution: {integrity: sha512-OQCYaFWoTBvovN2IJmkAW+7FgHMJiih1WA/xqgpKIx0ImZjB4z5FrKgzQeXsrYcLEsynyaj+xN3JFUKsz5bzGQ==} peerDependencies: - storybook: ^9.1.16 + storybook: ^9.1.17 vite: ^5.0.0 || ^6.0.0 || ^7.0.0 - '@storybook/csf-plugin@9.1.16': - resolution: {integrity: sha512-GKlNNlmWeFBQxhQY5hZOSnFGbeKq69jal0dYNWoSImTjor28eYRHb9iQkDzRpijLPizBaB9MlxLsLrgFDp7adA==} + '@storybook/csf-plugin@9.1.17': + resolution: {integrity: sha512-o+ebQDdSfZHDRDhu2hNDGhCLIazEB4vEAqJcHgz1VsURq+l++bgZUcKojPMCAbeblptSEz2bwS0eYAOvG7aSXg==} peerDependencies: - storybook: ^9.1.16 + storybook: ^9.1.17 '@storybook/global@5.0.0': resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==} @@ -4439,29 +4439,29 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - '@storybook/react-dom-shim@9.1.16': - resolution: {integrity: sha512-MsI4qTxdT6lMXQmo3IXhw3EaCC+vsZboyEZBx4pOJ+K/5cDJ6ZoQ3f0d4yGpVhumDxaxlnNAg954+f8WWXE1rQ==} + '@storybook/react-dom-shim@9.1.17': + resolution: {integrity: sha512-Ss/lNvAy0Ziynu+KniQIByiNuyPz3dq7tD62hqSC/pHw190X+M7TKU3zcZvXhx2AQx1BYyxtdSHIZapb+P5mxQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^9.1.16 + storybook: ^9.1.17 - '@storybook/react-vite@9.1.16': - resolution: {integrity: sha512-WRKSq0XfQ/Qx66aKisQCfa/1UKwN9HjVbY6xrmsX7kI5zBdITxIcKInq6PWoPv91SJD7+Et956yX+F86R1aEXw==} + '@storybook/react-vite@9.1.17': + resolution: {integrity: sha512-RZHsqD1mnTMo4MCJw68t3swS5BTMSTpeRhlelMwjoTEe7jJCPa+qx00uMlWliR1QBN1hMO8Y1dkchxSiUS9otA==} engines: {node: '>=20.0.0'} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^9.1.16 + storybook: ^9.1.17 vite: ^5.0.0 || ^6.0.0 || ^7.0.0 - '@storybook/react@9.1.16': - resolution: {integrity: sha512-M/SkHJJdtiGpodBJq9+DYmSkEOD+VqlPxKI+FvbHESTNs//1IgqFIjEWetd8quhd9oj/gvo4ICBAPu+UmD6M9w==} + '@storybook/react@9.1.17': + resolution: {integrity: sha512-TZCplpep5BwjHPIIcUOMHebc/2qKadJHYPisRn5Wppl014qgT3XkFLpYkFgY1BaRXtqw8Mn3gqq4M/49rQ7Iww==} engines: {node: '>=20.0.0'} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^9.1.16 + storybook: ^9.1.17 typescript: '>= 4.9.x' peerDependenciesMeta: typescript: @@ -10543,8 +10543,8 @@ packages: resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==} engines: {node: '>=4', npm: '>=6'} - storybook@9.1.16: - resolution: {integrity: sha512-339U14K6l46EFyRvaPS2ZlL7v7Pb+LlcXT8KAETrGPxq8v1sAjj2HAOB6zrlAK3M+0+ricssfAwsLCwt7Eg8TQ==} + storybook@9.1.17: + resolution: {integrity: sha512-kfr6kxQAjA96ADlH6FMALJwJ+eM80UqXy106yVHNgdsAP/CdzkkicglRAhZAvUycXK9AeadF6KZ00CWLtVMN4w==} hasBin: true peerDependencies: prettier: ^2 || ^3 @@ -13059,13 +13059,13 @@ snapshots: '@biomejs/cli-win32-x64@2.0.0': optional: true - '@chromatic-com/storybook@4.1.2(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))': + '@chromatic-com/storybook@4.1.2(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))': dependencies: '@neoconfetti/react': 1.0.0 chromatic: 12.2.0 filesize: 10.1.6 jsonfile: 6.2.0 - storybook: 9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + storybook: 9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) strip-ansi: 7.1.2 transitivePeerDependencies: - '@chromatic-com/cypress' @@ -16000,35 +16000,35 @@ snapshots: '@standard-schema/spec@1.0.0': {} - '@storybook/addon-a11y@9.1.16(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))': + '@storybook/addon-a11y@9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))': dependencies: '@storybook/global': 5.0.0 axe-core: 4.11.0 - storybook: 9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + storybook: 9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@storybook/addon-docs@9.1.16(@types/react@19.2.2)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))': + '@storybook/addon-docs@9.1.17(@types/react@19.2.2)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))': dependencies: '@mdx-js/react': 3.1.1(@types/react@19.2.2)(react@19.2.0) - '@storybook/csf-plugin': 9.1.16(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) + '@storybook/csf-plugin': 9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) '@storybook/icons': 1.6.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@storybook/react-dom-shim': 9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) + '@storybook/react-dom-shim': 9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - storybook: 9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + storybook: 9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) ts-dedent: 2.2.0 transitivePeerDependencies: - '@types/react' - '@storybook/addon-onboarding@9.1.16(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))': + '@storybook/addon-onboarding@9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))': dependencies: - storybook: 9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + storybook: 9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@storybook/addon-vitest@9.1.16(@vitest/browser-playwright@4.0.15)(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(@vitest/runner@4.0.15)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@4.0.15)': + '@storybook/addon-vitest@9.1.17(@vitest/browser-playwright@4.0.15)(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(@vitest/runner@4.0.15)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@4.0.15)': dependencies: '@storybook/global': 5.0.0 '@storybook/icons': 1.6.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) prompts: 2.4.2 - storybook: 9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + storybook: 9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) ts-dedent: 2.2.0 optionalDependencies: '@vitest/browser': 4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) @@ -16039,16 +16039,16 @@ snapshots: - react - react-dom - '@storybook/builder-vite@9.1.16(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': + '@storybook/builder-vite@9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': dependencies: - '@storybook/csf-plugin': 9.1.16(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) - storybook: 9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + '@storybook/csf-plugin': 9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) + storybook: 9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) ts-dedent: 2.2.0 vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - '@storybook/csf-plugin@9.1.16(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))': + '@storybook/csf-plugin@9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))': dependencies: - storybook: 9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + storybook: 9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) unplugin: 1.16.1 '@storybook/global@5.0.0': {} @@ -16058,25 +16058,25 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@storybook/react-dom-shim@9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))': + '@storybook/react-dom-shim@9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))': dependencies: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - storybook: 9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + storybook: 9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@storybook/react-vite@9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.52.5)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': + '@storybook/react-vite@9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.52.5)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': dependencies: '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.1(typescript@5.8.3)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) '@rollup/pluginutils': 5.3.0(rollup@4.52.5) - '@storybook/builder-vite': 9.1.16(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@storybook/react': 9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3) + '@storybook/builder-vite': 9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + '@storybook/react': 9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3) find-up: 7.0.0 magic-string: 0.30.21 react: 19.2.0 react-docgen: 8.0.2 react-dom: 19.2.0(react@19.2.0) resolve: 1.22.11 - storybook: 9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + storybook: 9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) tsconfig-paths: 4.2.0 vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) transitivePeerDependencies: @@ -16084,13 +16084,13 @@ snapshots: - supports-color - typescript - '@storybook/react@9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3)': + '@storybook/react@9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3)': dependencies: '@storybook/global': 5.0.0 - '@storybook/react-dom-shim': 9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) + '@storybook/react-dom-shim': 9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - storybook: 9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + storybook: 9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) optionalDependencies: typescript: 5.8.3 @@ -23423,7 +23423,7 @@ snapshots: stoppable@1.1.0: {} - storybook@9.1.16(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)): + storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)): dependencies: '@storybook/global': 5.0.0 '@testing-library/jest-dom': 6.9.1 From c906f9dcd9c44f6fb47724b9c39dfa6ba80ae827 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Thu, 18 Dec 2025 16:57:29 -0500 Subject: [PATCH 58/74] fix: add CI variable documentation in storybook configuration --- packages/cellix/vitest-config/src/configs/storybook.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/cellix/vitest-config/src/configs/storybook.config.ts b/packages/cellix/vitest-config/src/configs/storybook.config.ts index b098f17a4..61289dcaa 100644 --- a/packages/cellix/vitest-config/src/configs/storybook.config.ts +++ b/packages/cellix/vitest-config/src/configs/storybook.config.ts @@ -20,6 +20,7 @@ export function createStorybookVitestConfig( const setupFiles = opts.setupFiles ?? ['.storybook/vitest.setup.ts']; const instances = opts.browsers ?? [{ browser: 'chromium' }]; + // https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml const isCI = process.env['TF_BUILD'] === 'True'; const storybookConfig = defineConfig({ From a5935b6332a4773884eb4735b8cef1d8d465b0f3 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Tue, 6 Jan 2026 10:41:31 -0500 Subject: [PATCH 59/74] refactor mock creation function to reduce biome-ignore comments --- .../src/index.test.ts | 24 +++++++------ .../account-plan.repository.test.ts | 14 +++++--- .../conversation.repository.test.ts | 15 +++++--- .../reservation-request.repository.test.ts | 17 ++++++--- .../admin-user/admin-user.repository.test.ts | 36 +++++++++++-------- .../personal-user.repository.test.ts | 36 +++++++++++-------- .../service-otel/src/otel-builder.test.ts | 24 +++++++++---- 7 files changed, 106 insertions(+), 60 deletions(-) diff --git a/packages/sthrift/messaging-service-twilio/src/index.test.ts b/packages/sthrift/messaging-service-twilio/src/index.test.ts index c0aa40098..dff662339 100644 --- a/packages/sthrift/messaging-service-twilio/src/index.test.ts +++ b/packages/sthrift/messaging-service-twilio/src/index.test.ts @@ -3,6 +3,15 @@ import { ServiceMessagingTwilio } from './index'; // Mock the Twilio module vi.mock('twilio', () => { + const makeNewableMock = ( + impl: (...args: TArgs) => TResult, + ) => { + // biome-ignore lint/complexity/useArrowFunction: Needs to be a regular function to be constructable (Vitest 4 ctor mocking) + return vi.fn(function (...args: TArgs) { + return impl(...args); + }); + }; + // Mock data must be inside the factory const mockConversationData = { sid: 'CHtest123', @@ -43,20 +52,14 @@ vi.mock('twilio', () => { conversations: { v1: { conversations: Object.assign( - // biome-ignore lint/complexity/useArrowFunction: Vitest 4.x requires constructor function pattern - vi.fn(function () { - return mockConversationInstance; - }), + makeNewableMock(() => mockConversationInstance), mockConversationsApi, ), }, }, }; - // biome-ignore lint/complexity/useArrowFunction: Vitest 4.x requires constructor function pattern - const TwilioConstructor = vi.fn(function () { - return mockClient; - }); + const TwilioConstructor = makeNewableMock(() => mockClient); return { default: { @@ -91,9 +94,8 @@ describe('ServiceMessagingTwilio', () => { }); it('should create instance with empty credentials and warn', () => { - // biome-ignore lint/complexity/useArrowFunction: Vitest 4.x requires constructor function pattern - const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(function () { - // Mock implementation + const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { + // empty implementation }); service = new ServiceMessagingTwilio('', ''); expect(service).toBeDefined(); diff --git a/packages/sthrift/persistence/src/datasources/domain/account-plan/account-plan/account-plan.repository.test.ts b/packages/sthrift/persistence/src/datasources/domain/account-plan/account-plan/account-plan.repository.test.ts index f9ed634b4..04a465c55 100644 --- a/packages/sthrift/persistence/src/datasources/domain/account-plan/account-plan/account-plan.repository.test.ts +++ b/packages/sthrift/persistence/src/datasources/domain/account-plan/account-plan/account-plan.repository.test.ts @@ -44,6 +44,15 @@ function makeEventBus(): DomainSeedwork.EventBus { } as DomainSeedwork.EventBus); } +function makeNewableMock( + impl: (...args: TArgs) => TResult, +) { + // biome-ignore lint/complexity/useArrowFunction: Needs to be a regular function to be constructable (Vitest 4 ctor mocking) + return vi.fn(function (...args: TArgs) { + return impl(...args); + }); +} + function makeAccountPlanDoc( id = 'plan-1', name = 'Basic Plan', @@ -277,10 +286,7 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { }; repository = setupAccountPlanRepo(mockDoc, { - // Use a real constructor function for the model mock - // Use a proper constructor function for Vitest 4.x compatibility - // biome-ignore lint/complexity/useArrowFunction: Constructor function must be a regular function - modelCtor: vi.fn(function() { return mockNewDoc; }) as unknown as Models.AccountPlan.AccountPlanModelType, + modelCtor: makeNewableMock(() => mockNewDoc) as unknown as Models.AccountPlan.AccountPlanModelType, }); result = await repository.getNewInstance(planInfo); diff --git a/packages/sthrift/persistence/src/datasources/domain/conversation/conversation/conversation.repository.test.ts b/packages/sthrift/persistence/src/datasources/domain/conversation/conversation/conversation.repository.test.ts index b8a090d59..04088ef67 100644 --- a/packages/sthrift/persistence/src/datasources/domain/conversation/conversation/conversation.repository.test.ts +++ b/packages/sthrift/persistence/src/datasources/domain/conversation/conversation/conversation.repository.test.ts @@ -39,6 +39,15 @@ function makeEventBus(): DomainSeedwork.EventBus { return vi.mocked({ dispatch: vi.fn(), register: vi.fn() } as DomainSeedwork.EventBus); } +function makeNewableMock( + impl: (...args: TArgs) => TResult, +) { + // biome-ignore lint/complexity/useArrowFunction: Needs to be a regular function to be constructable (Vitest 4 ctor mocking) + return vi.fn(function (...args: TArgs) { + return impl(...args); + }); +} + function makeUserDoc(id: string): Models.User.PersonalUser { const validId = createValidObjectId(id); return { @@ -352,10 +361,8 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { }); // Setup repository with constructor mock - repository = setupConversationRepo(mockDoc, { - // Use a proper constructor function for Vitest 4.x compatibility - // biome-ignore lint/complexity/useArrowFunction: Constructor function must be a regular function - modelCtor: vi.fn(function() { return mockNewDoc; }) as unknown as Models.Conversation.ConversationModelType + repository = setupConversationRepo(mockDoc, { + modelCtor: makeNewableMock(() => mockNewDoc) as unknown as Models.Conversation.ConversationModelType, }); result = await repository.getNewInstance(sharer, reserver, listing); diff --git a/packages/sthrift/persistence/src/datasources/domain/reservation-request/reservation-request/reservation-request.repository.test.ts b/packages/sthrift/persistence/src/datasources/domain/reservation-request/reservation-request/reservation-request.repository.test.ts index 1649cfd48..2902a1465 100644 --- a/packages/sthrift/persistence/src/datasources/domain/reservation-request/reservation-request/reservation-request.repository.test.ts +++ b/packages/sthrift/persistence/src/datasources/domain/reservation-request/reservation-request/reservation-request.repository.test.ts @@ -39,6 +39,15 @@ function makeEventBus(): DomainSeedwork.EventBus { return vi.mocked({ dispatch: vi.fn(), register: vi.fn() } as DomainSeedwork.EventBus); } +function makeNewableMock( + impl: (...args: TArgs) => TResult, +) { + // biome-ignore lint/complexity/useArrowFunction: Needs to be a regular function to be constructable (Vitest 4 ctor mocking) + return vi.fn(function (...args: TArgs) { + return impl(...args); + }); +} + function makeUserDoc(id: string): Models.User.PersonalUser { const validId = createValidObjectId(id); return { @@ -294,11 +303,9 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { set: vi.fn(), }; - // Setup repository with constructor mock - repository = setupReservationRequestRepo(mockDoc, { - // Use a proper constructor function for Vitest 4.x compatibility - // biome-ignore lint/complexity/useArrowFunction: Constructor function must be a regular function - modelCtor: vi.fn(function() { return mockNewDoc; }) as unknown as Models.ReservationRequest.ReservationRequestModelType + // Setup repository with constructor mock + repository = setupReservationRequestRepo(mockDoc, { + modelCtor: makeNewableMock(() => mockNewDoc) as unknown as Models.ReservationRequest.ReservationRequestModelType, }); result = await repository.getNewInstance( diff --git a/packages/sthrift/persistence/src/datasources/domain/user/admin-user/admin-user.repository.test.ts b/packages/sthrift/persistence/src/datasources/domain/user/admin-user/admin-user.repository.test.ts index 8db033421..ab1d4fe80 100644 --- a/packages/sthrift/persistence/src/datasources/domain/user/admin-user/admin-user.repository.test.ts +++ b/packages/sthrift/persistence/src/datasources/domain/user/admin-user/admin-user.repository.test.ts @@ -32,6 +32,15 @@ function makeEventBus(): DomainSeedwork.EventBus { } as DomainSeedwork.EventBus); } +function makeNewableMock( + impl: (...args: TArgs) => TResult, +) { + // biome-ignore lint/complexity/useArrowFunction: Needs to be a regular function to be constructable (Vitest 4 ctor mocking) + return vi.fn(function (...args: TArgs) { + return impl(...args); + }); +} + function makeSession(): mongoose.ClientSession { return vi.mocked({} as mongoose.ClientSession); } @@ -168,22 +177,19 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { 'I call getNewInstance with email "newadmin@example.com", username "newadmin", firstName "New", and lastName "Admin"', async () => { const newDoc = { ...mockDoc }; - // Create a proper constructor function mock - // Use a proper constructor function for Vitest 4.x compatibility - // biome-ignore lint/complexity/useArrowFunction: Constructor function must be a regular function - const ModelConstructor = vi.fn(function() { return newDoc; }); - Object.assign(ModelConstructor, { - findOne: mockModel.findOne, - findById: mockModel.findById, - }); + const ModelConstructor = makeNewableMock(() => newDoc); + Object.assign(ModelConstructor, { + findOne: mockModel.findOne, + findById: mockModel.findById, + }); - repository = new AdminUserRepository( - passport, - ModelConstructor as unknown as Models.User.AdminUserModelType, - new AdminUserConverter(), - eventBus, - session, - ); + repository = new AdminUserRepository( + passport, + ModelConstructor as unknown as Models.User.AdminUserModelType, + new AdminUserConverter(), + eventBus, + session, + ); result = await repository.getNewInstance( 'newadmin@example.com', 'newadmin', diff --git a/packages/sthrift/persistence/src/datasources/domain/user/personal-user/personal-user.repository.test.ts b/packages/sthrift/persistence/src/datasources/domain/user/personal-user/personal-user.repository.test.ts index 1ba5ecb2e..5c2c2d583 100644 --- a/packages/sthrift/persistence/src/datasources/domain/user/personal-user/personal-user.repository.test.ts +++ b/packages/sthrift/persistence/src/datasources/domain/user/personal-user/personal-user.repository.test.ts @@ -32,6 +32,15 @@ function makeEventBus(): DomainSeedwork.EventBus { } as DomainSeedwork.EventBus); } +function makeNewableMock( + impl: (...args: TArgs) => TResult, +) { + // biome-ignore lint/complexity/useArrowFunction: Needs to be a regular function to be constructable (Vitest 4 ctor mocking) + return vi.fn(function (...args: TArgs) { + return impl(...args); + }); +} + function makeSession(): mongoose.ClientSession { return vi.mocked({} as mongoose.ClientSession); } @@ -178,22 +187,19 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { 'I call getNewInstance with email "new@example.com", firstName "New", and lastName "User"', async () => { const newDoc = { ...mockDoc }; - // Create a proper constructor function mock - // Use a proper constructor function for Vitest 4.x compatibility - // biome-ignore lint/complexity/useArrowFunction: Constructor function must be a regular function - const ModelConstructor = vi.fn(function() { return newDoc; }); - Object.assign(ModelConstructor, { - findOne: mockModel.findOne, - findById: mockModel.findById, - }); + const ModelConstructor = makeNewableMock(() => newDoc); + Object.assign(ModelConstructor, { + findOne: mockModel.findOne, + findById: mockModel.findById, + }); - repository = new PersonalUserRepository( - passport, - ModelConstructor as unknown as Models.User.PersonalUserModelType, - new PersonalUserConverter(), - eventBus, - session, - ); + repository = new PersonalUserRepository( + passport, + ModelConstructor as unknown as Models.User.PersonalUserModelType, + new PersonalUserConverter(), + eventBus, + session, + ); result = await repository.getNewInstance( 'new@example.com', 'New', diff --git a/packages/sthrift/service-otel/src/otel-builder.test.ts b/packages/sthrift/service-otel/src/otel-builder.test.ts index c1eac3af8..c967dfd04 100644 --- a/packages/sthrift/service-otel/src/otel-builder.test.ts +++ b/packages/sthrift/service-otel/src/otel-builder.test.ts @@ -37,12 +37,24 @@ vi.mock('@azure/monitor-opentelemetry-exporter', () => { } } - // biome-ignore lint/complexity/useArrowFunction: Vitest 4.x requires constructor function pattern - const AzureMonitorTraceExporter = vi.fn(function (args: Record) {return new MockExporter(args)}); - // biome-ignore lint/complexity/useArrowFunction: Vitest 4.x requires constructor function pattern - const AzureMonitorMetricExporter = vi.fn(function (args: Record) {return new MockExporter(args)}); - // biome-ignore lint/complexity/useArrowFunction: Vitest 4.x requires constructor function pattern - const AzureMonitorLogExporter = vi.fn(function (args: Record) {return new MockExporter(args)}); + const makeNewableMock = ( + impl: (...args: TArgs) => TResult, + ) => { + // biome-ignore lint/complexity/useArrowFunction: Needs to be a regular function to be constructable (Vitest 4 ctor mocking) + return vi.fn(function (...args: TArgs) { + return impl(...args); + }); + }; + + const AzureMonitorTraceExporter = makeNewableMock( + (args: Record) => new MockExporter(args), + ); + const AzureMonitorMetricExporter = makeNewableMock( + (args: Record) => new MockExporter(args), + ); + const AzureMonitorLogExporter = makeNewableMock( + (args: Record) => new MockExporter(args), + ); return { AzureMonitorTraceExporter, From aa537a488d0f6d13325abef08d41669ba0e9987d Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Tue, 6 Jan 2026 14:29:35 -0500 Subject: [PATCH 60/74] refactor makeNewableMock into a package to reduce duplication --- .../mongo-unit-of-work.test.ts | 4 +-- packages/cellix/test-utils/.gitignore | 5 +++ packages/cellix/test-utils/.prettierrc.json | 7 +++++ packages/cellix/test-utils/package.json | 31 +++++++++++++++++++ packages/cellix/test-utils/readme.md | 1 + packages/cellix/test-utils/src/index.ts | 14 +++++++++ packages/cellix/test-utils/tsconfig.json | 9 ++++++ packages/cellix/test-utils/turbo.json | 3 ++ .../graphql/src/schema/resolver-helper.ts | 2 -- packages/sthrift/persistence/package.json | 4 ++- .../account-plan.repository.test.ts | 10 ++---- .../conversation.repository.test.ts | 10 ++---- .../reservation-request.repository.test.ts | 10 ++---- .../admin-user/admin-user.repository.test.ts | 10 ++---- .../personal-user.repository.test.ts | 10 ++---- packages/sthrift/service-otel/package.json | 6 ++-- .../service-otel/src/otel-builder.test.ts | 17 +++------- pnpm-lock.yaml | 29 +++++++++++++++++ 18 files changed, 122 insertions(+), 60 deletions(-) create mode 100644 packages/cellix/test-utils/.gitignore create mode 100644 packages/cellix/test-utils/.prettierrc.json create mode 100644 packages/cellix/test-utils/package.json create mode 100644 packages/cellix/test-utils/readme.md create mode 100644 packages/cellix/test-utils/src/index.ts create mode 100644 packages/cellix/test-utils/tsconfig.json create mode 100644 packages/cellix/test-utils/turbo.json diff --git a/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts b/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts index 58f5d50b9..61fec263c 100644 --- a/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts +++ b/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts @@ -82,7 +82,7 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { class TestRepoClass extends RepoMock {} let domainOperation: RepoOpMock; - function setupMockModelReturningAggregate() { + const setupMockModelReturningAggregate = () => { (mockModel.findById as ReturnType).mockReturnValue({ exec: vi.fn().mockResolvedValue({ _id: 'agg-1', @@ -91,7 +91,7 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { }); } - function setupRepoNoEvents() { + const setupRepoNoEvents = () => { repoInstance.getIntegrationEvents = vi.fn(() => []) as typeof repoInstance.getIntegrationEvents; repoInstance.get = vi.fn().mockResolvedValue( new AggregateRootMock( diff --git a/packages/cellix/test-utils/.gitignore b/packages/cellix/test-utils/.gitignore new file mode 100644 index 000000000..47069c6ec --- /dev/null +++ b/packages/cellix/test-utils/.gitignore @@ -0,0 +1,5 @@ +/dist +/node_modules + +tsconfig.tsbuidinfo +.turbo \ No newline at end of file diff --git a/packages/cellix/test-utils/.prettierrc.json b/packages/cellix/test-utils/.prettierrc.json new file mode 100644 index 000000000..8bbdcf3b2 --- /dev/null +++ b/packages/cellix/test-utils/.prettierrc.json @@ -0,0 +1,7 @@ +{ + "tabWidth": 2, + "useTabs": false, + "jsxSingleQuote": false, + "singleQuote": false, + "printWidth": 150 +} diff --git a/packages/cellix/test-utils/package.json b/packages/cellix/test-utils/package.json new file mode 100644 index 000000000..ea6e17b77 --- /dev/null +++ b/packages/cellix/test-utils/package.json @@ -0,0 +1,31 @@ +{ + "name": "@cellix/test-utils", + "version": "1.0.0", + "private": true, + "type": "module", + "files": [ + "dist" + ], + "exports": { + ".": { + "types": "./dist/src/index.d.ts", + "default": "./dist/src/index.js" + } + }, + "scripts": { + "prebuild": "biome lint", + "build": "tsc --build", + "watch": "tsc --watch", + "lint": "biome lint", + "clean": "rimraf dist" + }, + "devDependencies": { + "rimraf": "^6.0.1", + "typescript": "^5.8.3", + "eslint": "^9.29.0", + "@eslint/js": "^9.29.0", + "typescript-eslint": "^8.34.0", + "@cellix/typescript-config": "workspace:*" + }, + "license": "MIT" +} diff --git a/packages/cellix/test-utils/readme.md b/packages/cellix/test-utils/readme.md new file mode 100644 index 000000000..4ec03ecc5 --- /dev/null +++ b/packages/cellix/test-utils/readme.md @@ -0,0 +1 @@ +npm i -D -w test-utils @tsconfig/node20 @tsconfig/node-ts typescript \ No newline at end of file diff --git a/packages/cellix/test-utils/src/index.ts b/packages/cellix/test-utils/src/index.ts new file mode 100644 index 000000000..898026ff8 --- /dev/null +++ b/packages/cellix/test-utils/src/index.ts @@ -0,0 +1,14 @@ +// Note: Do not use inside vi.mock() calls to avoid hoisting issues. +export function makeNewableMock( + impl: (...args: TArgs) => TResult, +) { + // Use a normal function so it can be used as a constructor with `new`. + // Keep the implementation minimal to match the localized helper used in tests. + // eslint-disable-next-line func-names + const fn = function (this: unknown, ...args: TArgs) { + // @ts-ignore - tests expect the function to return mocked instances + return impl(...(args as TArgs)); + } as unknown as (...args: TArgs) => TResult; + + return fn as unknown as (...args: TArgs) => TResult; +} diff --git a/packages/cellix/test-utils/tsconfig.json b/packages/cellix/test-utils/tsconfig.json new file mode 100644 index 000000000..d979e1092 --- /dev/null +++ b/packages/cellix/test-utils/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "@cellix/typescript-config/node.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "." + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/cellix/test-utils/turbo.json b/packages/cellix/test-utils/turbo.json new file mode 100644 index 000000000..a87e1a781 --- /dev/null +++ b/packages/cellix/test-utils/turbo.json @@ -0,0 +1,3 @@ +{ + "extends": ["//"] +} \ No newline at end of file diff --git a/packages/sthrift/graphql/src/schema/resolver-helper.ts b/packages/sthrift/graphql/src/schema/resolver-helper.ts index ca4f9c5c1..350a90370 100644 --- a/packages/sthrift/graphql/src/schema/resolver-helper.ts +++ b/packages/sthrift/graphql/src/schema/resolver-helper.ts @@ -106,7 +106,6 @@ export const extractUserProfileFromJwt = (context: GraphContext): { * Used for GraphQL field resolvers that need to resolve User union types. */ export const PopulateUserFromField = (fieldName: string) => { - // biome-ignore lint/suspicious/noExplicitAny: parent can be various types with dynamic field access return async (parent: any, _: unknown, context: GraphContext) => { if (parent[fieldName] && isValidObjectId(parent[fieldName].id)) { const userId = parent[fieldName].id; @@ -142,7 +141,6 @@ export const PopulateUserFromField = (fieldName: string) => { }; export const PopulateItemListingFromField = (fieldName: string) => { - // biome-ignore lint/suspicious/noExplicitAny: parent can be various types with dynamic field access return async (parent: any, _: unknown, context: GraphContext) => { if (parent[fieldName] && isValidObjectId(parent[fieldName].id)) { return await context.applicationServices.Listing.ItemListing.queryById({ diff --git a/packages/sthrift/persistence/package.json b/packages/sthrift/persistence/package.json index 2fcf2f3cf..aebf9ee0a 100644 --- a/packages/sthrift/persistence/package.json +++ b/packages/sthrift/persistence/package.json @@ -31,7 +31,9 @@ "@sthrift/data-sources-mongoose-models": "workspace:*", "@sthrift/domain": "workspace:*", "mongodb": "catalog:", - "mongoose": "catalog:" + "mongoose": "catalog:", + "@cellix/test-utils": "workspace:*" + }, "devDependencies": { "@cellix/typescript-config": "workspace:*", diff --git a/packages/sthrift/persistence/src/datasources/domain/account-plan/account-plan/account-plan.repository.test.ts b/packages/sthrift/persistence/src/datasources/domain/account-plan/account-plan/account-plan.repository.test.ts index 04a465c55..9347a4c39 100644 --- a/packages/sthrift/persistence/src/datasources/domain/account-plan/account-plan/account-plan.repository.test.ts +++ b/packages/sthrift/persistence/src/datasources/domain/account-plan/account-plan/account-plan.repository.test.ts @@ -9,6 +9,7 @@ import type mongoose from 'mongoose'; import { expect, vi } from 'vitest'; import { AccountPlanConverter } from './account-plan.domain-adapter.ts'; import { AccountPlanRepository } from './account-plan.repository.ts'; +import { makeNewableMock } from '@cellix/test-utils'; const test = { for: describeFeature }; const __dirname = path.dirname(fileURLToPath(import.meta.url)); @@ -44,14 +45,7 @@ function makeEventBus(): DomainSeedwork.EventBus { } as DomainSeedwork.EventBus); } -function makeNewableMock( - impl: (...args: TArgs) => TResult, -) { - // biome-ignore lint/complexity/useArrowFunction: Needs to be a regular function to be constructable (Vitest 4 ctor mocking) - return vi.fn(function (...args: TArgs) { - return impl(...args); - }); -} +// use shared makeNewableMock from test-utils function makeAccountPlanDoc( id = 'plan-1', diff --git a/packages/sthrift/persistence/src/datasources/domain/conversation/conversation/conversation.repository.test.ts b/packages/sthrift/persistence/src/datasources/domain/conversation/conversation/conversation.repository.test.ts index 04088ef67..9927b438b 100644 --- a/packages/sthrift/persistence/src/datasources/domain/conversation/conversation/conversation.repository.test.ts +++ b/packages/sthrift/persistence/src/datasources/domain/conversation/conversation/conversation.repository.test.ts @@ -7,6 +7,7 @@ import { Domain } from '@sthrift/domain'; import type mongoose from 'mongoose'; import { MongooseSeedwork } from '@cellix/mongoose-seedwork'; import { expect, vi } from 'vitest'; +import { makeNewableMock } from '@cellix/test-utils'; import { ConversationConverter } from './conversation.domain-adapter.ts'; import { ConversationRepository } from './conversation.repository.ts'; @@ -39,14 +40,7 @@ function makeEventBus(): DomainSeedwork.EventBus { return vi.mocked({ dispatch: vi.fn(), register: vi.fn() } as DomainSeedwork.EventBus); } -function makeNewableMock( - impl: (...args: TArgs) => TResult, -) { - // biome-ignore lint/complexity/useArrowFunction: Needs to be a regular function to be constructable (Vitest 4 ctor mocking) - return vi.fn(function (...args: TArgs) { - return impl(...args); - }); -} +// use shared makeNewableMock from test-utils function makeUserDoc(id: string): Models.User.PersonalUser { const validId = createValidObjectId(id); diff --git a/packages/sthrift/persistence/src/datasources/domain/reservation-request/reservation-request/reservation-request.repository.test.ts b/packages/sthrift/persistence/src/datasources/domain/reservation-request/reservation-request/reservation-request.repository.test.ts index 2902a1465..c9615af20 100644 --- a/packages/sthrift/persistence/src/datasources/domain/reservation-request/reservation-request/reservation-request.repository.test.ts +++ b/packages/sthrift/persistence/src/datasources/domain/reservation-request/reservation-request/reservation-request.repository.test.ts @@ -7,6 +7,7 @@ import { Domain } from '@sthrift/domain'; import type mongoose from 'mongoose'; import { MongooseSeedwork } from '@cellix/mongoose-seedwork'; import { expect, vi } from 'vitest'; +import { makeNewableMock } from '@cellix/test-utils'; import { ReservationRequestConverter } from './reservation-request.domain-adapter.ts'; import { ReservationRequestRepository } from './reservation-request.repository.ts'; @@ -39,14 +40,7 @@ function makeEventBus(): DomainSeedwork.EventBus { return vi.mocked({ dispatch: vi.fn(), register: vi.fn() } as DomainSeedwork.EventBus); } -function makeNewableMock( - impl: (...args: TArgs) => TResult, -) { - // biome-ignore lint/complexity/useArrowFunction: Needs to be a regular function to be constructable (Vitest 4 ctor mocking) - return vi.fn(function (...args: TArgs) { - return impl(...args); - }); -} +// use shared makeNewableMock from test-utils function makeUserDoc(id: string): Models.User.PersonalUser { const validId = createValidObjectId(id); diff --git a/packages/sthrift/persistence/src/datasources/domain/user/admin-user/admin-user.repository.test.ts b/packages/sthrift/persistence/src/datasources/domain/user/admin-user/admin-user.repository.test.ts index ab1d4fe80..26781d062 100644 --- a/packages/sthrift/persistence/src/datasources/domain/user/admin-user/admin-user.repository.test.ts +++ b/packages/sthrift/persistence/src/datasources/domain/user/admin-user/admin-user.repository.test.ts @@ -6,6 +6,7 @@ import type { Models } from '@sthrift/data-sources-mongoose-models'; import { Domain } from '@sthrift/domain'; import type mongoose from 'mongoose'; import { expect, vi } from 'vitest'; +import { makeNewableMock } from '@cellix/test-utils'; import { AdminUserConverter } from './admin-user.domain-adapter.ts'; import { AdminUserRepository } from './admin-user.repository.ts'; @@ -32,14 +33,7 @@ function makeEventBus(): DomainSeedwork.EventBus { } as DomainSeedwork.EventBus); } -function makeNewableMock( - impl: (...args: TArgs) => TResult, -) { - // biome-ignore lint/complexity/useArrowFunction: Needs to be a regular function to be constructable (Vitest 4 ctor mocking) - return vi.fn(function (...args: TArgs) { - return impl(...args); - }); -} +// use shared makeNewableMock from test-utils function makeSession(): mongoose.ClientSession { return vi.mocked({} as mongoose.ClientSession); diff --git a/packages/sthrift/persistence/src/datasources/domain/user/personal-user/personal-user.repository.test.ts b/packages/sthrift/persistence/src/datasources/domain/user/personal-user/personal-user.repository.test.ts index 5c2c2d583..dbc0cecfd 100644 --- a/packages/sthrift/persistence/src/datasources/domain/user/personal-user/personal-user.repository.test.ts +++ b/packages/sthrift/persistence/src/datasources/domain/user/personal-user/personal-user.repository.test.ts @@ -6,6 +6,7 @@ import type { Models } from '@sthrift/data-sources-mongoose-models'; import { Domain } from '@sthrift/domain'; import type mongoose from 'mongoose'; import { expect, vi } from 'vitest'; +import { makeNewableMock } from '@cellix/test-utils'; import { PersonalUserConverter } from './personal-user.domain-adapter.ts'; import { PersonalUserRepository } from './personal-user.repository.ts'; @@ -32,14 +33,7 @@ function makeEventBus(): DomainSeedwork.EventBus { } as DomainSeedwork.EventBus); } -function makeNewableMock( - impl: (...args: TArgs) => TResult, -) { - // biome-ignore lint/complexity/useArrowFunction: Needs to be a regular function to be constructable (Vitest 4 ctor mocking) - return vi.fn(function (...args: TArgs) { - return impl(...args); - }); -} +// use shared makeNewableMock from test-utils function makeSession(): mongoose.ClientSession { return vi.mocked({} as mongoose.ClientSession); diff --git a/packages/sthrift/service-otel/package.json b/packages/sthrift/service-otel/package.json index 29c414f7a..f74fe0a0a 100644 --- a/packages/sthrift/service-otel/package.json +++ b/packages/sthrift/service-otel/package.json @@ -35,13 +35,15 @@ "@opentelemetry/sdk-metrics": "1.30.1", "@opentelemetry/sdk-node": "0.57.2", "@opentelemetry/sdk-trace-node": "1.30.1", - "@opentelemetry/semantic-conventions": "1.28.0" + "@opentelemetry/semantic-conventions": "1.28.0", + "@cellix/test-utils": "workspace:*" }, "devDependencies": { "@cellix/typescript-config": "workspace:*", "@cellix/vitest-config": "workspace:*", "rimraf": "^6.0.1", - "typescript": "^5.8.3" + "typescript": "^5.8.3", + "@cellix/test-utils": "workspace:*" }, "license": "MIT" } diff --git a/packages/sthrift/service-otel/src/otel-builder.test.ts b/packages/sthrift/service-otel/src/otel-builder.test.ts index c967dfd04..dc7edfcad 100644 --- a/packages/sthrift/service-otel/src/otel-builder.test.ts +++ b/packages/sthrift/service-otel/src/otel-builder.test.ts @@ -15,7 +15,6 @@ import { MongooseInstrumentation } from '@opentelemetry/instrumentation-mongoose import { expect, vi } from 'vitest'; import { OtelBuilder } from './otel-builder.ts'; - /** * Type for mock exporter class used in tests. * The actual class is defined inside vi.mock() to avoid hoisting issues. @@ -37,24 +36,16 @@ vi.mock('@azure/monitor-opentelemetry-exporter', () => { } } - const makeNewableMock = ( - impl: (...args: TArgs) => TResult, - ) => { + const makeNewableMock = (impl: (...args: TArgs) => TResult) => { // biome-ignore lint/complexity/useArrowFunction: Needs to be a regular function to be constructable (Vitest 4 ctor mocking) return vi.fn(function (...args: TArgs) { return impl(...args); }); }; - const AzureMonitorTraceExporter = makeNewableMock( - (args: Record) => new MockExporter(args), - ); - const AzureMonitorMetricExporter = makeNewableMock( - (args: Record) => new MockExporter(args), - ); - const AzureMonitorLogExporter = makeNewableMock( - (args: Record) => new MockExporter(args), - ); + const AzureMonitorTraceExporter = makeNewableMock((args: Record) => new MockExporter(args)); + const AzureMonitorMetricExporter = makeNewableMock((args: Record) => new MockExporter(args)); + const AzureMonitorLogExporter = makeNewableMock((args: Record) => new MockExporter(args)); return { AzureMonitorTraceExporter, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 37870d199..b8f00b207 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -573,6 +573,27 @@ importers: specifier: workspace:* version: link:../typescript-config + packages/cellix/test-utils: + devDependencies: + '@cellix/typescript-config': + specifier: workspace:* + version: link:../typescript-config + '@eslint/js': + specifier: ^9.29.0 + version: 9.38.0 + eslint: + specifier: ^9.29.0 + version: 9.38.0(jiti@2.6.1) + rimraf: + specifier: ^6.0.1 + version: 6.0.1 + typescript: + specifier: ^5.8.3 + version: 5.8.3 + typescript-eslint: + specifier: ^8.34.0 + version: 8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.8.3) + packages/cellix/typescript-config: {} packages/cellix/ui-core: @@ -1065,6 +1086,9 @@ importers: '@cellix/payment-service': specifier: workspace:* version: link:../../cellix/payment-service + '@cellix/test-utils': + specifier: workspace:* + version: link:../../cellix/test-utils '@sthrift/data-sources-mongoose-models': specifier: workspace:* version: link:../data-sources-mongoose-models @@ -1198,6 +1222,9 @@ importers: '@opentelemetry/semantic-conventions': specifier: 1.28.0 version: 1.28.0 + '@cellix/test-utils': + specifier: workspace:* + version: link:../../cellix/test-utils devDependencies: '@cellix/typescript-config': specifier: workspace:* @@ -10182,6 +10209,7 @@ packages: scmp@2.1.0: resolution: {integrity: sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==} + deprecated: Just use Node.js's crypto.timingSafeEqual() scroll-into-view-if-needed@3.1.0: resolution: {integrity: sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==} @@ -11468,6 +11496,7 @@ packages: whatwg-encoding@3.1.1: resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} engines: {node: '>=18'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation whatwg-mimetype@4.0.0: resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} From 79b56e44184f37523c9be11f5e94eee56087825c Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Tue, 6 Jan 2026 14:34:29 -0500 Subject: [PATCH 61/74] remove unused dependencies --- packages/sthrift/service-otel/package.json | 6 ++---- pnpm-lock.yaml | 3 --- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/sthrift/service-otel/package.json b/packages/sthrift/service-otel/package.json index f74fe0a0a..29c414f7a 100644 --- a/packages/sthrift/service-otel/package.json +++ b/packages/sthrift/service-otel/package.json @@ -35,15 +35,13 @@ "@opentelemetry/sdk-metrics": "1.30.1", "@opentelemetry/sdk-node": "0.57.2", "@opentelemetry/sdk-trace-node": "1.30.1", - "@opentelemetry/semantic-conventions": "1.28.0", - "@cellix/test-utils": "workspace:*" + "@opentelemetry/semantic-conventions": "1.28.0" }, "devDependencies": { "@cellix/typescript-config": "workspace:*", "@cellix/vitest-config": "workspace:*", "rimraf": "^6.0.1", - "typescript": "^5.8.3", - "@cellix/test-utils": "workspace:*" + "typescript": "^5.8.3" }, "license": "MIT" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b8f00b207..39492b095 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1222,9 +1222,6 @@ importers: '@opentelemetry/semantic-conventions': specifier: 1.28.0 version: 1.28.0 - '@cellix/test-utils': - specifier: workspace:* - version: link:../../cellix/test-utils devDependencies: '@cellix/typescript-config': specifier: workspace:* From cfe5b6cf81645af1a23aa02b94ce116c4c4385a6 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Tue, 6 Jan 2026 14:43:28 -0500 Subject: [PATCH 62/74] remove unused devDeps --- packages/cellix/test-utils/package.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/cellix/test-utils/package.json b/packages/cellix/test-utils/package.json index ea6e17b77..72171a464 100644 --- a/packages/cellix/test-utils/package.json +++ b/packages/cellix/test-utils/package.json @@ -22,9 +22,6 @@ "devDependencies": { "rimraf": "^6.0.1", "typescript": "^5.8.3", - "eslint": "^9.29.0", - "@eslint/js": "^9.29.0", - "typescript-eslint": "^8.34.0", "@cellix/typescript-config": "workspace:*" }, "license": "MIT" From 498945aa09a1de9c69b7789e019ac2928dc7c450 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Tue, 6 Jan 2026 14:49:04 -0500 Subject: [PATCH 63/74] update lock file after removing unused devDeps --- pnpm-lock.yaml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 39492b095..9f54419f6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -578,21 +578,12 @@ importers: '@cellix/typescript-config': specifier: workspace:* version: link:../typescript-config - '@eslint/js': - specifier: ^9.29.0 - version: 9.38.0 - eslint: - specifier: ^9.29.0 - version: 9.38.0(jiti@2.6.1) rimraf: specifier: ^6.0.1 version: 6.0.1 typescript: specifier: ^5.8.3 version: 5.8.3 - typescript-eslint: - specifier: ^8.34.0 - version: 8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.8.3) packages/cellix/typescript-config: {} From ae5bb18e8806d2e1a917a8fdbdbcaec8bbf48065 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Tue, 6 Jan 2026 15:37:45 -0500 Subject: [PATCH 64/74] add test coverage for test-utils package --- packages/cellix/test-utils/package.json | 7 ++- .../test-utils/src/features/index.feature | 11 ++++ packages/cellix/test-utils/src/index.test.ts | 60 +++++++++++++++++++ packages/cellix/test-utils/vitest.config.ts | 16 +++++ pnpm-lock.yaml | 3 + 5 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 packages/cellix/test-utils/src/features/index.feature create mode 100644 packages/cellix/test-utils/src/index.test.ts create mode 100644 packages/cellix/test-utils/vitest.config.ts diff --git a/packages/cellix/test-utils/package.json b/packages/cellix/test-utils/package.json index 72171a464..e40e45f9e 100644 --- a/packages/cellix/test-utils/package.json +++ b/packages/cellix/test-utils/package.json @@ -17,12 +17,15 @@ "build": "tsc --build", "watch": "tsc --watch", "lint": "biome lint", - "clean": "rimraf dist" + "clean": "rimraf dist", + "test": "vitest run", + "test:watch": "vitest" }, "devDependencies": { "rimraf": "^6.0.1", "typescript": "^5.8.3", - "@cellix/typescript-config": "workspace:*" + "@cellix/typescript-config": "workspace:*", + "@cellix/vitest-config": "workspace:*" }, "license": "MIT" } diff --git a/packages/cellix/test-utils/src/features/index.feature b/packages/cellix/test-utils/src/features/index.feature new file mode 100644 index 000000000..9ca398e80 --- /dev/null +++ b/packages/cellix/test-utils/src/features/index.feature @@ -0,0 +1,11 @@ +Feature: makeNewableMock helper + + Scenario: Constructor behaviour + Given an implementation function that constructs `Impl` instances + When makeNewableMock is created from that function + Then the returned function can be used as a constructor and produce an `Impl` instance with expected value + + Scenario: Callable behaviour + Given a function that returns the sum of two numbers + When makeNewableMock is created from that function + Then calling the returned function should proxy the call and return the sum diff --git a/packages/cellix/test-utils/src/index.test.ts b/packages/cellix/test-utils/src/index.test.ts new file mode 100644 index 000000000..dfb16fcd4 --- /dev/null +++ b/packages/cellix/test-utils/src/index.test.ts @@ -0,0 +1,60 @@ +/** biome-ignore-all lint/suspicious/noExplicitAny: */ +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { describeFeature, loadFeature } from '@amiceli/vitest-cucumber'; +import { expect, vi } from 'vitest'; +import { makeNewableMock } from './index.ts'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const feature = await loadFeature(path.resolve(__dirname, 'features/index.feature')); + +describeFeature(feature, ({ Scenario,BeforeEachScenario }) => { + let Impl: any; + let Mock: any; + let fn: any; + let instance: any; + let result: any; + + BeforeEachScenario(() => { + Impl = undefined; + Mock = undefined; + fn = undefined; + instance = undefined; + result = undefined; + }); + + Scenario('Constructor behaviour', ({ Given, When, Then }) => { + Given('an implementation function that constructs `Impl` instances', () => { + function ImplCtor(this: any, value: number) { + this.value = value; + } + Impl = ImplCtor; + }); + + When('makeNewableMock is created from that function', () => { + Mock = makeNewableMock((v: number) => new (Impl as any)(v)); + }); + + Then('the returned function can be used as a constructor and produce an `Impl` instance with expected value', () => { + instance = new (Mock as any)(42); + expect(instance.value).toBe(42); + expect(instance).toBeInstanceOf(Impl); + }); + }); + + Scenario('Callable behaviour', ({ Given, When, Then }) => { + Given('a function that returns the sum of two numbers', () => { + fn = vi.fn((a: number, b: number) => a + b); + }); + + When('makeNewableMock is created from that function', () => { + Mock = makeNewableMock((a: number, b: number) => fn(a, b)); + }); + + Then('calling the returned function should proxy the call and return the sum', () => { + result = (Mock as any)(2, 3); + expect(result).toBe(5); + expect(fn).toHaveBeenCalledWith(2, 3); + }); + }); +}); diff --git a/packages/cellix/test-utils/vitest.config.ts b/packages/cellix/test-utils/vitest.config.ts new file mode 100644 index 000000000..296287991 --- /dev/null +++ b/packages/cellix/test-utils/vitest.config.ts @@ -0,0 +1,16 @@ +import { nodeConfig } from '@cellix/vitest-config'; +import { defineConfig, mergeConfig } from 'vitest/config'; + +export default mergeConfig( + nodeConfig, + defineConfig({ + // Add package-specific overrides here if needed + test: { + include: ['src/**/*.test.ts'], + retry: 0, + coverage: { + exclude: ['**/index.ts'], + }, + }, + }), +); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9f54419f6..4dfdcb093 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -578,6 +578,9 @@ importers: '@cellix/typescript-config': specifier: workspace:* version: link:../typescript-config + '@cellix/vitest-config': + specifier: workspace:* + version: link:../vitest-config rimraf: specifier: ^6.0.1 version: 6.0.1 From 36fa368e3e6e0b57eb68b0a5e3fbc3b9de81b1ae Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Tue, 6 Jan 2026 15:56:56 -0500 Subject: [PATCH 65/74] update to include test coverage for index file --- packages/cellix/test-utils/vitest.config.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/cellix/test-utils/vitest.config.ts b/packages/cellix/test-utils/vitest.config.ts index 296287991..35059f3e9 100644 --- a/packages/cellix/test-utils/vitest.config.ts +++ b/packages/cellix/test-utils/vitest.config.ts @@ -8,9 +8,6 @@ export default mergeConfig( test: { include: ['src/**/*.test.ts'], retry: 0, - coverage: { - exclude: ['**/index.ts'], - }, }, }), ); From 93b0a06b96fa7eec931c20351490eba3e7fee41e Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Tue, 6 Jan 2026 16:29:12 -0500 Subject: [PATCH 66/74] unify vite version across packages --- apps/ui-sharethrift/package.json | 2 +- package.json | 2 +- packages/sthrift/ui-components/package.json | 2 +- pnpm-lock.yaml | 379 +++----------------- pnpm-workspace.yaml | 1 + 5 files changed, 55 insertions(+), 331 deletions(-) diff --git a/apps/ui-sharethrift/package.json b/apps/ui-sharethrift/package.json index 43b386ae0..a87d0af44 100644 --- a/apps/ui-sharethrift/package.json +++ b/apps/ui-sharethrift/package.json @@ -55,7 +55,7 @@ "storybook": "catalog:", "typescript": "~5.8.3", "typescript-eslint": "^8.35.1", - "vite": "^7.1.2", + "vite": "catalog:", "vitest": "catalog:" }, "license": "MIT" diff --git a/package.json b/package.json index 77dc63d35..9b66894d2 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ "tsx": "^4.20.3", "turbo": "^2.5.8", "typescript": "^5.8.3", - "vite": "^7.0.4", + "vite": "catalog:", "vitest": "catalog:" } } \ No newline at end of file diff --git a/packages/sthrift/ui-components/package.json b/packages/sthrift/ui-components/package.json index 07aa56958..aba0671e9 100644 --- a/packages/sthrift/ui-components/package.json +++ b/packages/sthrift/ui-components/package.json @@ -73,7 +73,7 @@ "rimraf": "^6.0.1", "storybook": "catalog:", "typescript": "^5.8.3", - "vite": "^7.0.4", + "vite": "catalog:", "vitest": "catalog:" }, "license": "MIT" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ffd586985..5bc74c513 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21,6 +21,9 @@ catalogs: storybook: specifier: 9.1.17 version: 9.1.17 + vite: + specifier: ^7.3.0 + version: 7.3.0 vitest: specifier: ^4.0.15 version: 4.0.15 @@ -70,10 +73,10 @@ importers: version: 24.9.2 '@vitest/browser-playwright': specifier: 'catalog:' - version: 4.0.15(playwright@1.56.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) + version: 4.0.15(playwright@1.56.1)(vite@7.3.0(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) '@vitest/coverage-v8': specifier: 'catalog:' - version: 4.0.15(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15) + version: 4.0.15(@vitest/browser@4.0.15(vite@7.3.0(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15) azurite: specifier: ^3.35.0 version: 3.35.0 @@ -105,8 +108,8 @@ importers: specifier: ^5.8.3 version: 5.8.3 vite: - specifier: ^7.0.4 - version: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + specifier: 'catalog:' + version: 7.3.0(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) vitest: specifier: 'catalog:' version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) @@ -304,7 +307,7 @@ importers: version: link:../../packages/cellix/vitest-config '@chromatic-com/storybook': specifier: ^4.1.0 - version: 4.1.2(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) + version: 4.1.2(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) '@eslint/js': specifier: ^9.30.1 version: 9.38.0 @@ -313,19 +316,19 @@ importers: version: 3.2.0(graphql@16.11.0) '@storybook/addon-a11y': specifier: ^9.1.17 - version: 9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) + version: 9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) '@storybook/addon-docs': specifier: ^9.1.17 - version: 9.1.17(@types/react@19.2.2)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) + version: 9.1.17(@types/react@19.2.2)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) '@storybook/addon-vitest': specifier: ^9.1.17 - version: 9.1.17(@vitest/browser-playwright@4.0.15)(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(@vitest/runner@4.0.15)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@4.0.15) + version: 9.1.17(@vitest/browser-playwright@4.0.15)(@vitest/browser@4.0.15(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(@vitest/runner@4.0.15)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@4.0.15) '@storybook/react': specifier: ^9.1.17 - version: 9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3) + version: 9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3) '@storybook/react-vite': specifier: ^9.1.17 - version: 9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.53.5)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + version: 9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.53.5)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) '@testing-library/jest-dom': specifier: ^6.9.1 version: 6.9.1 @@ -340,10 +343,10 @@ importers: version: 19.2.2(@types/react@19.2.2) '@vitejs/plugin-react': specifier: ^4.7.0 - version: 4.7.0(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + version: 4.7.0(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) '@vitest/coverage-v8': specifier: 'catalog:' - version: 4.0.15(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15) + version: 4.0.15(@vitest/browser@4.0.15(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15) eslint: specifier: ^9.30.1 version: 9.38.0(jiti@2.6.1) @@ -358,7 +361,7 @@ importers: version: 16.4.0 storybook: specifier: 'catalog:' - version: 9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + version: 9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) typescript: specifier: ~5.8.3 version: 5.8.3 @@ -366,8 +369,8 @@ importers: specifier: ^8.35.1 version: 8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.8.3) vite: - specifier: ^7.1.2 - version: 7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + specifier: 'catalog:' + version: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) vitest: specifier: 'catalog:' version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) @@ -1315,25 +1318,25 @@ importers: version: link:../../cellix/vitest-config '@chromatic-com/storybook': specifier: ^4.1.1 - version: 4.1.2(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) + version: 4.1.2(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) '@storybook/addon-a11y': specifier: ^9.1.17 - version: 9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) + version: 9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) '@storybook/addon-docs': specifier: ^9.1.17 - version: 9.1.17(@types/react@19.2.2)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) + version: 9.1.17(@types/react@19.2.2)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) '@storybook/addon-onboarding': specifier: ^9.1.17 - version: 9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) + version: 9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) '@storybook/addon-vitest': specifier: ^9.1.17 - version: 9.1.17(@vitest/browser-playwright@4.0.15)(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(@vitest/runner@4.0.15)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@4.0.15) + version: 9.1.17(@vitest/browser-playwright@4.0.15)(@vitest/browser@4.0.15(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(@vitest/runner@4.0.15)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@4.0.15) '@storybook/react': specifier: ^9.1.17 - version: 9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3) + version: 9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3) '@storybook/react-vite': specifier: ^9.1.17 - version: 9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.53.5)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + version: 9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.53.5)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) '@types/react': specifier: ^19.1.11 version: 19.2.2 @@ -1342,7 +1345,7 @@ importers: version: 19.2.2(@types/react@19.2.2) '@vitest/coverage-v8': specifier: 'catalog:' - version: 4.0.15(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15) + version: 4.0.15(@vitest/browser@4.0.15(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15) jsdom: specifier: ^26.1.0 version: 26.1.0 @@ -1351,13 +1354,13 @@ importers: version: 6.0.1 storybook: specifier: 'catalog:' - version: 9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + version: 9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) typescript: specifier: ^5.8.3 version: 5.8.3 vite: - specifier: ^7.0.4 - version: 7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + specifier: 'catalog:' + version: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) vitest: specifier: 'catalog:' version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) @@ -11641,46 +11644,6 @@ packages: vfile@6.0.3: resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} - vite@7.1.12: - resolution: {integrity: sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - jiti: '>=1.21.0' - less: ^4.0.0 - lightningcss: ^1.21.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - vite@7.3.0: resolution: {integrity: sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -13451,18 +13414,6 @@ snapshots: '@biomejs/cli-win32-x64@2.0.0': optional: true - '@chromatic-com/storybook@4.1.2(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))': - dependencies: - '@neoconfetti/react': 1.0.0 - chromatic: 12.2.0 - filesize: 10.1.6 - jsonfile: 6.2.0 - storybook: 9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - strip-ansi: 7.1.2 - transitivePeerDependencies: - - '@chromatic-com/cypress' - - '@chromatic-com/playwright' - '@chromatic-com/storybook@4.1.2(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))': dependencies: '@neoconfetti/react': 1.0.0 @@ -15590,15 +15541,6 @@ snapshots: '@types/yargs': 17.0.34 chalk: 4.1.2 - '@joshwooding/vite-plugin-react-docgen-typescript@0.6.1(typescript@5.8.3)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': - dependencies: - glob: 10.5.0 - magic-string: 0.30.21 - react-docgen-typescript: 2.4.0(typescript@5.8.3) - vite: 7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - optionalDependencies: - typescript: 5.8.3 - '@joshwooding/vite-plugin-react-docgen-typescript@0.6.1(typescript@5.8.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': dependencies: glob: 10.5.0 @@ -16569,31 +16511,12 @@ snapshots: '@standard-schema/spec@1.0.0': {} - '@storybook/addon-a11y@9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))': - dependencies: - '@storybook/global': 5.0.0 - axe-core: 4.11.0 - storybook: 9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@storybook/addon-a11y@9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))': dependencies: '@storybook/global': 5.0.0 axe-core: 4.11.0 storybook: 9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@storybook/addon-docs@9.1.17(@types/react@19.2.2)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))': - dependencies: - '@mdx-js/react': 3.1.1(@types/react@19.2.2)(react@19.2.0) - '@storybook/csf-plugin': 9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) - '@storybook/icons': 1.6.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@storybook/react-dom-shim': 9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - storybook: 9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - ts-dedent: 2.2.0 - transitivePeerDependencies: - - '@types/react' - '@storybook/addon-docs@9.1.17(@types/react@19.2.2)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))': dependencies: '@mdx-js/react': 3.1.1(@types/react@19.2.2)(react@19.2.0) @@ -16607,30 +16530,10 @@ snapshots: transitivePeerDependencies: - '@types/react' - '@storybook/addon-onboarding@9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))': - dependencies: - storybook: 9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@storybook/addon-onboarding@9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))': dependencies: storybook: 9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@storybook/addon-vitest@9.1.17(@vitest/browser-playwright@4.0.15)(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(@vitest/runner@4.0.15)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@4.0.15)': - dependencies: - '@storybook/global': 5.0.0 - '@storybook/icons': 1.6.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - prompts: 2.4.2 - storybook: 9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - ts-dedent: 2.2.0 - optionalDependencies: - '@vitest/browser': 4.0.15(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) - '@vitest/browser-playwright': 4.0.15(playwright@1.56.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) - '@vitest/runner': 4.0.15 - vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - transitivePeerDependencies: - - react - - react-dom - '@storybook/addon-vitest@9.1.17(@vitest/browser-playwright@4.0.15)(@vitest/browser@4.0.15(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(@vitest/runner@4.0.15)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vitest@4.0.15)': dependencies: '@storybook/global': 5.0.0 @@ -16647,13 +16550,6 @@ snapshots: - react - react-dom - '@storybook/builder-vite@9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': - dependencies: - '@storybook/csf-plugin': 9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) - storybook: 9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - ts-dedent: 2.2.0 - vite: 7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - '@storybook/builder-vite@9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': dependencies: '@storybook/csf-plugin': 9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) @@ -16661,11 +16557,6 @@ snapshots: ts-dedent: 2.2.0 vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - '@storybook/csf-plugin@9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))': - dependencies: - storybook: 9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - unplugin: 1.16.1 - '@storybook/csf-plugin@9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))': dependencies: storybook: 9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) @@ -16678,38 +16569,12 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@storybook/react-dom-shim@9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))': - dependencies: - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - storybook: 9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@storybook/react-dom-shim@9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))': dependencies: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) storybook: 9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@storybook/react-vite@9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.53.5)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': - dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.1(typescript@5.8.3)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@rollup/pluginutils': 5.3.0(rollup@4.53.5) - '@storybook/builder-vite': 9.1.17(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@storybook/react': 9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3) - find-up: 7.0.0 - magic-string: 0.30.21 - react: 19.2.0 - react-docgen: 8.0.2 - react-dom: 19.2.0(react@19.2.0) - resolve: 1.22.11 - storybook: 9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - tsconfig-paths: 4.2.0 - vite: 7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - transitivePeerDependencies: - - rollup - - supports-color - - typescript - '@storybook/react-vite@9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.53.5)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': dependencies: '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.1(typescript@5.8.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) @@ -16730,16 +16595,6 @@ snapshots: - supports-color - typescript - '@storybook/react@9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3)': - dependencies: - '@storybook/global': 5.0.0 - '@storybook/react-dom-shim': 9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - storybook: 9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - optionalDependencies: - typescript: 5.8.3 - '@storybook/react@9.1.17(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)))(typescript@5.8.3)': dependencies: '@storybook/global': 5.0.0 @@ -17303,7 +17158,7 @@ snapshots: '@ungap/structured-clone@1.3.0': {} - '@vitejs/plugin-react@4.7.0(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': + '@vitejs/plugin-react@4.7.0(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': dependencies: '@babel/core': 7.28.5 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5) @@ -17311,37 +17166,10 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.27 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) transitivePeerDependencies: - supports-color - '@vitest/browser-playwright@4.0.15(playwright@1.56.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15)': - dependencies: - '@vitest/browser': 4.0.15(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) - '@vitest/mocker': 4.0.15(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - playwright: 1.56.1 - tinyrainbow: 3.0.3 - vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - transitivePeerDependencies: - - bufferutil - - msw - - utf-8-validate - - vite - optional: true - - '@vitest/browser-playwright@4.0.15(playwright@1.56.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15)': - dependencies: - '@vitest/browser': 4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) - '@vitest/mocker': 4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - playwright: 1.56.1 - tinyrainbow: 3.0.3 - vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - transitivePeerDependencies: - - bufferutil - - msw - - utf-8-validate - - vite - '@vitest/browser-playwright@4.0.15(playwright@1.56.1)(vite@7.3.0(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15)': dependencies: '@vitest/browser': 4.0.15(vite@7.3.0(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) @@ -17369,69 +17197,64 @@ snapshots: - utf-8-validate - vite - '@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15)': + '@vitest/browser-playwright@4.0.15(playwright@1.56.1)(vite@7.3.0(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15)': dependencies: - '@vitest/mocker': 4.0.15(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@vitest/utils': 4.0.15 - magic-string: 0.30.21 - pixelmatch: 7.1.0 - pngjs: 7.0.0 - sirv: 3.0.2 + '@vitest/browser': 4.0.15(vite@7.3.0(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) + '@vitest/mocker': 4.0.15(vite@7.3.0(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + playwright: 1.56.1 tinyrainbow: 3.0.3 - vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - ws: 8.18.3 + vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) transitivePeerDependencies: - bufferutil - msw - utf-8-validate - vite - optional: true - '@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15)': + '@vitest/browser@4.0.15(vite@7.3.0(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15)': dependencies: - '@vitest/mocker': 4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + '@vitest/mocker': 4.0.15(vite@7.3.0(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) '@vitest/utils': 4.0.15 magic-string: 0.30.21 pixelmatch: 7.1.0 pngjs: 7.0.0 sirv: 3.0.2 tinyrainbow: 3.0.3 - vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.19.0)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) ws: 8.18.3 transitivePeerDependencies: - bufferutil - msw - utf-8-validate - vite + optional: true - '@vitest/browser@4.0.15(vite@7.3.0(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15)': + '@vitest/browser@4.0.15(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15)': dependencies: - '@vitest/mocker': 4.0.15(vite@7.3.0(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + '@vitest/mocker': 4.0.15(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) '@vitest/utils': 4.0.15 magic-string: 0.30.21 pixelmatch: 7.1.0 pngjs: 7.0.0 sirv: 3.0.2 tinyrainbow: 3.0.3 - vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.19.0)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) ws: 8.18.3 transitivePeerDependencies: - bufferutil - msw - utf-8-validate - vite - optional: true - '@vitest/browser@4.0.15(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15)': + '@vitest/browser@4.0.15(vite@7.3.0(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15)': dependencies: - '@vitest/mocker': 4.0.15(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + '@vitest/mocker': 4.0.15(vite@7.3.0(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) '@vitest/utils': 4.0.15 magic-string: 0.30.21 pixelmatch: 7.1.0 pngjs: 7.0.0 sirv: 3.0.2 tinyrainbow: 3.0.3 - vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) ws: 8.18.3 transitivePeerDependencies: - bufferutil @@ -17439,7 +17262,7 @@ snapshots: - utf-8-validate - vite - '@vitest/coverage-v8@4.0.15(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15)': + '@vitest/coverage-v8@4.0.15(@vitest/browser@4.0.15(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15)': dependencies: '@bcoe/v8-coverage': 1.0.2 '@vitest/utils': 4.0.15 @@ -17454,11 +17277,11 @@ snapshots: tinyrainbow: 3.0.3 vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) optionalDependencies: - '@vitest/browser': 4.0.15(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) + '@vitest/browser': 4.0.15(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) transitivePeerDependencies: - supports-color - '@vitest/coverage-v8@4.0.15(@vitest/browser@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15)': + '@vitest/coverage-v8@4.0.15(@vitest/browser@4.0.15(vite@7.3.0(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15)': dependencies: '@bcoe/v8-coverage': 1.0.2 '@vitest/utils': 4.0.15 @@ -17473,26 +17296,7 @@ snapshots: tinyrainbow: 3.0.3 vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) optionalDependencies: - '@vitest/browser': 4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) - transitivePeerDependencies: - - supports-color - - '@vitest/coverage-v8@4.0.15(@vitest/browser@4.0.15(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15)': - dependencies: - '@bcoe/v8-coverage': 1.0.2 - '@vitest/utils': 4.0.15 - ast-v8-to-istanbul: 0.3.8 - istanbul-lib-coverage: 3.2.2 - istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 5.0.6 - istanbul-reports: 3.2.0 - magicast: 0.5.1 - obug: 2.1.1 - std-env: 3.10.0 - tinyrainbow: 3.0.3 - vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - optionalDependencies: - '@vitest/browser': 4.0.15(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) + '@vitest/browser': 4.0.15(vite@7.3.0(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) transitivePeerDependencies: - supports-color @@ -17513,14 +17317,6 @@ snapshots: chai: 6.2.1 tinyrainbow: 3.0.3 - '@vitest/mocker@3.2.4(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': - dependencies: - '@vitest/spy': 3.2.4 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - '@vitest/mocker@3.2.4(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': dependencies: '@vitest/spy': 3.2.4 @@ -17529,23 +17325,6 @@ snapshots: optionalDependencies: vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - '@vitest/mocker@4.0.15(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': - dependencies: - '@vitest/spy': 4.0.15 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - optional: true - - '@vitest/mocker@4.0.15(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': - dependencies: - '@vitest/spy': 4.0.15 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - '@vitest/mocker@4.0.15(vite@7.3.0(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': dependencies: '@vitest/spy': 4.0.15 @@ -24283,28 +24062,6 @@ snapshots: stoppable@1.1.0: {} - storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)): - dependencies: - '@storybook/global': 5.0.0 - '@testing-library/jest-dom': 6.9.1 - '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.1) - '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@vitest/spy': 3.2.4 - better-opn: 3.0.2 - esbuild: 0.25.12 - esbuild-register: 3.6.0(esbuild@0.25.12) - recast: 0.23.11 - semver: 7.7.3 - ws: 8.18.3 - transitivePeerDependencies: - - '@testing-library/dom' - - bufferutil - - msw - - supports-color - - utf-8-validate - - vite - storybook@9.1.17(@testing-library/dom@10.4.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)): dependencies: '@storybook/global': 5.0.0 @@ -25082,40 +24839,6 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vite@7.1.12(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1): - dependencies: - esbuild: 0.25.11 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.53.5 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 24.10.4 - fsevents: 2.3.3 - jiti: 2.6.1 - lightningcss: 1.30.2 - terser: 5.44.0 - tsx: 4.20.6 - yaml: 2.8.1 - - vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1): - dependencies: - esbuild: 0.25.11 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.53.5 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 24.9.2 - fsevents: 2.3.3 - jiti: 2.6.1 - lightningcss: 1.30.2 - terser: 5.44.0 - tsx: 4.20.6 - yaml: 2.8.1 - vite@7.3.0(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1): dependencies: esbuild: 0.27.2 @@ -25272,7 +24995,7 @@ snapshots: optionalDependencies: '@opentelemetry/api': 1.9.0 '@types/node': 24.9.2 - '@vitest/browser-playwright': 4.0.15(playwright@1.56.1)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) + '@vitest/browser-playwright': 4.0.15(playwright@1.56.1)(vite@7.3.0(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) jsdom: 26.1.0 transitivePeerDependencies: - jiti diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 0f2191c86..be78125a5 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -11,6 +11,7 @@ catalog: '@vitest/coverage-v8': ^4.0.15 '@vitest/browser-playwright': ^4.0.15 storybook: 9.1.17 + vite: ^7.3.0 overrides: node-forge@<1.3.2: '>=1.3.2' \ No newline at end of file From 9211bc779429b66821bda5bd90deef8b7afbfa93 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Tue, 6 Jan 2026 16:44:50 -0500 Subject: [PATCH 67/74] unify @types/node version --- pnpm-lock.yaml | 289 ++++++++++++++----------------------------------- 1 file changed, 84 insertions(+), 205 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5bc74c513..0a455eece 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -43,7 +43,7 @@ importers: version: 2.0.0 '@graphql-codegen/cli': specifier: ^5.0.7 - version: 5.0.7(@parcel/watcher@2.5.1)(@types/node@24.9.2)(graphql@16.11.0)(typescript@5.8.3) + version: 5.0.7(@parcel/watcher@2.5.1)(@types/node@24.10.4)(graphql@16.11.0)(typescript@5.8.3) '@graphql-codegen/introspection': specifier: ^4.0.3 version: 4.0.3(graphql@16.11.0) @@ -70,13 +70,13 @@ importers: version: 4.3.2 '@types/node': specifier: ^24.7.2 - version: 24.9.2 + version: 24.10.4 '@vitest/browser-playwright': specifier: 'catalog:' - version: 4.0.15(playwright@1.56.1)(vite@7.3.0(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) + version: 4.0.15(playwright@1.56.1)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) '@vitest/coverage-v8': specifier: 'catalog:' - version: 4.0.15(@vitest/browser@4.0.15(vite@7.3.0(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15) + version: 4.0.15(@vitest/browser@4.0.15(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15) azurite: specifier: ^3.35.0 version: 3.35.0 @@ -88,7 +88,7 @@ importers: version: 3.0.2 knip: specifier: ^5.61.1 - version: 5.73.3(@types/node@24.9.2)(typescript@5.8.3) + version: 5.73.3(@types/node@24.10.4)(typescript@5.8.3) rimraf: specifier: ^6.0.1 version: 6.0.1 @@ -109,10 +109,10 @@ importers: version: 5.8.3 vite: specifier: 'catalog:' - version: 7.3.0(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + version: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) vitest: specifier: 'catalog:' - version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) apps/api: dependencies: @@ -909,7 +909,7 @@ importers: version: link:../mock-messaging-server '@types/node': specifier: ^22.0.0 - version: 22.19.0 + version: 22.19.3 typescript: specifier: ^5.8.3 version: 5.8.3 @@ -934,13 +934,13 @@ importers: version: link:../../cellix/vitest-config '@types/node': specifier: ^22.0.0 - version: 22.19.0 + version: 22.19.3 typescript: specifier: ^5.8.3 version: 5.8.3 vitest: specifier: 'catalog:' - version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.19.0)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.19.3)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) packages/sthrift/mock-messaging-server: dependencies: @@ -965,7 +965,7 @@ importers: version: 4.17.25 '@types/node': specifier: ^22.0.0 - version: 22.19.0 + version: 22.19.3 '@types/supertest': specifier: ^6.0.2 version: 6.0.3 @@ -983,7 +983,7 @@ importers: version: 5.8.3 vitest: specifier: 'catalog:' - version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.19.0)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.19.3)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) packages/sthrift/mock-mongodb-memory-server: dependencies: @@ -1042,7 +1042,7 @@ importers: version: link:../../cellix/vitest-config '@types/node': specifier: ^20.0.0 - version: 20.19.25 + version: 20.19.27 typescript: specifier: ^5.8.3 version: 5.8.3 @@ -5078,18 +5078,15 @@ packages: '@types/node@17.0.45': resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} - '@types/node@20.19.25': - resolution: {integrity: sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ==} + '@types/node@20.19.27': + resolution: {integrity: sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==} - '@types/node@22.19.0': - resolution: {integrity: sha512-xpr/lmLPQEj+TUnHmR+Ab91/glhJvsqcjB+yY0Ix9GO70H6Lb4FHH5GeqdOE5btAx7eIMwuHkp4H2MSkLcqWbA==} + '@types/node@22.19.3': + resolution: {integrity: sha512-1N9SBnWYOJTrNZCdh/yJE+t910Y128BoyY+zBLWhL3r0TYzlTmFdXrPwHL9DyFZmlEXNQQolTZh3KHV31QDhyA==} '@types/node@24.10.4': resolution: {integrity: sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg==} - '@types/node@24.9.2': - resolution: {integrity: sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA==} - '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -12155,7 +12152,7 @@ snapshots: minimist: 1.2.8 parsecurrency: 1.1.1 ts-morph: 26.0.0 - vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.10.4)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) '@ant-design/colors@7.2.1': dependencies: @@ -14963,7 +14960,7 @@ snapshots: graphql: 16.11.0 tslib: 2.6.3 - '@graphql-codegen/cli@5.0.7(@parcel/watcher@2.5.1)(@types/node@24.9.2)(graphql@16.11.0)(typescript@5.8.3)': + '@graphql-codegen/cli@5.0.7(@parcel/watcher@2.5.1)(@types/node@24.10.4)(graphql@16.11.0)(typescript@5.8.3)': dependencies: '@babel/generator': 7.28.5 '@babel/template': 7.27.2 @@ -14974,12 +14971,12 @@ snapshots: '@graphql-tools/apollo-engine-loader': 8.0.22(graphql@16.11.0) '@graphql-tools/code-file-loader': 8.1.22(graphql@16.11.0) '@graphql-tools/git-loader': 8.0.26(graphql@16.11.0) - '@graphql-tools/github-loader': 8.0.22(@types/node@24.9.2)(graphql@16.11.0) + '@graphql-tools/github-loader': 8.0.22(@types/node@24.10.4)(graphql@16.11.0) '@graphql-tools/graphql-file-loader': 8.1.2(graphql@16.11.0) '@graphql-tools/json-file-loader': 8.0.20(graphql@16.11.0) '@graphql-tools/load': 8.1.2(graphql@16.11.0) - '@graphql-tools/prisma-loader': 8.0.17(@types/node@24.9.2)(graphql@16.11.0) - '@graphql-tools/url-loader': 8.0.33(@types/node@24.9.2)(graphql@16.11.0) + '@graphql-tools/prisma-loader': 8.0.17(@types/node@24.10.4)(graphql@16.11.0) + '@graphql-tools/url-loader': 8.0.33(@types/node@24.10.4)(graphql@16.11.0) '@graphql-tools/utils': 10.9.1(graphql@16.11.0) '@whatwg-node/fetch': 0.10.11 chalk: 4.1.2 @@ -14987,8 +14984,8 @@ snapshots: debounce: 1.2.1 detect-indent: 6.1.0 graphql: 16.11.0 - graphql-config: 5.1.5(@types/node@24.9.2)(graphql@16.11.0)(typescript@5.8.3) - inquirer: 8.2.7(@types/node@24.9.2) + graphql-config: 5.1.5(@types/node@24.10.4)(graphql@16.11.0)(typescript@5.8.3) + inquirer: 8.2.7(@types/node@24.10.4) is-glob: 4.0.3 jiti: 1.21.7 json-to-pretty-yaml: 1.2.2 @@ -15237,7 +15234,7 @@ snapshots: - uWebSockets.js - utf-8-validate - '@graphql-tools/executor-http@1.3.3(@types/node@24.9.2)(graphql@16.11.0)': + '@graphql-tools/executor-http@1.3.3(@types/node@24.10.4)(graphql@16.11.0)': dependencies: '@graphql-hive/signal': 1.0.0 '@graphql-tools/executor-common': 0.0.4(graphql@16.11.0) @@ -15247,7 +15244,7 @@ snapshots: '@whatwg-node/fetch': 0.10.11 '@whatwg-node/promise-helpers': 1.3.2 graphql: 16.11.0 - meros: 1.3.2(@types/node@24.9.2) + meros: 1.3.2(@types/node@24.10.4) tslib: 2.8.1 transitivePeerDependencies: - '@types/node' @@ -15286,9 +15283,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@graphql-tools/github-loader@8.0.22(@types/node@24.9.2)(graphql@16.11.0)': + '@graphql-tools/github-loader@8.0.22(@types/node@24.10.4)(graphql@16.11.0)': dependencies: - '@graphql-tools/executor-http': 1.3.3(@types/node@24.9.2)(graphql@16.11.0) + '@graphql-tools/executor-http': 1.3.3(@types/node@24.10.4)(graphql@16.11.0) '@graphql-tools/graphql-tag-pluck': 8.3.21(graphql@16.11.0) '@graphql-tools/utils': 10.9.1(graphql@16.11.0) '@whatwg-node/fetch': 0.10.11 @@ -15374,9 +15371,9 @@ snapshots: graphql: 16.11.0 tslib: 2.8.1 - '@graphql-tools/prisma-loader@8.0.17(@types/node@24.9.2)(graphql@16.11.0)': + '@graphql-tools/prisma-loader@8.0.17(@types/node@24.10.4)(graphql@16.11.0)': dependencies: - '@graphql-tools/url-loader': 8.0.33(@types/node@24.9.2)(graphql@16.11.0) + '@graphql-tools/url-loader': 8.0.33(@types/node@24.10.4)(graphql@16.11.0) '@graphql-tools/utils': 10.9.1(graphql@16.11.0) '@types/js-yaml': 4.0.9 '@whatwg-node/fetch': 0.10.11 @@ -15427,10 +15424,10 @@ snapshots: tslib: 2.8.1 value-or-promise: 1.0.11 - '@graphql-tools/url-loader@8.0.33(@types/node@24.9.2)(graphql@16.11.0)': + '@graphql-tools/url-loader@8.0.33(@types/node@24.10.4)(graphql@16.11.0)': dependencies: '@graphql-tools/executor-graphql-ws': 2.0.7(graphql@16.11.0) - '@graphql-tools/executor-http': 1.3.3(@types/node@24.9.2)(graphql@16.11.0) + '@graphql-tools/executor-http': 1.3.3(@types/node@24.10.4)(graphql@16.11.0) '@graphql-tools/executor-legacy-ws': 1.1.19(graphql@16.11.0) '@graphql-tools/utils': 10.9.1(graphql@16.11.0) '@graphql-tools/wrap': 10.1.4(graphql@16.11.0) @@ -15506,12 +15503,12 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} - '@inquirer/external-editor@1.0.2(@types/node@24.9.2)': + '@inquirer/external-editor@1.0.2(@types/node@24.10.4)': dependencies: chardet: 2.1.0 iconv-lite: 0.7.0 optionalDependencies: - '@types/node': 24.9.2 + '@types/node': 24.10.4 '@isaacs/balanced-match@4.0.1': {} @@ -15537,7 +15534,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 24.9.2 + '@types/node': 24.10.4 '@types/yargs': 17.0.34 chalk: 4.1.2 @@ -16795,11 +16792,11 @@ snapshots: '@types/body-parser@1.19.6': dependencies: '@types/connect': 3.4.38 - '@types/node': 24.9.2 + '@types/node': 24.10.4 '@types/bonjour@3.5.13': dependencies: - '@types/node': 24.9.2 + '@types/node': 24.10.4 '@types/chai@5.2.3': dependencies: @@ -16809,11 +16806,11 @@ snapshots: '@types/connect-history-api-fallback@1.5.4': dependencies: '@types/express-serve-static-core': 5.1.0 - '@types/node': 24.9.2 + '@types/node': 24.10.4 '@types/connect@3.4.38': dependencies: - '@types/node': 24.9.2 + '@types/node': 24.10.4 '@types/cookiejar@2.1.5': {} @@ -16843,14 +16840,14 @@ snapshots: '@types/express-serve-static-core@4.19.7': dependencies: - '@types/node': 24.9.2 + '@types/node': 24.10.4 '@types/qs': 6.14.0 '@types/range-parser': 1.2.7 '@types/send': 1.2.1 '@types/express-serve-static-core@5.1.0': dependencies: - '@types/node': 24.9.2 + '@types/node': 24.10.4 '@types/qs': 6.14.0 '@types/range-parser': 1.2.7 '@types/send': 1.2.1 @@ -16882,7 +16879,7 @@ snapshots: '@types/http-proxy@1.17.17': dependencies: - '@types/node': 24.9.2 + '@types/node': 24.10.4 '@types/istanbul-lib-coverage@2.0.6': {} @@ -16901,7 +16898,7 @@ snapshots: '@types/jsonwebtoken@9.0.10': dependencies: '@types/ms': 2.1.0 - '@types/node': 24.9.2 + '@types/node': 24.10.4 '@types/lodash@4.17.20': {} @@ -16921,15 +16918,15 @@ snapshots: '@types/node-forge@1.3.14': dependencies: - '@types/node': 24.9.2 + '@types/node': 24.10.4 '@types/node@17.0.45': {} - '@types/node@20.19.25': + '@types/node@20.19.27': dependencies: undici-types: 6.21.0 - '@types/node@22.19.0': + '@types/node@22.19.3': dependencies: undici-types: 6.21.0 @@ -16937,10 +16934,6 @@ snapshots: dependencies: undici-types: 7.16.0 - '@types/node@24.9.2': - dependencies: - undici-types: 7.16.0 - '@types/normalize-package-data@2.4.4': {} '@types/prismjs@1.26.5': {} @@ -16976,7 +16969,7 @@ snapshots: '@types/readable-stream@4.0.22': dependencies: - '@types/node': 24.9.2 + '@types/node': 24.10.4 '@types/resolve@1.20.6': {} @@ -16984,18 +16977,18 @@ snapshots: '@types/sax@1.2.7': dependencies: - '@types/node': 24.9.2 + '@types/node': 24.10.4 '@types/semver@7.7.1': {} '@types/send@0.17.6': dependencies: '@types/mime': 1.3.5 - '@types/node': 24.9.2 + '@types/node': 24.10.4 '@types/send@1.2.1': dependencies: - '@types/node': 24.9.2 + '@types/node': 24.10.4 '@types/serve-index@1.9.4': dependencies: @@ -17004,14 +16997,14 @@ snapshots: '@types/serve-static@1.15.10': dependencies: '@types/http-errors': 2.0.5 - '@types/node': 24.9.2 + '@types/node': 24.10.4 '@types/send': 0.17.6 '@types/shimmer@1.2.0': {} '@types/sockjs@0.3.36': dependencies: - '@types/node': 24.9.2 + '@types/node': 24.10.4 '@types/strip-bom@3.0.0': {} @@ -17021,7 +17014,7 @@ snapshots: dependencies: '@types/cookiejar': 2.1.5 '@types/methods': 1.1.4 - '@types/node': 24.9.2 + '@types/node': 22.19.3 form-data: 4.0.4 '@types/supertest@6.0.3': @@ -17047,7 +17040,7 @@ snapshots: '@types/ws@8.18.1': dependencies: - '@types/node': 24.9.2 + '@types/node': 24.10.4 '@types/yargs-parser@21.0.3': {} @@ -17170,13 +17163,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitest/browser-playwright@4.0.15(playwright@1.56.1)(vite@7.3.0(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15)': + '@vitest/browser-playwright@4.0.15(playwright@1.56.1)(vite@7.3.0(@types/node@22.19.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15)': dependencies: - '@vitest/browser': 4.0.15(vite@7.3.0(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) - '@vitest/mocker': 4.0.15(vite@7.3.0(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + '@vitest/browser': 4.0.15(vite@7.3.0(@types/node@22.19.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) + '@vitest/mocker': 4.0.15(vite@7.3.0(@types/node@22.19.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) playwright: 1.56.1 tinyrainbow: 3.0.3 - vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.19.0)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.19.3)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) transitivePeerDependencies: - bufferutil - msw @@ -17197,29 +17190,16 @@ snapshots: - utf-8-validate - vite - '@vitest/browser-playwright@4.0.15(playwright@1.56.1)(vite@7.3.0(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15)': + '@vitest/browser@4.0.15(vite@7.3.0(@types/node@22.19.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15)': dependencies: - '@vitest/browser': 4.0.15(vite@7.3.0(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) - '@vitest/mocker': 4.0.15(vite@7.3.0(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - playwright: 1.56.1 - tinyrainbow: 3.0.3 - vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - transitivePeerDependencies: - - bufferutil - - msw - - utf-8-validate - - vite - - '@vitest/browser@4.0.15(vite@7.3.0(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15)': - dependencies: - '@vitest/mocker': 4.0.15(vite@7.3.0(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + '@vitest/mocker': 4.0.15(vite@7.3.0(@types/node@22.19.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) '@vitest/utils': 4.0.15 magic-string: 0.30.21 pixelmatch: 7.1.0 pngjs: 7.0.0 sirv: 3.0.2 tinyrainbow: 3.0.3 - vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.19.0)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.19.3)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) ws: 8.18.3 transitivePeerDependencies: - bufferutil @@ -17245,23 +17225,6 @@ snapshots: - utf-8-validate - vite - '@vitest/browser@4.0.15(vite@7.3.0(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15)': - dependencies: - '@vitest/mocker': 4.0.15(vite@7.3.0(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@vitest/utils': 4.0.15 - magic-string: 0.30.21 - pixelmatch: 7.1.0 - pngjs: 7.0.0 - sirv: 3.0.2 - tinyrainbow: 3.0.3 - vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - ws: 8.18.3 - transitivePeerDependencies: - - bufferutil - - msw - - utf-8-validate - - vite - '@vitest/coverage-v8@4.0.15(@vitest/browser@4.0.15(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15)': dependencies: '@bcoe/v8-coverage': 1.0.2 @@ -17281,25 +17244,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitest/coverage-v8@4.0.15(@vitest/browser@4.0.15(vite@7.3.0(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15))(vitest@4.0.15)': - dependencies: - '@bcoe/v8-coverage': 1.0.2 - '@vitest/utils': 4.0.15 - ast-v8-to-istanbul: 0.3.8 - istanbul-lib-coverage: 3.2.2 - istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 5.0.6 - istanbul-reports: 3.2.0 - magicast: 0.5.1 - obug: 2.1.1 - std-env: 3.10.0 - tinyrainbow: 3.0.3 - vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - optionalDependencies: - '@vitest/browser': 4.0.15(vite@7.3.0(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) - transitivePeerDependencies: - - supports-color - '@vitest/expect@3.2.4': dependencies: '@types/chai': 5.2.3 @@ -17325,13 +17269,13 @@ snapshots: optionalDependencies: vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - '@vitest/mocker@4.0.15(vite@7.3.0(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': + '@vitest/mocker@4.0.15(vite@7.3.0(@types/node@22.19.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': dependencies: '@vitest/spy': 4.0.15 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.0(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + vite: 7.3.0(@types/node@22.19.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) '@vitest/mocker@4.0.15(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': dependencies: @@ -17341,14 +17285,6 @@ snapshots: optionalDependencies: vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - '@vitest/mocker@4.0.15(vite@7.3.0(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))': - dependencies: - '@vitest/spy': 4.0.15 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 7.3.0(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - '@vitest/pretty-format@3.2.4': dependencies: tinyrainbow: 2.0.0 @@ -19355,7 +19291,7 @@ snapshots: eval@0.1.8: dependencies: - '@types/node': 24.9.2 + '@types/node': 24.10.4 require-like: 0.1.2 event-stream@3.3.4: @@ -19909,13 +19845,13 @@ snapshots: graphemer@1.4.0: {} - graphql-config@5.1.5(@types/node@24.9.2)(graphql@16.11.0)(typescript@5.8.3): + graphql-config@5.1.5(@types/node@24.10.4)(graphql@16.11.0)(typescript@5.8.3): dependencies: '@graphql-tools/graphql-file-loader': 8.1.2(graphql@16.11.0) '@graphql-tools/json-file-loader': 8.0.20(graphql@16.11.0) '@graphql-tools/load': 8.1.2(graphql@16.11.0) '@graphql-tools/merge': 9.1.1(graphql@16.11.0) - '@graphql-tools/url-loader': 8.0.33(@types/node@24.9.2)(graphql@16.11.0) + '@graphql-tools/url-loader': 8.0.33(@types/node@24.10.4)(graphql@16.11.0) '@graphql-tools/utils': 10.9.1(graphql@16.11.0) cosmiconfig: 8.3.6(typescript@5.8.3) graphql: 16.11.0 @@ -20357,9 +20293,9 @@ snapshots: inline-style-parser@0.2.4: {} - inquirer@8.2.7(@types/node@24.9.2): + inquirer@8.2.7(@types/node@24.10.4): dependencies: - '@inquirer/external-editor': 1.0.2(@types/node@24.9.2) + '@inquirer/external-editor': 1.0.2(@types/node@24.10.4) ansi-escapes: 4.3.2 chalk: 4.1.2 cli-cursor: 3.1.0 @@ -20656,7 +20592,7 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 24.9.2 + '@types/node': 24.10.4 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -20664,13 +20600,13 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 24.9.2 + '@types/node': 24.10.4 merge-stream: 2.0.0 supports-color: 8.1.1 jest-worker@29.7.0: dependencies: - '@types/node': 24.9.2 + '@types/node': 24.10.4 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -20835,10 +20771,10 @@ snapshots: kleur@3.0.3: {} - knip@5.73.3(@types/node@24.9.2)(typescript@5.8.3): + knip@5.73.3(@types/node@24.10.4)(typescript@5.8.3): dependencies: '@nodelib/fs.walk': 1.2.8 - '@types/node': 24.9.2 + '@types/node': 24.10.4 fast-glob: 3.3.3 formatly: 0.3.0 jiti: 2.6.1 @@ -21319,9 +21255,9 @@ snapshots: merge2@1.4.1: {} - meros@1.3.2(@types/node@24.9.2): + meros@1.3.2(@types/node@24.10.4): optionalDependencies: - '@types/node': 24.9.2 + '@types/node': 24.10.4 methods@1.1.2: {} @@ -22774,7 +22710,7 @@ snapshots: '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.0 - '@types/node': 24.9.2 + '@types/node': 24.10.4 long: 5.3.2 proxy-addr@2.0.7: @@ -24839,7 +24775,7 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vite@7.3.0(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1): + vite@7.3.0(@types/node@22.19.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1): dependencies: esbuild: 0.27.2 fdir: 6.5.0(picomatch@4.0.3) @@ -24848,7 +24784,7 @@ snapshots: rollup: 4.53.5 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 22.19.0 + '@types/node': 22.19.3 fsevents: 2.3.3 jiti: 2.6.1 lightningcss: 1.30.2 @@ -24873,27 +24809,10 @@ snapshots: tsx: 4.20.6 yaml: 2.8.1 - vite@7.3.0(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1): - dependencies: - esbuild: 0.27.2 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.53.5 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 24.9.2 - fsevents: 2.3.3 - jiti: 2.6.1 - lightningcss: 1.30.2 - terser: 5.44.0 - tsx: 4.20.6 - yaml: 2.8.1 - - vitest@4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.19.0)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1): + vitest@4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.19.3)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1): dependencies: '@vitest/expect': 4.0.15 - '@vitest/mocker': 4.0.15(vite@7.3.0(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) + '@vitest/mocker': 4.0.15(vite@7.3.0(@types/node@22.19.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) '@vitest/pretty-format': 4.0.15 '@vitest/runner': 4.0.15 '@vitest/snapshot': 4.0.15 @@ -24910,12 +24829,12 @@ snapshots: tinyexec: 1.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 7.3.0(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) + vite: 7.3.0(@types/node@22.19.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.0 - '@types/node': 22.19.0 - '@vitest/browser-playwright': 4.0.15(playwright@1.56.1)(vite@7.3.0(@types/node@22.19.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) + '@types/node': 22.19.3 + '@vitest/browser-playwright': 4.0.15(playwright@1.56.1)(vite@7.3.0(@types/node@22.19.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) jsdom: 26.1.0 transitivePeerDependencies: - jiti @@ -24970,46 +24889,6 @@ snapshots: - tsx - yaml - vitest@4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.9.2)(@vitest/browser-playwright@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1): - dependencies: - '@vitest/expect': 4.0.15 - '@vitest/mocker': 4.0.15(vite@7.3.0(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1)) - '@vitest/pretty-format': 4.0.15 - '@vitest/runner': 4.0.15 - '@vitest/snapshot': 4.0.15 - '@vitest/spy': 4.0.15 - '@vitest/utils': 4.0.15 - es-module-lexer: 1.7.0 - expect-type: 1.2.2 - magic-string: 0.30.21 - obug: 2.1.1 - pathe: 2.0.3 - picomatch: 4.0.3 - std-env: 3.10.0 - tinybench: 2.9.0 - tinyexec: 1.0.2 - tinyglobby: 0.2.15 - tinyrainbow: 3.0.3 - vite: 7.3.0(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1) - why-is-node-running: 2.3.0 - optionalDependencies: - '@opentelemetry/api': 1.9.0 - '@types/node': 24.9.2 - '@vitest/browser-playwright': 4.0.15(playwright@1.56.1)(vite@7.3.0(@types/node@24.9.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.1))(vitest@4.0.15) - jsdom: 26.1.0 - transitivePeerDependencies: - - jiti - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - yaml - w3c-xmlserializer@5.0.0: dependencies: xml-name-validator: 5.0.0 @@ -25282,7 +25161,7 @@ snapshots: wkx@0.5.0: dependencies: - '@types/node': 24.9.2 + '@types/node': 24.10.4 word-wrap@1.2.5: {} From 4cf0f3dcac08bfefeda95666feca782c11f3a3d8 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Tue, 6 Jan 2026 17:45:19 -0500 Subject: [PATCH 68/74] feat(tests): add coverage script to test-utils package --- packages/cellix/test-utils/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/cellix/test-utils/package.json b/packages/cellix/test-utils/package.json index e40e45f9e..9fb06b54d 100644 --- a/packages/cellix/test-utils/package.json +++ b/packages/cellix/test-utils/package.json @@ -19,7 +19,8 @@ "lint": "biome lint", "clean": "rimraf dist", "test": "vitest run", - "test:watch": "vitest" + "test:watch": "vitest", + "test:coverage": "vitest run --coverage" }, "devDependencies": { "rimraf": "^6.0.1", From 80d2aa8d86a23a6d2f069bba689d2125b956e929 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Wed, 7 Jan 2026 09:57:40 -0500 Subject: [PATCH 69/74] refactor(tests): update mongo-unit-of-work tests to use mocks and simplify domain operations (per sourcery's suggestions) --- .../mongo-unit-of-work.test.ts | 155 +++++++++++------- 1 file changed, 93 insertions(+), 62 deletions(-) diff --git a/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts b/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts index 61fec263c..7633eb315 100644 --- a/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts +++ b/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts @@ -1,13 +1,13 @@ -import { describeFeature, loadFeature } from '@amiceli/vitest-cucumber'; -import { expect, vi, type MockInstance } from 'vitest'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; +import { describeFeature, loadFeature } from '@amiceli/vitest-cucumber'; +import { DomainSeedwork } from '@cellix/domain-seedwork'; import type { ClientSession, Model } from 'mongoose'; import mongoose from 'mongoose'; -import { DomainSeedwork } from '@cellix/domain-seedwork'; +import { expect, vi, type Mock } from 'vitest'; import type { Base } from './index.ts'; -import { MongoUnitOfWork } from './mongo-unit-of-work.ts'; import { MongoRepositoryBase } from './mongo-repository.ts'; +import { MongoUnitOfWork } from './mongo-unit-of-work.ts'; const test = { for: describeFeature }; @@ -32,32 +32,6 @@ class RepoMock extends MongoRepositoryBase {} -// Helper types and factories for domain operations -type RepoOp = (repo: RepoMock) => Promise; -type RepoOpMock = RepoOp & MockInstance; -type DispatchMock = ReturnType; - -function makeDomainOpWithoutEvents(): RepoOpMock { - const op: RepoOp = async (repo) => { - const aggregate = await repo.get('agg-1'); - aggregate.foo = 'new-foo'; - await repo.save(aggregate); - }; - return vi.fn(op) as RepoOpMock; -} - -function makeDomainOpWithEvents(events: TestEvent[]): RepoOpMock { - const op: RepoOp = async (repo) => { - const aggregate = await repo.get('agg-1'); - aggregate.foo = 'new-foo'; - for (const e of events) { - aggregate.addIntegrationEvent(TestEvent, e.payload); - } - await repo.save(aggregate); - }; - return vi.fn(op) as RepoOpMock; -} - vi.mock('mongoose', async () => { const original = await vi.importActual('mongoose'); return { @@ -73,14 +47,14 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { let repoInstance: RepoMock; let eventBus: DomainSeedwork.EventBus; let integrationEventBus: DomainSeedwork.EventBus; - let dispatchMock: DispatchMock; let session: ClientSession; let mockModel: Model; let typeConverter: DomainSeedwork.TypeConverter; const Passport = {}; - class TestRepoClass extends RepoMock {} - let domainOperation: RepoOpMock; + const TestRepoClass = RepoMock; + + let domainOperation: Mock<(repo: RepoMock) => Promise>; const setupMockModelReturningAggregate = () => { (mockModel.findById as ReturnType).mockReturnValue({ @@ -89,24 +63,7 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { foo: 'old-foo', }), }); - } - - const setupRepoNoEvents = () => { - repoInstance.getIntegrationEvents = vi.fn(() => []) as typeof repoInstance.getIntegrationEvents; - repoInstance.get = vi.fn().mockResolvedValue( - new AggregateRootMock( - { - id: 'agg-1', - foo: 'old-foo', - createdAt: new Date(), - updatedAt: new Date(), - schemaVersion: '1', - } as PropType, - {}, - ), - ); - repoInstance.save = vi.fn().mockResolvedValue(undefined); - } + }; BeforeEachScenario(() => { session = {} as ClientSession; @@ -138,9 +95,8 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { dispatch: vi.fn(), register: vi.fn(), }) as DomainSeedwork.EventBus; - dispatchMock = vi.fn() as DispatchMock; integrationEventBus = { - dispatch: dispatchMock, + dispatch: vi.fn(), register: vi.fn(), } as unknown as DomainSeedwork.EventBus; repoInstance = new RepoMock( @@ -157,7 +113,11 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { typeConverter, TestRepoClass, ); - domainOperation = makeDomainOpWithoutEvents(); + domainOperation = vi.fn<(repo: RepoMock) => Promise>(async (repo) => { + const aggregate = await repo.get('agg-1'); + aggregate.foo = 'new-foo'; + await repo.save(aggregate); + }); vi.clearAllMocks(); vi.spyOn(mongoose.connection, 'transaction').mockImplementation( async (cb: (session: ClientSession) => Promise) => { @@ -185,14 +145,33 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { Scenario('Domain operation with no events, completes successfully', ({ Given, When, Then }) => { Given('a domain operation that emits no domain or integration events', () => { - setupRepoNoEvents(); + repoInstance.getIntegrationEvents = vi.fn(() => []) as typeof repoInstance.getIntegrationEvents; + repoInstance.get = vi.fn().mockResolvedValue( + new AggregateRootMock( + { + id: 'agg-1', + foo: 'old-foo', + createdAt: new Date(), + updatedAt: new Date(), + schemaVersion: '1', + } as PropType, + {}, + ), + ); + repoInstance.save = vi.fn().mockResolvedValue(undefined); }); When('the operation completes successfully', async () => { + const dispatchMock = integrationEventBus.dispatch as unknown as Mock< + (event: unknown, data: unknown) => Promise + >; domainOperation.mockClear(); dispatchMock.mockClear(); await unitOfWork.withTransaction(Passport, domainOperation); }); Then('the transaction is committed and no events are dispatched', () => { + const dispatchMock = integrationEventBus.dispatch as unknown as Mock< + (event: unknown, data: unknown) => Promise + >; expect(domainOperation).toHaveBeenCalledWith(expect.any(TestRepoClass)); expect(dispatchMock).not.toHaveBeenCalled(); }); @@ -201,7 +180,20 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { Scenario('Domain operation with no events, throws error', ({ Given, When, Then }) => { let domainError: Error; Given('a domain operation that emits no domain or integration events', () => { - setupRepoNoEvents(); + repoInstance.getIntegrationEvents = vi.fn(() => []) as typeof repoInstance.getIntegrationEvents; + repoInstance.get = vi.fn().mockResolvedValue( + new AggregateRootMock( + { + id: 'agg-1', + foo: 'old-foo', + createdAt: new Date(), + updatedAt: new Date(), + schemaVersion: '1', + } as PropType, + {}, + ), + ); + repoInstance.save = vi.fn().mockResolvedValue(undefined); domainError = new Error('Domain failure'); }); When('the operation throws an error', async () => { @@ -213,6 +205,9 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { ).rejects.toThrow(domainError); }); Then('the transaction is rolled back and no events are dispatched', () => { + const dispatchMock = integrationEventBus.dispatch as unknown as Mock< + (event: unknown, data: unknown) => Promise + >; expect(dispatchMock).not.toHaveBeenCalled(); }); }); @@ -220,21 +215,33 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { Scenario('Domain operation emits integration events, all dispatch succeed', ({ Given, When, Then }) => { let event1: TestEvent; let event2: TestEvent; - let customDomainOp: RepoOpMock; + let customDomainOp: Mock<(repo: RepoMock) => Promise>; Given('integration events are emitted during the domain operation', () => { event1 = new TestEvent('id'); event1.payload = { foo: 'bar1' }; event2 = new TestEvent('id'); event2.payload = { foo: 'bar2' }; - customDomainOp = makeDomainOpWithEvents([event1, event2]); + customDomainOp = vi.fn<(repo: RepoMock) => Promise>(async (repo) => { + const aggregate = await repo.get('agg-1'); + aggregate.foo = 'new-foo'; + aggregate.addIntegrationEvent(TestEvent, event1.payload); + aggregate.addIntegrationEvent(TestEvent, event2.payload); + await repo.save(aggregate); + }); }); When('the transaction completes successfully', async () => { + const dispatchMock = integrationEventBus.dispatch as unknown as Mock< + (event: unknown, data: unknown) => Promise + >; dispatchMock.mockClear(); dispatchMock.mockResolvedValueOnce(undefined); dispatchMock.mockResolvedValueOnce(undefined); await unitOfWork.withTransaction(Passport, customDomainOp); }); Then('all integration events are dispatched after the transaction commits', () => { + const dispatchMock = integrationEventBus.dispatch as unknown as Mock< + (event: unknown, data: unknown) => Promise + >; expect(dispatchMock).toHaveBeenCalledTimes(2); expect(dispatchMock).toHaveBeenNthCalledWith(1, event1.constructor, event1.payload); expect(dispatchMock).toHaveBeenNthCalledWith(2, event2.constructor, event2.payload); @@ -244,20 +251,32 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { Scenario('Integration event dispatch fails', ({ Given, When, Then }) => { let event1: TestEvent; let event2: TestEvent; - let customDomainOp: RepoOpMock; + let customDomainOp: Mock<(repo: RepoMock) => Promise>; Given('integration events are emitted during the domain operation', () => { event1 = new TestEvent('id'); event1.payload = { foo: 'bar1' }; event2 = new TestEvent('id'); event2.payload = { foo: 'bar2' }; - customDomainOp = makeDomainOpWithEvents([event1, event2]); + customDomainOp = vi.fn<(repo: RepoMock) => Promise>(async (repo) => { + const aggregate = await repo.get('agg-1'); + aggregate.foo = 'new-foo'; + aggregate.addIntegrationEvent(TestEvent, event1.payload); + aggregate.addIntegrationEvent(TestEvent, event2.payload); + await repo.save(aggregate); + }); }); When('integration event dispatch fails', async () => { + const dispatchMock = integrationEventBus.dispatch as unknown as Mock< + (event: unknown, data: unknown) => Promise + >; dispatchMock.mockClear(); dispatchMock.mockRejectedValueOnce(new Error('rejected promise')); await expect(unitOfWork.withTransaction(Passport, customDomainOp)).rejects.toThrow('rejected promise'); }); Then('the error from dispatch is propagated and the transaction is not rolled back by the unit of work', () => { + const dispatchMock = integrationEventBus.dispatch as unknown as Mock< + (event: unknown, data: unknown) => Promise + >; expect(dispatchMock).toHaveBeenCalledTimes(1); }); }); @@ -265,21 +284,33 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { Scenario('Multiple integration events are emitted and all succeed', ({ Given, When, Then }) => { let event1: TestEvent; let event2: TestEvent; - let customDomainOp: RepoOpMock; + let customDomainOp: Mock<(repo: RepoMock) => Promise>; Given('integration events are emitted during the domain operation', () => { event1 = new TestEvent('id'); event1.payload = { foo: 'bar1' }; event2 = new TestEvent('id'); event2.payload = { foo: 'bar2' }; - customDomainOp = makeDomainOpWithEvents([event1, event2]); + customDomainOp = vi.fn<(repo: RepoMock) => Promise>(async (repo) => { + const aggregate = await repo.get('agg-1'); + aggregate.foo = 'new-foo'; + aggregate.addIntegrationEvent(TestEvent, event1.payload); + aggregate.addIntegrationEvent(TestEvent, event2.payload); + await repo.save(aggregate); + }); }); When('multiple integration events are emitted and all succeed', async () => { + const dispatchMock = integrationEventBus.dispatch as unknown as Mock< + (event: unknown, data: unknown) => Promise + >; dispatchMock.mockClear(); dispatchMock.mockResolvedValueOnce(undefined); dispatchMock.mockResolvedValueOnce(undefined); await unitOfWork.withTransaction(Passport, customDomainOp); }); Then('all are dispatched after the transaction', () => { + const dispatchMock = integrationEventBus.dispatch as unknown as Mock< + (event: unknown, data: unknown) => Promise + >; expect(dispatchMock).toHaveBeenCalledTimes(2); }); }); From a50b4eadbab21e11348030e88557bc5a29ce7ff3 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Wed, 7 Jan 2026 11:13:53 -0500 Subject: [PATCH 70/74] refactor(tests): enhance mongo-unit-of-work tests by simplifying domain operations and improving event handling (per sourcery's suggestions) --- .../mongo-unit-of-work.test.ts | 149 ++++++------------ 1 file changed, 50 insertions(+), 99 deletions(-) diff --git a/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts b/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts index 7633eb315..f0cb86dc5 100644 --- a/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts +++ b/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts @@ -44,10 +44,14 @@ vi.mock('mongoose', async () => { test.for(feature, ({ Scenario, BeforeEachScenario }) => { let unitOfWork: MongoUnitOfWork; - let repoInstance: RepoMock; let eventBus: DomainSeedwork.EventBus; - let integrationEventBus: DomainSeedwork.EventBus; - let session: ClientSession; + type IntegrationDispatchMock = Mock<(event: unknown, data: unknown) => Promise>; + type IntegrationEventBusMock = { + dispatch: IntegrationDispatchMock; + register: Mock<(handler: unknown) => void>; + }; + + let integrationEventBus: IntegrationEventBusMock; let mockModel: Model; let typeConverter: DomainSeedwork.TypeConverter; @@ -56,17 +60,23 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { let domainOperation: Mock<(repo: RepoMock) => Promise>; - const setupMockModelReturningAggregate = () => { - (mockModel.findById as ReturnType).mockReturnValue({ - exec: vi.fn().mockResolvedValue({ - _id: 'agg-1', - foo: 'old-foo', - }), + const getIntegrationDispatchMock = (): IntegrationDispatchMock => integrationEventBus.dispatch; + + const makeDomainOperation = (options?: { + events?: Array<{ ctor: typeof TestEvent; payload: { foo: string } }>; + }): Mock<(repo: RepoMock) => Promise> => + vi.fn(async (repo: RepoMock) => { + const aggregate = await repo.get('agg-1'); + aggregate.foo = 'new-foo'; + + for (const event of options?.events ?? []) { + aggregate.addIntegrationEvent(event.ctor, event.payload); + } + + await repo.save(aggregate); }); - }; BeforeEachScenario(() => { - session = {} as ClientSession; mockModel = { findById: vi.fn().mockReturnValue({ exec: vi.fn().mockResolvedValue({ @@ -98,33 +108,21 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { integrationEventBus = { dispatch: vi.fn(), register: vi.fn(), - } as unknown as DomainSeedwork.EventBus; - repoInstance = new RepoMock( - vi.mocked({}), - mockModel, - typeConverter, - eventBus, - session, - ); + }; unitOfWork = new MongoUnitOfWork( eventBus, - integrationEventBus, + integrationEventBus as unknown as DomainSeedwork.EventBus, mockModel, typeConverter, TestRepoClass, ); - domainOperation = vi.fn<(repo: RepoMock) => Promise>(async (repo) => { - const aggregate = await repo.get('agg-1'); - aggregate.foo = 'new-foo'; - await repo.save(aggregate); - }); + domainOperation = makeDomainOperation(); vi.clearAllMocks(); vi.spyOn(mongoose.connection, 'transaction').mockImplementation( async (cb: (session: ClientSession) => Promise) => { return await cb({} as ClientSession); }, ); - setupMockModelReturningAggregate(); }); Scenario('Initializing the MongoUnitOfWork', ({ Given, When, Then }) => { @@ -145,33 +143,16 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { Scenario('Domain operation with no events, completes successfully', ({ Given, When, Then }) => { Given('a domain operation that emits no domain or integration events', () => { - repoInstance.getIntegrationEvents = vi.fn(() => []) as typeof repoInstance.getIntegrationEvents; - repoInstance.get = vi.fn().mockResolvedValue( - new AggregateRootMock( - { - id: 'agg-1', - foo: 'old-foo', - createdAt: new Date(), - updatedAt: new Date(), - schemaVersion: '1', - } as PropType, - {}, - ), - ); - repoInstance.save = vi.fn().mockResolvedValue(undefined); + domainOperation = makeDomainOperation(); }); When('the operation completes successfully', async () => { - const dispatchMock = integrationEventBus.dispatch as unknown as Mock< - (event: unknown, data: unknown) => Promise - >; + const dispatchMock = getIntegrationDispatchMock(); domainOperation.mockClear(); dispatchMock.mockClear(); await unitOfWork.withTransaction(Passport, domainOperation); }); Then('the transaction is committed and no events are dispatched', () => { - const dispatchMock = integrationEventBus.dispatch as unknown as Mock< - (event: unknown, data: unknown) => Promise - >; + const dispatchMock = getIntegrationDispatchMock(); expect(domainOperation).toHaveBeenCalledWith(expect.any(TestRepoClass)); expect(dispatchMock).not.toHaveBeenCalled(); }); @@ -180,20 +161,7 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { Scenario('Domain operation with no events, throws error', ({ Given, When, Then }) => { let domainError: Error; Given('a domain operation that emits no domain or integration events', () => { - repoInstance.getIntegrationEvents = vi.fn(() => []) as typeof repoInstance.getIntegrationEvents; - repoInstance.get = vi.fn().mockResolvedValue( - new AggregateRootMock( - { - id: 'agg-1', - foo: 'old-foo', - createdAt: new Date(), - updatedAt: new Date(), - schemaVersion: '1', - } as PropType, - {}, - ), - ); - repoInstance.save = vi.fn().mockResolvedValue(undefined); + domainOperation = makeDomainOperation(); domainError = new Error('Domain failure'); }); When('the operation throws an error', async () => { @@ -205,9 +173,7 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { ).rejects.toThrow(domainError); }); Then('the transaction is rolled back and no events are dispatched', () => { - const dispatchMock = integrationEventBus.dispatch as unknown as Mock< - (event: unknown, data: unknown) => Promise - >; + const dispatchMock = getIntegrationDispatchMock(); expect(dispatchMock).not.toHaveBeenCalled(); }); }); @@ -221,27 +187,22 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { event1.payload = { foo: 'bar1' }; event2 = new TestEvent('id'); event2.payload = { foo: 'bar2' }; - customDomainOp = vi.fn<(repo: RepoMock) => Promise>(async (repo) => { - const aggregate = await repo.get('agg-1'); - aggregate.foo = 'new-foo'; - aggregate.addIntegrationEvent(TestEvent, event1.payload); - aggregate.addIntegrationEvent(TestEvent, event2.payload); - await repo.save(aggregate); + customDomainOp = makeDomainOperation({ + events: [ + { ctor: TestEvent, payload: event1.payload }, + { ctor: TestEvent, payload: event2.payload }, + ], }); }); When('the transaction completes successfully', async () => { - const dispatchMock = integrationEventBus.dispatch as unknown as Mock< - (event: unknown, data: unknown) => Promise - >; + const dispatchMock = getIntegrationDispatchMock(); dispatchMock.mockClear(); dispatchMock.mockResolvedValueOnce(undefined); dispatchMock.mockResolvedValueOnce(undefined); await unitOfWork.withTransaction(Passport, customDomainOp); }); Then('all integration events are dispatched after the transaction commits', () => { - const dispatchMock = integrationEventBus.dispatch as unknown as Mock< - (event: unknown, data: unknown) => Promise - >; + const dispatchMock = getIntegrationDispatchMock(); expect(dispatchMock).toHaveBeenCalledTimes(2); expect(dispatchMock).toHaveBeenNthCalledWith(1, event1.constructor, event1.payload); expect(dispatchMock).toHaveBeenNthCalledWith(2, event2.constructor, event2.payload); @@ -257,26 +218,21 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { event1.payload = { foo: 'bar1' }; event2 = new TestEvent('id'); event2.payload = { foo: 'bar2' }; - customDomainOp = vi.fn<(repo: RepoMock) => Promise>(async (repo) => { - const aggregate = await repo.get('agg-1'); - aggregate.foo = 'new-foo'; - aggregate.addIntegrationEvent(TestEvent, event1.payload); - aggregate.addIntegrationEvent(TestEvent, event2.payload); - await repo.save(aggregate); + customDomainOp = makeDomainOperation({ + events: [ + { ctor: TestEvent, payload: event1.payload }, + { ctor: TestEvent, payload: event2.payload }, + ], }); }); When('integration event dispatch fails', async () => { - const dispatchMock = integrationEventBus.dispatch as unknown as Mock< - (event: unknown, data: unknown) => Promise - >; + const dispatchMock = getIntegrationDispatchMock(); dispatchMock.mockClear(); dispatchMock.mockRejectedValueOnce(new Error('rejected promise')); await expect(unitOfWork.withTransaction(Passport, customDomainOp)).rejects.toThrow('rejected promise'); }); Then('the error from dispatch is propagated and the transaction is not rolled back by the unit of work', () => { - const dispatchMock = integrationEventBus.dispatch as unknown as Mock< - (event: unknown, data: unknown) => Promise - >; + const dispatchMock = getIntegrationDispatchMock(); expect(dispatchMock).toHaveBeenCalledTimes(1); }); }); @@ -290,27 +246,22 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { event1.payload = { foo: 'bar1' }; event2 = new TestEvent('id'); event2.payload = { foo: 'bar2' }; - customDomainOp = vi.fn<(repo: RepoMock) => Promise>(async (repo) => { - const aggregate = await repo.get('agg-1'); - aggregate.foo = 'new-foo'; - aggregate.addIntegrationEvent(TestEvent, event1.payload); - aggregate.addIntegrationEvent(TestEvent, event2.payload); - await repo.save(aggregate); + customDomainOp = makeDomainOperation({ + events: [ + { ctor: TestEvent, payload: event1.payload }, + { ctor: TestEvent, payload: event2.payload }, + ], }); }); When('multiple integration events are emitted and all succeed', async () => { - const dispatchMock = integrationEventBus.dispatch as unknown as Mock< - (event: unknown, data: unknown) => Promise - >; + const dispatchMock = getIntegrationDispatchMock(); dispatchMock.mockClear(); dispatchMock.mockResolvedValueOnce(undefined); dispatchMock.mockResolvedValueOnce(undefined); await unitOfWork.withTransaction(Passport, customDomainOp); }); Then('all are dispatched after the transaction', () => { - const dispatchMock = integrationEventBus.dispatch as unknown as Mock< - (event: unknown, data: unknown) => Promise - >; + const dispatchMock = getIntegrationDispatchMock(); expect(dispatchMock).toHaveBeenCalledTimes(2); }); }); From 53f3161c4fa06d609b262e4bafbc14dc2db1061b Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Wed, 7 Jan 2026 12:10:55 -0500 Subject: [PATCH 71/74] clean up --- .../mongo-unit-of-work.test.ts | 71 +++++++------------ 1 file changed, 27 insertions(+), 44 deletions(-) diff --git a/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts b/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts index f0cb86dc5..6250a49f6 100644 --- a/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts +++ b/packages/cellix/mongoose-seedwork/src/mongoose-seedwork/mongo-unit-of-work.test.ts @@ -45,22 +45,11 @@ vi.mock('mongoose', async () => { test.for(feature, ({ Scenario, BeforeEachScenario }) => { let unitOfWork: MongoUnitOfWork; let eventBus: DomainSeedwork.EventBus; - type IntegrationDispatchMock = Mock<(event: unknown, data: unknown) => Promise>; - type IntegrationEventBusMock = { - dispatch: IntegrationDispatchMock; - register: Mock<(handler: unknown) => void>; - }; - - let integrationEventBus: IntegrationEventBusMock; + let integrationEventBus: DomainSeedwork.EventBus; let mockModel: Model; let typeConverter: DomainSeedwork.TypeConverter; const Passport = {}; - const TestRepoClass = RepoMock; - - let domainOperation: Mock<(repo: RepoMock) => Promise>; - - const getIntegrationDispatchMock = (): IntegrationDispatchMock => integrationEventBus.dispatch; const makeDomainOperation = (options?: { events?: Array<{ ctor: typeof TestEvent; payload: { foo: string } }>; @@ -105,19 +94,17 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { dispatch: vi.fn(), register: vi.fn(), }) as DomainSeedwork.EventBus; - integrationEventBus = { + integrationEventBus = vi.mocked({ dispatch: vi.fn(), register: vi.fn(), - }; + }) as DomainSeedwork.EventBus; unitOfWork = new MongoUnitOfWork( eventBus, - integrationEventBus as unknown as DomainSeedwork.EventBus, + integrationEventBus, mockModel, typeConverter, - TestRepoClass, + RepoMock, ); - domainOperation = makeDomainOperation(); - vi.clearAllMocks(); vi.spyOn(mongoose.connection, 'transaction').mockImplementation( async (cb: (session: ClientSession) => Promise) => { return await cb({} as ClientSession); @@ -137,31 +124,30 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { expect(unitOfWork.typeConverter).toBe(typeConverter); expect(unitOfWork.bus).toBe(eventBus); expect(unitOfWork.integrationEventBus).toBe(integrationEventBus); - expect(unitOfWork.repoClass).toBe(TestRepoClass); + expect(unitOfWork.repoClass).toBe(RepoMock); }); }); Scenario('Domain operation with no events, completes successfully', ({ Given, When, Then }) => { + let domainOperation: Mock<(repo: RepoMock) => Promise>; + Given('a domain operation that emits no domain or integration events', () => { domainOperation = makeDomainOperation(); }); When('the operation completes successfully', async () => { - const dispatchMock = getIntegrationDispatchMock(); - domainOperation.mockClear(); - dispatchMock.mockClear(); await unitOfWork.withTransaction(Passport, domainOperation); }); Then('the transaction is committed and no events are dispatched', () => { - const dispatchMock = getIntegrationDispatchMock(); - expect(domainOperation).toHaveBeenCalledWith(expect.any(TestRepoClass)); + const dispatchMock = integrationEventBus.dispatch as Mock; + expect(domainOperation).toHaveBeenCalledWith(expect.any(RepoMock)); expect(dispatchMock).not.toHaveBeenCalled(); }); }); Scenario('Domain operation with no events, throws error', ({ Given, When, Then }) => { let domainError: Error; + Given('a domain operation that emits no domain or integration events', () => { - domainOperation = makeDomainOperation(); domainError = new Error('Domain failure'); }); When('the operation throws an error', async () => { @@ -173,7 +159,7 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { ).rejects.toThrow(domainError); }); Then('the transaction is rolled back and no events are dispatched', () => { - const dispatchMock = getIntegrationDispatchMock(); + const dispatchMock = integrationEventBus.dispatch as Mock; expect(dispatchMock).not.toHaveBeenCalled(); }); }); @@ -181,13 +167,13 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { Scenario('Domain operation emits integration events, all dispatch succeed', ({ Given, When, Then }) => { let event1: TestEvent; let event2: TestEvent; - let customDomainOp: Mock<(repo: RepoMock) => Promise>; + let domainOperation: Mock<(repo: RepoMock) => Promise>; Given('integration events are emitted during the domain operation', () => { event1 = new TestEvent('id'); event1.payload = { foo: 'bar1' }; event2 = new TestEvent('id'); event2.payload = { foo: 'bar2' }; - customDomainOp = makeDomainOperation({ + domainOperation = makeDomainOperation({ events: [ { ctor: TestEvent, payload: event1.payload }, { ctor: TestEvent, payload: event2.payload }, @@ -195,14 +181,13 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { }); }); When('the transaction completes successfully', async () => { - const dispatchMock = getIntegrationDispatchMock(); - dispatchMock.mockClear(); + const dispatchMock = integrationEventBus.dispatch as Mock; dispatchMock.mockResolvedValueOnce(undefined); dispatchMock.mockResolvedValueOnce(undefined); - await unitOfWork.withTransaction(Passport, customDomainOp); + await unitOfWork.withTransaction(Passport, domainOperation); }); Then('all integration events are dispatched after the transaction commits', () => { - const dispatchMock = getIntegrationDispatchMock(); + const dispatchMock = integrationEventBus.dispatch as Mock; expect(dispatchMock).toHaveBeenCalledTimes(2); expect(dispatchMock).toHaveBeenNthCalledWith(1, event1.constructor, event1.payload); expect(dispatchMock).toHaveBeenNthCalledWith(2, event2.constructor, event2.payload); @@ -212,13 +197,13 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { Scenario('Integration event dispatch fails', ({ Given, When, Then }) => { let event1: TestEvent; let event2: TestEvent; - let customDomainOp: Mock<(repo: RepoMock) => Promise>; + let domainOperation: Mock<(repo: RepoMock) => Promise>; Given('integration events are emitted during the domain operation', () => { event1 = new TestEvent('id'); event1.payload = { foo: 'bar1' }; event2 = new TestEvent('id'); event2.payload = { foo: 'bar2' }; - customDomainOp = makeDomainOperation({ + domainOperation = makeDomainOperation({ events: [ { ctor: TestEvent, payload: event1.payload }, { ctor: TestEvent, payload: event2.payload }, @@ -226,13 +211,12 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { }); }); When('integration event dispatch fails', async () => { - const dispatchMock = getIntegrationDispatchMock(); - dispatchMock.mockClear(); + const dispatchMock = integrationEventBus.dispatch as Mock; dispatchMock.mockRejectedValueOnce(new Error('rejected promise')); - await expect(unitOfWork.withTransaction(Passport, customDomainOp)).rejects.toThrow('rejected promise'); + await expect(unitOfWork.withTransaction(Passport, domainOperation)).rejects.toThrow('rejected promise'); }); Then('the error from dispatch is propagated and the transaction is not rolled back by the unit of work', () => { - const dispatchMock = getIntegrationDispatchMock(); + const dispatchMock = integrationEventBus.dispatch as Mock; expect(dispatchMock).toHaveBeenCalledTimes(1); }); }); @@ -240,13 +224,13 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { Scenario('Multiple integration events are emitted and all succeed', ({ Given, When, Then }) => { let event1: TestEvent; let event2: TestEvent; - let customDomainOp: Mock<(repo: RepoMock) => Promise>; + let domainOperation: Mock<(repo: RepoMock) => Promise>; Given('integration events are emitted during the domain operation', () => { event1 = new TestEvent('id'); event1.payload = { foo: 'bar1' }; event2 = new TestEvent('id'); event2.payload = { foo: 'bar2' }; - customDomainOp = makeDomainOperation({ + domainOperation = makeDomainOperation({ events: [ { ctor: TestEvent, payload: event1.payload }, { ctor: TestEvent, payload: event2.payload }, @@ -254,14 +238,13 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { }); }); When('multiple integration events are emitted and all succeed', async () => { - const dispatchMock = getIntegrationDispatchMock(); - dispatchMock.mockClear(); + const dispatchMock = integrationEventBus.dispatch as Mock; dispatchMock.mockResolvedValueOnce(undefined); dispatchMock.mockResolvedValueOnce(undefined); - await unitOfWork.withTransaction(Passport, customDomainOp); + await unitOfWork.withTransaction(Passport, domainOperation); }); Then('all are dispatched after the transaction', () => { - const dispatchMock = getIntegrationDispatchMock(); + const dispatchMock = integrationEventBus.dispatch as Mock; expect(dispatchMock).toHaveBeenCalledTimes(2); }); }); From 0a310f1b1be10ebf606707d3ea2f43a40db1c44a Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Wed, 7 Jan 2026 14:42:08 -0500 Subject: [PATCH 72/74] update implementation for test coverage of ui and node packages --- apps/ui-sharethrift/package.json | 2 +- build-pipeline/core/monorepo-build-stage.yml | 4 ++-- package.json | 9 +++------ packages/cellix/domain-seedwork/package.json | 2 +- packages/cellix/event-bus-seedwork-node/package.json | 2 +- packages/cellix/mongoose-seedwork/package.json | 2 +- packages/cellix/test-utils/package.json | 2 +- packages/cellix/ui-core/package.json | 2 +- packages/sthrift/application-services/package.json | 2 +- packages/sthrift/domain/package.json | 2 +- packages/sthrift/graphql/package.json | 2 +- packages/sthrift/messaging-service-mock/package.json | 2 +- packages/sthrift/persistence/package.json | 2 +- packages/sthrift/service-mongoose/package.json | 2 +- packages/sthrift/service-otel/package.json | 2 +- packages/sthrift/ui-components/package.json | 2 +- turbo.json | 7 ++++++- 17 files changed, 25 insertions(+), 23 deletions(-) diff --git a/apps/ui-sharethrift/package.json b/apps/ui-sharethrift/package.json index a87d0af44..f91951742 100644 --- a/apps/ui-sharethrift/package.json +++ b/apps/ui-sharethrift/package.json @@ -12,7 +12,7 @@ "storybook": "storybook dev -p 6006", "build-storybook": "storybook build", "test": "vitest run", - "test:coverage": "vitest run --coverage", + "test:coverage:ui": "vitest run --coverage", "test:watch": "vitest" }, "dependencies": { diff --git a/build-pipeline/core/monorepo-build-stage.yml b/build-pipeline/core/monorepo-build-stage.yml index f4749f3c7..f7f181454 100644 --- a/build-pipeline/core/monorepo-build-stage.yml +++ b/build-pipeline/core/monorepo-build-stage.yml @@ -245,9 +245,9 @@ stages: echo "Testing affected packages only (PR/branch build)..." export TURBO_SCM_BASE="origin/$(System.PullRequest.TargetBranch)" echo "Running Node unit tests with coverage..." - pnpm run test:coverage:node:affected + pnpm run test:coverage:node --affected echo "Running Storybook/Playwright tests with coverage..." - pnpm run test:coverage:ui:affected + pnpm run test:coverage:ui --affected pnpm run merge-lcov-reports else echo "Testing all packages (main branch build)..." diff --git a/package.json b/package.json index 9b66894d2..a730e69c7 100644 --- a/package.json +++ b/package.json @@ -27,13 +27,10 @@ "start-emulator:payment-server": "pnpm run start --workspace=@cellix/mock-payment-server", "start-emulator:messaging-server": "pnpm run start --workspace=@sthrift/mock-messaging-server", "test:all": "turbo run test:all", - "test:coverage": "pnpm run test:coverage:node && pnpm run test:coverage:ui", - "test:coverage:node": "turbo run test:coverage --filter=!@cellix/ui-core --filter=!@sthrift/ui-components --filter=!@sthrift/ui-sharethrift", - "test:coverage:ui": "turbo run test:coverage --filter=@cellix/ui-core --filter=@sthrift/ui-components --filter=@sthrift/ui-sharethrift", - "test:coverage:node:affected": "turbo run test:coverage --filter=\"...[${TURBO_SCM_BASE:-origin/main}]\" --filter=!@cellix/ui-core --filter=!@sthrift/ui-components --filter=!@sthrift/ui-sharethrift", - "test:coverage:ui:affected": "turbo run test:coverage --filter=\"@cellix/ui-core...[${TURBO_SCM_BASE:-origin/main}]\" --filter=\"@sthrift/ui-components...[${TURBO_SCM_BASE:-origin/main}]\" --filter=\"@sthrift/ui-sharethrift...[${TURBO_SCM_BASE:-origin/main}]\"", + "test:coverage": "turbo run test:coverage:ui && turbo run test:coverage:node", + "test:coverage:node": "turbo run test:coverage:node", + "test:coverage:ui": "turbo run test:coverage:ui", "test:coverage:merge": "pnpm run test:coverage && pnpm run merge-lcov-reports", - "test:coverage:merge:affected": "pnpm run test:coverage:node:affected && pnpm run test:coverage:ui:affected && pnpm run merge-lcov-reports", "merge-lcov-reports": "node build-pipeline/scripts/merge-coverage.js", "test:integration": "turbo run test:integration", "test:serenity": "turbo run test:serenity", diff --git a/packages/cellix/domain-seedwork/package.json b/packages/cellix/domain-seedwork/package.json index 8c685280b..7f257d221 100644 --- a/packages/cellix/domain-seedwork/package.json +++ b/packages/cellix/domain-seedwork/package.json @@ -17,7 +17,7 @@ "build": "tsc --build", "watch": "tsc --watch", "test": "vitest run", - "test:coverage": "vitest run --coverage", + "test:coverage:node": "vitest run --coverage", "test:watch": "vitest", "lint": "biome lint", "clean": "rimraf dist" diff --git a/packages/cellix/event-bus-seedwork-node/package.json b/packages/cellix/event-bus-seedwork-node/package.json index 009235196..9ab7319ed 100644 --- a/packages/cellix/event-bus-seedwork-node/package.json +++ b/packages/cellix/event-bus-seedwork-node/package.json @@ -17,7 +17,7 @@ "build": "tsc --build", "watch": "tsc --watch", "test": "vitest run", - "test:coverage": "vitest run --coverage", + "test:coverage:node": "vitest run --coverage", "test:watch": "vitest", "lint": "biome lint", "clean": "rimraf dist" diff --git a/packages/cellix/mongoose-seedwork/package.json b/packages/cellix/mongoose-seedwork/package.json index d1440783f..597f448e4 100644 --- a/packages/cellix/mongoose-seedwork/package.json +++ b/packages/cellix/mongoose-seedwork/package.json @@ -17,7 +17,7 @@ "build": "tsc --build", "watch": "tsc --watch", "test": "vitest run", - "test:coverage": "vitest run --coverage", + "test:coverage:node": "vitest run --coverage", "test:integration": "vitest run integration.test.ts", "test:unit": "vitest run --exclude tests/integration/**/*.test.ts", "test:watch": "vitest", diff --git a/packages/cellix/test-utils/package.json b/packages/cellix/test-utils/package.json index 9fb06b54d..f68ef562d 100644 --- a/packages/cellix/test-utils/package.json +++ b/packages/cellix/test-utils/package.json @@ -20,7 +20,7 @@ "clean": "rimraf dist", "test": "vitest run", "test:watch": "vitest", - "test:coverage": "vitest run --coverage" + "test:coverage:node": "vitest run --coverage" }, "devDependencies": { "rimraf": "^6.0.1", diff --git a/packages/cellix/ui-core/package.json b/packages/cellix/ui-core/package.json index 1dc44ecaa..b5fa12e17 100644 --- a/packages/cellix/ui-core/package.json +++ b/packages/cellix/ui-core/package.json @@ -21,7 +21,7 @@ "build": "tsc --build", "watch": "tsc --watch", "test": "vitest run", - "test:coverage": "vitest run --coverage", + "test:coverage:ui": "vitest run --coverage", "test:watch": "vitest", "lint": "biome lint", "clean": "rimraf dist", diff --git a/packages/sthrift/application-services/package.json b/packages/sthrift/application-services/package.json index afc88da2c..9aa24ebda 100644 --- a/packages/sthrift/application-services/package.json +++ b/packages/sthrift/application-services/package.json @@ -17,7 +17,7 @@ "build": "tsc --build", "watch": "tsc --watch", "test": "vitest run", - "test:coverage": "vitest run --coverage", + "test:coverage:node": "vitest run --coverage", "test:watch": "vitest", "lint": "biome lint", "clean": "rimraf dist" diff --git a/packages/sthrift/domain/package.json b/packages/sthrift/domain/package.json index 5a629be5a..2a6724754 100644 --- a/packages/sthrift/domain/package.json +++ b/packages/sthrift/domain/package.json @@ -17,7 +17,7 @@ "build": "tsc --build", "watch": "tsc --watch", "test": "vitest run", - "test:coverage": "vitest run --coverage", + "test:coverage:node": "vitest run --coverage", "test:integration": "vitest run integration.test.ts", "test:serenity": "cucumber-js", "test:unit": "vitest run --exclude tests/integration/**/*.test.ts", diff --git a/packages/sthrift/graphql/package.json b/packages/sthrift/graphql/package.json index ac72c9226..022168d18 100644 --- a/packages/sthrift/graphql/package.json +++ b/packages/sthrift/graphql/package.json @@ -18,7 +18,7 @@ "build": "tsc --build", "watch": "tsc --build --watch", "test": "vitest run", - "test:coverage": "vitest run --coverage", + "test:coverage:node": "vitest run --coverage", "test:watch": "vitest", "lint": "biome lint", "clean": "rimraf dist" diff --git a/packages/sthrift/messaging-service-mock/package.json b/packages/sthrift/messaging-service-mock/package.json index e6cb131df..d601239cd 100644 --- a/packages/sthrift/messaging-service-mock/package.json +++ b/packages/sthrift/messaging-service-mock/package.json @@ -14,7 +14,7 @@ "scripts": { "build": "tsc --project tsconfig.json", "test": "vitest run", - "test:coverage": "vitest run --coverage", + "test:coverage:node": "vitest run --coverage", "test:watch": "vitest" }, "dependencies": { diff --git a/packages/sthrift/persistence/package.json b/packages/sthrift/persistence/package.json index aebf9ee0a..542b577c1 100644 --- a/packages/sthrift/persistence/package.json +++ b/packages/sthrift/persistence/package.json @@ -17,7 +17,7 @@ "build": "tsc --build", "watch": "tsc --watch", "test": "vitest run", - "test:coverage": "vitest run --coverage", + "test:coverage:node": "vitest run --coverage", "test:watch": "vitest", "lint": "biome lint", "clean": "rimraf dist" diff --git a/packages/sthrift/service-mongoose/package.json b/packages/sthrift/service-mongoose/package.json index 1e57c5e0d..028a96a92 100644 --- a/packages/sthrift/service-mongoose/package.json +++ b/packages/sthrift/service-mongoose/package.json @@ -17,7 +17,7 @@ "build": "tsc --build", "watch": "tsc --watch", "test": "vitest run", - "test:coverage": "vitest run --coverage", + "test:coverage:node": "vitest run --coverage", "test:watch": "vitest", "lint": "biome lint", "clean": "rimraf dist" diff --git a/packages/sthrift/service-otel/package.json b/packages/sthrift/service-otel/package.json index 29c414f7a..8dc4bb94b 100644 --- a/packages/sthrift/service-otel/package.json +++ b/packages/sthrift/service-otel/package.json @@ -17,7 +17,7 @@ "build": "tsc --build", "watch": "tsc --watch", "test": "vitest run", - "test:coverage": "vitest run --coverage", + "test:coverage:node": "vitest run --coverage", "test:watch": "vitest", "lint": "biome lint", "clean": "rimraf dist" diff --git a/packages/sthrift/ui-components/package.json b/packages/sthrift/ui-components/package.json index aba0671e9..56f05e48d 100644 --- a/packages/sthrift/ui-components/package.json +++ b/packages/sthrift/ui-components/package.json @@ -37,7 +37,7 @@ "copy-css": "cpx \"src/**/*.{css,svg,png,jpg,jpeg,gif}\" dist/src", "watch": "tsc --watch", "test": "vitest run", - "test:coverage": "vitest run --coverage", + "test:coverage:ui": "vitest run --coverage", "test:watch": "vitest", "lint": "biome lint", "clean": "rimraf dist", diff --git a/turbo.json b/turbo.json index 03980c8b4..df140205e 100644 --- a/turbo.json +++ b/turbo.json @@ -10,7 +10,12 @@ "dependsOn": ["^build", "@cellix/vitest-config#build"], "inputs": ["src/**", "tests/**", "vitest*.config.*"] }, - "test:coverage": { + "test:coverage:node": { + "dependsOn": ["build", "^build", "@cellix/vitest-config#build"], + "inputs": ["src/**", "tests/**", "vitest*.config.*"], + "outputs": ["coverage/lcov.info"] + }, + "test:coverage:ui": { "dependsOn": ["build", "^build", "@cellix/vitest-config#build"], "inputs": ["src/**", "tests/**", "vitest*.config.*"], "outputs": ["coverage/lcov.info"] From 992e1bba2126a13fa82ff031221fae9b7c4a4ce3 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Wed, 7 Jan 2026 15:47:48 -0500 Subject: [PATCH 73/74] remove affected flag to check if tests run successfully --- build-pipeline/core/monorepo-build-stage.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-pipeline/core/monorepo-build-stage.yml b/build-pipeline/core/monorepo-build-stage.yml index f7f181454..47774de3c 100644 --- a/build-pipeline/core/monorepo-build-stage.yml +++ b/build-pipeline/core/monorepo-build-stage.yml @@ -245,9 +245,9 @@ stages: echo "Testing affected packages only (PR/branch build)..." export TURBO_SCM_BASE="origin/$(System.PullRequest.TargetBranch)" echo "Running Node unit tests with coverage..." - pnpm run test:coverage:node --affected + pnpm run test:coverage:node echo "Running Storybook/Playwright tests with coverage..." - pnpm run test:coverage:ui --affected + pnpm run test:coverage:ui pnpm run merge-lcov-reports else echo "Testing all packages (main branch build)..." From 3c43ca8752ae07f962e45e37804ee2577c457931 Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Wed, 7 Jan 2026 16:00:01 -0500 Subject: [PATCH 74/74] revert affected flag to original after checking tests are running fine --- build-pipeline/core/monorepo-build-stage.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-pipeline/core/monorepo-build-stage.yml b/build-pipeline/core/monorepo-build-stage.yml index 47774de3c..f7f181454 100644 --- a/build-pipeline/core/monorepo-build-stage.yml +++ b/build-pipeline/core/monorepo-build-stage.yml @@ -245,9 +245,9 @@ stages: echo "Testing affected packages only (PR/branch build)..." export TURBO_SCM_BASE="origin/$(System.PullRequest.TargetBranch)" echo "Running Node unit tests with coverage..." - pnpm run test:coverage:node + pnpm run test:coverage:node --affected echo "Running Storybook/Playwright tests with coverage..." - pnpm run test:coverage:ui + pnpm run test:coverage:ui --affected pnpm run merge-lcov-reports else echo "Testing all packages (main branch build)..."