Skip to content

test: unit tests for app/ with regression coverage + PR workflow - #672

Merged
farfromrefug merged 6 commits into
mainfrom
copilot/add-unit-testing-for-app-folder
Jul 27, 2026
Merged

test: unit tests for app/ with regression coverage + PR workflow#672
farfromrefug merged 6 commits into
mainfrom
copilot/add-unit-testing-for-app-folder

Conversation

Copilot AI commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Adds Vitest unit tests for app/, a test script, and a pull-request workflow.

Merged main (branch was 87 commits behind) and resolved both conflicts:

  • yarn.lock — both hunks were the tools submodule hash; the submodule itself merged cleanly to main's commit, so main's hashes are the correct side.
  • .github/workflows/test.ymlmain already has an unrelated test.yml, which this branch had overwritten. Main's file is restored and the unit-test CI now lives in its own unit-tests.yml.

Running the tests

yarn test

yarn test:watch for watch mode, npx vitest run <path> to isolate a file. CI runs yarn test on every pull request via .github/workflows/unit-tests.yml.

Regression detection

The point of the suite is to fail when behaviour changes, so the export-rename path was checked by mutation rather than assumed: removing : from the forbidden-character set in cleanFilename fails 8 tests across 2 files.

To get there, buildExportImageNames() was extracted so the whole chain the export screen actually runs — creation date → user filename format → forbidden-character sanitising → collision suffixes — is covered end to end, instead of only its individual pieces.

The same extract-then-test approach was applied to sync folder filtering: SyncWorker's two private filter methods moved into app/services/sync/folderFilter.ts (the worker delegates to it, behaviour unchanged) so the rules can be pinned — an empty folder list means "no filter", and documents in no folder are excluded once a filter is active.

Fixes to tests already on this branch

  • exportUtils.test.ts re-declared the export regex inline and asserted against that copy. It tested a duplicate, so editing the real regex could never fail it. Removed — the real cleanFilename is covered in utils.common.test.ts.
  • matrix.test.ts actually tested color_matrix.ts. Renamed to color_matrix.test.ts; a real matrix.test.ts now covers getPageColorMatrix (filter selection, brightness/contrast composition, NaN handling).
  • Timezone fragility. A date assertion passed locally and failed under UTC. TZ is now pinned to UTC in the Vitest config — this app formats dates into filenames, so this would have been a recurring CI flake.

New coverage

Area What is pinned
utils/exportUtils export filename pipeline, collision suffixes
utils/matrix page colour matrix selection and composition
utils/pkpass barcode formats, transit icons, display-name fallbacks, field alignment
services/api queryString URL building and parameter extraction
services/sync/folderFilter per-service folder filtering rules
services/sync/types each sync type owns a unique single bit, in 32-bit range
services/sync/BaseSyncService stored-settings round-trip, per-service update isolation

Test harness

  • ApplicationSettings is now an in-memory store that resets between tests, so settings-dependent behaviour can be exercised instead of only default values.
  • Native plugins are mocked and the webpack DefinePlugin globals plus NativeScript's .common.ts platform resolution are mirrored in the Vitest config. This unblocks importing pkpass, api and locale, which previously failed at import time.

251 tests across 14 files. New files typecheck against tsconfig.test.json and pass ESLint.

Not covered, and why

  • app/components/** (Svelte) — no component test setup; would need a renderer.
  • app/models/OCRDocument.ts — transitively imports the NativeScript UI layer and cannot be imported under Vitest. Documented in .claude/CLAUDE.md along with the extract-the-pure-logic workaround.
  • app/services/documents.ts — SQL-backed; needs a database fixture rather than unit tests.

Two things worth a maintainer decision

  1. .github/workflows/test.yml on main runs echo "${{ toJSON(secrets) }}", which writes every repository secret into the build log. It is workflow_dispatch-only, so triggering it needs maintainer access, but logs are readable by anyone with read access. Left untouched here as out of scope — worth deleting and rotating those secrets.
  2. app/services/trashUtils.ts is unreferenced. The shipping trash logic is SQL-backed in documents.ts, so the existing trash.test.ts guards code the app never runs. Left as-is: either wire the module in or drop it.

Copilot AI added 2 commits June 2, 2026 16:27
- Add vitest.config.ts with path aliases (~/, @shared/) and NativeScript globals
- Add tsconfig.test.json extending main tsconfig to include *.test.ts files
- Add vitest.setup.ts with mocks for @nativescript/core and @akylas/nativescript-app-utils
- Extract deduplicateFilenames() to app/utils/exportUtils.ts; use it in index.common.ts
- Add app/utils/path.test.ts (dirname, basename, extname)
- Fix basename() bug: use slice() instead of substring() for negative-index ext strip
- Add app/utils/matrix.test.ts (concatTwoColorMatrices, concatColorMatrices)
- Add app/utils/utils.common.test.ts (cleanFilename, pick, omit, sortByKey, ellipsize)
- Add app/helpers/formatter.test.ts (convertTime with dayjs)
- Add app/utils/exportUtils.test.ts (deduplicateFilenames + cleanFilename regex spec)
- Fix app/services/sync/deletedDocuments.test.ts to match tuple return type
- Add 'test' and 'test:watch' scripts to package.json
- Update .github/workflows/test.yml: trigger on PRs, run yarn install + yarn test
farfromrefug and others added 2 commits July 27, 2026 12:04
# Conflicts:
#	.github/workflows/test.yml
#	yarn.lock
Continues the vitest setup on this branch after merging main.

Test quality:
- Drop the cleanFilename suite that re-declared the export regex inline: it
  tested a copy, so a change to the real regex could never fail it. The real
  function is already covered in utils.common.test.ts.
- Rename matrix.test.ts to color_matrix.test.ts (it tested color_matrix.ts) and
  add a real matrix.test.ts for getPageColorMatrix.

Export rename regression coverage (the headline case):
- Extract buildExportImageNames() so the format -> sanitise -> deduplicate chain
  used by exportImages() is testable end to end instead of only in pieces.
- Verified by mutation: removing ':' from the forbidden-character set fails 8
  tests across 2 files.

New coverage against real production code:
- sync folder filtering: extracted SyncWorker's two private filters into
  services/sync/folderFilter.ts and pinned the rules (empty list means "no
  filter"; unfoldered documents are excluded when a filter is active).
- sync bitmasks: every SyncTypes entry owns a unique single bit in 32-bit range.
- BaseSyncService: stored-settings round-trip and per-service update isolation.
- pkpass: barcode formats, transit icons, display-name fallbacks, alignment.
- api: queryString URL building and parameter extraction.

Harness:
- ApplicationSettings is now an in-memory store that resets between tests, so
  settings-dependent behaviour can be exercised rather than only defaults.
- Mock the native plugins and mirror the webpack DefinePlugin globals and the
  .common.ts platform resolution, which unblocks importing pkpass/api/locale.
- Pin TZ=UTC: filename formatting is timezone sensitive and would otherwise
  pass locally and fail on CI.

CI runs on pull requests via .github/workflows/unit-tests.yml; main's unrelated
test.yml is left untouched.

251 tests across 14 files.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@farfromrefug farfromrefug changed the title test: add Vitest unit tests for app utilities, helpers, and services test: unit tests for app/ with regression coverage + PR workflow Jul 27, 2026
@farfromrefug
farfromrefug marked this pull request as ready for review July 27, 2026 11:03
@farfromrefug
farfromrefug merged commit d898e6e into main Jul 27, 2026
1 check passed
@farfromrefug
farfromrefug deleted the copilot/add-unit-testing-for-app-folder branch July 27, 2026 11:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants