fix(client): show correct lab progress on resubmission (#67894)

This commit is contained in:
Mahima Thacker
2026-06-12 12:01:46 +05:30
committed by GitHub
parent 492bc0310a
commit 11cc102d9d
3 changed files with 64 additions and 1 deletions
@@ -84,6 +84,22 @@ describe('get-completion-percentage', () => {
expect(result).toBe(33);
});
it('reports 100% when resubmitting an already-completed single-challenge lab block', () => {
// Regression test for #67867: a completed lab whose block contains only
// the lab itself should read 100%, not 0%, on resubmission.
const labId = 'lab-challenge';
const completedChallengesIds = [labId];
const currentBlockIds = [labId];
const result = getCompletedPercentage(
completedChallengesIds,
currentBlockIds,
labId
);
expect(result).toBe(100);
});
});
describe('getCompletedChallengesInBlock', () => {
@@ -251,6 +267,40 @@ describe('get-completion-percentage', () => {
expect(result).toEqual(['project-1', 'project-2']);
});
// Regression test for #67867: labs are project-based but each is its own
// standalone block, so they must use their block IDs rather than the
// certification's tests (otherwise resubmitting a completed lab reads 0%).
it('returns block IDs for labs even when a certificate is available', () => {
const allChallengesInfo: AllChallengesInfo = {
challengeNodes: [
{
challenge: {
id: 'lab-challenge',
block: 'lab-all-true-property-validator',
certification: Certification.JsV9
}
} as Partial<ChallengeNode> as ChallengeNode
],
certificateNodes: [
{
challenge: {
certification: Certification.JsV9,
tests: [{ id: 'javascript-certification-exam' }]
}
}
]
};
const result = getCurrentBlockIds(
allChallengesInfo,
'lab-all-true-property-validator',
Certification.JsV9,
challengeTypes.jsLab
);
expect(result).toEqual(['lab-challenge']);
});
it('returns empty array when no matching challenges found', () => {
const allChallengesInfo: AllChallengesInfo = {
challengeNodes: [
@@ -1,4 +1,5 @@
import { type Certification } from '@freecodecamp/shared/config/certification-settings';
import { getIsLabChallenge } from '@freecodecamp/shared/config/challenge-types';
import { AllChallengesInfo } from '../redux/prop-types';
import { isProjectBased } from './curriculum-layout';
@@ -53,7 +54,10 @@ export const getCurrentBlockIds = (
)
.map(node => node.challenge.id);
if (isProjectBased(challengeType)) {
// Labs are project-based, but each lab is its own standalone block rather than
// part of a certification's project list. Excluding them keeps the progress bar
// accurate (otherwise an already-completed lab reads 0% on resubmit). See #67867.
if (isProjectBased(challengeType) && !getIsLabChallenge(challengeType)) {
return currentCertificateIds.length > 0
? currentCertificateIds
: currentBlockIds;
@@ -178,6 +178,15 @@ const dailyCodingChallengeTypes = [
export const getIsDailyCodingChallenge = (challengeType: number): boolean =>
dailyCodingChallengeTypes.includes(challengeType);
const labChallengeTypes = [
challengeTypes.lab,
challengeTypes.jsLab,
challengeTypes.pyLab
];
export const getIsLabChallenge = (challengeType: number): boolean =>
labChallengeTypes.includes(challengeType);
const dailyCodingChallengeLanguages = {
[challengeTypes.dailyChallengeJs]: 'javascript',
[challengeTypes.dailyChallengePy]: 'python'