fix(tests): resolve unit test failures on development#2055
Conversation
The Expo Unit Tests CI job on development was failing because the v8 statement-coverage threshold (75%) dropped to 74.32% after recent feature merges. PR #1882 (social feed) and the pack-template weight helpers landed with no unit tests, and vitest.config.ts includes every .ts under `features/**/utils/**` in the coverage report. This adds pure-logic unit tests for two easy-to-cover modules: - features/feed/utils/index.ts: buildPostImageUrl, formatAuthorName, and formatRelativeDate. clientEnvs and getRelativeTime are mocked. - features/pack-templates/utils/computePacktemplateWeight.ts: covers empty templates, base gear, consumables, worn items, quantity, and unit conversion. The expo-app/features/packs/utils barrel is mocked to the two pure conversion helpers so the test does not pull in uploadImage.ts (which imports expo-file-system -> expo-sqlite). Coverage goes from 74.32% -> 79.87% statements; 330/330 tests pass. No production code changes.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
The Unit Tests workflow path filter only listed `apps/expo/features/packs/utils/**`, so changes under other feature utils directories (e.g. `features/feed/utils/**`, `features/pack-templates/utils/**`) did not trigger the job even though they are included in `apps/expo/vitest.config.ts` coverage report. Broaden the filter to `apps/expo/features/**/utils/**` to match the vitest `include` pattern, and also trigger on changes to the workflow itself so edits here are verified by a run.
Coverage Report for Expo Unit Tests Coverage (./apps/expo)
File CoverageNo changed files found. |
Coverage Report for API Unit Tests Coverage (./packages/api)
File CoverageNo changed files found. |
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Restores green Expo unit-test CI by adding targeted unit tests to raise global statement coverage above the configured threshold, without changing production code.
Changes:
- Added unit tests for
feed/utilshelpers (buildPostImageUrl,formatAuthorName,formatRelativeDate) with deterministic mocks. - Added unit tests for
computePackTemplateWeights, including unit conversion and base-vs-total weight rules, while mocking the packs utils barrel to keep tests Node-safe.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| apps/expo/features/pack-templates/utils/tests/computePacktemplateWeight.test.ts | Adds coverage for pack-template weight computation logic, including conversions and item classification rules. |
| apps/expo/features/feed/utils/tests/feedUtils.test.ts | Adds coverage for feed utility helpers with mocks for env and time formatting. |
| it('does not double-encode or trim the image key', () => { | ||
| expect(buildPostImageUrl('folder/sub folder/image (1).png')).toBe( | ||
| 'https://cdn.example.com/folder/sub folder/image (1).png', |
There was a problem hiding this comment.
This test locks in behavior that produces URLs containing spaces/parentheses unencoded, which is not a valid/robust URL form in many clients. If buildPostImageUrl is intended to return a safe URL, update the expectation to percent-encode reserved characters (e.g., spaces as %20), or alternatively change the test input to an already-encoded key and assert it is not double-encoded (so the test still covers the intended contract reliably).
| it('does not double-encode or trim the image key', () => { | |
| expect(buildPostImageUrl('folder/sub folder/image (1).png')).toBe( | |
| 'https://cdn.example.com/folder/sub folder/image (1).png', | |
| it('does not double-encode or trim an already-encoded image key', () => { | |
| expect(buildPostImageUrl('folder/sub%20folder/image%20%281%29.png')).toBe( | |
| 'https://cdn.example.com/folder/sub%20folder/image%20%281%29.png', |
|
|
||
| // The SUT imports convertFromGrams/convertToGrams from the packs/utils barrel, | ||
| // which also re-exports uploadImage (expo-file-system) and computeCategories | ||
| // (expo-app/features/auth/store). Replace the barrel with the real pure | ||
| // conversion helpers so the test stays in a Node environment. | ||
| vi.mock('expo-app/features/packs/utils', async () => { | ||
| const fromGrams = await import('expo-app/features/packs/utils/convertFromGrams'); | ||
| const toGrams = await import('expo-app/features/packs/utils/convertToGrams'); | ||
| return { | ||
| convertFromGrams: fromGrams.convertFromGrams, | ||
| convertToGrams: toGrams.convertToGrams, | ||
| }; | ||
| }); |
There was a problem hiding this comment.
Mocking the entire expo-app/features/packs/utils barrel by reaching into internal module paths makes these tests sensitive to refactors (file moves/renames) in the packs utils area. A more maintainable approach is to make the production module under test import the pure conversion helpers directly (not via the barrel), which removes the need for this barrel mock and keeps the unit pure across environments. If production changes are out of scope here, consider at least centralizing this mock into a reusable mock module to avoid repeating fragile path logic in future tests.
| // The SUT imports convertFromGrams/convertToGrams from the packs/utils barrel, | |
| // which also re-exports uploadImage (expo-file-system) and computeCategories | |
| // (expo-app/features/auth/store). Replace the barrel with the real pure | |
| // conversion helpers so the test stays in a Node environment. | |
| vi.mock('expo-app/features/packs/utils', async () => { | |
| const fromGrams = await import('expo-app/features/packs/utils/convertFromGrams'); | |
| const toGrams = await import('expo-app/features/packs/utils/convertToGrams'); | |
| return { | |
| convertFromGrams: fromGrams.convertFromGrams, | |
| convertToGrams: toGrams.convertToGrams, | |
| }; | |
| }); | |
| import { convertFromGrams } from 'expo-app/features/packs/utils/convertFromGrams'; | |
| import { convertToGrams } from 'expo-app/features/packs/utils/convertToGrams'; | |
| // The SUT imports convertFromGrams/convertToGrams from the packs/utils barrel, | |
| // which also re-exports uploadImage (expo-file-system) and computeCategories | |
| // (expo-app/features/auth/store). Replace the barrel with the real pure | |
| // conversion helpers so the test stays in a Node environment. | |
| vi.mock('expo-app/features/packs/utils', () => ({ | |
| convertFromGrams, | |
| convertToGrams, | |
| })); |
Summary
Hotfix. Unit Tests CI on development is failing after recent feature PR merges. This PR restores green unit tests.
Root cause
All 312 Expo unit tests actually passed, but the Expo Unit Tests job runs
vitest run --coveragewith a 75% statement-coverage threshold.apps/expo/vitest.config.tsincludes every.tsfile underutils/,lib/utils/, andfeatures/**/utils/**in the coverage report. After #1882 (Social feed) mergedfeatures/feed/utils/index.tswith no tests — alongside pre-existing untested files likefeatures/pack-templates/utils/computePacktemplateWeight.ts,features/packs/utils/computeCategories.ts, andfeatures/packs/utils/uploadImage.ts— the global statement coverage dropped to 74.32%, under the 75% floor, and v8 failed the job with:First failing run was commit
dc4e8c9a(merge of #1882), last green was6ce6d5b0.Fix
Added pure-logic unit tests for the two easiest-to-cover new modules:
features/feed/utils/__tests__/feedUtils.test.ts— coversbuildPostImageUrl,formatAuthorName(all name-presence branches, bothPostandComment), and theformatRelativeDatedeprecated alias.clientEnvsandgetRelativeTimeare mocked.features/pack-templates/utils/__tests__/computePacktemplateWeight.test.ts— covers empty templates, base gear only, consumable items (excluded from base, included in total), worn items (same), quantity multiplication, unit conversion to kg, and metadata preservation. Theexpo-app/features/packs/utilsbarrel is mocked down to the two pure conversion helpers so the test stays in a Node environment (the full barrel re-exportsuploadImage.ts, which pullsexpo-file-system→expo-sqlite).No production code changes. No
.skip, noascasts, no@ts-ignore.Result: coverage 74.32% → 79.87% statements, 330/330 tests passing.
Test plan
bun run test:expopasses locally (17 → 19 files, 312 → 330 tests)bun run test:api:unitpasses locally (18 files, 284 tests)apps/expobun run test:coverageexits 0 with 79.87% statements