---
title: Dart and Flutter reference
description: Reference documentation for the Allure Dart and Flutter integration | Drop-in wrappers | Runtime API | Steps | Attachments | Custom integrations
---

# Dart and Flutter reference

These are the main building blocks you can use to integrate Dart and Flutter tests with Allure by using `allure_dart_test` and `allure_flutter_test`.

## Drop-in test wrappers

The drop-in libraries replace the declaration functions of the underlying framework and re-export everything else unchanged:

- `package:allure_dart_test/test.dart` replaces `test`, `group`, `setUp`, `tearDown`, `setUpAll`, and `tearDownAll` from `package:test`,
- `package:allure_flutter_test/flutter_test.dart` additionally replaces `testWidgets` from `flutter_test`,
- `package:allure_flutter_test/integration_test.dart` provides the same wrappers plus the `integration_test` exports, including `IntegrationTestWidgetsFlutterBinding`.

The wrappers accept the same arguments as the originals. On top of the original behavior, they:

- report each test as an Allure result with [automatic labels](/docs/dart-configuration/#automatic-labels-and-identifiers) derived from the file path and group hierarchy,
- parse [inline metadata markers](/docs/dart/#add-metadata) from test names,
- report `setUp`, `tearDown`, `setUpAll`, and `tearDownAll` callbacks as Allure fixtures,
- declaration-skip tests excluded by an [Allure test plan](/docs/dart-configuration/#allure-testplan-path) (no Allure result is written).

### `testWidgets` and variants

When a widget test uses a `TestVariant` (for example, `ValueVariant`), the Allure wrapper reports each variant value as a separate test result:

```dart
testWidgets(
  'renders both layouts',
  (tester) async {
    // ...
  },
  variant: ValueVariant<String>({'compact', 'expanded'}),
);
```

Each result is named `renders both layouts (variant: compact)` and `renders both layouts (variant: expanded)`, carries a `variant` parameter with the value, and shares the `renders both layouts` test case name. Test plan selectors match the variant-specific full names.

### Auto screenshot and golden-diff attachments

`allure_flutter_test`'s `installAllure()` — not the `allure_dart_test` one — accepts two Flutter-only flags:

- `installAllure(autoScreenshotOnFailure: true)` — on a failing test, captures a screenshot of the widget tree and attaches it as `screenshot-on-failure` (PNG).
- `installAllure(autoAttachGoldenDiff: true)` — on a `matchesGoldenFile` mismatch, attaches the actual rendered image as `golden-actual`, plus, best-effort (when the comparator is the default `LocalFileComparator`), whichever of `golden-masterImage`, `golden-testImage`, `golden-maskedDiff`, and `golden-isolatedDiff` it already wrote to disk. The comparator only computes a pixel diff when the actual and golden images are the same size, so a dimension mismatch attaches just the master and test images, while a same-size pixel mismatch also attaches the two diff visualizations.

Both flags install a process-wide hook the first time either is passed as `true`, are best-effort (a capture failure never masks the original test failure), and are monotonic — once enabled, a later bare `installAllure()` call in the same process does not disable them:

```dart
import 'dart:async';

import 'package:allure_flutter_test/allure_flutter_test.dart';

Future<void> testExecutable(FutureOr<void> Function() testMain) async {
  installAllure(autoScreenshotOnFailure: true, autoAttachGoldenDiff: true);
  await testMain();
}
```

You can still attach screenshots or golden files manually with the regular attachment APIs, whether or not these hooks are enabled.

## Runtime API

The runtime functions are exported by `package:allure_dart_test/allure_dart_test.dart` and `package:allure_flutter_test/allure_flutter_test.dart`. They apply to the currently running test — or, when called inside a fixture, to the fixture and its scope. All of them are asynchronous and should be awaited. Import the library with a prefix to keep the short names readable:

```dart
import 'package:allure_dart_test/allure_dart_test.dart' as allure;
```

### Metadata and labels

- `allure.displayName(name)` — overrides the test name shown in the report
- `allure.description(markdown)`
- `allure.descriptionHtml(html)`
- `allure.label(name, value)`
- `allure.labels([AllureLabel(...), ...])`
- `allure.allureId(value)`
- `allure.owner(value)`
- `allure.severity(value)`
- `allure.layer(value)`
- `allure.tag(value)`
- `allure.tags(['smoke', 'auth'])`
- `allure.testCaseName(value)`
- `allure.testCaseId(value)`
- `allure.historyId(value)`

Example:

```dart
test('login works', () async {
  await allure.description('Checks that a valid user can sign in.');
  await allure.owner('John Doe');
  await allure.severity('critical');
  await allure.label('microservice', 'ui');
  await allure.tags(['smoke', 'auth']);
});
```

### Hierarchies

- `allure.epic(value)`
- `allure.feature(value)`
- `allure.story(value)`
- `allure.parentSuite(value)`
- `allure.suite(value)`
- `allure.subSuite(value)`

### Links and parameters

- `allure.link(url, name: ..., type: ...)`
- `allure.links([AllureLink(...), ...])`
- `allure.issue(url, name: ...)`
- `allure.tms(url, name: ...)`
- `allure.parameter(name, value, excluded: ..., mode: ...)`

A parameter value can be any object; non-string values are JSON-encoded. Parameters with `excluded: true` don't affect the test's history ID. The `mode` argument controls rendering: `AllureParameterMode.masked` hides the value behind asterisks, and `AllureParameterMode.hidden` omits the parameter from the report.

```dart
test('login works', () async {
  await allure.issue('https://jira.example.com/browse/AUTH-123', name: 'AUTH-123');
  await allure.parameter('browser', 'firefox');
  await allure.parameter('password', 'qwerty', mode: allure.AllureParameterMode.masked);
});
```

### Statuses

- `allure.statusDetails(message: ..., trace: ..., known: ..., muted: ..., flaky: ..., actual: ..., expected: ...)`
- `allure.markKnown()`
- `allure.markMuted()`
- `allure.markFlaky()`

A test's status is resolved automatically: assertion failures (such as failed `expect` matchers) are reported as **failed**, any other errors as **broken**, and skipped tests (for example, via `markTestSkipped`, or a declaration-time `skip:` on the drop-in wrappers, which is converted into a runtime self-skip) as **skipped**. The one exception is a declaration-time `skip:` with `installAllure()` and the original framework imports: the framework never runs `setUp` for a declaration-skipped test, which is where that style schedules the result, so no result is produced at all — see [Skip tests](/docs/dart/#skip-tests) for the full breakdown, including the group-skip fixture tradeoff. For matcher failures, the actual and expected values are extracted into the status details automatically. The `statusDetails` call lets you add classification flags on top:

```dart
test('login works', () async {
  await allure.statusDetails(flaky: true);
});
```

### Steps

- `allure.step(name, (step) async { ... })` — runs the body inside a step and returns its value
- `allure.logStep(name, status: ..., error: ...)` — records an instant, already-completed step

The `step` context object passed to the body provides:

- `step.displayName(name)` — renames the current step
- `step.parameter(name, value, mode: ...)` — adds a parameter to the current step

```dart
test('login works', () async {
  final session = await allure.step('create session', (step) async {
    await step.parameter('user', 'alice');
    return Session('alice');
  });

  await allure.logStep('cleanup skipped', status: allure.AllureStatus.skipped);
});
```

Steps nest: a `step` call inside another step's body creates a child step. If the body throws, the step is marked failed or broken and the error is rethrown.

### Attachments

- `allure.attachment(name, content, contentType: ..., fileExtension: ..., wrapInStep: ..., timestamp: ...)`
- `allure.attachmentPath(name, path, contentType: ..., fileExtension: ..., wrapInStep: ..., timestamp: ...)`
- `allure.attachTrace(name, path)` — attaches an existing [Playwright trace](/docs/attachments/#playwright-traces) archive so the report opens it in the Trace Viewer (does not generate traces or depend on Playwright)

Attachment content can be a `String`, a list of bytes, or any JSON-encodable object. With `wrapInStep: true` (the default), the attachment is added as an attachment step, so it keeps its position between the surrounding steps.

Warning:
Inside a Flutter `testWidgets` body, real I/O attachment calls (`attachmentPath`, or `attachment` with stream content) must run inside `tester.runAsync(...)`, or the test hangs — `testWidgets` runs on a fake-async zone that never pumps real I/O callbacks otherwise.

```dart
test('login works', () async {
  await allure.attachment(
    'response.json',
    '{"status":"ok","user":"demo"}',
    contentType: 'application/json',
    fileExtension: 'json',
  );

  await allure.attachmentPath(
    'screenshot',
    'screenshots/failure.png',
    contentType: 'image/png',
  );
});
```

### Run-level attachments and errors

These write run-level data not tied to any single test — for example, a server log for the whole run or an infrastructure failure:

- `allure.globalAttachment(name, content, contentType: ..., fileExtension: ...)`
- `allure.globalAttachmentPath(name, path, contentType: ..., fileExtension: ...)`
- `allure.globalError(message: ..., trace: ..., known: ..., muted: ..., flaky: ..., actual: ..., expected: ...)`

## `allureTest`

`allureTest` from `package:allure_dart_test/allure_dart_test.dart` is an alternative to the drop-in wrappers for individual tests. It declares a `package:test` test whose body receives a context object with test-scoped helpers, including durable attachment APIs for large or late-produced artifacts:

```dart
import 'package:allure_dart_test/allure_dart_test.dart';

void main() {
  allureTest('captures logs', (allure) async {
    await allure.step('start server', () async {
      // ...
    });

    await allure.streamAttachment(
      name: 'server log',
      type: 'text/plain',
      extension: 'log',
      content: logFile.openRead(),
    );
  });
}
```

The context object provides:

- `step(name, body)` — like the top-level step API, without the step context argument
- `label(name, value)`, `parameter(name, value, ...)`, `testCaseName(value)`, `statusDetails(...)`
- `attachment(name: ..., type: ..., content: ..., extension: ..., wrapInStep: ...)` — binary content
- `textAttachment(name: ..., content: ..., type: ..., extension: ..., wrapInStep: ...)` — text content, `text/plain` by default
- `streamAttachment(name: ..., content: ..., type: ..., extension: ..., wrapInStep: ...)` — writes from a byte stream
- `preparedAttachment(name: ..., type: ..., extension: ..., write: ..., wrapInStep: ...)` — reserves an attachment file and lets your callback write it before the result references it

`allureTest` also accepts `timeout`, `skip`, and initial `labels`, `parameters`, and `links` lists.

## Customizing the lifecycle

`installAllure()` accepts a custom `AllureLifecycle`, which is the place to set run-level report data:

```dart
import 'package:allure_dart_test/allure_dart_test.dart';
import 'package:test/test.dart';

void main() {
  installAllure(
    lifecycle: AllureLifecycle(
      linkUrlTemplates: {
        'issue': 'https://jira.example.com/browse/{}',
        'tms': 'https://tms.example.com/cases/{}',
      },
      executorInfo: const AllureExecutorInfo(
        name: 'GitHub Actions',
        type: 'github',
        buildName: 'Build #42',
      ),
      environmentInfo: const {'stand': 'staging'},
      categories: [
        AllureCategory(name: 'Infrastructure', messageRegex: RegExp('timeout')),
      ],
    ),
  );

  // ...
}
```

The most useful options:

- `linkUrlTemplates` / `linkNameTemplates` — templates keyed by link type, applied to links whose URL is not absolute. `{}` (or `%s`) is replaced by the link value, so `allure.issue('AUTH-123')` resolves to the full tracker URL.
- `executorInfo` — CI or launcher metadata written to `executor.json` (name, type, build name, build URL, report URL, build order).
- `environmentInfo` — key-value pairs written to `environment.properties`, merged with the [config file](/docs/dart-configuration/#allure-dart-yaml) values.
- `categories` — custom defect category definitions written to `categories.json`, matching results by message or trace regular expressions.
- `globalLabels` — labels added to every test result, merged with the config file values.
- `listeners` — a list of `AllureLifecycleListener` implementations. A listener observes lifecycle events (test start/stop/write, step stop, container write, attachments, global errors) and can mutate a result before it is written — for example, to add labels or scrub data. A throwing listener is reported to stderr without failing the run.

Warning:
`installAllure()` is safe to call more than once in the same process as long as `lifecycle` (and `frameworkLabelResolver`) are omitted or identical each time — a bare `installAllure()` never disturbs an already-installed configuration. Calling it again with a genuinely different `lifecycle` instance throws a `StateError` instead of silently keeping the first one.

## Building a custom integration with `allure_dart_commons`

Use `allure_dart_commons` when you need low-level control over the lifecycle:

```dart
import 'package:allure_dart_commons/allure_dart_commons.dart';

Future<void> main() async {
  final lifecycle = AllureLifecycle(
    writer: AllureResultsWriter(outputDirectory: 'allure-results'),
  );

  final testUuid = lifecycle.startTest(
    name: 'login works',
    fullName: 'auth/login_test.dart#login works',
  );
  lifecycle.startStep(testUuid, 'submit credentials');
  lifecycle.stopStep(testUuid, status: AllureStatus.passed);
  await lifecycle.stopTest(testUuid, status: AllureStatus.passed);
  await lifecycle.writeTest(testUuid);
}
```

The main low-level types are:

- `AllureLifecycle` — starts, updates, stops, and writes tests, fixtures, and steps; handles attachments and run-level data
- `AllureResultsWriter` — writes result files, containers, and attachments to the results directory
- `AllureConfig` — loads `allure-dart.yaml`
- `AllureLifecycleListener` — lifecycle event hooks
- `AllureStatus`, `AllureStatusDetails`, `AllureLabel`, `AllureLink`, `AllureParameter`, and the other model types

For streaming and late artifacts, the lifecycle exposes `addAttachmentStreamToRoot` and `addPreparedAttachmentToRoot`, which write the payload durably before the result references it. To route the top-level runtime API to your own lifecycle, wire a `MessageTestRuntime` with `setGlobalTestRuntime` and carry the execution context across async boundaries with `runWithAllureContext`.
