Skip to content

test(NcUploadPicker): cover upload retries and harden request assertions - #8922

Draft
skjnldsv wants to merge 14 commits into
mainfrom
test/nc-upload-picker-coverage
Draft

skjnldsv wants to merge 14 commits into
mainfrom
test/nc-upload-picker-coverage

Conversation

@skjnldsv

@skjnldsv skjnldsv commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

☑️ Resolves

Follow-up on #7882, based on that branch. Merge it into #7882 if you prefer a single PR, or keep it as a second step.

Covers scenarios from the Cypress suite in @nextcloud/upload that had no equivalent after the migration.

🖼️ What changed

Test only, no component code touched.

Retry coverage (new retry.spec.ts)

retryCondition in @nextcloud/files (lib/upload/utils/upload.ts) has no spec of its own, so all three branches were untested in every repo:

  • a network error is retried
  • a locked file (423) is retried, since it is usually a preview being generated
  • insufficient storage (507) is permanent and must not be retried

The three tests validate each other: the 507 case proves that "no retry" is detectable, so the 423 and network cases are not passing vacuously.

Progress across a retry

A retry must not discard the progress of uploads that already finished. The retry is held back so the assertion runs while it is in flight, instead of racing the progress bar being hidden once the queue is done.

Negative request assertions

received(...).toHaveLength(0) only looks at what arrived so far, so it can pass because a request has not been sent yet rather than because it never will be. Replaced with a new expectNoMore() helper, plus a sync point that proves the uploader got far enough.

Reusable helpers

  • UploadStatus mirror with a satisfies drift guard, replacing the hand written status numbers. The upstream constant cannot be imported at runtime here because @nextcloud/files/upload touches window on import while the test bodies run in Node. Changing a value now fails type checking with Type '99' is not assignable to type '4'.
  • skipWithoutFilePicker() centralises the WebKit skip and its reason
  • createFile() takes a MIME type
  • mockDav({ fail }) can abort a request with a network error
  • the WebDAV root pattern is non greedy, so a path repeating /remote.php/dav is not over stripped

🧪 Testing

npm run test:component -- --project=chromium tests/component/components/NcUploadPicker

Before: 32 passed, 5 failed. After: 36 passed, 5 failed, so 4 new tests.

The 5 failures are pre-existing on the base branch and are not touched here. They are all in conflicts.spec.ts, which looks for a dialog named 1 file conflict. That string does not exist in @nextcloud/dialogs, the name is Select file to keep or Select files to keep. Single conflicts also render Cancel / Keep both / Replace buttons rather than per version checkboxes, so keepVersion() cannot match. Left for #7882, see the review comments there.

🚧 Deliberately not covered

Byte level progress inside a single file. It comes from upload progress events that a mocked route never emits, so with route.fulfill the bar stays at 0 for the whole upload of one file. Observing it needs real network throttling, which is what the old Cypress suite did with CDP Network.emulateNetworkConditions and what made those tests flaky.

🏁 Checklist

  • ⛑️ Tests are included or are not applicable
  • 📘 Component documentation has been extended, updated or is not applicable
  • 2️⃣ Backport to stable8 for maintained Vue 2 version or not applicable

This change was AI assisted.

susnux and others added 14 commits September 3, 2026 00:38
…load`

Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Adds the shared pieces the upload specs kept repeating:

- `UploadStatus` mirrors the upstream constant from `@nextcloud/files/upload`,
  which cannot be imported at runtime here because it touches `window` on
  import while the test bodies run in Node. The `satisfies` clause makes the
  type checker fail if the upstream values ever change, so the mirror cannot
  silently drift like the hand-written numbers it replaces.
- `skipWithoutFilePicker()` centralises the WebKit skip and its reason.
- `expectNoMore()` asserts that no *further* matching request arrives. A plain
  `received(...)` check only looks at what happened so far, so it can pass
  simply because a request the uploader is about to send has not been sent yet.
- `createFile()` takes the MIME type, and `mockDav()` can `fail()` a request
  with a network error, which is needed to cover the retry behaviour.

The WebDAV root pattern is made non-greedy so a path that repeats
`/remote.php/dav` is not over-stripped.

Assisted-by: ClaudeCode:claude-opus-5
Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
Adds the retry scenarios that were covered by the Cypress suite in
`@nextcloud/upload` but had no equivalent after the migration. The
`retryCondition` in `@nextcloud/files` (`lib/upload/utils/upload.ts`) has no
test of its own, so all three branches were untested:

- a network error is retried,
- a locked file (423) is retried, because it is usually a preview being
  generated,
- insufficient storage (507) is permanent and must not be retried.

Also asserts that retrying an upload keeps the progress of the uploads that
already finished instead of starting over. The retry is held back so the
progress is observed while it is actually running, rather than racing the
progress bar being hidden once the queue is done.

Finally, the negative request assertions now use `expectNoMore()` and only run
after a request that proves the uploader got far enough, so they cannot pass
just because nothing has happened yet.

Byte level progress within a single file is deliberately not covered: it is
driven by upload progress events that a mocked route never emits, so it would
need real network throttling to observe.

Assisted-by: ClaudeCode:claude-opus-5
Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
@skjnldsv skjnldsv added 2. developing Work in progress enhancement New feature or request labels Sep 4, 2026
@codecov

codecov Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 53.62%. Comparing base (431159c) to head (a07312f).

Additional details and impacted files
@@                Coverage Diff                @@
##           feat/nc-uploader    #8922   +/-   ##
=================================================
  Coverage             53.62%   53.62%           
=================================================
  Files                   124      124           
  Lines                  4513     4513           
  Branches               1340     1342    +2     
=================================================
  Hits                   2420     2420           
  Misses                 1774     1774           
  Partials                319      319           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Base automatically changed from feat/nc-uploader to main September 8, 2026 22:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

2. developing Work in progress enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants