Skip to content

Fix the first-start config save and two flaky e2e tests - #83

Merged
firsttris merged 4 commits into
masterfrom
fixes
Nov 4, 2026
Merged

firsttris merged 4 commits into
masterfrom
fixes

Conversation

@firsttris

Copy link
Copy Markdown
Owner

Three fixes and one finding.

First start without a data directory: "Failed to save default config: ENOENT"

Without login nothing had created SNAPRAID_BASE_PATH when loadAppConfig saved the defaults. Only loadSessionSecret and the log manager run mkdir, and the log manager runs after the config is loaded. So the save failed and config.json appeared only on the second start. saveAppConfig now creates the directory with mkdir's default mode, the same way the log manager does.

  • Test (apps/server/src/__tests__/config.test.ts): a child process with SNAPRAID_BASE_PATH set to a directory that does not exist yet. It checks that no error is logged, that config.json is saved and that the directory mode is 0777 & ~umask. It fails on master and passes with the fix.
  • The binary run from an empty directory now logs Created default config at …/snapraid/config.json. snapraid/ and snapraid/logs are both 755.

Flaky "deleted and encrypted files are restored…"

Each job gets its own toast, and toasts stay for 5 s (Feedback.tsx). The UI is right to keep both results. When the second restore finished within 5 s of the first, expectFinished found two toasts and failed with a strict mode violation. expectFinished now closes the toast it waited for. The close is a dispatched click because an open wizard's overlay covers the toasts (replace.spec.ts).

  • Red: with the toast duration temporarily set to 20 s, this test fails on master with exactly that strict mode violation. Green: it passes with the change, and replace.spec.ts passes too.

Flaky "a disk that is not mounted pauses the scheduled sync"

The dashboard keeps the status in localStorage (__root.tsx, written with a 1 s throttle), and the default staleTime is 10 s. If the first visit's status was saved before the test moved on to /schedules, the last visit to / reused that 4 s old "Disk not available" status. It sent no status request (the trace shows only one), so "All good" never appeared. Under load the gap is more than 1 s. The disk comes back without the app knowing, so the test now presses Refresh, as a user would. There are no added timeouts or retries.

  • Red: under CPU load the test failed 5 of 10 runs on master. Waiting 1.5 s after the first health check makes it fail 3 of 3. Green: it passes 3 of 3 with the same wait, and 20 of 20 under the same load.

test:image / scripts/image-test.sh: nothing to fix

The script has been at e2e/scripts/image-test.sh since #26 and was never missing. e2e/package.json runs from e2e/, so bash scripts/image-test.sh resolves to it. E2E_IMAGE=snapraid-ui:e2e bun run test:image --list lists all 34 tests. CI builds the image itself and runs bun run test with E2E_IMAGE set.

Checks

  • bun install --frozen-lockfile
  • server: bun test gives 234 pass and 2 skip, tsc is clean
  • web: biome check, typecheck, 60 vitest tests and the build all pass
  • e2e: typecheck passes. The full local target gives 32 passed and 2 skipped. The full binary target gives 33 passed and 1 skipped (docker).
  • The two fixed tests with --repeat-each=10 (default workers, which is 1 in the config) pass 20 of 20 on both the local and the binary target, with and without CPU load.

Generated by Claude Code

…not there yet

