Troupeby AliveDocsSign in

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
// Playwright
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
// Troupe
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

PlaywrightTroupeNote
test, test.only, test.skip, test.fixme, test.fail, test.fail.only, test.slowsameA 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.skipsameA step that passes its timeout fails the test
test.use, test.extend, mergeTests, test.info(), test.setTimeoutsameFixture options scope, auto, option, timeout, title, box
mergeExpects, test.expectabsentexpect.extend returns a new expect; import expect
pagescreenThe foreground app; screen.system for system UI
browser, context, browserNamedevice, platform
timezoneId, colorScheme, navigationTimeouttimeZone, appearance, launchTimeout
locale, permissions, actionTimeout, tracesame
request, baseURL, headless, viewport, launchOptions, geolocation, offline, extraHTTPHeaders, storageState, testIdAttribute, the screenshot and video optionsabsentThe 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

PlaywrightTroupeNote
getByRole, getByText, getByLabel, getByPlaceholder, getByTestIdsameText 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
scrollIntoViewIfNeededscrollIntoView
locator(selector), frameLocator, getByAltText, getByTitleabsentscreen.locator({ root }) picks a scope, not a selector. Use getByLabel
check, uncheck, setChecked, hover, focus, blur, selectOption, setInputFiles, dispatchEvent, evaluate, innerHTML, innerText, getAttribute, isEditableabsentTap a switch to toggle it

Assertions

PlaywrightTroupeNote
toBeVisible, toBeHidden, toBeAttached, toBeEnabled, toBeDisabled, toBeChecked, toBeFocused, toHaveText, toContainText, toHaveValue, toHaveCount, toHaveAccessibleName, toHaveRole, toMatchAriaSnapshotsame
toHaveScreenshot with threshold, maxDiffPixels, maxDiffPixelRatio, timeoutsameNo 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.extendsame
toPasssameWithout a timeout it stops at the assertion timeout; Playwright's waits without limit
toBeEditable, toBeEmpty, toBeInViewport, toHaveAttribute, toHaveClass, toHaveCSS, toHaveId, toHaveJSProperty, toHaveValues, toHaveAccessibleDescription, toHaveTitle, toHaveURLabsentThey describe a DOM or a page

Configuration

PlaywrightTroupeNote
testDir, testMatch, testIgnore, timeout, retries, repeatEach, workers, fullyParallel, forbidOnly, maxFailures, grep, grepInvert, shard, reporter, outputDir, globalTimeout, failOnFlakyTests, metadatasameretries is 2 when CI is set
projects with name, use, dependencies, testDir, testMatch, retries, timeout, grep, tag, fullyParallel, outputDir, expectsameA project is a device, not a browser
expect.timeout, expect.toPasssame
webServersameOptions 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

PlaywrightTroupeNote
list, line, dot, json, junit, blob, htmlsameThe HTML report is written to troupe-report/ and never opens a browser. JUnit reports errored as <error>
github, nullabsent
A custom reportersame eventsMethods 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-reportssameEach prints an address and does not open a browser
codegen, --ui, --debugabsent

What Troupe adds

AdditionWhat 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

esc

    Type to search every page, the protocol reference and the cloud API.