test(frontend): add browser tests, starting with the export menu - #365
Merged
Conversation
Implements #339. CI ran one check on static/js -- a syntax parse -- so any behavioural regression shipped unnoticed until a user hit it. #335 is the case in point: "Export All Stems" became permanently unclickable after a single export, for every track, until the app restarted. It shipped in alpha 15 and a user found it. Setup is Playwright against the real backend. tests/e2e/serve.sh seeds a throwaway jobs directory with one finished track and execs uvicorn against it, with every data path redirected, so a run cannot read or touch a developer's library. Only the separation pipeline is skipped; the endpoints, the registry and the Range requests for stems are real. Two details in the fixtures are load-bearing, both learned by getting them wrong first: - The sidebar renders from the library store, not /api/jobs. A job on disk but absent from the store is invisible in the UI, and a test that clicks nothing passes for the wrong reason. - stubTauri installs a controllable window.__TAURI__ so the desktop code path runs. This is the point of the exercise: #335 was invisible in a browser, because there the synthetic <a>.click() closes the chip panel before the busy state is applied and the bug hides. The stub also leaves save_audio_file pending until the test settles it, so the busy state machine is driven rather than raced. Nine tests cover all four defects from #335 and #337: rows re-enabled after an export in both host modes, a second export still working, the busy state waiting on the save rather than a timer, failures surfacing and recovering, and export errors not offering a "Try again" that sends the user to the URL import field. Verified by reintroducing each defect and watching the suite fail: clearing only the visible rows on reset fails 3 tests (the panel is closed by then, so a visibility-filtered clear clears nothing), the fixed-timer reset fails 1, and the retry button fails 1. MP4 format switching is only partly covered. The video format is hidden unless the track has one, and a video fixture is its own piece of work, so what is here pins that MP4 is not offered for audio-only tracks. Beat grid and transport coverage remain open on #339. Closes #339
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #339.
CI ran exactly one check on
static/js: a syntax parse. This adds browser tests that drive the real UI against the real backend, starting with the area that has already cost the most.Setup
tests/e2e/serve.shseeds a throwaway jobs directory with one finished track and execs uvicorn against it, with every data path (JOBS_DIR,DATA_DIR, cache, logs, models, downloads) redirected into it. A run cannot read or touch a developer's real library. Only the separation pipeline is skipped: the endpoints, the registry, and the Range requests for stems are real.Two fixture details are load-bearing, and I got both wrong first:
/api/jobs. A job that exists on disk but is absent from the store is invisible in the UI, so a test that clicks nothing passes for the wrong reason.stubTauriinstalls a controllablewindow.__TAURI__so the desktop code path actually runs. This is the whole point: [Bug]: Unable to export stems again after exporting stems without restarting the program #335 was invisible in a browser, because there the synthetic<a>.click()closes the chip panel before the busy state is applied and the bug hides. The stub also leavessave_audio_filepending until the test settles it, so the busy state machine is driven rather than raced.Coverage
Nine tests, all four defects from #335 and #337:
Do these tests actually catch anything?
Verified by reintroducing each defect and watching the suite fail.
The first one is sharper than the issue describes:
flashBusycloses the panel, so by reset time every row hasoffsetParent === nulland a visibility-filtered clear clears nothing. That is why the row stayed disabled for the rest of the session.Runtime is 11s locally, 9 tests, one worker.
Deferred, still open on #339
Notes
package.json;@playwright/testis the only dependency and it is dev-only. The app itself still has no build step and no runtime dependencies.frontend-e2eCI job, with the Playwright report uploaded on failure.tests/test_stems_api.py::test_all_stems_zip_oggfails identically on cleanmain(local ffmpeg has nolibvorbis; the skip guard only checks that ffmpeg exists). Unrelated, untouched. 539 passed otherwise.