Without ./snapraid, loadAppConfig logs "Failed to save default config: ENOENT" and the
defaults are not saved: the directory is made only later, by the log manager.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y3rdfbWb1xDUdPRng7TX9Z
On the first start without login nothing had made SNAPRAID_BASE_PATH yet when loadAppConfig
saved the defaults (only loadSessionSecret and the log manager mkdir it), so the save failed
with ENOENT and config.json appeared only on the next start. saveAppConfig now makes the
directory with mkdir's default mode, as the log manager does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y3rdfbWb1xDUdPRng7TX9Z
expectFinished matched any "<label>" finished successfully. Each job gets its own toast and
they stay for 5 s (Feedback.tsx), so when the second restore of "deleted and encrypted files
are restored" finished within 5 s of the first, the locator found both toasts: strict mode
violation. The UI is right to keep both, one result per job; expectFinished now closes the
toast it waited for, so the next call of the same command finds only its own. Reproduced
with the toast duration raised to 20 s: fails on master, passes with this change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y3rdfbWb1xDUdPRng7TX9Z
The dashboard keeps the last status in localStorage (__root.tsx, persisted with a 1 s
throttle) and the default staleTime is 10 s, so opening it again within 10 s shows the kept
status without asking SnapRAID. When the first visit's status got persisted before the test
went on to /schedules (more than 1 s between them, as under load), the last visit showed
"Disk not available" from 4 s earlier and never sent a status request: "All good" timed
out. The disk is put back behind the app's back, so the test refreshes the status, as a
user would. Reproduced by waiting 1.5 s after the first health check: fails 3/3 on master,
passes with this change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y3rdfbWb1xDUdPRng7TX9Z

Copy link
Copy Markdown
Owner Author

TDD-Review: keine belegten Findings

Jeder Verdacht wurde mit einem Test geprüft; keiner wurde rot, deshalb gibt es keine Fixes.

Nicht belegt (Tests grün):

  • saveAppConfig (apps/server/src/config-parser.ts:178), mit loadAppConfig in einem eigenen Prozess (Prüf-Test in bun:test, nicht committet):
    • SNAPRAID_BASE_PATH unter einer regulären Datei (ENOTDIR): kein Absturz, Exit 0, die Defaults werden zurückgegeben, Failed to save default config wird geloggt.
    • Ein bestehender Ordner mit Modus 0700 behält 0700.
    • Der Basispfad ist ein Symlink auf einen Ordner: config.json landet im Ziel.
    • Ein hängender Symlink: geloggt, kein Absturz (vorher genauso mit ENOENT).
    • Verschachtelte, fehlende Elternordner bekommen 0777 & ~umask, wie der Log-Ordner und auth.ts.
    • Owner: Der Ordner gehört dem Prozess-User, wie bei den übrigen mkdir-Stellen. Vorher wurde gar kein Ordner angelegt, das ist also keine Regression.
  • expectFinished (e2e/harness/fixtures.ts:51): Eine Fehler- oder Abbruch-Meldung passt nicht auf den Filter, der Aufruf läuft also weiterhin in den Timeout und verdeckt nichts. toHaveCount(0) stellt sicher, dass der nächste Aufruf nur noch den Toast des neuen Jobs findet. Alle 8 Specs, die expectFinished nutzen, laufen lokal und mit dem Binary grün (22 bestanden, docker übersprungen), darunter changes.spec, wo zwei Restores hintereinander laufen.
  • Refresh in schedules.spec.ts:128: Das Pausieren (skipped/disk_missing, die Anzeige „d1 missing or empty“) wird vor dem Remount geprüft und bleibt unberührt. Refresh ruft dieselbe Status-Abfrage auf (refetch), ohne Sonderpfad. Gegenprobe: Ohne remount('d1') wird der Test rot (expectHealth(page, 'All good'): toBeVisible failed). Die Prüfung greift also weiterhin.

Checks: Server bun test (234 bestanden, 2 übersprungen), tsc für Server und e2e, die betroffenen e2e-Specs lokal und mit dem Binary. CI auf 2977d28 ist grün. Die Basis ist aktuell (master ist Vorfahre von fixes).


Generated by Claude Code

Copy link
Copy Markdown
Owner Author

TDD-Review abgeschlossen: keine belegten Findings (Details im vorigen Kommentar). CI grün: backend, frontend, install, e2e local/binary/image je 2/2.

Merge per Squash.


Generated by Claude Code

@firsttris
firsttris merged commit 713bfe0 into master Nov 4, 2026
9 checks passed
@firsttris
firsttris deleted the fixes branch November 4, 2026 05:08
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