Skip to content
This repository was archived by the owner on Apr 7, 2026. It is now read-only.
This repository was archived by the owner on Apr 7, 2026. It is now read-only.

[EPIC] Multi-threaded WASM UX Testing Support #14

Description

@noahgift

Problem Statement

Probar currently CANNOT properly test multi-threaded WASM applications like whisper.apr's real-time streaming transcription. This is a critical gap for any serious WASM testing framework.

What We Can't Test Today

  1. Web Worker lifecycle - Worker creation, message passing, termination
  2. SharedArrayBuffer operations - Atomic operations, memory sharing between threads
  3. Audio/Media streaming - Real-time audio processing with VAD state machines
  4. COOP/COEP header validation - Required for SharedArrayBuffer
  5. Thread synchronization UX - Visual feedback during multi-threaded operations
  6. State machine transitions - VAD states (Silence → Speech → Transcribing)

Related Issues

Required Features

1. WorkerEmulator

Test Web Worker creation and messaging without JavaScript:

pub struct WorkerEmulator {
    workers: HashMap<String, WorkerState>,
}

pub enum WorkerState {
    Created,
    Running,
    Terminated,
    Error(String),
}

pub struct WorkerMessage {
    pub data: Vec<u8>,
    pub timestamp: u64,
}

impl WorkerEmulator {
    /// Detect all workers created by the page
    pub async fn detect_workers(page: &Page) -> ProbarResult<Vec<WorkerInfo>>;
    
    /// Wait for worker to be ready
    pub async fn wait_for_worker(page: &Page, timeout_ms: u32) -> ProbarResult<()>;
    
    /// Inject message into worker (for testing)
    pub async fn post_message(page: &Page, worker_id: &str, data: &[u8]) -> ProbarResult<()>;
    
    /// Capture messages from worker
    pub async fn capture_messages(page: &Page, worker_id: &str) -> ProbarResult<Vec<WorkerMessage>>;
    
    /// Assert worker is running
    pub fn assert_worker_running(&self, worker_id: &str) -> ProbarResult<()>;
}

2. ThreadSyncAssertions

Assert on multi-threaded state synchronization:

pub struct ThreadSyncAssertions {
    main_thread_state: HashMap<String, String>,
    worker_thread_state: HashMap<String, String>,
}

impl ThreadSyncAssertions {
    /// Assert main thread and worker are synchronized
    pub async fn assert_synchronized(
        page: &Page,
        main_selector: &str,
        worker_id: &str,
        timeout_ms: u32,
    ) -> ProbarResult<()>;
    
    /// Assert state machine transition occurred
    pub async fn assert_state_transition(
        page: &Page,
        from_state: &str,
        to_state: &str,
        timeout_ms: u32,
    ) -> ProbarResult<()>;
    
    /// Assert atomic operation completed
    pub async fn assert_atomic_complete(
        page: &Page,
        operation_id: &str,
    ) -> ProbarResult<()>;
}

3. StreamingUxValidator

Validate real-time streaming UX elements:

pub struct StreamingUxValidator {
    expected_states: Vec<String>,
    observed_states: Vec<(String, u64)>, // (state, timestamp)
}

impl StreamingUxValidator {
    /// Track state indicator element
    pub async fn track_state_indicator(page: &Page, selector: &str) -> ProbarResult<Self>;
    
    /// Assert state sequence occurred
    pub fn assert_state_sequence(&self, expected: &[&str]) -> ProbarResult<()>;
    
    /// Assert VU meter is responding (level changes)
    pub async fn assert_vu_meter_active(
        page: &Page,
        selector: &str,
        min_change: f32,
        timeout_ms: u32,
    ) -> ProbarResult<()>;
    
    /// Assert progress bar advances
    pub async fn assert_progress_advancing(
        page: &Page,
        selector: &str,
        timeout_ms: u32,
    ) -> ProbarResult<()>;
    
    /// Assert latency is within bounds
    pub fn assert_latency(&self, max_latency_ms: u32) -> ProbarResult<()>;
}

