test: make the LoadedTabPage streak test actually assert - #2108
Merged
brian-smith-tcril merged 1 commit intoSep 23, 2026
Merged
Conversation
brian-smith-tcril
added this pull request to stack #2080
September 23, 2026 13:56
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #2108 +/- ##
=======================================
Coverage 93.95% 93.95%
=======================================
Files 367 367
Lines 5939 5939
Branches 1435 1435
=======================================
Hits 5580 5580
Misses 345 345
Partials 14 14 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
brian-smith-tcril
marked this pull request as ready for review
September 23, 2026 14:04
brian-smith-tcril
force-pushed
the
bsmith/loaded-tab-page-streak-test-assert
branch
from
September 23, 2026 14:05
01a9403 to
bece479
Compare
Base automatically changed from
bsmith/progress-tab-readers-no-refetch
to
master
September 23, 2026 14:11
The *shows streak celebration modal* case could not fail. Its `StreakModal` mock rendered a bare div whatever its props, and `LoadedTabPage` always renders `StreakModal`, open or closed, so "the mock is in the document" was true on every render. Its fixture also set `celebrations` on the courseware metadata factory, while `LoadedTabPage` has read `celebrations` from `courseHomeMeta` since AA-1018; the test store builds that from a separate factory with `celebrations: null`, so the streak never reached the component. Removing `celebrations` from the fixture left the test green. The fixture now goes on the `courseHomeMetadata` factory, through the `initializeTestStore` option the suite's staff case already uses, and the modal is no longer mocked: closed it renders nothing, open it renders a dialog titled with the streak length, so the case asserts a dialog reading "3 day streak" is on the page and *renders correctly* asserts there is no dialog on the default fixture. Removing `celebrations` from the fixture now fails the streak case, and forcing the modal open in the component fails the contrast. The component is unchanged. Part of #1946 (Stage 1). Closes #2107. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
brian-smith-tcril
force-pushed
the
bsmith/loaded-tab-page-streak-test-assert
branch
from
September 23, 2026 14:11
bece479 to
d908d76
Compare
Merged
21 tasks
brian-smith-tcril
deleted the
bsmith/loaded-tab-page-streak-test-assert
branch
September 23, 2026 17:04
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Make the shows streak celebration modal case in
tab-page/LoadedTabPage.test.jsxactually assert. It could not fail: theStreakModalmock rendered a bare div whatever its props, andLoadedTabPagerendersStreakModalon every render, open or closed; and its fixture setcelebrationson the courseware metadata factory, while the component has readcelebrationsfromcourseHomeMetasince AA-1018 (2022), which the test store fills from a separate factory withcelebrations: null. Removingcelebrationsfrom the fixture left the test green. Test-only;LoadedTabPage.tsxis untouched. Stacked on #2106 as the stack top; below B2 (#2085), which rewrites this suite's data source and should land on a case that checks something. Part of #1946 as test hygiene on code the migration touches. Closes #2107.What changed
courseHomeMetadatafactory, through theinitializeTestStoreoption the suite's staff case already uses, so the streak reaches the model the component reads, camel-cased by the real normalizer.StreakCelebrationModalrenders nothing; open, it renders a dialog titled with the streak length. The case asserts a dialog reading "3 day streak" is on the page. Rendering it costs what its own suite pays: the analytics module mocked and anactwrapper around the render.renders correctlyasserts the contrast: no dialog on the default fixture. A modal that is always open cannot satisfy the streak case's assertion.Testing
npm run typesandnpm run lintclean;LoadedTabPage.test.jsx3/3 with no console output. Negative checks on this layer: removingcelebrationsfrom the fixture fails the streak case (no element with roledialog); forcing the modal open in the component fails the contrast (a dialog titled "null day streak"). The full suite was not run for a one-file test change.Provenance
The mock has been unconditional since the case was written in #354 (2021-02-22). The fixture stopped reaching the component in AA-1018 (3fe5bb1, 2022-01-14), which moved
LoadedTabPage's read tocourseHomeMetaand gave the test store its owncourseHomeMetadatafactory. Found while planning B2 (#2085), which rewrites how this suite gets its data; split out as its own layer, like #2078 / #2079 and #2100 / #2101, so B2's diff to the suite is only the data-source swap.Decisions
Full decision log
Decisions — make the LoadedTabPage streak test actually assert (#2107)
Test-only layer between #2103 (PR #2106) and B2 (#2085). Entries 1 and 2 were
settled while reviewing the #2085 plan; the rest landed with the code.
A layer of its own, below B2. B2 rewrites how
LoadedTabPage.test.jsxgets its data (the query instead of the store), so it would have had to
touch this case anyway, and the first draft of the B2 plan fixed it there.
Rejected in review for the Make the courseware redirect-rule tests actually assert: un-awaited
waitForand unwired mocks from #1501 #2078 / Make theuseIsCourseLoadedtests actually assert: replaced mocks and unsettled checks from #2071 #2100 shape: a small issue and a tinytest:layer first, so B2's diff to the suite is only the data-sourceswap and the repair of a 2021 test is reviewed as what it is. It sits on
Stop the progress tab data refetching from components under the tab #2103 because that is the stack top; nothing in it depends on Stop the progress tab data refetching from components under the tab #2103.
Two defects, either of which alone keeps the case green.
StreakCelebrationModalwasmocked as a component returning
<div data-testid="StreakModal" />whatever its props, and
LoadedTabPagealways rendersStreakModal(
LoadedTabPage.tsx:71-77), open or closed. "The mock is in thedocument" is true on every render. So since the case was written
(2525805, [AA-304] Create three day streak celebration #354, 2021-02-22).
courseware metadata factory with
celebrations, butLoadedTabPagehasread
celebrationsfromcourseHomeMetasince 3fe5bb1 (AA-1018,2022-01-14), and
initializeTestStorefills that model from a separatecourseHomeMetadatafactory built withcelebrations: null(
buildSimpleCourseAndSequenceMetadata,sequenceMetadata.factory.js).The case was not updated then. b3d3366 (Updated frontend-build to v12 #962, 2023) only reformatted
the mock for a lint rule.
Removing
celebrationsfrom the fixture left the case green, on thislayer's base with no other change.
The fixture goes on the
courseHomeMetadatafactory, through theinitializeTestStoreoption.initializeTestStore({ courseHomeMetadata })is the shape the suite's staff case already uses
(
original_user_is_staff: true), and the store fillscourseHomeMetafrom the mocked
course_metadataendpoint through the real normalizer, sostreak_length_to_celebratearrives camel-cased exactly as productiondata does. The course id comes from
getTestStoreIds(testStore)ratherthan a hand-built
courseMetadata, since the case no longer builds one.The modal is not mocked; the case asserts on the dialog. A first
version kept a mock and made it a
jest.fncomponent(
UnitSuspense.test.jsx:20-21's shape), asserting on the propsLoadedTabPagepassed it —isStreakCelebrationOpen: true,streakLengthToCelebrate: 3. Rejected in review: that tests thatLoadedTabPagehands a stub an open flag, not that anything is shown,which is what the case is named for. The real
StreakCelebrationModalreturns
nullwhen closed (StreakCelebrationModal.jsx:117-119) andrenders a Paragon
ModalDialogtitled${streakLengthToCelebrate} day streakwhen open (:143-161), so thecase now asserts
getByRole('dialog')has text3 day streak: both theopen flag and the length flow through the real component to what a
learner sees. Rendering it costs what its own suite pays
(
StreakCelebrationModal.test.jsx:18-19,56):jest.mock('@edx/frontend-platform/analytics'),because opening fires
recordStreakCelebration→sendTrackEvent, and anactwrapper around the render for the modal's effects. Its ownuseModel('courseHomeMeta')read (org,username) is served by thesame store the fixture fills; its discount effect is skipped because
streakDiscountCouponEnabledisnullon the default fixture.renders correctlyasserts the contrast. On the default fixture(
celebrations: null) there is no dialog on the page(
queryByRole('dialog')is null). Without it the streak case's assertioncould be satisfied by a modal that is always open — the mirror of
defect 1. It also pins the
!!coercion on the prop(
LoadedTabPage.tsx:75): forcing the prop totruein the componentrenders a dialog titled "null day streak" and fails this case.
Test-only, one file.
LoadedTabPage.tsxis untouched; the diff issrc/tab-page/LoadedTabPage.test.jsxalone (10 insertions, 8 deletions).Suite 3/3 with no console output;
npm run lintandnpm run typesclean. Negative checks on this layer: removing
celebrationsfrom thefixture fails shows streak celebration modal (no element with role
dialog); replacing!!isStreakCelebrationOpenwith a bareisStreakCelebrationOpenon theStreakModalprop fails renderscorrectly. The full suite was not run for a one-file test change.
🤖 Generated with Claude Code