diff --git a/api/__mocks__/exam-environment-exam.ts b/api/__fixtures__/exam-environment-exam.ts similarity index 100% rename from api/__mocks__/exam-environment-exam.ts rename to api/__fixtures__/exam-environment-exam.ts diff --git a/api/__mocks__/exam.ts b/api/__fixtures__/exam.ts similarity index 100% rename from api/__mocks__/exam.ts rename to api/__fixtures__/exam.ts diff --git a/api/src/exam-environment/routes/exam-environment.test.ts b/api/src/exam-environment/routes/exam-environment.test.ts index b821638734f..cbf78f1cd3a 100644 --- a/api/src/exam-environment/routes/exam-environment.test.ts +++ b/api/src/exam-environment/routes/exam-environment.test.ts @@ -23,7 +23,7 @@ import { examEnvironmentPostExamAttempt, examEnvironmentPostExamGeneratedExam } from '../schemas/index.js'; -import * as mock from '../../../__mocks__/exam-environment-exam.js'; +import * as mock from '../../../__fixtures__/exam-environment-exam.js'; import { constructUserExam } from '../utils/exam-environment.js'; import { JWT_SECRET } from '../../utils/env.js'; import { ExamAttemptStatus } from '../schemas/exam-environment-exam-attempt.js'; @@ -50,7 +50,11 @@ describe('/exam-environment/', () => { superGet = createSuperRequest({ method: 'GET', setCookies }); // Add exam environment authorization token const res = await superPost('/user/exam-environment/token'); - expect(res.status).toBe(201); + if (res.status !== 201) { + throw new Error( + `Expected exam environment token request to return 201, got ${res.status}` + ); + } // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment examEnvironmentAuthorizationToken = // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access @@ -289,6 +293,8 @@ describe('/exam-environment/', () => { await fastifyTestInstance.prisma.examEnvironmentExamModeration.findMany( {} ); + // Verifies cascading cleanup of moderation records when attempt data is removed in teardown. + // eslint-disable-next-line vitest/no-standalone-expect expect(a).toHaveLength(0); }); @@ -920,6 +926,7 @@ describe('/exam-environment/', () => { await fastifyTestInstance.prisma.examEnvironmentExamModeration.findMany( {} ); + // eslint-disable-next-line vitest/no-standalone-expect expect(moderationRecords).toHaveLength(0); }); @@ -996,15 +1003,17 @@ describe('/exam-environment/', () => { expect(res.status).toBe(200); }); - it.skip('TODO: (once serialization is serializable) should return 400 if no attempt id is given', async () => { - const res = await superGet('/exam-environment/exam/attempt/').set( - 'exam-environment-authorization-token', - examEnvironmentAuthorizationToken - ); - - expect(res.status).toBe(400); - }); + it.todo( + '(once serialization is serializable) should return 400 if no attempt id is given', + async () => { + const res = await superGet('/exam-environment/exam/attempt/').set( + 'exam-environment-authorization-token', + examEnvironmentAuthorizationToken + ); + expect(res.status).toBe(400); + } + ); it('should return the attempt without results, if the attempt has not been moderated', async () => { const startTime = new Date( Date.now() - mock.exam.config.totalTimeInS * 1000 @@ -1093,6 +1102,7 @@ describe('/exam-environment/', () => { await fastifyTestInstance.prisma.examEnvironmentExamModeration.findMany( {} ); + // eslint-disable-next-line vitest/no-standalone-expect expect(moderationRecords).toHaveLength(0); }); diff --git a/api/src/exam-environment/utils/exam-environment.test.ts b/api/src/exam-environment/utils/exam-environment.test.ts index bb6b53c252a..90895ca5a50 100644 --- a/api/src/exam-environment/utils/exam-environment.test.ts +++ b/api/src/exam-environment/utils/exam-environment.test.ts @@ -10,7 +10,7 @@ import { examAttempt, generatedExam, oid -} from '../../../__mocks__/exam-environment-exam.js'; +} from '../../../__fixtures__/exam-environment-exam.js'; import * as schemas from '../schemas/index.js'; import { setupServer } from '../../../vitest.utils.js'; import { diff --git a/api/src/plugins/error-handling.test.ts b/api/src/plugins/error-handling.test.ts index 480402540ba..9d16c35a276 100644 --- a/api/src/plugins/error-handling.test.ts +++ b/api/src/plugins/error-handling.test.ts @@ -251,7 +251,7 @@ describe('errorHandling', () => { }); }); - test.skip('should capture the error with Sentry', async () => { + test.todo('should capture the error with Sentry', async () => { const receivedRequest = createRequestListener(); await fastify.inject({ diff --git a/api/src/routes/protected/certificate.test.ts b/api/src/routes/protected/certificate.test.ts index e7cd9d570b2..f2860e12254 100644 --- a/api/src/routes/protected/certificate.test.ts +++ b/api/src/routes/protected/certificate.test.ts @@ -80,7 +80,7 @@ describe('certificate routes', () => { // TODO: Revisit this test after deciding if we need/want to fetch the // entire user during authorization or just the user id. - test.skip('should return 500 if user not found in db', async () => { + test.todo('should return 500 if user not found in db', async () => { vi.spyOn( fastifyTestInstance.prisma.user, 'findUnique' diff --git a/api/src/routes/protected/challenge.test.ts b/api/src/routes/protected/challenge.test.ts index a6453914f36..513aed54eed 100644 --- a/api/src/routes/protected/challenge.test.ts +++ b/api/src/routes/protected/challenge.test.ts @@ -53,7 +53,7 @@ import { examWithTwoCorrect, examWithAllCorrect, type ExamSubmission -} from '../../../__mocks__/exam.js'; +} from '../../../__fixtures__/exam.js'; import { Answer } from '../../utils/exam-types.js'; import type { getSessionUser } from '../../schemas/user/get-session-user.js'; import { verifyTrophyWithMicrosoft } from '../helpers/challenge-helpers.js'; diff --git a/api/src/routes/protected/user.test.ts b/api/src/routes/protected/user.test.ts index ba65621d858..a71739a4b30 100644 --- a/api/src/routes/protected/user.test.ts +++ b/api/src/routes/protected/user.test.ts @@ -34,7 +34,7 @@ import { seedEnvExam, seedEnvExamAttempt, seedExamEnvExamAuthToken -} from '../../../__mocks__/exam-environment-exam.js'; +} from '../../../__fixtures__/exam-environment-exam.js'; import { getMsTranscriptApiUrl } from './user.js'; const mockedFetch = vi.fn(); diff --git a/api/src/routes/public/email-subscription.test.ts b/api/src/routes/public/email-subscription.test.ts index 22a60bd4c8c..699c0aeaa21 100644 --- a/api/src/routes/public/email-subscription.test.ts +++ b/api/src/routes/public/email-subscription.test.ts @@ -101,13 +101,22 @@ describe('Email Subscription endpoints', () => { }); expect(users).toHaveLength(4); - users.forEach(user => { - if (['user1@freecodecamp.org'].includes(user.email!)) { - expect(user.sendQuincyEmail).toBe(false); - } else { - expect(user.sendQuincyEmail).toBe(true); - } - }); + const unsubscribedUsers = users.filter( + user => user.email === 'user1@freecodecamp.org' + ); + const remainingUsers = users.filter( + user => user.email !== 'user1@freecodecamp.org' + ); + + expect(unsubscribedUsers).toHaveLength(2); + expect( + unsubscribedUsers.map(({ sendQuincyEmail }) => sendQuincyEmail) + ).toStrictEqual([false, false]); + + expect(remainingUsers).toHaveLength(2); + expect( + remainingUsers.map(({ sendQuincyEmail }) => sendQuincyEmail) + ).toStrictEqual([true, true]); expect(response.headers.location).toStrictEqual( `${HOME_LOCATION}/unsubscribed/${unsubscribeId1}${urlEncodedSuccessMessage1}` @@ -146,17 +155,27 @@ describe('Email Subscription endpoints', () => { }); expect(users).toHaveLength(4); - users.forEach(user => { - if ( - ['user1@freecodecamp.org', 'user2@freecodecamp.org'].includes( + const unsubscribedUsers = users.filter(user => + ['user1@freecodecamp.org', 'user2@freecodecamp.org'].includes( + user.email! + ) + ); + const remainingUsers = users.filter( + user => + !['user1@freecodecamp.org', 'user2@freecodecamp.org'].includes( user.email! ) - ) { - expect(user.sendQuincyEmail).toBe(false); - } else { - expect(user.sendQuincyEmail).toBe(true); - } - }); + ); + + expect(unsubscribedUsers).toHaveLength(3); + expect( + unsubscribedUsers.map(({ sendQuincyEmail }) => sendQuincyEmail) + ).toStrictEqual([false, false, false]); + + expect(remainingUsers).toHaveLength(1); + expect( + remainingUsers.map(({ sendQuincyEmail }) => sendQuincyEmail) + ).toStrictEqual([true]); expect(response.headers.location).toStrictEqual( `${HOME_LOCATION}/unsubscribed/${unsubscribeId2}${urlEncodedSuccessMessage1}` @@ -214,13 +233,22 @@ describe('Email Subscription endpoints', () => { }); expect(users).toHaveLength(3); - users.forEach(user => { - if (user.unsubscribeId === unsubscribeId1) { - expect(user.sendQuincyEmail).toBe(true); - } else { - expect(user.sendQuincyEmail).toBe(false); - } - }); + const resubscribedUsers = users.filter( + user => user.unsubscribeId === unsubscribeId1 + ); + const remainingUsers = users.filter( + user => user.unsubscribeId !== unsubscribeId1 + ); + + expect(resubscribedUsers).toHaveLength(1); + expect( + resubscribedUsers.map(({ sendQuincyEmail }) => sendQuincyEmail) + ).toStrictEqual([true]); + + expect(remainingUsers).toHaveLength(2); + expect( + remainingUsers.map(({ sendQuincyEmail }) => sendQuincyEmail) + ).toStrictEqual([false, false]); expect(response.headers.location).toStrictEqual( `${HOME_LOCATION}${urlEncodedSuccessMessage2}` @@ -256,13 +284,22 @@ describe('Email Subscription endpoints', () => { }); expect(users).toHaveLength(3); - users.forEach(user => { - if (user.email === 'user2@freecodecamp.org') { - expect(user.sendQuincyEmail).toBe(true); - } else { - expect(user.sendQuincyEmail).toBe(false); - } - }); + const resubscribedUsers = users.filter( + user => user.email === 'user2@freecodecamp.org' + ); + const remainingUsers = users.filter( + user => user.email !== 'user2@freecodecamp.org' + ); + + expect(resubscribedUsers).toHaveLength(1); + expect( + resubscribedUsers.map(({ sendQuincyEmail }) => sendQuincyEmail) + ).toStrictEqual([true]); + + expect(remainingUsers).toHaveLength(2); + expect( + remainingUsers.map(({ sendQuincyEmail }) => sendQuincyEmail) + ).toStrictEqual([false, false]); expect(response.headers.location).toStrictEqual( `${HOME_LOCATION}${urlEncodedSuccessMessage2}` diff --git a/api/src/utils/exam.test.ts b/api/src/utils/exam.test.ts index cb011b85afc..5999699de9a 100644 --- a/api/src/utils/exam.test.ts +++ b/api/src/utils/exam.test.ts @@ -10,7 +10,7 @@ import { mockResultsOneCorrect, mockResultsTwoCorrect, mockResultsAllCorrect -} from '../../__mocks__/exam.js'; +} from '../../__fixtures__/exam.js'; import { generateRandomExam, createExamResults } from './exam.js'; import { GeneratedExam } from './exam-types.js'; diff --git a/api/tools/exam-environment/seed/index.ts b/api/tools/exam-environment/seed/index.ts index 158a63ea0c5..f8dd712cc08 100644 --- a/api/tools/exam-environment/seed/index.ts +++ b/api/tools/exam-environment/seed/index.ts @@ -1,5 +1,5 @@ import { PrismaClient } from '@prisma/client'; -import * as mocks from '../../../__mocks__/exam-environment-exam.js'; +import * as mocks from '../../../__fixtures__/exam-environment-exam.js'; import { MONGOHQ_URL } from '../../../src/utils/env.js'; const prisma = new PrismaClient({ diff --git a/api/vitest.utils.ts b/api/vitest.utils.ts index 4da759983c2..cda642c1955 100644 --- a/api/vitest.utils.ts +++ b/api/vitest.utils.ts @@ -4,7 +4,7 @@ import request from 'supertest'; import { build, buildOptions } from './src/app.js'; import { createUserInput } from './src/utils/create-user.js'; -import { examJson } from './__mocks__/exam.js'; +import { examJson } from './__fixtures__/exam.js'; import { CSRF_COOKIE, CSRF_HEADER } from './src/plugins/csrf.js'; type FastifyTestInstance = Awaited>; diff --git a/client/config/cert-and-project-map.test.ts b/client/config/cert-and-project-map.test.ts index 0645063ba7f..1c1ce8c2136 100644 --- a/client/config/cert-and-project-map.test.ts +++ b/client/config/cert-and-project-map.test.ts @@ -35,41 +35,43 @@ describe('certifications', () => { ).toHaveProperty('projects'); // skip legacy-full-stack as it has no projects - if (filename !== 'legacy-full-stack.yml') { - expect( - Array.isArray(matchingCert?.projects), - `Matching cert 'projects' is not an array` - ).toBe(true); - - const certProjects = matchingCert?.projects; - - expect( - certProjects?.length, - `Project count mismatch: allCerts has ${certProjects?.length} projects, YAML has ${certTests.length} tests` - ).toBe(certTests.length); - - certTests.forEach((test, i) => { - expect( - test, - `Test at index ${i} in missing id property` - ).toHaveProperty('id'); - expect( - test, - `Test at index ${i} missing title property` - ).toHaveProperty('title'); - - const matchingProject = certProjects?.[i]; - - expect( - matchingProject, - `No project found at index ${i} for test ${test.id}` - ).toBeDefined(); - expect( - matchingProject?.id, - `Project ID mismatch at index ${i}: allCerts has "${matchingProject?.id}", YAML has "${test.id}"` - ).toBe(test.id); - }); + if (filename === 'legacy-full-stack.yml') { + return; } + + expect( + Array.isArray(matchingCert?.projects), + `Matching cert 'projects' is not an array` + ).toBe(true); + + const certProjects = matchingCert?.projects; + + expect( + certProjects?.length, + `Project count mismatch: allCerts has ${certProjects?.length} projects, YAML has ${certTests.length} tests` + ).toBe(certTests.length); + + certTests.forEach((test, i) => { + expect( + test, + `Test at index ${i} in missing id property` + ).toHaveProperty('id'); + expect( + test, + `Test at index ${i} missing title property` + ).toHaveProperty('title'); + + const matchingProject = certProjects?.[i]; + + expect( + matchingProject, + `No project found at index ${i} for test ${test.id}` + ).toBeDefined(); + expect( + matchingProject?.id, + `Project ID mismatch at index ${i}: allCerts has "${matchingProject?.id}", YAML has "${test.id}"` + ).toBe(test.id); + }); }); }); }); diff --git a/client/i18n/locales.test.ts b/client/i18n/locales.test.ts index 5bd81ce345a..367397b287c 100644 --- a/client/i18n/locales.test.ts +++ b/client/i18n/locales.test.ts @@ -93,9 +93,10 @@ describe('Intro file structure tests:', () => { expect(typeof typedIntro[superBlock].title).toBe('string'); // catalog superblocks should have a summary - if (catalogSuperBlocks.includes(superBlock)) { - expect(typedIntro[superBlock].summary).toBeInstanceOf(Array); - } + expect( + !catalogSuperBlocks.includes(superBlock) || + Array.isArray(typedIntro[superBlock].summary) + ).toBe(true); expect(typedIntro[superBlock].intro).toBeInstanceOf(Array); expect(typedIntro[superBlock].blocks).toBeInstanceOf(Object); diff --git a/client/src/templates/Challenges/components/pinyin-to-hanzi-input.test.tsx b/client/src/templates/Challenges/components/pinyin-to-hanzi-input.test.tsx index 63a8a6849e7..2cfada9ab65 100644 --- a/client/src/templates/Challenges/components/pinyin-to-hanzi-input.test.tsx +++ b/client/src/templates/Challenges/components/pinyin-to-hanzi-input.test.tsx @@ -137,12 +137,9 @@ describe('PinyinToHanziInput component', () => { ); const input = screen.getByLabelText('blank'); - - if (expectedAriaInvalid) { - expect(input).toHaveAttribute('aria-invalid', 'true'); - } else { - expect(input).not.toHaveAttribute('aria-invalid'); - } + expect(input.getAttribute('aria-invalid')).toBe( + expectedAriaInvalid ? 'true' : null + ); } ); diff --git a/client/src/templates/Introduction/super-block-intro.test.tsx b/client/src/templates/Introduction/super-block-intro.test.tsx index cb489d582a2..7bb57975feb 100644 --- a/client/src/templates/Introduction/super-block-intro.test.tsx +++ b/client/src/templates/Introduction/super-block-intro.test.tsx @@ -392,8 +392,27 @@ const scenarios: Scenario[] = [ } ]; +const scenariosWithCta = scenarios.filter( + ( + scenario + ): scenario is Scenario & { + expected: { + labelKey: string; + dataLabel: 'start-learning' | 'continue-learning'; + nextOrder: number; + }; + } => + scenario.expected.labelKey !== null && + scenario.expected.dataLabel !== null && + scenario.expected.nextOrder !== null +); + +const scenariosWithoutCta = scenarios.filter( + scenario => scenario.expected.labelKey === null +); + describe('SuperBlockIntroductionPage', () => { - it.each(scenarios)('%s', async scenario => { + it.each(scenariosWithCta)('$description', async scenario => { const { superBlock, completedOrders, expected } = scenario; const setup = createSetup(superBlock); @@ -418,31 +437,56 @@ describe('SuperBlockIntroductionPage', () => { render(); - if (expected.labelKey) { - const expectedText = translationMap[expected.labelKey] as string; - const cta = await screen.findByRole('link', { - name: expectedText - }); + const expectedText = translationMap[expected.labelKey] as string; + const cta = await screen.findByRole('link', { + name: expectedText + }); - expect(cta).toHaveAttribute('data-test-label', expected.dataLabel); + expect(cta).toHaveAttribute('data-test-label', expected.dataLabel); - const nextChallenge = setup.challengeByOrder.get(expected.nextOrder!); - expect(nextChallenge).toBeDefined(); - expect(cta).toHaveAttribute('href', nextChallenge?.fields.slug ?? ''); - } else { - await waitFor(() => - expect( - screen.queryByRole('link', { - name: translationMap['misc.fsd-b-cta'] as string - }) - ).toBeNull() - ); + const nextChallenge = setup.challengeByOrder.get(expected.nextOrder); + if (!nextChallenge) { + throw new Error(`Missing challenge for order ${expected.nextOrder}`); + } + expect(cta).toHaveAttribute('href', nextChallenge.fields.slug); + }); + it.each(scenariosWithoutCta)('$description', async scenario => { + const { superBlock, completedOrders } = scenario; + const setup = createSetup(superBlock); + + const completedChallenges = completedOrders.map(order => { + const challenge = setup.challengeByOrder.get(order); + if (!challenge) { + throw new Error(`Missing challenge for order ${order}`); + } + + return { + id: challenge.id, + completedDate: order * 100 + }; + }); + + const props = createPageProps(setup, superBlock, { + user: { + completedChallenges, + isDonating: false + } + }); + + render(); + + await waitFor(() => { + expect( + screen.queryByRole('link', { + name: translationMap['misc.fsd-b-cta'] as string + }) + ).toBeNull(); expect( screen.queryByRole('link', { name: translationMap['misc.continue-learning'] as string }) ).toBeNull(); - } + }); }); }); diff --git a/curriculum/package.json b/curriculum/package.json index 31b0435b99a..b3eb365779f 100644 --- a/curriculum/package.json +++ b/curriculum/package.json @@ -66,7 +66,7 @@ "@types/js-yaml": "4.0.9", "@types/polka": "0.5.8", "@typescript/vfs-1.6.1": "npm:@typescript/vfs@1.6.4", - "@vitest/ui": "4.0.15", + "@vitest/ui": "4.1.4", "eslint": "9.39.4", "glob": "13.0.6", "joi": "17.13.3", @@ -81,7 +81,7 @@ "puppeteer": "22.15.0", "sirv": "3.0.2", "typescript-5.9.2": "npm:typescript@5.9.2", - "vitest": "4.0.15" + "vitest": "4.1.4" }, "dependencies": { "@types/node": "24.12.2" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0e54bd3998c..1954744c7a6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -34,7 +34,7 @@ importers: version: 10.4.1 '@testing-library/jest-dom': specifier: 6.9.1 - version: 6.9.1(vitest@4.0.15) + version: 6.9.1(vitest@4.1.4) '@types/lodash': specifier: 4.17.24 version: 4.17.24 @@ -218,7 +218,7 @@ importers: version: 13.15.10 '@vitest/ui': specifier: ^4.0.15 - version: 4.0.15(vitest@4.0.15) + version: 4.1.4(vitest@4.1.4) dotenv-cli: specifier: 7.4.4 version: 7.4.4 @@ -245,7 +245,7 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.15 - version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/ui@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(msw@2.13.4(@types/node@24.12.2)(typescript@5.9.3))(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + version: 4.1.4(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/ui@4.1.4)(jsdom@26.1.0)(msw@2.13.4(@types/node@24.12.2)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) client: dependencies: @@ -552,7 +552,7 @@ importers: version: link:../packages/shared '@testing-library/jest-dom': specifier: ^6.8.0 - version: 6.9.1(vitest@4.0.15) + version: 6.9.1(vitest@4.1.4) '@testing-library/react': specifier: 14.3.1 version: 14.3.1(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -621,7 +621,7 @@ importers: version: 13.15.10 '@vitest/ui': specifier: ^4.0.15 - version: 4.0.15(vitest@4.0.15) + version: 4.1.4(vitest@4.1.4) autoprefixer: specifier: 10.4.27 version: 10.4.27(postcss@8.4.35) @@ -675,7 +675,7 @@ importers: version: 13.0.4 vitest: specifier: ^4.0.15 - version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/ui@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(msw@2.13.4(@types/node@25.6.0)(typescript@5.9.3))(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + version: 4.1.4(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/ui@4.1.4)(jsdom@26.1.0)(msw@2.13.4(@types/node@25.6.0)(typescript@5.9.3))(vite@7.3.1(@types/node@25.6.0)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) webpack: specifier: 5.106.2 version: 5.106.2(webpack-cli@4.10.0) @@ -723,8 +723,8 @@ importers: specifier: npm:@typescript/vfs@1.6.4 version: '@typescript/vfs@1.6.4(typescript@5.9.3)' '@vitest/ui': - specifier: 4.0.15 - version: 4.0.15(vitest@4.0.15) + specifier: 4.1.4 + version: 4.1.4(vitest@4.1.4) eslint: specifier: 9.39.4 version: 9.39.4(jiti@2.6.1) @@ -768,8 +768,8 @@ importers: specifier: npm:typescript@5.9.2 version: typescript@5.9.2 vitest: - specifier: 4.0.15 - version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/ui@4.0.15)(jiti@2.6.1)(jsdom@16.7.0)(msw@2.13.4(@types/node@24.12.2)(typescript@5.9.3))(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + specifier: 4.1.4 + version: 4.1.4(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/ui@4.1.4)(jsdom@16.7.0)(msw@2.13.4(@types/node@24.12.2)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) e2e: devDependencies: @@ -885,7 +885,7 @@ importers: version: 0.59.0(eslint@9.39.4(jiti@2.6.1)) '@vitest/eslint-plugin': specifier: ^1.4.3 - version: 1.4.3(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.15) + version: 1.6.16(@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)(vitest@4.1.4) eslint: specifier: ^9.39.1 version: 9.39.4(jiti@2.6.1) @@ -936,7 +936,7 @@ importers: version: link:../eslint-config '@vitest/ui': specifier: ^4.0.15 - version: 4.0.15(vitest@4.0.15) + version: 4.1.4(vitest@4.1.4) eslint: specifier: ^9.39.1 version: 9.39.4(jiti@2.6.1) @@ -945,7 +945,7 @@ importers: version: 0.21.8(typescript@5.9.3) vitest: specifier: ^4.0.15 - version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/ui@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(msw@2.13.4(@types/node@25.6.0)(typescript@5.9.3))(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + version: 4.1.4(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/ui@4.1.4)(jsdom@26.1.0)(msw@2.13.4(@types/node@25.6.0)(typescript@5.9.3))(vite@7.3.1(@types/node@25.6.0)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) tools/challenge-helper-scripts: devDependencies: @@ -966,7 +966,7 @@ importers: version: 0.6.1 '@vitest/ui': specifier: ^4.0.15 - version: 4.0.15(vitest@4.0.15) + version: 4.1.4(vitest@4.1.4) bson: specifier: ^7.0.0 version: 7.2.0 @@ -984,7 +984,7 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.15 - version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/ui@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(msw@2.13.4(@types/node@25.6.0)(typescript@5.9.3))(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + version: 4.1.4(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/ui@4.1.4)(jsdom@26.1.0)(msw@2.13.4(@types/node@25.6.0)(typescript@5.9.3))(vite@7.3.1(@types/node@25.6.0)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) tools/challenge-parser: dependencies: @@ -1093,7 +1093,7 @@ importers: version: 3.0.4 vitest: specifier: ^4.0.15 - version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/ui@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(msw@2.13.4(@types/node@25.6.0)(typescript@5.9.3))(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + version: 4.1.4(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/ui@4.1.4)(jsdom@26.1.0)(msw@2.13.4(@types/node@25.6.0)(typescript@5.9.3))(vite@7.3.1(@types/node@25.6.0)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) tools/client-plugins/browser-scripts: dependencies: @@ -4018,124 +4018,141 @@ packages: '@rolldown/pluginutils@1.0.0-rc.15': resolution: {integrity: sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==} - '@rollup/rollup-android-arm-eabi@4.54.0': - resolution: {integrity: sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==} + '@rollup/rollup-android-arm-eabi@4.60.1': + resolution: {integrity: sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.54.0': - resolution: {integrity: sha512-Skx39Uv+u7H224Af+bDgNinitlmHyQX1K/atIA32JP3JQw6hVODX5tkbi2zof/E69M1qH2UoN3Xdxgs90mmNYw==} + '@rollup/rollup-android-arm64@4.60.1': + resolution: {integrity: sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.54.0': - resolution: {integrity: sha512-k43D4qta/+6Fq+nCDhhv9yP2HdeKeP56QrUUTW7E6PhZP1US6NDqpJj4MY0jBHlJivVJD5P8NxrjuobZBJTCRw==} + '@rollup/rollup-darwin-arm64@4.60.1': + resolution: {integrity: sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.54.0': - resolution: {integrity: sha512-cOo7biqwkpawslEfox5Vs8/qj83M/aZCSSNIWpVzfU2CYHa2G3P1UN5WF01RdTHSgCkri7XOlTdtk17BezlV3A==} + '@rollup/rollup-darwin-x64@4.60.1': + resolution: {integrity: sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.54.0': - resolution: {integrity: sha512-miSvuFkmvFbgJ1BevMa4CPCFt5MPGw094knM64W9I0giUIMMmRYcGW/JWZDriaw/k1kOBtsWh1z6nIFV1vPNtA==} + '@rollup/rollup-freebsd-arm64@4.60.1': + resolution: {integrity: sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.54.0': - resolution: {integrity: sha512-KGXIs55+b/ZfZsq9aR026tmr/+7tq6VG6MsnrvF4H8VhwflTIuYh+LFUlIsRdQSgrgmtM3fVATzEAj4hBQlaqQ==} + '@rollup/rollup-freebsd-x64@4.60.1': + resolution: {integrity: sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.54.0': - resolution: {integrity: sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==} + '@rollup/rollup-linux-arm-gnueabihf@4.60.1': + resolution: {integrity: sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==} cpu: [arm] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.54.0': - resolution: {integrity: sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==} + '@rollup/rollup-linux-arm-musleabihf@4.60.1': + resolution: {integrity: sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==} cpu: [arm] os: [linux] libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.54.0': - resolution: {integrity: sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==} + '@rollup/rollup-linux-arm64-gnu@4.60.1': + resolution: {integrity: sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.54.0': - resolution: {integrity: sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==} + '@rollup/rollup-linux-arm64-musl@4.60.1': + resolution: {integrity: sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.54.0': - resolution: {integrity: sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==} + '@rollup/rollup-linux-loong64-gnu@4.60.1': + resolution: {integrity: sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==} cpu: [loong64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-gnu@4.54.0': - resolution: {integrity: sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==} + '@rollup/rollup-linux-loong64-musl@4.60.1': + resolution: {integrity: sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-ppc64-gnu@4.60.1': + resolution: {integrity: sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-gnu@4.54.0': - resolution: {integrity: sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==} + '@rollup/rollup-linux-ppc64-musl@4.60.1': + resolution: {integrity: sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==} + cpu: [ppc64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-riscv64-gnu@4.60.1': + resolution: {integrity: sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==} cpu: [riscv64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.54.0': - resolution: {integrity: sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==} + '@rollup/rollup-linux-riscv64-musl@4.60.1': + resolution: {integrity: sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==} cpu: [riscv64] os: [linux] libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.54.0': - resolution: {integrity: sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==} + '@rollup/rollup-linux-s390x-gnu@4.60.1': + resolution: {integrity: sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.54.0': - resolution: {integrity: sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==} + '@rollup/rollup-linux-x64-gnu@4.60.1': + resolution: {integrity: sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg==} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.54.0': - resolution: {integrity: sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==} + '@rollup/rollup-linux-x64-musl@4.60.1': + resolution: {integrity: sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w==} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-openharmony-arm64@4.54.0': - resolution: {integrity: sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==} + '@rollup/rollup-openbsd-x64@4.60.1': + resolution: {integrity: sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.60.1': + resolution: {integrity: sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.54.0': - resolution: {integrity: sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw==} + '@rollup/rollup-win32-arm64-msvc@4.60.1': + resolution: {integrity: sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.54.0': - resolution: {integrity: sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ==} + '@rollup/rollup-win32-ia32-msvc@4.60.1': + resolution: {integrity: sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.54.0': - resolution: {integrity: sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ==} + '@rollup/rollup-win32-x64-gnu@4.60.1': + resolution: {integrity: sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.54.0': - resolution: {integrity: sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg==} + '@rollup/rollup-win32-x64-msvc@4.60.1': + resolution: {integrity: sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ==} cpu: [x64] os: [win32] @@ -5030,14 +5047,17 @@ packages: '@vercel/webpack-asset-relocator-loader@1.7.3': resolution: {integrity: sha512-vizrI18v8Lcb1PmNNUBz7yxPxxXoOeuaVEjTG9MjvDrphjiSxFZrRJ5tIghk+qdLFRCXI5HBCshgobftbmrC5g==} - '@vitest/eslint-plugin@1.4.3': - resolution: {integrity: sha512-ba+YDKyZdViNAOg8P86a9tIEawPA/O+nLbwhg8g7nkqsLOAVum6GoZhkNxgwX621oqWAbB8N2xb+G5kkpXehcA==} + '@vitest/eslint-plugin@1.6.16': + resolution: {integrity: sha512-2pBN1F1JXq6zTSaYC58CMJa7pGxXIRsLfOioeZM4cPE3pRdSh1ySTSoHPQlOTEF5WgoVzWZQxhGQ3ygT78hOVg==} engines: {node: '>=18'} peerDependencies: + '@typescript-eslint/eslint-plugin': '*' eslint: '>=8.57.0' typescript: '>=5.0.0' vitest: '*' peerDependenciesMeta: + '@typescript-eslint/eslint-plugin': + optional: true typescript: optional: true vitest: @@ -5046,8 +5066,8 @@ packages: '@vitest/expect@3.2.4': resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} - '@vitest/expect@4.0.15': - resolution: {integrity: sha512-Gfyva9/GxPAWXIWjyGDli9O+waHDC0Q0jaLdFP1qPAUUfo1FEXPXUfUkp3eZA0sSq340vPycSyOlYUeM15Ft1w==} + '@vitest/expect@4.1.4': + resolution: {integrity: sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww==} '@vitest/mocker@3.2.4': resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} @@ -5060,11 +5080,11 @@ packages: vite: optional: true - '@vitest/mocker@4.0.15': - resolution: {integrity: sha512-CZ28GLfOEIFkvCFngN8Sfx5h+Se0zN+h4B7yOsPVCcgtiO7t5jt9xQh2E1UkFep+eb9fjyMfuC5gBypwb07fvQ==} + '@vitest/mocker@4.1.4': + resolution: {integrity: sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg==} peerDependencies: msw: ^2.4.9 - vite: ^6.0.0 || ^7.0.0-0 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: msw: optional: true @@ -5074,42 +5094,42 @@ packages: '@vitest/pretty-format@3.2.4': resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} - '@vitest/pretty-format@4.0.15': - resolution: {integrity: sha512-SWdqR8vEv83WtZcrfLNqlqeQXlQLh2iilO1Wk1gv4eiHKjEzvgHb2OVc3mIPyhZE6F+CtfYjNlDJwP5MN6Km7A==} + '@vitest/pretty-format@4.1.4': + resolution: {integrity: sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A==} '@vitest/runner@3.2.4': resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} - '@vitest/runner@4.0.15': - resolution: {integrity: sha512-+A+yMY8dGixUhHmNdPUxOh0la6uVzun86vAbuMT3hIDxMrAOmn5ILBHm8ajrqHE0t8R9T1dGnde1A5DTnmi3qw==} + '@vitest/runner@4.1.4': + resolution: {integrity: sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ==} '@vitest/snapshot@3.2.4': resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} - '@vitest/snapshot@4.0.15': - resolution: {integrity: sha512-A7Ob8EdFZJIBjLjeO0DZF4lqR6U7Ydi5/5LIZ0xcI+23lYlsYJAfGn8PrIWTYdZQRNnSRlzhg0zyGu37mVdy5g==} + '@vitest/snapshot@4.1.4': + resolution: {integrity: sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw==} '@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/spy@4.1.4': + resolution: {integrity: sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ==} '@vitest/ui@3.2.4': resolution: {integrity: sha512-hGISOaP18plkzbWEcP/QvtRW1xDXF2+96HbEX6byqQhAUbiS5oH6/9JwW+QsQCIYON2bI6QZBF+2PvOmrRZ9wA==} peerDependencies: vitest: 3.2.4 - '@vitest/ui@4.0.15': - resolution: {integrity: sha512-sxSyJMaKp45zI0u+lHrPuZM1ZJQ8FaVD35k+UxVrha1yyvQ+TZuUYllUixwvQXlB7ixoDc7skf3lQPopZIvaQw==} + '@vitest/ui@4.1.4': + resolution: {integrity: sha512-EgFR7nlj5iTDYZYCvavjFokNYwr3c3ry0sFiCg+N7B233Nwp+NNx7eoF/XvMWDCKY71xXAG3kFkt97ZHBJVL8A==} peerDependencies: - vitest: 4.0.15 + vitest: 4.1.4 '@vitest/utils@3.2.4': resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} - '@vitest/utils@4.0.15': - resolution: {integrity: sha512-HXjPW2w5dxhTD0dLwtYHDnelK3j8sR8cWIaLxr22evTyY6q8pRCjZSmhRWVjBaOVXChQd6AwMzi9pucorXCPZA==} + '@vitest/utils@4.1.4': + resolution: {integrity: sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw==} '@vscode/l10n@0.0.18': resolution: {integrity: sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==} @@ -5961,8 +5981,8 @@ packages: resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==} engines: {node: '>=4'} - chai@5.2.1: - resolution: {integrity: sha512-5nFxhUrX0PqtyogoYOA8IPswy5sZFTOsBFl/9bNsmDLgsxYTzSZQJDPppDnZPTQbzSEm0hqGjWPzRemQCYbD6A==} + chai@5.3.3: + resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} engines: {node: '>=18'} chai@6.2.2: @@ -6020,8 +6040,8 @@ packages: check-error@1.0.3: resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} - check-error@2.1.1: - resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} + check-error@2.1.3: + resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} engines: {node: '>= 16'} chokidar@3.6.0: @@ -9059,8 +9079,8 @@ packages: resolution: {integrity: sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==} deprecated: Please upgrade to 2.3.7 which fixes GHSA-4q6p-r6v2-jvc5 - loupe@3.2.0: - resolution: {integrity: sha512-2NCfZcT5VGVNX9mSZIxLRkEAegDGBpuQZBy13desuHeVORmBDyAET4TkJr4SjqQy3A8JDofMN6LpkK8Xcm/dlw==} + loupe@3.2.1: + resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} lower-case-first@2.0.2: resolution: {integrity: sha512-EVm/rR94FJTZi3zefZ82fLWab+GX14LJN4HrWBcuo6Evmsl9hEfnqxgcHCKb9q+mNf6EVdsjx/qucYFIIB84pg==} @@ -10418,8 +10438,8 @@ packages: resolution: {integrity: sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==} engines: {node: ^10 || ^12 || >=14} - postcss@8.5.9: - resolution: {integrity: sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw==} + postcss@8.5.10: + resolution: {integrity: sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==} engines: {node: ^10 || ^12 || >=14} postgres-array@2.0.0: @@ -11174,8 +11194,8 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - rollup@4.54.0: - resolution: {integrity: sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==} + rollup@4.60.1: + resolution: {integrity: sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -11595,6 +11615,9 @@ packages: std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + std-env@4.1.0: + resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} + stop-iteration-iterator@1.1.0: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} @@ -11738,8 +11761,8 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - strip-literal@3.0.0: - resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==} + strip-literal@3.1.0: + resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} stripe@16.12.0: resolution: {integrity: sha512-H7eFVLDxeTNNSn4JTRfL2//LzCbDrMSZ+2q1c7CanVWgK2qIW5TwS+0V7N9KcKZZNpYh/uCqK0PyZh/2UsaAtQ==} @@ -11933,12 +11956,12 @@ 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==} + tinyrainbow@3.1.0: + resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} engines: {node: '>=14.0.0'} - tinyspy@4.0.3: - resolution: {integrity: sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==} + tinyspy@4.0.4: + resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} engines: {node: '>=14.0.0'} title-case@3.0.3: @@ -12570,20 +12593,23 @@ packages: jsdom: optional: true - vitest@4.0.15: - resolution: {integrity: sha512-n1RxDp8UJm6N0IbJLQo+yzLZ2sQCDyl1o0LeugbPWf8+8Fttp29GghsQBjYJVmWq3gBFfe9Hs1spR44vovn2wA==} + vitest@4.1.4: + resolution: {integrity: sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@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 + '@vitest/browser-playwright': 4.1.4 + '@vitest/browser-preview': 4.1.4 + '@vitest/browser-webdriverio': 4.1.4 + '@vitest/coverage-istanbul': 4.1.4 + '@vitest/coverage-v8': 4.1.4 + '@vitest/ui': 4.1.4 happy-dom: '*' jsdom: '*' + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: '@edge-runtime/vm': optional: true @@ -12597,6 +12623,10 @@ packages: optional: true '@vitest/browser-webdriverio': optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true '@vitest/ui': optional: true happy-dom: @@ -17313,70 +17343,79 @@ snapshots: '@rolldown/pluginutils@1.0.0-rc.15': {} - '@rollup/rollup-android-arm-eabi@4.54.0': + '@rollup/rollup-android-arm-eabi@4.60.1': optional: true - '@rollup/rollup-android-arm64@4.54.0': + '@rollup/rollup-android-arm64@4.60.1': optional: true - '@rollup/rollup-darwin-arm64@4.54.0': + '@rollup/rollup-darwin-arm64@4.60.1': optional: true - '@rollup/rollup-darwin-x64@4.54.0': + '@rollup/rollup-darwin-x64@4.60.1': optional: true - '@rollup/rollup-freebsd-arm64@4.54.0': + '@rollup/rollup-freebsd-arm64@4.60.1': optional: true - '@rollup/rollup-freebsd-x64@4.54.0': + '@rollup/rollup-freebsd-x64@4.60.1': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.54.0': + '@rollup/rollup-linux-arm-gnueabihf@4.60.1': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.54.0': + '@rollup/rollup-linux-arm-musleabihf@4.60.1': optional: true - '@rollup/rollup-linux-arm64-gnu@4.54.0': + '@rollup/rollup-linux-arm64-gnu@4.60.1': optional: true - '@rollup/rollup-linux-arm64-musl@4.54.0': + '@rollup/rollup-linux-arm64-musl@4.60.1': optional: true - '@rollup/rollup-linux-loong64-gnu@4.54.0': + '@rollup/rollup-linux-loong64-gnu@4.60.1': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.54.0': + '@rollup/rollup-linux-loong64-musl@4.60.1': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.54.0': + '@rollup/rollup-linux-ppc64-gnu@4.60.1': optional: true - '@rollup/rollup-linux-riscv64-musl@4.54.0': + '@rollup/rollup-linux-ppc64-musl@4.60.1': optional: true - '@rollup/rollup-linux-s390x-gnu@4.54.0': + '@rollup/rollup-linux-riscv64-gnu@4.60.1': optional: true - '@rollup/rollup-linux-x64-gnu@4.54.0': + '@rollup/rollup-linux-riscv64-musl@4.60.1': optional: true - '@rollup/rollup-linux-x64-musl@4.54.0': + '@rollup/rollup-linux-s390x-gnu@4.60.1': optional: true - '@rollup/rollup-openharmony-arm64@4.54.0': + '@rollup/rollup-linux-x64-gnu@4.60.1': optional: true - '@rollup/rollup-win32-arm64-msvc@4.54.0': + '@rollup/rollup-linux-x64-musl@4.60.1': optional: true - '@rollup/rollup-win32-ia32-msvc@4.54.0': + '@rollup/rollup-openbsd-x64@4.60.1': optional: true - '@rollup/rollup-win32-x64-gnu@4.54.0': + '@rollup/rollup-openharmony-arm64@4.60.1': optional: true - '@rollup/rollup-win32-x64-msvc@4.54.0': + '@rollup/rollup-win32-arm64-msvc@4.60.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.60.1': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.60.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.60.1': optional: true '@rtsao/scc@1.1.0': {} @@ -17840,7 +17879,7 @@ snapshots: lz-string: 1.5.0 pretty-format: 27.5.1 - '@testing-library/jest-dom@6.9.1(vitest@4.0.15)': + '@testing-library/jest-dom@6.9.1(vitest@4.1.4)': dependencies: '@adobe/css-tools': 4.4.4 aria-query: 5.3.2 @@ -17848,7 +17887,7 @@ snapshots: dom-accessibility-api: 0.6.3 picocolors: 1.1.1 redent: 3.0.0 - vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/ui@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(msw@2.13.4(@types/node@24.12.2)(typescript@5.9.3))(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + vitest: 4.1.4(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/ui@4.1.4)(jsdom@26.1.0)(msw@2.13.4(@types/node@24.12.2)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) '@testing-library/react@14.3.1(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: @@ -18512,14 +18551,15 @@ snapshots: dependencies: resolve: 1.22.12 - '@vitest/eslint-plugin@1.4.3(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.15)': + '@vitest/eslint-plugin@1.6.16(@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)(vitest@4.1.4)': dependencies: '@typescript-eslint/scope-manager': 8.58.2 '@typescript-eslint/utils': 8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.4(jiti@2.6.1) optionalDependencies: + '@typescript-eslint/eslint-plugin': 8.58.2(@typescript-eslint/parser@8.58.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) typescript: 5.9.3 - vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/ui@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(msw@2.13.4(@types/node@25.6.0)(typescript@5.9.3))(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + vitest: 4.1.4(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/ui@4.1.4)(jsdom@26.1.0)(msw@2.13.4(@types/node@25.6.0)(typescript@5.9.3))(vite@7.3.1(@types/node@25.6.0)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) transitivePeerDependencies: - supports-color @@ -18528,17 +18568,17 @@ snapshots: '@types/chai': 5.2.3 '@vitest/spy': 3.2.4 '@vitest/utils': 3.2.4 - chai: 5.2.1 + chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/expect@4.0.15': + '@vitest/expect@4.1.4': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.0.15 - '@vitest/utils': 4.0.15 + '@vitest/spy': 4.1.4 + '@vitest/utils': 4.1.4 chai: 6.2.2 - tinyrainbow: 3.0.3 + tinyrainbow: 3.1.0 '@vitest/mocker@3.2.4(msw@2.13.4(@types/node@25.6.0)(typescript@5.9.3))(vite@7.3.1(@types/node@25.6.0)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: @@ -18549,18 +18589,18 @@ snapshots: msw: 2.13.4(@types/node@25.6.0)(typescript@5.9.3) vite: 7.3.1(@types/node@25.6.0)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - '@vitest/mocker@4.0.15(msw@2.13.4(@types/node@24.12.2)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': + '@vitest/mocker@4.1.4(msw@2.13.4(@types/node@24.12.2)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: - '@vitest/spy': 4.0.15 + '@vitest/spy': 4.1.4 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: msw: 2.13.4(@types/node@24.12.2)(typescript@5.9.3) vite: 7.3.1(@types/node@24.12.2)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - '@vitest/mocker@4.0.15(msw@2.13.4(@types/node@25.6.0)(typescript@5.9.3))(vite@7.3.1(@types/node@25.6.0)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': + '@vitest/mocker@4.1.4(msw@2.13.4(@types/node@25.6.0)(typescript@5.9.3))(vite@7.3.1(@types/node@25.6.0)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: - '@vitest/spy': 4.0.15 + '@vitest/spy': 4.1.4 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: @@ -18571,19 +18611,19 @@ snapshots: dependencies: tinyrainbow: 2.0.0 - '@vitest/pretty-format@4.0.15': + '@vitest/pretty-format@4.1.4': dependencies: - tinyrainbow: 3.0.3 + tinyrainbow: 3.1.0 '@vitest/runner@3.2.4': dependencies: '@vitest/utils': 3.2.4 pathe: 2.0.3 - strip-literal: 3.0.0 + strip-literal: 3.1.0 - '@vitest/runner@4.0.15': + '@vitest/runner@4.1.4': dependencies: - '@vitest/utils': 4.0.15 + '@vitest/utils': 4.1.4 pathe: 2.0.3 '@vitest/snapshot@3.2.4': @@ -18592,17 +18632,18 @@ snapshots: magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/snapshot@4.0.15': + '@vitest/snapshot@4.1.4': dependencies: - '@vitest/pretty-format': 4.0.15 + '@vitest/pretty-format': 4.1.4 + '@vitest/utils': 4.1.4 magic-string: 0.30.21 pathe: 2.0.3 '@vitest/spy@3.2.4': dependencies: - tinyspy: 4.0.3 + tinyspy: 4.0.4 - '@vitest/spy@4.0.15': {} + '@vitest/spy@4.1.4': {} '@vitest/ui@3.2.4(vitest@3.2.4)': dependencies: @@ -18615,27 +18656,28 @@ snapshots: tinyrainbow: 2.0.0 vitest: 3.2.4(@types/debug@4.1.13)(@types/node@25.6.0)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(msw@2.13.4(@types/node@25.6.0)(typescript@5.9.3))(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - '@vitest/ui@4.0.15(vitest@4.0.15)': + '@vitest/ui@4.1.4(vitest@4.1.4)': dependencies: - '@vitest/utils': 4.0.15 + '@vitest/utils': 4.1.4 fflate: 0.8.2 flatted: 3.4.2 pathe: 2.0.3 sirv: 3.0.2 tinyglobby: 0.2.16 - tinyrainbow: 3.0.3 - vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/ui@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(msw@2.13.4(@types/node@24.12.2)(typescript@5.9.3))(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + tinyrainbow: 3.1.0 + vitest: 4.1.4(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/ui@4.1.4)(jsdom@26.1.0)(msw@2.13.4(@types/node@24.12.2)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) '@vitest/utils@3.2.4': dependencies: '@vitest/pretty-format': 3.2.4 - loupe: 3.2.0 + loupe: 3.2.1 tinyrainbow: 2.0.0 - '@vitest/utils@4.0.15': + '@vitest/utils@4.1.4': dependencies: - '@vitest/pretty-format': 4.0.15 - tinyrainbow: 3.0.3 + '@vitest/pretty-format': 4.1.4 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.0 '@vscode/l10n@0.0.18': {} @@ -19725,12 +19767,12 @@ snapshots: pathval: 1.1.1 type-detect: 4.0.8 - chai@5.2.1: + chai@5.3.3: dependencies: assertion-error: 2.0.1 - check-error: 2.1.1 + check-error: 2.1.3 deep-eql: 5.0.2 - loupe: 3.2.0 + loupe: 3.2.1 pathval: 2.0.1 chai@6.2.2: {} @@ -19815,7 +19857,7 @@ snapshots: dependencies: get-func-name: 2.0.2 - check-error@2.1.1: {} + check-error@2.1.3: {} chokidar@3.6.0: dependencies: @@ -23742,7 +23784,7 @@ snapshots: dependencies: get-func-name: 2.0.2 - loupe@3.2.0: {} + loupe@3.2.1: {} lower-case-first@2.0.2: dependencies: @@ -25278,9 +25320,9 @@ snapshots: postcss-resolve-nested-selector@0.1.6: {} - postcss-safe-parser@7.0.1(postcss@8.5.9): + postcss-safe-parser@7.0.1(postcss@8.5.10): dependencies: - postcss: 8.5.9 + postcss: 8.5.10 postcss-selector-parser@6.1.2: dependencies: @@ -25311,7 +25353,7 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - postcss@8.5.9: + postcss@8.5.10: dependencies: nanoid: 3.3.11 picocolors: 1.1.1 @@ -26252,32 +26294,35 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.15 '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.15 - rollup@4.54.0: + rollup@4.60.1: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.54.0 - '@rollup/rollup-android-arm64': 4.54.0 - '@rollup/rollup-darwin-arm64': 4.54.0 - '@rollup/rollup-darwin-x64': 4.54.0 - '@rollup/rollup-freebsd-arm64': 4.54.0 - '@rollup/rollup-freebsd-x64': 4.54.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.54.0 - '@rollup/rollup-linux-arm-musleabihf': 4.54.0 - '@rollup/rollup-linux-arm64-gnu': 4.54.0 - '@rollup/rollup-linux-arm64-musl': 4.54.0 - '@rollup/rollup-linux-loong64-gnu': 4.54.0 - '@rollup/rollup-linux-ppc64-gnu': 4.54.0 - '@rollup/rollup-linux-riscv64-gnu': 4.54.0 - '@rollup/rollup-linux-riscv64-musl': 4.54.0 - '@rollup/rollup-linux-s390x-gnu': 4.54.0 - '@rollup/rollup-linux-x64-gnu': 4.54.0 - '@rollup/rollup-linux-x64-musl': 4.54.0 - '@rollup/rollup-openharmony-arm64': 4.54.0 - '@rollup/rollup-win32-arm64-msvc': 4.54.0 - '@rollup/rollup-win32-ia32-msvc': 4.54.0 - '@rollup/rollup-win32-x64-gnu': 4.54.0 - '@rollup/rollup-win32-x64-msvc': 4.54.0 + '@rollup/rollup-android-arm-eabi': 4.60.1 + '@rollup/rollup-android-arm64': 4.60.1 + '@rollup/rollup-darwin-arm64': 4.60.1 + '@rollup/rollup-darwin-x64': 4.60.1 + '@rollup/rollup-freebsd-arm64': 4.60.1 + '@rollup/rollup-freebsd-x64': 4.60.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.60.1 + '@rollup/rollup-linux-arm-musleabihf': 4.60.1 + '@rollup/rollup-linux-arm64-gnu': 4.60.1 + '@rollup/rollup-linux-arm64-musl': 4.60.1 + '@rollup/rollup-linux-loong64-gnu': 4.60.1 + '@rollup/rollup-linux-loong64-musl': 4.60.1 + '@rollup/rollup-linux-ppc64-gnu': 4.60.1 + '@rollup/rollup-linux-ppc64-musl': 4.60.1 + '@rollup/rollup-linux-riscv64-gnu': 4.60.1 + '@rollup/rollup-linux-riscv64-musl': 4.60.1 + '@rollup/rollup-linux-s390x-gnu': 4.60.1 + '@rollup/rollup-linux-x64-gnu': 4.60.1 + '@rollup/rollup-linux-x64-musl': 4.60.1 + '@rollup/rollup-openbsd-x64': 4.60.1 + '@rollup/rollup-openharmony-arm64': 4.60.1 + '@rollup/rollup-win32-arm64-msvc': 4.60.1 + '@rollup/rollup-win32-ia32-msvc': 4.60.1 + '@rollup/rollup-win32-x64-gnu': 4.60.1 + '@rollup/rollup-win32-x64-msvc': 4.60.1 fsevents: 2.3.3 rrweb-cssom@0.8.0: @@ -26802,6 +26847,8 @@ snapshots: std-env@3.10.0: {} + std-env@4.1.0: {} + stop-iteration-iterator@1.1.0: dependencies: es-errors: 1.3.0 @@ -26980,7 +27027,7 @@ snapshots: strip-json-comments@3.1.1: {} - strip-literal@3.0.0: + strip-literal@3.1.0: dependencies: js-tokens: 9.0.1 @@ -27049,9 +27096,9 @@ snapshots: micromatch: 4.0.8 normalize-path: 3.0.0 picocolors: 1.1.1 - postcss: 8.5.9 + postcss: 8.5.10 postcss-resolve-nested-selector: 0.1.6 - postcss-safe-parser: 7.0.1(postcss@8.5.9) + postcss-safe-parser: 7.0.1(postcss@8.5.10) postcss-selector-parser: 7.1.1 postcss-value-parser: 4.2.0 resolve-from: 5.0.0 @@ -27263,9 +27310,9 @@ snapshots: tinyrainbow@2.0.0: {} - tinyrainbow@3.0.3: {} + tinyrainbow@3.1.0: {} - tinyspy@4.0.3: {} + tinyspy@4.0.4: {} title-case@3.0.3: dependencies: @@ -27894,8 +27941,8 @@ snapshots: esbuild: 0.27.7 fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 - postcss: 8.5.9 - rollup: 4.54.0 + postcss: 8.5.10 + rollup: 4.60.1 tinyglobby: 0.2.16 optionalDependencies: '@types/node': 24.12.2 @@ -27910,8 +27957,8 @@ snapshots: esbuild: 0.27.7 fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 - postcss: 8.5.9 - rollup: 4.54.0 + postcss: 8.5.10 + rollup: 4.60.1 tinyglobby: 0.2.16 optionalDependencies: '@types/node': 25.6.0 @@ -27953,7 +28000,7 @@ snapshots: '@vitest/snapshot': 3.2.4 '@vitest/spy': 3.2.4 '@vitest/utils': 3.2.4 - chai: 5.2.1 + chai: 5.3.3 debug: 4.4.3(supports-color@8.1.1) expect-type: 1.3.0 magic-string: 0.30.21 @@ -27987,125 +28034,95 @@ snapshots: - tsx - yaml - vitest@4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/ui@4.0.15)(jiti@2.6.1)(jsdom@16.7.0)(msw@2.13.4(@types/node@24.12.2)(typescript@5.9.3))(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3): + vitest@4.1.4(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/ui@4.1.4)(jsdom@16.7.0)(msw@2.13.4(@types/node@24.12.2)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: - '@vitest/expect': 4.0.15 - '@vitest/mocker': 4.0.15(msw@2.13.4(@types/node@24.12.2)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) - '@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 + '@vitest/expect': 4.1.4 + '@vitest/mocker': 4.1.4(msw@2.13.4(@types/node@24.12.2)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + '@vitest/pretty-format': 4.1.4 + '@vitest/runner': 4.1.4 + '@vitest/snapshot': 4.1.4 + '@vitest/spy': 4.1.4 + '@vitest/utils': 4.1.4 + es-module-lexer: 2.0.0 expect-type: 1.3.0 magic-string: 0.30.21 obug: 2.1.1 pathe: 2.0.3 picomatch: 4.0.4 - std-env: 3.10.0 + std-env: 4.1.0 tinybench: 2.9.0 tinyexec: 1.1.1 tinyglobby: 0.2.16 - tinyrainbow: 3.0.3 + tinyrainbow: 3.1.0 vite: 7.3.1(@types/node@24.12.2)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.0 '@types/node': 24.12.2 - '@vitest/ui': 4.0.15(vitest@4.0.15) + '@vitest/ui': 4.1.4(vitest@4.1.4) jsdom: 16.7.0 transitivePeerDependencies: - - jiti - - less - - lightningcss - msw - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - yaml - vitest@4.0.15(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/ui@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(msw@2.13.4(@types/node@24.12.2)(typescript@5.9.3))(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3): + vitest@4.1.4(@opentelemetry/api@1.9.0)(@types/node@24.12.2)(@vitest/ui@4.1.4)(jsdom@26.1.0)(msw@2.13.4(@types/node@24.12.2)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: - '@vitest/expect': 4.0.15 - '@vitest/mocker': 4.0.15(msw@2.13.4(@types/node@24.12.2)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) - '@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 + '@vitest/expect': 4.1.4 + '@vitest/mocker': 4.1.4(msw@2.13.4(@types/node@24.12.2)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + '@vitest/pretty-format': 4.1.4 + '@vitest/runner': 4.1.4 + '@vitest/snapshot': 4.1.4 + '@vitest/spy': 4.1.4 + '@vitest/utils': 4.1.4 + es-module-lexer: 2.0.0 expect-type: 1.3.0 magic-string: 0.30.21 obug: 2.1.1 pathe: 2.0.3 picomatch: 4.0.4 - std-env: 3.10.0 + std-env: 4.1.0 tinybench: 2.9.0 tinyexec: 1.1.1 tinyglobby: 0.2.16 - tinyrainbow: 3.0.3 + tinyrainbow: 3.1.0 vite: 7.3.1(@types/node@24.12.2)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.0 '@types/node': 24.12.2 - '@vitest/ui': 4.0.15(vitest@4.0.15) + '@vitest/ui': 4.1.4(vitest@4.1.4) jsdom: 26.1.0 transitivePeerDependencies: - - jiti - - less - - lightningcss - msw - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - yaml - vitest@4.0.15(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/ui@4.0.15)(jiti@2.6.1)(jsdom@26.1.0)(msw@2.13.4(@types/node@25.6.0)(typescript@5.9.3))(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3): + vitest@4.1.4(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/ui@4.1.4)(jsdom@26.1.0)(msw@2.13.4(@types/node@25.6.0)(typescript@5.9.3))(vite@7.3.1(@types/node@25.6.0)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: - '@vitest/expect': 4.0.15 - '@vitest/mocker': 4.0.15(msw@2.13.4(@types/node@25.6.0)(typescript@5.9.3))(vite@7.3.1(@types/node@25.6.0)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) - '@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 + '@vitest/expect': 4.1.4 + '@vitest/mocker': 4.1.4(msw@2.13.4(@types/node@25.6.0)(typescript@5.9.3))(vite@7.3.1(@types/node@25.6.0)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + '@vitest/pretty-format': 4.1.4 + '@vitest/runner': 4.1.4 + '@vitest/snapshot': 4.1.4 + '@vitest/spy': 4.1.4 + '@vitest/utils': 4.1.4 + es-module-lexer: 2.0.0 expect-type: 1.3.0 magic-string: 0.30.21 obug: 2.1.1 pathe: 2.0.3 picomatch: 4.0.4 - std-env: 3.10.0 + std-env: 4.1.0 tinybench: 2.9.0 tinyexec: 1.1.1 tinyglobby: 0.2.16 - tinyrainbow: 3.0.3 + tinyrainbow: 3.1.0 vite: 7.3.1(@types/node@25.6.0)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.0 '@types/node': 25.6.0 - '@vitest/ui': 4.0.15(vitest@4.0.15) + '@vitest/ui': 4.1.4(vitest@4.1.4) jsdom: 26.1.0 transitivePeerDependencies: - - jiti - - less - - lightningcss - msw - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - yaml vm-browserify@1.1.2: {} diff --git a/tools/challenge-parser/parser/plugins/replace-imports.test.js b/tools/challenge-parser/parser/plugins/replace-imports.test.js index d31d2739fa6..9e98306568e 100644 --- a/tools/challenge-parser/parser/plugins/replace-imports.test.js +++ b/tools/challenge-parser/parser/plugins/replace-imports.test.js @@ -73,21 +73,24 @@ describe('replace-imports', () => { it('should fail when the imported file cannot be found', async () => { expect.assertions(2); - console.error = vi.fn(); + const consoleErrorSpy = vi + .spyOn(console, 'error') + .mockImplementation(() => {}); const plugin = addImports(); await expect( new Promise((resolve, reject) => { plugin(importsAST, incorrectFile, err => { if (err) { - expect(console.error).toHaveBeenCalledTimes(2); - resolve(); + reject(err); } else { - reject('An error should have been thrown by addImports'); + resolve(); } }); }) - ).resolves.toBeUndefined(); + ).rejects.toBeTruthy(); + expect(consoleErrorSpy).toHaveBeenCalledTimes(2); + consoleErrorSpy.mockRestore(); }); it('should modify the tree when there are imports', async () => { @@ -219,22 +222,25 @@ describe('replace-imports', () => { }); it('should reject imported files with editable region markers', async () => { - expect.assertions(2); // One inside the callback and one for the outer expect - console.error = vi.fn(); + expect.assertions(2); + const consoleErrorSpy = vi + .spyOn(console, 'error') + .mockImplementation(() => {}); const plugin = addImports(); await expect( new Promise((resolve, reject) => { plugin(markerAST, correctFile, err => { if (err) { - expect(console.error).toHaveBeenCalledTimes(2); + reject(err); } else { - reject('An error should have been thrown by addImports'); + resolve(); } - resolve(); }); }) - ).resolves.toBeUndefined(); + ).rejects.toBeTruthy(); + expect(consoleErrorSpy).toHaveBeenCalledTimes(2); + consoleErrorSpy.mockRestore(); }); it('should have an output to match the snapshot', async () => { diff --git a/tools/challenge-parser/translation-parser/__mocks__/mock-comments.js b/tools/challenge-parser/translation-parser/__fixtures__/mock-comments.js similarity index 100% rename from tools/challenge-parser/translation-parser/__mocks__/mock-comments.js rename to tools/challenge-parser/translation-parser/__fixtures__/mock-comments.js diff --git a/tools/challenge-parser/translation-parser/index.test.js b/tools/challenge-parser/translation-parser/index.test.js index f27ba80a103..f59f5abc055 100644 --- a/tools/challenge-parser/translation-parser/index.test.js +++ b/tools/challenge-parser/translation-parser/index.test.js @@ -1,6 +1,6 @@ import { describe, beforeEach, afterEach, it, expect, vi } from 'vitest'; import { ENGLISH_CHALLENGE_NO_FILES } from './__fixtures__/challenge-objects'; -import { SIMPLE_TRANSLATION } from './__mocks__/mock-comments'; +import { SIMPLE_TRANSLATION } from './__fixtures__/mock-comments'; import { translateComments, translateCommentsInChallenge,