Spaces:
Running
Running
| # Manual Testing β Marionette | |
| Step-by-step procedure for manually testing every user-facing feature. | |
| Run through this checklist after significant changes, on each platform | |
| (Linux, macOS, Windows), and on each browser (Chrome, Firefox, Safari). | |
| **Prerequisites:** | |
| - Reachy Mini robot powered on and connected (Wireless or Lite) | |
| - App deployed and running on the robot (see below) | |
| - Browser open at `http://reachy-mini.local:8042` | |
| - A short WAV or MP3 file ready for upload tests (~2-5s) | |
| - Hugging Face CLI logged in (`huggingface-cli login`) for HF tests | |
| **Starting the app (Wireless):** | |
| The fastest way to deploy and start marionette on a Wireless robot: | |
| ```bash | |
| cd marionette | |
| ./deploy_wireless.sh | |
| ``` | |
| This syncs your local code to the robot, starts the app via the daemon, | |
| and streams logs to your terminal. See the script header for prerequisites | |
| (SSH key setup, daemon status). Pass an IP if mDNS doesn't resolve: | |
| `./deploy_wireless.sh 192.168.1.42` | |
| To stop the app: `./stop_app.sh` (or use the dashboard). | |
| **Starting the app (Lite or local dev):** | |
| ```bash | |
| cd marionette && python -m marionette | |
| ``` | |
| --- | |
| ## 1. Startup & Page Load | |
| | # | Step | Expected result | | |
| |---|------|-----------------| | |
| | 1.1 | Start the app with robot connected | Robot plays intro audio, head moves to init pose then sleep pose, antennas splay at 15 deg, motors disable. Terminal shows no errors. | | |
| | 1.2 | Open the web UI during startup | Mode pill shows **STARTING_UP**, status shows "Starting up...". All buttons are disabled. | | |
| | 1.3 | Wait for startup to complete | Mode pill changes to **IDLE**, status shows "Ready to capture moves". Record button enables. | | |
| | 1.4 | Check initial form state | Duration field is pre-filled (default 5.0s). Name field is empty (or restored from last session). Dataset dropdown is populated. Moves list shows existing moves or "No moves recorded yet." | | |
| | 1.5 | Check mode pill during idle | Shows **IDLE** in the header, no buttons say "Stop". | | |
| --- | |
| ## 2. Recording β Silent Mode | |
| | # | Step | Expected result | | |
| |---|------|-----------------| | |
| | 2.1 | Expand **Options**, select **Silent** radio | Upload area stays hidden. Audio hint clears. | | |
| | 2.2 | Type a name (e.g. `test-silent`), set duration to **3**, click **Record** | Button briefly says "Queuing...", mode pill changes to **QUEUED**. | | |
| | 2.3 | Watch the countdown | Mode changes to **COUNTDOWN**. Large blue countdown shows 3, 2, 1. Progress bar fills. "Get ready" label visible. Stop Recording button appears. | | |
| | 2.4 | Watch the recording phase | Mode changes to **RECORDING**. Display turns red, shows remaining seconds. Progress bar counts down for 3s. | | |
| | 2.5 | Wait for recording to finish | Mode returns to **IDLE**. Status shows "Recorded test-silent - N poses (X.X/s)". Recording stats hint shows frame count. | | |
| | 2.6 | Check the moves list | New move `test-silent` appears at top. Shows "3.0s", silent icon, creation timestamp. Play and Delete buttons visible. | | |
| | 2.7 | Verify files on disk | `<dataset-dir>/test-silent.json` exists. No `.wav` file. JSON has `time`, `set_target_data` arrays with ~300 frames. | | |
| --- | |
| ## 3. Recording β Mic Audio | |
| | # | Step | Expected result | | |
| |---|------|-----------------| | |
| | 3.1 | Expand **Options**, select **Mic** radio | Audio hint shows "Live audio captured via robot's microphone." (If mic unavailable: hint says so, radio is disabled.) | | |
| | 3.2 | Set duration to **2**, click **Record** | Countdown starts (3s), then recording starts (2s). | | |
| | 3.3 | Speak or make noise during recording | Recording completes normally. | | |
| | 3.4 | Check the moves list | New move shows microphone icon. | | |
| | 3.5 | Verify files on disk | Both `.json` and `.wav` exist. WAV duration is ~2s. | | |
| --- | |
| ## 4. Recording β Uploaded Audio | |
| | # | Step | Expected result | | |
| |---|------|-----------------| | |
| | 4.1 | Expand **Options**, select **Upload** radio | Upload area appears with "Choose file..." button. | | |
| | 4.2 | Click **Choose file...** and select a WAV | Upload status shows "Uploading...", then "Uploaded: filename.wav (X.Xs). Adjust duration if needed." Duration field auto-fills with audio length. | | |
| | 4.3 | Click **Record** | Countdown starts. When recording starts, the uploaded audio plays through robot's speaker. You can move the robot in sync with the audio. | | |
| | 4.4 | Wait for recording to finish | Move saved. `.wav` file is a copy of the uploaded audio (not mic recording). | | |
| | 4.5 | **Drag-and-drop test**: drag a WAV onto the upload area | Upload area highlights with border. File uploads on drop. | | |
| | 4.6 | **Drag non-audio file** (e.g. .txt) | Status shows "Please drop a WAV or MP3 file." No upload happens. | | |
| | 4.7 | **MP3 upload**: select an MP3 file | Status shows "Uploading and converting MP3 to WAV..." Conversion completes. Duration field updates. | | |
| | 4.8 | Switch audio source away from Upload, then back | Uploaded file reference is cleared. Must re-upload. | | |
| | 4.9 | Try to Record with Upload selected but no file uploaded | Status shows "Please upload an audio file first." No recording starts. | | |
| --- | |
| ## 5. Stop Recording | |
| | # | Step | Expected result | | |
| |---|------|-----------------| | |
| | 5.1 | Start a 10s recording, click **Stop Recording** during countdown | Recording is cancelled immediately. Status: "Recording cancelled". No move saved. | | |
| | 5.2 | Start a 10s recording, wait for recording phase, click **Stop Recording** after ~2s | Recording stops early. Move is saved with ~2s of data. Status: "Saved ... (stopped early) - N poses". | | |
| | 5.3 | Verify partial recording on disk | JSON file exists with ~200 frames (not 1000). | | |
| --- | |
| ## 6. Playback | |
| | # | Step | Expected result | | |
| |---|------|-----------------| | |
| | 6.1 | Click **Play** on a silent move | Mode pill shows **PLAYING**. Robot enables motors, moves to start pose, replays the motion, returns to init pose, disables motors. Mode returns to **IDLE**. | | |
| | 6.2 | Click **Play** on a move with audio | Same as above, plus audio plays through robot's speaker in sync with motion. | | |
| | 6.3 | During playback, verify UI state | Record button disabled. All Play/Delete buttons disabled. Dataset selector disabled. Stop Playback button visible. | | |
| | 6.4 | After playback completes | Status: "Finished playing ...". Stop Playback button hides. All controls re-enable. | | |
| --- | |
| ## 7. Stop Playback | |
| | # | Step | Expected result | | |
| |---|------|-----------------| | |
| | 7.1 | Start playback on a 5s+ move, click **Stop Playback** mid-stream | Playback stops immediately. Robot stops moving. Audio stops. Status: "Playback stopped for ...". Mode returns to **IDLE**. | | |
| | 7.2 | Click **Stop Playback** again when already idle | Nothing happens (button should be hidden). | | |
| --- | |
| ## 8. Delete a Move | |
| | # | Step | Expected result | | |
| |---|------|-----------------| | |
| | 8.1 | Click **Delete** on a move | Browser confirm dialog: "Delete move 'move-id'? This cannot be undone." | | |
| | 8.2 | Click **Cancel** in dialog | Move stays in list. No files deleted. | | |
| | 8.3 | Click **OK** in dialog | Move disappears from list. JSON and WAV files are deleted from disk. | | |
| --- | |
| ## 9. Dataset Management | |
| | # | Step | Expected result | | |
| |---|------|-----------------| | |
| | 9.1 | Click **+ New** next to dataset dropdown | Inline form appears. "+ New" button hides. | | |
| | 9.2 | Type a name with spaces/caps (e.g. `My Dataset`) | Input auto-transforms to `my_dataset` (lowercase, spaces to underscores). | | |
| | 9.3 | Click **Create** | Dataset created. Dropdown now includes `my_dataset`. Moves list is empty (new dataset). | | |
| | 9.4 | Click **Cancel** (or press Escape) without typing | Form hides. "+ New" button reappears. No dataset created. | | |
| | 9.5 | Try to create a dataset with the same name | Error shown: "Dataset name already used." | | |
| | 9.6 | Switch dataset in dropdown | Active dataset changes. Moves list updates to show that dataset's moves. Path hint updates. | | |
| | 9.7 | Switch to a downloaded dataset | Record button disables with tooltip "Switch to a local dataset to record". Play still works. | | |
| --- | |
| ## 10. Hugging Face Upload | |
| | # | Step | Expected result | | |
| |---|------|-----------------| | |
| | 10.1 | If HF CLI logged in: check username field | Auto-filled with detected username, read-only, green tint, label says "Logged in as". | | |
| | 10.2 | If not logged in: type a username | Field is editable. Value persists after page reload (localStorage). | | |
| | 10.3 | Select one or more move checkboxes | Sync button enables (if username present). | | |
| | 10.4 | Click **Upload selected** | Button says "Synchronizing...". Status shows "Uploading selected moves...". | | |
| | 10.5 | Wait for upload to complete | Status shows "N moves synced to user/dataset." with clickable link. | | |
| | 10.6 | Check uploaded moves | Green "UPLOADED" badge appears on synced moves. | | |
| | 10.7 | Clear username and try to upload | Sync button is disabled. Hint: "Enter your Hugging Face username." | | |
| | 10.8 | Select no moves | Sync button disabled. Hint: "Select at least one move to upload." | | |
| --- | |
| ## 11. Community Datasets | |
| | # | Step | Expected result | | |
| |---|------|-----------------| | |
| | 11.1 | Expand **Community** section | "Fetch community datasets" button visible. | | |
| | 11.2 | Click **Fetch community datasets** | Status: "Searching Hugging Face...". After loading, list of community datasets appears with names, authors, likes, tags. | | |
| | 11.3 | Select one or more datasets, click **Download selected** | Status: "Downloading...". After completion, new datasets appear in dropdown with "down-arrow" prefix. | | |
| | 11.4 | Switch to downloaded dataset | Moves list shows downloaded moves. Record is disabled (read-only). Play works. | | |
| | 11.5 | Try to download the same dataset again | Error: "Dataset '...' already exists locally." | | |
| --- | |
| ## 12. Settings | |
| | # | Step | Expected result | | |
| |---|------|-----------------| | |
| | 12.1 | Expand **Settings** section | "Datasets folder" input with current path shown. | | |
| | 12.2 | Change the path and click **Update** | Button says "Updating...". Path changes. All datasets are remapped to new root. | | |
| | 12.3 | Enter a non-existent path | Path is created automatically. Datasets folder now lives there. | | |
| | 12.4 | Expand **Experimental** section | "Enable motion compensation models" checkbox visible. | | |
| | 12.5 | Toggle motion models on | Model selector appears below. | | |
| | 12.6 | Select a model, play a move | Playback uses filtered trajectory (visual difference may be subtle). | | |
| | 12.7 | Toggle motion models off | Model selector hides. | | |
| --- | |
| ## 13. Edge Cases & Stress Tests | |
| | # | Step | Expected result | | |
| |---|------|-----------------| | |
| | 13.1 | **Empty name**: leave Name blank, record | Auto-generated name `take-YYYYMMDD-HHMMSS` used. | | |
| | 13.2 | **Long name**: type 80 characters, record | Accepted. Truncated to 80 chars. | | |
| | 13.3 | **Special characters**: name with `@#$! spaces` | Slugified (lowercase, special chars removed, spaces to dashes). | | |
| | 13.4 | **Min duration**: set duration to `0.5`, record | Rejected (must be > 0.5, not >= 0.5). Try `0.6` β accepted. | | |
| | 13.5 | **Max duration**: set duration to `300`, record | Accepted. (Don't wait 5 min β stop it early to verify.) | | |
| | 13.6 | **Close browser tab mid-recording** | Recording continues server-side. Reopen tab: move appears in list when done. | | |
| | 13.7 | **Two browser tabs** | Open same URL in two tabs. Record from tab 1 β tab 2 shows mode changes on next poll. Try to record from tab 2 while tab 1 is recording β rejected ("Robot is busy"). | | |
| | 13.8 | **Rapid record/play cycles** | Record 1.5s, play it, record again, play again. Repeat 5 times. Robot should stay responsive, no stuck states. | | |
| | 13.9 | **Delete a file externally** | While app is running, delete a `.json` file from the dataset folder. Click Refresh. Move disappears from list. No crash. | | |
| | 13.10 | **Replace a .wav file** | Copy a different WAV file over an existing move's `.wav`. Click Refresh. Play the move β new audio plays. | | |
| | 13.11 | **Server unavailable** | Stop the app (`./stop_app.sh`). UI shows "Unable to reach backend." Restart (`./deploy_wireless.sh`) β UI recovers on next poll. | | |
| | 13.12 | **No robot connected** | Start app without robot (`python -m marionette`). App may fail to start or show error in terminal. UI should not hang. | | |
| --- | |
| ## 14. Cross-Browser Checks | |
| Test these on each browser (Chrome, Firefox, Safari/WebKit): | |
| | # | Check | Notes | | |
| |---|-------|-------| | |
| | 14.1 | Page loads, all sections render | CSS layout, fonts, spacing | | |
| | 14.2 | Form validation works | Duration min/max, pattern validation on dataset name | | |
| | 14.3 | Progress bar animates smoothly | requestAnimationFrame timing | | |
| | 14.4 | Drag-and-drop works | Audio upload area | | |
| | 14.5 | localStorage persistence | Name and HF username survive reload | | |
| | 14.6 | confirm() dialog works | Delete move | | |
| | 14.7 | Details/summary elements toggle | Options, Community, Settings | | |
| --- | |
| ## 15. Mobile / Responsive | |
| | # | Step | Expected result | | |
| |---|------|-----------------| | |
| | 15.1 | Open UI on a phone or narrow window (<720px) | Form fields stack vertically. Record button is full-width. | | |
| | 15.2 | Record form works on touch | Can tap Record, tap Stop. Duration input works with on-screen keyboard. | | |
| | 15.3 | Move list is scrollable | Long list doesn't break layout. | | |
| | 15.4 | All collapsible sections work | Tap to expand/collapse Options, Community, Settings. | | |
| --- | |
| ## Test Matrix | |
| Track results in this grid. Mark each cell with PASS, FAIL, or SKIP: | |
| ``` | |
| β Chrome β Firefox β Safari β Mobile | |
| βββββββββββββββββββΌβββββββββΌββββββββββΌβββββββββΌβββββββ | |
| Startup (1.x) β β β β | |
| Silent record (2) β β β β | |
| Mic record (3) β β β β | |
| Upload record (4) β β β β | |
| Stop record (5) β β β β | |
| Playback (6) β β β β | |
| Stop playback (7) β β β β | |
| Delete move (8) β β β β | |
| Datasets (9) β β β β | |
| HF upload (10) β β β β | |
| Community (11) β β β β | |
| Settings (12) β β β β | |
| Edge cases (13) β β β β | |
| Responsive (15) β β β β | |
| ``` | |
| --- | |
| ## What Automated Tests Already Cover | |
| Before doing a full manual pass, you can run the automated suites to catch | |
| regressions quickly: | |
| ```bash | |
| cd marionette | |
| # Unit tests (no robot needed, ~4s) | |
| pytest tests/test_api.py -q | |
| # E2E browser tests (no robot needed, ~90s) | |
| pytest tests/e2e --browser chromium --browser firefox | |
| # Hardware tests (robot required) | |
| pytest tests/test_hardware.py -m hardware | |
| # Everything at once (no robot) | |
| pytest tests/ --browser chromium | |
| ``` | |
| Current coverage: 95 unit + 44 E2E + 37 hardware = 176 automated tests. | |
| The manual testing procedure above focuses on **what automated tests cannot | |
| cover**: subjective UX quality, audio sync perception, motor smoothness, | |
| visual layout, and cross-browser rendering. Automated tests handle API | |
| validation, state machine transitions, and form logic. | |