4. WasmThreadCapabilities

Detect and validate WASM threading support:

pub struct WasmThreadCapabilities {
    pub shared_array_buffer: bool,
    pub atomics: bool,
    pub bulk_memory: bool,
    pub threads: bool,
    pub simd: bool,
    pub coop_header: Option<String>,
    pub coep_header: Option<String>,
}

impl WasmThreadCapabilities {
    /// Detect all threading capabilities
    pub async fn detect(page: &Page) -> ProbarResult<Self>;
    
    /// Assert streaming requirements met
    pub fn assert_streaming_ready(&self) -> ProbarResult<()> {
        if !self.shared_array_buffer {
            return Err(ProbarError::Capability(
                "SharedArrayBuffer unavailable. Server must send COOP/COEP headers."
            ));
        }
        if !self.atomics {
            return Err(ProbarError::Capability("Atomics unavailable"));
        }
        Ok(())
    }
    
    /// Assert headers are correct
    pub fn assert_isolation_headers(&self) -> ProbarResult<()>;
}

Example Test (What We Want to Write)

#[probar::test]
async fn test_streaming_transcription_ux(ctx: &mut TestContext) -> ProbarResult<()> {
    let page = ctx.new_page().await?;
    
    // Verify threading capabilities
    let caps = WasmThreadCapabilities::detect(&page).await?;
    caps.assert_streaming_ready()?;
    
    // Inject speech-like audio
    let audio = AudioEmulator::new(16000, 1);
    audio.inject(&page, AudioSource::SpeechPattern {
        pattern: vec![
            (0.0, 500),   // 500ms silence
            (0.8, 2000),  // 2s speech
            (0.0, 500),   // 500ms silence (triggers endpoint)
        ],
    }).await?;
    
    // Start recording
    page.click("#start_recording").await?;
    
    // Track state transitions
    let validator = StreamingUxValidator::track_state_indicator(&page, "#state_label").await?;
    
    // Wait for worker to process audio
    let worker = WorkerEmulator::wait_for_worker(&page, 5000).await?;
    
    // Assert UX elements respond
    validator.assert_vu_meter_active(&page, "#vu_meter", 0.1, 3000).await?;
    validator.assert_progress_advancing(&page, "#chunk_progress", 5000).await?;
    
    // Assert state machine transitions
    validator.assert_state_sequence(&[
        "Listening",      // Initial
        "Recording",      // Speech detected
        "Transcribing",   // Endpoint detected, processing
    ])?;
    
    // Assert transcription appears
    page.wait_for_text("#transcript", ".*", 10000).await?;
    
    // Assert latency is acceptable (< 500ms from speech end to transcription)
    validator.assert_latency(500)?;
    
    Ok(())
}

Why This Matters

Without these features, testing multi-threaded WASM apps requires:

  • Ad-hoc JavaScript injection (violates "ABSOLUTE ZERO JS" principle)
  • Manual browser testing (not reproducible)
  • Hope and prayer (not engineering)

Real-time streaming apps like whisper.apr, video conferencing, games with workers, etc. are untestable with current probar.

Acceptance Criteria

  • WorkerEmulator can detect and monitor Web Workers
  • ThreadSyncAssertions can validate state synchronization
  • StreamingUxValidator can track real-time UX elements
  • WasmThreadCapabilities can verify COOP/COEP headers
  • AudioEmulator can inject controlled audio (Issue Add AudioEmulator for microphone/getUserMedia testing #12)
  • Example test passes on whisper.apr demo
  • Documentation in mdBook
  • 95% test coverage on all new modules

Priority

P0 - BLOCKING for any serious WASM application testing

Toyota Way

  • Jidoka: Fail fast when threading requirements not met
  • Poka-Yoke: Type-safe state machine assertions prevent silent failures
  • Genchi Genbutsu: Actually test in real browser with real workers
  • Muda: Eliminate manual testing waste

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions