overdub
FirmwareM-VAVE FM-1

fm1-playwright

DimmKirr/fm1-playwright · ★ 0

Playwright test harness for fm1-emu: rotates encoders, presses buttons, plays notes, captures screenshots and records GIFs of firmware UIs.

README from GitHub, MIT

fm1-playwright

Playwright test harness for FM-1 emulator firmware UI testing. Rotate encoders, press buttons, play notes, capture screenshots, and record GIFs.

Playing notes on the FM-1 emulator

Scrolling presets

More demo artifacts
ArtifactLink
Happy Birthday (MP3)felucca-happy-birthday.mp3
Happy Birthday (MP4)felucca-happy-birthday.mp4
Happy Birthday (GIF)felucca-happy-birthday.gif
Full demo (MP4)felucca-demo.mp4
Full demo (GIF)felucca-demo.gif
Home screenshotfelucca-home.png
Final screenshotfelucca-final.png

All artifacts are auto-generated by CI on every push to main.

Install

pip install fm1-playwright
playwright install chromium

System dependencies

Some features require system packages. Install them via your package manager or use the provided flake.nix:

nix develop  # provides all dependencies below
PackageRequired forWithout it
ChromiumEverything (Playwright browser)Nothing works
ffmpegGIF recording, video recording, MP4/MP3 conversion, video+audio muxingScreenshots and raw audio capture still work
PulseAudioAudio recording in headed mode (WebAudio routing)Audio capture may fail without an audio server
XvfbHeaded mode in CI (virtual display)Use FM1_HEADLESS=1 instead

Quick start

Subclass FirmwareUITest and write tests:

from fm1_playwright import FirmwareUITest
from fm1_playwright.testing import BOOT_PATTERN

class MyFirmwareTest(FirmwareUITest):
    def test_boot(self):
        self._get_page()
        self._screenshot('home')
        status = self._get_page().text_content('#status')
        self.assertIn(BOOT_PATTERN, status)

    def test_change_preset(self):
        self.rotate_encoder('k2', direction=1, steps=1, delay_ms=800)
        self._screenshot('preset-next')

Run with:

FM1_WEB_DIR=$HOME/.fm1-emulator/web \
FIRMWARE_NAME=felucca \
python3 -m unittest my_tests -v

GitHub Actions

Use with setup-fm1-emulator to run in CI:

jobs:
  test:
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-python@v7
        with:
          python-version: '3.12'
      - uses: dimmkirr/setup-fm1-emulator@v1
      - run: pip install fm1-playwright
      - env:
          FM1_WEB_DIR: ${{ steps.emu.outputs.web-path }}
          FIRMWARE_NAME: felucca
          FIRMWARE_URL: https://thefirmwarehub.com/fw/felucca-1.6.1.fwsc
        run: python3 -m unittest tests.test_firmware -v

API

Emulator control

MethodDescription
rotate_encoder(name, direction, steps, delay_ms)Rotate an encoder (select, k1, k2, presets, algorithm, master, knob1-4)
press_button(name, delay_ms)Press a button (home, scl, env, lfo, edit, fx, etc.)
play_note(note, hold_ms, delay_ms)Play a note (C4..F5)
hold_button(name)Context manager: hold a button while performing other actions

Capture

MethodDescription
_screenshot(name)Save a PNG of the device canvas or LCD screen
record_gif(name, fps)Context manager: record frames into an animated GIF
record_video(name, fps)Context manager: record frames into a webm video

Audio recording

Record audio output from the emulator's Web Audio API:

from fm1_playwright.recording import (
    audio_patch, start_audio_recording, stop_audio_recording,
    mux_video_audio, webm_to_mp3,
)

# audio_patch must wrap page creation and navigation
with audio_patch(web_dir):
    # ... create page, navigate, boot ...
    start_audio_recording(page)
    # ... play notes, record video frames ...
    stop_audio_recording(page, 'audio.webm')

# Combine video + audio into a single MP4
mux_video_audio('video.webm', 'audio.webm', 'output.mp4')

# Or convert audio to MP3
webm_to_mp3('audio.webm', 'output.mp3')

View modes

Set FM1_VIEW to control screenshot capture:

ValueCapturesSize
DEVICE (default)Full device canvas (panel + buttons + keys)Variable
SCREENLCD screen only240x240

Environment variables

VariableDescriptionDefault
FM1_WEB_DIRPath to fm1-emu WASM directoryrequired
FIRMWARE_NAMEFirmware name for URL and filenamesrequired
FIRMWARE_URLURL to a .fwsc firmware fileoptional
RESULTS_DIROutput directory for screenshots/GIFsresults
FM1_VIEWDEVICE or SCREENDEVICE
FM1_SCALELCD pixel scaling (1-4)2
FM1_HEADLESS1 for headless, 0 for headed1
CHROMIUM_PATHCustom Chromium binary pathauto-detected

Examples

See examples/ for a full E2E test suite with screenshots and GIF recording.

Credits

Built on fm1-emu by Joakim Eriksson.

License

MIT