Skip to content

Refactor arbitrary size values in SelectContentPage.spec.js tests for clarity#14782

Merged
marcellamaki merged 5 commits into
learningequality:developfrom
akolson:abitrary-size-values
Jun 4, 2026
Merged

Refactor arbitrary size values in SelectContentPage.spec.js tests for clarity#14782
marcellamaki merged 5 commits into
learningequality:developfrom
akolson:abitrary-size-values

Conversation

@akolson
Copy link
Copy Markdown
Member

@akolson akolson commented Jun 2, 2026

Summary

SelectContentPage.spec.js contained hard-coded size strings (1,000 5 GB, 2,000 95 MB, 0 0 B) with no visible connection to the store data that produces them, making the tests hard to understand and maintain.

This PR:

  • Exports selectContentTransferredChannel from makeStore.js as a named constant so it serves as a single source of truth for both the store factory and test assertions
  • Replaces the opaque size literals with values derived from that constant via bytesForHumans and .toLocaleString() / .toString()
  • Cleans up the remaining test assertions: named variables for version numbers (removing post-render NEW_VERSION declarations), fixes a silent bug where the negative version test was asserting against '1000' instead of the actual channel version, introduces draftNewerVersion to name the repeated 5 across the draft-channel tests, and removes a stale TODO comment

All 10 tests pass unchanged.

References

Closes #14781
Related to #14656

Reviewer guidance

Tests only — no production code was modified.

To verify: pnpm test-jest kolibri/plugins/device/frontend/views/__tests__/SelectContentPage.spec.js

AI usage

Claude Code (Sonnet 4.6) was used to implement the refactor. I reviewed each change for correctness, engaged critically with the approach (e.g. choosing bytesForHumans over hard-coded strings, catching the wrong-version bug in the negative test), and ran the test suite after each step to verify nothing broke.

akolson and others added 2 commits June 2, 2026 13:33
Export selectContentTransferredChannel from makeStore.js so tests can
derive expected display values from the same source of truth rather than
hard-coding untraceble literals like '1,000 5 GB' and '2,000 95 MB'.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace magic literals with named variables derived from
selectContentTransferredChannel throughout: channel metadata in the
thumbnail/title test, newVersion/newerVersion/draftNewerVersion for
version comparison tests, and fix the negative version test which was
checking for version 1000 instead of the actual installed version.
Also remove a stale TODO comment.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions github-actions Bot added APP: Device Re: Device App (content import/export, facility-syncing, user permissions, etc.) DEV: frontend SIZE: small labels Jun 2, 2026
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@akolson akolson requested a review from rtibblesbot June 2, 2026 10:42
Copy link
Copy Markdown
Contributor

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean test-only refactor that achieves the single-source-of-truth goal from issue #14781. CI passes (all 10 frontend tests green).

Praise: The extracted selectContentTransferredChannel constant is the right approach — future fixture changes propagate automatically to both the store and the test assertions. The silent bug fix in the "no notification" test (asserting on a version that was never actually rendered) is a real correctness improvement.

Suggestion: channelsOnDevice[0] in makeStore.js (lines 46–52, outside the diff) still duplicates the same on_device_resources: 2000 and on_device_file_size: 95189556 values from selectContentTransferredChannel. Since the PR's stated goal is a single source of truth, consider updating it to { ...selectContentTransferredChannel, available: true }. Otherwise a future change to the fixture values here would silently diverge from channelsOnDevice. Not blocking — the constant's primary purpose is test assertions — but worth noting given the stated goal.

Nitpick: See inline comment on .toString() vs .toLocaleString() asymmetry.


@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Reviewed the pull request diff checking for:

  • Correctness: bugs, edge cases, undocumented behavior, resource leaks, hardcoded values
  • Design: unnecessary complexity, naming, readability, comment accuracy, redundant state
  • Architecture: duplicated concerns, minimal interfaces, composition over inheritance
  • Testing: behavior-based assertions, mocks only at hard boundaries, accurate coverage
  • Completeness: missing dependencies, unupdated usages, i18n, accessibility, security
  • Principles: DRY (same reason to change), SRP, Rule of Three (no premature abstraction)
  • Checked CI status and linked issue acceptance criteria
  • For UI changes: inspected screenshots for layout, visual completeness, and consistency

