Skip to main content

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.

tests/checkout.spec.ts
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:

tests/permissions.spec.ts
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:

tests/locale.spec.ts
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:

tests/legacy.spec.ts
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:

tests/cart.spec.ts
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:

tests/upload.spec.ts
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 @:

tests/smoke.spec.ts
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:

tests/regression.spec.ts
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:

tests/regression.spec.ts
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' });
// ...
});
CI annotations are different

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

AnnotationEffect
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.