Annotations
Annotations let you mark a test as skipped, expected to fail, or slow, tag it for
filtering, and attach metadata that surfaces in the report. Taqwright runs on
Playwright's test runner, so the whole annotation API is inherited unchanged: the
modifiers below are exactly Playwright's test.skip / test.fixme / test.fail /
test.slow, the tag option, and custom annotations. You apply them to the same
taqwright tests you already write, driving the mobile fixture. New to writing tests?
Start with Writing tests.
Skip a test
test.skip marks a test as not-to-run. Reach for it when a flow is unsupported on the
current platform, gated behind a feature flag, or temporarily parked.
import { test, expect } from '@taqwright/taqwright';
// Skip unconditionally: the test is collected but never executed.
test.skip('apple pay checkout', async ({ mobile }) => {
await mobile.getByLabel('Apple Pay').click();
});
Pass a condition and a reason to skip only some of the time. This reads well for platform-specific flows, since the demo app's Android-only screens have no iOS equivalent:
import { test, expect, Platform } from '@taqwright/taqwright';
test('grant camera permission via system dialog', async ({ mobile }, testInfo) => {
test.skip(
testInfo.project.use.platform === Platform.IOS,
'setPermission is Android-only',
);
await mobile.setPermission('android.permission.CAMERA', 'grant');
await expect(mobile.getByLabel('Scan')).toBeVisible();
});
You can also decide to skip partway through a test, once you know something only the running device can tell you:
import { test, expect } from '@taqwright/taqwright';
test('renders right-to-left layout', async ({ mobile }) => {
const size = await mobile.getScreenSize();
test.skip(size.width < 600, 'RTL layout only ships on tablets');
await expect(mobile.getByLabel('Menu')).toBeVisible();
});
To skip a whole group, use test.describe.skip:
import { test } from '@taqwright/taqwright';
test.describe.skip('Legacy onboarding', () => {
test('welcome carousel', async ({ mobile }) => { /* ... */ });
test('account setup', async ({ mobile }) => { /* ... */ });
});
Fixme, fail, and slow
Three more modifiers cover the rest of the lifecycle:
import { test, expect } from '@taqwright/taqwright';
// fixme: known-broken, do not run (and do not let it fail the suite).
test.fixme('promo code stacks with sale price', async ({ mobile }) => {
await mobile.getByLabel('Promo code').fill('SAVE10');
});
// fail: the test is EXPECTED to fail. It passes the suite only if it does fail,
// which flips back to a real failure the moment the underlying bug is fixed.
test.fail('negative quantity is rejected', async ({ mobile }) => {
await mobile.getByLabel('Quantity').fill('-1');
await expect(mobile.getByLabel('Subtotal')).toHaveText('$0.00');
});
// slow: triples the test timeout. Good for long flows on cold-booted emulators.
test('full purchase flow', async ({ mobile }) => {
test.slow();
await mobile.getByLabel('View All').click();
// ... many steps ...
});
Like skip, both fixme and slow accept the conditional (condition, reason) form,
so you can mark a test broken or slow only on the platform where that is true.
Conditional modifiers
The (condition, reason) signature is the common thread across skip, fixme, and
slow. The condition is any boolean you can compute at runtime, an environment
variable, the project platform, a device query, so you keep one test definition instead
of forking it per device:
import { test } from '@taqwright/taqwright';
test('upload a large file', async ({ mobile }) => {
test.slow(!!process.env.CI, 'cloud devices are slower than local emulators');
await mobile.pushFile('/sdcard/Download/sample.bin', 'x'.repeat(1_000_000));
// ...
});
Tags
Tags group tests so you can run a subset from the CLI. Pass tag to either an
individual test or a whole describe block. A tag is a string starting with @:
import { test, expect } from '@taqwright/taqwright';
test('login smoke', { tag: '@smoke' }, async ({ mobile }) => {
await mobile.getByLabel('Username').fill('emma@demoapp.com');
await mobile.getByLabel('Password').fill('10203040');
await mobile.getByLabel('Login').click();
await expect(mobile.getByLabel('View All')).toBeVisible();
});
// Tag every test in the group at once, and stack multiple tags.
test.describe('Checkout', { tag: ['@smoke', '@payments'] }, () => {
test('card payment', async ({ mobile }) => { /* ... */ });
});
Filter by tag at run time with --grep (and its inverse --grep-invert):
# Run only the smoke tests
npx taqwright test --grep @smoke
# Run everything EXCEPT the payments tests
npx taqwright test --grep-invert @payments
This is the same matcher behind the grep config knob shown in
Configuration, so you can also pin a tag filter per project
instead of passing it on every command.
Custom annotations
Custom annotations attach freeform { type, description } metadata to a test. They do
not change whether the test runs; they show up in the HTML report (open it with
npx taqwright show-report) so reviewers can see why a test exists or what it covers:
import { test, expect } from '@taqwright/taqwright';
test(
'cart survives backgrounding',
{ annotation: { type: 'issue', description: 'TAQ-482' } },
async ({ mobile }) => {
await mobile.getByLabel('Add to Cart').click();
await mobile.backgroundApp(3);
await expect(mobile.getByLabel('VIEW CART')).toBeVisible();
},
);
You can also add annotations at run time once you know something the static option
could not, by pushing to test.info().annotations:
import { test } from '@taqwright/taqwright';
test('renders offline banner', async ({ mobile }) => {
await mobile.setNetworkConnection({ wifi: false, data: false, airplane: true });
test.info().annotations.push({ type: 'env', description: 'airplane mode' });
// ...
});
The GitHub Actions annotations that highlight failures in pull-request checks come from
the 'github' reporter, not from these test annotations. See
Running and debugging for that.
Summary
| Annotation | Effect |
|---|---|
test.skip() | Test is collected but never run. |
test.skip(condition, reason) | Skipped only when condition is true. |
test.describe.skip(...) | Skips every test in the group. |
test.fixme() | Known-broken; not run and not counted as a failure. |
test.fail() | Test is expected to fail; passes the suite only if it does. |
test.slow() | Triples the test timeout. |
{ tag: '@smoke' } | Tags a test or group; filter with --grep / --grep-invert. |
{ annotation: { type, description } } | Attaches metadata shown in the HTML report. |
test.info().annotations.push(...) | Adds an annotation at run time. |