feat(testmu): hosted Chrome and Edge for the web engine with testmuBrowsers()

Merged
AM
6d ago
+630-18

What and why

  • testmuBrowsers() from @e2e-dev/testmu/web: a BrowserProvider that runs web targets in TestMu AI (formerly LambdaTest) hosted Chrome and Edge over CDP (wss://cdp.lambdatest.com/puppeteer). Each worker slot gets one session.
  • One package per service: it ships in @e2e-dev/testmu next to testmu(). @e2e-dev/mobile and @e2e-dev/web are optional peers. The root entry never imports @e2e-dev/web, and ./web never imports @e2e-dev/mobile or agent-device, so a project with one engine loads and type-checks the entry it uses, with skipLibCheck: false too. packages/testmu/tests/unit/entries.test.ts pins it.
  • Session names (e2e-<run id>-<target>-<slot>) and the e2e project default come from packages/testmu/src/dashboard.ts, shared with testmu(), so a run's device and browser sessions sit in one build and can't drift.
  • Options are browserName (Chrome by default, or MicrosoftEdge) and capabilities. browserVersion is sent next to browserName; every other key goes into LT:Options. user, accessKey and name are reserved. A nested LT:Options, a browserName inside capabilities, a non-array browserOptions, or a value JSON can't carry fails at config load.
  • Defaults: platform: 'Windows 11' (the hub refuses a session without one), project: 'e2e', build: <run id>, idleTimeout: 600, and for Edge --user-data-dir=remote-debug-profile-edge in browserOptions (without it the Edge CDP connect never completes). A user-set value wins.
  • LT_USERNAME and LT_ACCESS_KEY go only into the CDP URL. Without them the lease fails before any session starts.
  • Docs: integrations/testmu-browsers next to integrations/testmu, plus the browser, integrations, environment, security and skill references.
  • First written by @SahilSawLT in LambdaTest/e2e#4, and split out of #772 on review.
import type { E2EConfig } from 'e2e';
import { web } from '@e2e-dev/web';
import { testmuBrowsers } from '@e2e-dev/testmu/web';

export default {
  targets: [
    {
      name: 'testmu-web',
      engine: web({ browser: testmuBrowsers({ browserName: 'MicrosoftEdge', capabilities: { platform: 'Windows 10' } }), viewport: null }),
      app: { url: 'https://staging.example.com' },
    },
  ],
} satisfies E2EConfig;

Verified

Ran it locally: yes

Live on TestMu AI production on 2026-10-20, with run-1200-live.sh, which packs the branch into a clean project:

ScenarioResult
Chrome, worker scope, defaults only✅ pass, 14.4 s including session start
Edge, worker scope, defaults only✅ pass, 13.2 s including session start
Bad access key✅ fails at connect: 401 Unauthorized, either Username or AccessKey is invalid
browserVersion: '0.0'✅ fails at connect: 400 Could not find a valid browserVersionData

After every scenario the script greps the log, report.json, summary.md, junit.xml, the traces and trace.md for the access key, raw, URL-encoded and base64. No hits.

After the move into @e2e-dev/testmu, packed e2e, @e2e-dev/web, @e2e-dev/mobile and @e2e-dev/testmu into clean projects under /tmp and installed them with npm:

ProjectInstalled @e2e-dev/*tsc, skipLibCheck: false
web only: testmuBrowsers from @e2e-dev/testmu/webtestmu, web✅
mobile only: testmu from @e2e-dev/testmumobile, testmu✅

e2e run in the web-only project with a fake key reaches the hub through the packed ./web entry:

 FAIL  |testmu-web| tests/smoke.e2e.ts > opens example.com
ENGINE_FAILURE: browser connect failed: browserType.connectOverCDP: WebSocket error: wss://cdp.lambdatest.com/puppeteer 401 Unauthorized
{"status":401,"value":{"message":"...: Unauthorized, either Username or AccessKey is invalid"}}

The fake key and username appear nowhere under .e2e/ (raw, URL-encoded, base64). With no credentials:

 ERROR  infrastructure error ENGINE_FAILURE (launch)
browser provider "testmu-browsers" could not lease a browser: LT_USERNAME and LT_ACCESS_KEY are not set; set LT_USERNAME and LT_ACCESS_KEY to your TestMu AI username and access key in the environment `e2e run` starts in while preparing engine web for target "testmu-web"

Checklist

  • Changeset added (pnpm changeset) for any change to a published package, or the change is testbed, docs, or CI only.
  • Breaking change: none. @e2e-dev/mobile becomes an optional peer of @e2e-dev/testmu.
  • Docs updated in the same PR: the docs/**/*.mdx page for the behavior, and skills/e2e/ if the skill describes it.
  • Contract change: n/a.
  • Engine contract change (e2e/engine): n/a.

🤖 Generated with Claude Code