chore(deps): update vitest (#67056)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Huyen Nguyen <25715018+huyenltnguyen@users.noreply.github.com>
This commit is contained in:
renovate[bot]
2026-04-25 11:41:36 +05:30
committed by GitHub
parent 3d72c7b3ee
commit a6d06fe724
21 changed files with 499 additions and 385 deletions
@@ -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 () => {
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);
});
@@ -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 {
+1 -1
View File
@@ -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({
+1 -1
View File
@@ -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'
+1 -1
View File
@@ -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';
+1 -1
View File
@@ -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();
@@ -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 (
const unsubscribedUsers = users.filter(user =>
['user1@freecodecamp.org', 'user2@freecodecamp.org'].includes(
user.email!
)
) {
expect(user.sendQuincyEmail).toBe(false);
} else {
expect(user.sendQuincyEmail).toBe(true);
}
});
);
const remainingUsers = users.filter(
user =>
!['user1@freecodecamp.org', 'user2@freecodecamp.org'].includes(
user.email!
)
);
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}`
+1 -1
View File
@@ -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';
+1 -1
View File
@@ -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({
+1 -1
View File
@@ -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<ReturnType<typeof build>>;
+4 -2
View File
@@ -35,7 +35,10 @@ describe('certifications', () => {
).toHaveProperty('projects');
// skip legacy-full-stack as it has no projects
if (filename !== 'legacy-full-stack.yml') {
if (filename === 'legacy-full-stack.yml') {
return;
}
expect(
Array.isArray(matchingCert?.projects),
`Matching cert 'projects' is not an array`
@@ -69,7 +72,6 @@ describe('certifications', () => {
`Project ID mismatch at index ${i}: allCerts has "${matchingProject?.id}", YAML has "${test.id}"`
).toBe(test.id);
});
}
});
});
});
+4 -3
View File
@@ -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);
@@ -137,12 +137,9 @@ describe('PinyinToHanziInput component', () => {
);
const input = screen.getByLabelText<HTMLInputElement>('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
);
}
);
@@ -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,7 +437,6 @@ describe('SuperBlockIntroductionPage', () => {
render(<SuperBlockIntroductionPage {...props} />);
if (expected.labelKey) {
const expectedText = translationMap[expected.labelKey] as string;
const cta = await screen.findByRole('link', {
name: expectedText
@@ -426,23 +444,49 @@ describe('SuperBlockIntroductionPage', () => {
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(() =>
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(<SuperBlockIntroductionPage {...props} />);
await waitFor(() => {
expect(
screen.queryByRole('link', {
name: translationMap['misc.fsd-b-cta'] as string
})
).toBeNull()
);
).toBeNull();
expect(
screen.queryByRole('link', {
name: translationMap['misc.continue-learning'] as string
})
).toBeNull();
}
});
});
});
+2 -2
View File
@@ -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"
+278 -261
View File
File diff suppressed because it is too large Load Diff
@@ -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();
}
});
})
).resolves.toBeUndefined();
).rejects.toBeTruthy();
expect(consoleErrorSpy).toHaveBeenCalledTimes(2);
consoleErrorSpy.mockRestore();
});
it('should have an output to match the snapshot', async () => {
@@ -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,