Testing
Coming from Playwright Troupe's test framework has Playwright's shape on purpose: if you know test, expect, locators and
fixtures, you know most of Troupe. This page lists what is the same, what has a mobile name, what does not
exist, and what Troupe adds.
The same test, on a device TypeScript Copy
import { expect, test } from '@playwright/test'
test ('signs in' , async ({ page }) => {
await page.getByLabel ('Email' ).fill ('a@b.co' )
await page.getByRole ('button' , { name: 'Sign in' }).click ()
await expect (page.getByRole ('heading' , { name: 'Welcome back' })).toBeVisible ()
})TypeScript Copy
import { expect, test } from '@alivelabs/troupe'
test ('signs in' , async ({ screen }) => {
await screen.getByLabel ('Email' ).fill ('a@b.co' )
await screen.getByRole ('button' , { name: 'Sign in' }).tap ()
await expect (screen.getByRole ('heading' , { name: 'Welcome back' })).toBeVisible ()
})What is different underneath Bun runs it. troupe is run by Bun, not Node: bunx troupe test in place of npx playwright test.Test files end in .e2e.ts. The default testMatch is **/*.e2e.{ts,tsx}.There is no DOM. Locators read the device's accessibility tree, so there are no CSS or XPath selectors,
no evaluate, and no frames.A worker holds a device, not a browser. The number of workers is capped by the devices the runtime may
run, and a device stays with its worker for all its tests.Device time is outside test time. Booting a device and installing the app are not charged to any test's
timeout.Timeouts are longer. A test gets 60 seconds (Playwright: 30) and an assertion 10 seconds (Playwright: 5).Infrastructure has its own status. A test that stops because the device or its driver failed ends
errored, not failed, and a run whose only problems are of that kind exits 3, not 1. Playwright's
interrupted is called canceled.Tests, hooks and fixtures Playwright Troupe Note test, test.only, test.skip, test.fixme, test.fail, test.fail.only, test.slowsame A modifier callback receives the project's option values, not live fixtures test.describe with .only, .skip, .fixme, .serial, .parallel, .configuresame test.beforeEach, afterEach, beforeAll, afterAllsame test.step with box, timeout, location; test.step.skipsame A step that passes its timeout fails the test test.use, test.extend, mergeTests, test.info(), test.setTimeoutsame Fixture options scope, auto, option, timeout, title, box mergeExpects, test.expectabsent expect.extend returns a new expect; import expectpagescreenThe foreground app; screen.system for system UI browser, context, browserNamedevice, platformtimezoneId, colorScheme, navigationTimeouttimeZone, appearance, launchTimeoutlocale, permissions, actionTimeout, tracesame request, baseURL, headless, viewport, launchOptions, geolocation, offline, extraHTTPHeaders, storageState, testIdAttribute, the screenshot and video optionsabsent The device is chosen by deviceType, os and orientation. Each platform defines its own test id. Video is not recorded
TestInfo has Playwright's fields and methods, from title and retry to attach and outputPath.
config, fn, snapshotDir, snapshotPath and snapshotSuffix are absent. status can also be errored.
Locators and actions Playwright Troupe Note getByRole, getByText, getByLabel, getByPlaceholder, getByTestIdsame Text matching follows Playwright's rules. Roles are ARIA's, plus text and keyboard filter (hasText, hasNotText, has, hasNot, visible), nth, first, last, and, or, describesame fill, clear, pressSequentially, dragTo, waitFor, count, all, isVisible, isHidden, isEnabled, isDisabled, isChecked, textContent, inputValue, boundingBox, screenshot, ariaSnapshotsame click, dblclicktap, doubleTapTouch, not a pointer pressscreen.pressKeyA key goes to the focused element scrollIntoViewIfNeededscrollIntoViewlocator(selector), frameLocator, getByAltText, getByTitleabsent screen.locator({ root }) picks a scope, not a selector. Use getByLabelcheck, uncheck, setChecked, hover, focus, blur, selectOption, setInputFiles, dispatchEvent, evaluate, innerHTML, innerText, getAttribute, isEditableabsent Tap a switch to toggle it
Assertions Playwright Troupe Note toBeVisible, toBeHidden, toBeAttached, toBeEnabled, toBeDisabled, toBeChecked, toBeFocused, toHaveText, toContainText, toHaveValue, toHaveCount, toHaveAccessibleName, toHaveRole, toMatchAriaSnapshotsame toHaveScreenshot with threshold, maxDiffPixels, maxDiffPixelRatio, timeoutsame No mask or animations, and it cannot be negated. The snapshot is <spec>-snapshots/<name>-<project>.png The generic matchers, asymmetric matchers, expect.soft, expect.poll, expect.configure, expect.extend same toPasssame Without a timeout it stops at the assertion timeout; Playwright's waits without limit toBeEditable, toBeEmpty, toBeInViewport, toHaveAttribute, toHaveClass, toHaveCSS, toHaveId, toHaveJSProperty, toHaveValues, toHaveAccessibleDescription, toHaveTitle, toHaveURLabsent They describe a DOM or a page
Configuration Playwright Troupe Note testDir, testMatch, testIgnore, timeout, retries, repeatEach, workers, fullyParallel, forbidOnly, maxFailures, grep, grepInvert, shard, reporter, outputDir, globalTimeout, failOnFlakyTests, metadatasame retries is 2 when CI is setprojects with name, use, dependencies, testDir, testMatch, retries, timeout, grep, tag, fullyParallel, outputDir, expectsame A project is a device, not a browser expect.timeout, expect.toPasssame webServersame Options command, url, reuseExisting, timeoutMs, env updateSnapshots-u, --update-snapshotsOr the variable TROUPE_UPDATE_SNAPSHOTS globalSetup, globalTeardown, project teardown, reportSlowTests, preserveOutput, respectGitIgnore, tsconfig, snapshotPathTemplate, ignoreSnapshotsabsent
Reporters and commands Playwright Troupe Note list, line, dot, json, junit, blob, htmlsame The HTML report is written to troupe-report/ and never opens a browser. JUnit reports errored as <error> github, nullabsent A custom reporter same events Methods receive the event's fields and a run model. playwrightAdapter wraps a reporter written for Playwright npx playwright testbunx troupe testThe same flags: --project, --grep, --workers, --shard, --retries, --reporter, --trace, --list npx playwright installbunx troupe installPrepares a platform, not a browser download show-report, show-trace, merge-reportssame Each prints an address and does not open a browser codegen, --ui, --debugabsent
What Troupe adds Addition What it is for app fixtureThe app under test: launch, terminate, relaunch, openUrl, clearData, reinstall, setPermissions appIsolation, app, bundleId, launchArgs, launchEnv, deviceTimeout optionsWhich build to install and how each test starts. See fixtures runtime fixtureAny runtime procedure, typed, as a step test.requires(capability)Skip tests on a platform that cannot do something longPress, swipe, scroll, screen.tapAt, screen.pressButton, screen.setOrientation, screen.hideKeyboardTouch gestures, hardware buttons and rotation node(), isFocused(), accessibleName() on a locatorReads of the accessibility node bundler configThe JavaScript bundler a debug build loads from xcodeBuild()An app found in Xcode's DerivedData errored status and exit code 3Infrastructure failures kept apart from test failures troupe doctor, troupe studio, troupe mcpEnvironment checks, a live device in the browser, and tools for coding agents
Next