// derive expected display values (resource counts, file sizes) from the same source of truth.
export const selectContentTransferredChannel = {
...allChannels[0],
on_device_resources: 2000,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: channelsOnDevice[0] (lines 46–52, above this hunk) sets the same on_device_resources: 2000 and on_device_file_size: 95189556 independently. Since this constant is the declared source of truth, consider using it there too:

const channelsOnDevice = [
  { ...selectContentTransferredChannel, available: true },
  ...
];

Not blocking, but leaving the duplicate untouched means a future change to these values here won't automatically flow to channelsOnDevice.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the duplication

renderComponent({ store });
expect(screen.getAllByRole('row')[2]).toHaveTextContent(
`${summaryTr.$tr('onDeviceRow')} 0 0 B`,
`${summaryTr.$tr('onDeviceRow')} ${onDeviceResources.toString()} ${bytesForHumans(onDeviceFileSize)}`,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: The non-zero resource count tests above use .toLocaleString(), matching the component's $formatNumber(..., { useGrouping: true }) call. This line uses .toString() — both produce "0" so it doesn't affect correctness, but using .toLocaleString() here too would make the pattern uniform and make the intent explicit.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed toString() to toLocaleString()

- Move selectContentTransferredChannel before channelsOnDevice so
  channelsOnDevice[0] can reference it as the source of truth rather
  than duplicating the on_device_resources/on_device_file_size values
- Use toLocaleString() consistently for resource counts, matching the
  pattern used by the non-zero resource tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delta review of PR #14782. No UI files changed — Phase 3 skipped.

See CI notes below.

The PR successfully meets all issue requirements: it identifies allChannels[0] as the source of the arbitrary fixture values, exports a selectContentTransferredChannel constant as a single source of truth (eliminating three-way duplication), and replaces hardcoded display strings with derived values using bytesForHumans and .toLocaleString(). Both prior review findings (the channelsOnDevice[0] spread and the .toString()-to-.toLocaleString() uniformity) have been resolved. No blocking issues were found. Three nitpicks are noted: newerVersion = 5 is numerically less than the base channel's version (10) which could confuse readers; a useful contextual comment was stripped from a still-present test; and two tests destructure fixture data after renderComponent rather than before, breaking the Arrange-Act-Assert order. All existing test coverage is preserved.


@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Compared the current PR state against findings from a prior review:

  • Retrieved prior bot reviews deterministically via the GitHub API
  • Classified each prior finding as RESOLVED, UNADDRESSED, ACKNOWLEDGED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Reviewed the pull request diff checking for correctness, design, architecture, testing, completeness, and adherence to DRY/SRP principles
  • Checked CI status and linked issue acceptance criteria


// The transferredChannel used by makeSelectContentPageStore, exported so tests can
// derive expected display values (resource counts, file sizes) from the same source of truth.
export const selectContentTransferredChannel = {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: Exporting selectContentTransferredChannel as a single source of truth is well-executed. It eliminates three previously-duplicated copies of on_device_resources: 2000 / on_device_file_size: 95189556 (in channelsOnDevice[0], in transferredChannel, and implicitly in the test expectations), and the spread of allChannels[0] means channel metadata like name, version, and description also flow through without duplication.

const { total_resources, total_file_size } = selectContentTransferredChannel;
expect(screen.getAllByRole('row')[1]).toHaveTextContent(
`${summaryTr.$tr('totalSizeRow')} 1,000 5 GB`,
`${summaryTr.$tr('totalSizeRow')} ${total_resources.toLocaleString()} ${bytesForHumans(total_file_size)}`,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: Using bytesForHumans(total_file_size) and bytesForHumans(onDeviceFileSize) in assertions instead of hardcoded strings like "5 GB" / "95 MB" / "0 B" is the right approach. Tests now stay correct if the formatting utility ever changes its rounding or unit thresholds, and the intent — "what the component renders" — is made explicit through the same function the component uses.


//Add translations strings to these tests & test these & commit the changes.
describe('draft channel (installed version = 0)', () => {
const newerVersion = 5;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: newerVersion = 5 is less than allChannels[0].version (10), so the name is slightly misleading in context. It is correctly newer than the installed version (0) that these tests set via setInstalledVersion(store, 0), but a reader unfamiliar with the fixture may find it odd that a "newer version" is numerically smaller than the channel's base version. A comment or a different value (e.g. 15) that is unambiguously newer than 10 would remove the ambiguity.

).toBeInTheDocument();
});

it('hides ContentTreeViewer when installed version > 0 and newer version available on Studio', () => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: The comment // Preserve existing non-draft behavior was removed from line 144 (the hides ContentTreeViewer test). The code it described is still present and unchanged — the project conventions say to only remove comments when the described code is deleted or the comment is provably incorrect. The comment clarified why this non-draft test lives inside the draft channel describe block, which is genuinely useful context.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test's description is sufficient to provide all the context

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right — the test description provides the context readers need. Withdrawing this finding.

});

it('shows the total size of the channel', () => {
renderComponent({ store });
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: renderComponent({ store }) is called on line 60 before the destructuring of selectContentTransferredChannel on line 61. Correctness is unaffected (the values come from the imported constant, not the rendered DOM), but the conventional order is to arrange all data first, then render, then assert. The same pattern appears in the onDeviceRow test (lines 68–69). Moving the destructuring above renderComponent would match the Arrange-Act-Assert pattern used elsewhere in this file.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 2, 2026

- Change newerVersion from 5 to 15 so it is unambiguously greater than
  both the installed version (0) and the base channel version (10)
- Move selectContentTransferredChannel destructuring above renderComponent
  in the totalSizeRow and onDeviceRow tests to follow Arrange-Act-Assert

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All five prior findings are resolved or acknowledged — thorough follow-through on every round of feedback.

CI: 8/9 checks complete, no failures; 1 still in progress. No UI files changed — Phase 3 skipped.

Prior findings

3 prior findings unchanged (2 resolved from round 1, 1 acknowledged/withdrawn from round 3).

Newly resolved:

  • newerVersion = 5 naming (nitpick) ← was UNADDRESSED — changed to 15, unambiguously greater than both the installed version (0) and the base channel version (10)
  • AAA ordering in totalSize/onDevice tests (nitpick) ← was UNADDRESSED — destructuring moved above renderComponent

5/5 prior findings resolved or acknowledged. 0 re-raised below.


@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Compared the current PR state against findings from a prior review:

  • Retrieved prior bot reviews deterministically via the GitHub API
  • Classified each prior finding as RESOLVED, UNADDRESSED, ACKNOWLEDGED, or CONTESTED
  • Only raised NEW findings for newly introduced code
  • Reviewed the pull request diff checking for correctness, design, architecture, testing, completeness, and adherence to DRY/SRP principles
  • Checked CI status and linked issue acceptance criteria

});

it('shows the total size of the channel', () => {
const { total_resources, total_file_size } = selectContentTransferredChannel;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: Extracting the fixture values before renderComponent now cleanly follows Arrange-Act-Assert — data setup is part of Arrange, not suspended mid-Act.


//Add translations strings to these tests & test these & commit the changes.
describe('draft channel (installed version = 0)', () => {
const newerVersion = 15;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: 15 is unambiguously greater than both the installed version (0) and the base channel version (10) — no more risk of a reader misreading "newer" as relative to the channel's base version field.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

15 is unambiguously greater than 0 and 10!! :)

Copy link
Copy Markdown
Member

@marcellamaki marcellamaki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, @akolson -- nice cleanup

@marcellamaki marcellamaki merged commit f9c4144 into learningequality:develop Jun 4, 2026
69 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

APP: Device Re: Device App (content import/export, facility-syncing, user permissions, etc.) DEV: frontend SIZE: small

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Refactor arbitrary size values in SelectContentPage.spec.js tests for clarity

3 participants