Skip to content
Allure report logoAllure Report
Main Navigation ModulesDocumentationStarter Project

English

Español

English

Español

Appearance

Sidebar Navigation

Allure 3

Install & Upgrade

Install Allure

Upgrade Allure

Configure

Create Reports

How to generate a report

How to view a report

Improving readability of your test reports

Improving navigation in your test report

Reading Allure charts

Migrate from Allure 2

Allure 2

Install & Upgrade

Install for Windows

Install for macOS

Install for Linux

Install for Node.js

Upgrade Allure

Create Reports

How to generate a report

How to view a report

Improving readability of your test reports

Improving navigation in your test report

Features

Agent Mode

Test steps

Attachments

Test statuses

Assertion diffs

Sorting and filtering

Environments

Multistage Builds

Categories

Visual analytics

Test stability analysis

History and retries

Self-hosted storage

Quality Gate

Global Errors and Attachments

Timeline

Export to CSV

Export metrics

Guides

JUnit 5 parametrization

JUnit 5 & Selenide: screenshots and attachments

JUnit 5 & Selenium: screenshots and attachments

Setting up JUnit 5 with GitHub Actions

Pytest parameterization

Pytest & Selenium: screenshots and attachments

Pytest & Playwright: screenshots and attachments

Pytest & Playwright: videos

Playwright parameterization

Publishing Reports to GitHub Pages

Deploying Self-Hosted Storage with Docker

Deploying Self-Hosted Storage on Cloudflare Workers

Allure Report 3: XCResults Reader

How it works

Overview

Glossary

Test result file

Container file

Categories file

Environment file

Executor file

History files

Test Identifiers

Integrations

Azure DevOps

Bamboo

GitHub Action

Gradle

Jenkins

JetBrains IDEs

Maven

TeamCity

Visual Studio Code

Frameworks

AVA

Getting started

Configuration

Reference

Axios

Getting started

Configuration

Reference

Behat

Getting started

Configuration

Reference

Behave

Getting started

Configuration

Reference

Bun

Getting started

Configuration

Reference

Chai

Getting started

Reference

Codeception

Getting started

Configuration

Reference

CodeceptJS

Getting started

Configuration

Reference

Cucumber.js

Getting started

Configuration

Reference

Cucumber-JVM

Getting started

Configuration

Reference

Cucumber.rb

Getting started

Configuration

Reference

Cypress

Getting started

Configuration

Reference

Dart and Flutter

Getting started

Configuration

Reference

Fetch

Getting started

Configuration

Reference

Go

Getting started

Configuration

Reference

Jasmine

Getting started

Configuration

Reference

JBehave

Getting started

Configuration

Reference

Jest

Getting started

Configuration

Reference

JUnit 4

Getting started

Configuration

Reference

JUnit 5

Getting started

Configuration

Reference

Mocha

Getting started

Configuration

Reference

Newman

Getting started

Configuration

Reference

Node.js Test Runner

Getting started

Configuration

Reference

NUnit

Getting started

Configuration

Reference

PHPUnit

Getting started

Configuration

Reference

Playwright

Getting started

Configuration

Reference

Playwright Java

Getting started

Configuration

Reference

pytest

Getting started

Configuration

Reference

Pytest-BDD

Getting started

Configuration

Reference

Reqnroll

Getting started

Configuration

Reference

REST Assured

Getting started

Configuration

Robot Framework

Getting started

Configuration

Reference

Rust Cargo Test

Getting started

Configuration

Reference

RSpec

Getting started

Configuration

Reference

SpecFlow

Getting started

Configuration

Reference

Spock

Getting started

Configuration

Reference

TestCafe

Getting started

Configuration

Reference

TestNG

Getting started

Configuration

Reference

Vitest

Getting started

Configuration

Reference

WebdriverIO

Getting started

Configuration

Reference

xUnit.net

Getting started

Configuration

Reference

On this page

Getting started with Dart and Flutter ​

allure_dart_test pub.dev latest version

allure_flutter_test pub.dev latest version

Generate beautiful HTML reports using Allure Report and your Dart and Flutter tests.

INFO

The main user-facing packages are allure_dart_test for package:test suites and allure_flutter_test for Flutter widget tests and host-run integration_test suites. If you are building your own integration for a custom runner or framework, use allure_dart_commons instead. All three packages live in the official allure-dart repository.

Setting up ​

1. Prepare your project ​

  1. Make sure a recent Dart or Flutter toolchain is installed.

    The official allure-dart packages require Dart 3.8 or newer. The Flutter adapter additionally requires Flutter 3.24 or newer.

  2. Open a terminal and go to the project directory. For example:

    bash
    cd /home/user/myproject
  3. Install Allure Report, following the installation guide.

  4. Add the integration as a dev dependency:

    bash
    dart pub add --dev allure_dart_test
    bash
    flutter pub add --dev allure_flutter_test
  5. Enable the integration in your test files. The simplest way is the drop-in import: replace the test framework import with the matching Allure import, and keep the rest of the file unchanged.

    Original importAllure drop-in import
    package:test/test.dartpackage:allure_dart_test/test.dart
    package:flutter_test/flutter_test.dartpackage:allure_flutter_test/flutter_test.dart
    package:integration_test/integration_test.dartpackage:allure_flutter_test/integration_test.dart

    The drop-in libraries re-export the original framework, so expect, matchers, and the other APIs keep working. Add a second, aliased import for Allure's runtime API:

    dart
    import 'package:allure_dart_test/test.dart';
    import 'package:allure_dart_test/allure_dart_test.dart' as allure;
    
    void main() {
      group('authentication', () {
        test('login works', () async {
          await allure.feature('Authentication');
          await allure.parameter('browser', 'chromium');
    
          await allure.step('submit credentials', (step) async {
            await step.parameter('user', 'alice');
            await allure.attachment(
              'request',
              '{"user":"alice"}',
              contentType: 'application/json',
              fileExtension: 'json',
            );
          });
    
          expect(2 + 2, equals(4));
        });
      });
    }
    dart
    import 'package:allure_flutter_test/flutter_test.dart';
    import 'package:allure_flutter_test/allure_flutter_test.dart' as allure;
    
    void main() {
      testWidgets('renders empty state', (tester) async {
        await allure.feature('Home screen');
    
        await allure.step('pump widget', (_) async {
          await tester.pumpWidget(const MyApp());
        });
    
        expect(find.text('No items'), findsOneWidget);
      });
    }
    dart
    import 'package:allure_flutter_test/integration_test.dart';
    import 'package:allure_flutter_test/allure_flutter_test.dart' as allure;
    
    void main() {
      IntegrationTestWidgetsFlutterBinding.ensureInitialized();
    
      testWidgets('signs in', (tester) async {
        await allure.story('Sign in');
        expect(find.text('Sign in'), findsOneWidget);
      });
    }

    Alternatively, if you prefer to keep the original framework imports, install the runtime plugin once with installAllure(). In Dart tests, call it at the start of main(); in Flutter tests, call it from test/flutter_test_config.dart so it applies to the whole suite:

    dart
    import 'package:allure_dart_test/allure_dart_test.dart';
    import 'package:test/test.dart';
    
    void main() {
      installAllure();
    
      test('login works', () async {
        await step('submit credentials', (_) async {
          expect(2 + 2, equals(4));
        });
      });
    }
    dart
    import 'dart:async';
    
    import 'package:allure_flutter_test/allure_flutter_test.dart';
    
    Future<void> testExecutable(FutureOr<void> Function() testMain) async {
      installAllure();
      await testMain();
    }

    Both styles produce Allure results and support the same runtime API. The drop-in style additionally reports setUp/tearDown callbacks as Allure fixtures, converts a declared skip: into a runtime self-skip so it's still reported (see Skip tests), and can skip tests excluded by a test plan.

2. Run tests ​

Run your tests the same way as usual:

bash
dart test
bash
flutter test

By default, the integration writes the results to an allure-results directory in the current working directory.

WARNING

These adapters only work on the Dart VM — the default platform for dart test and flutter test. On browsers or Node.js (dart test -p chrome, dart test -p node, flutter test --platform chrome), every test fails with a message Allure cannot write test results on this platform (no filesystem), even ones that never call the Allure API, because the adapters always try to write a result file with no filesystem to write it to.

To use a different directory, set ALLURE_RESULTS_DIR before the test run:

bash
ALLURE_RESULTS_DIR=build/allure-results dart test

If the results directory already exists, the new files are added to the existing ones, so that a future report will be based on all of them.

3. Generate a report ​

After the test run, generate and open the report with the Allure CLI:

bash
allure generate ./allure-results --output ./allure-report --clean
allure open ./allure-report

If you changed the results directory, use that path in the allure generate command.

Writing tests ​

The Allure Dart adapters extend plain dart test and flutter test output with richer reporting features. You can use them to:

  • add descriptions, owners, links, and other metadata,
  • organize tests into behavior-based and suite-based hierarchies,
  • split the execution into nested steps,
  • describe parameters and attachments,
  • report setup and teardown fixtures,
  • skip tests without losing them from the report,
  • run only selected tests through a test plan file.

Add metadata ​

Inside a test body, use the top-level runtime functions to enrich the test result:

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

void main() {
  test('login works', () async {
    await allure.displayName('Login works');
    await allure.description('This test verifies login with a username and a password.');
    await allure.owner('John Doe');
    await allure.tag('smoke');
    await allure.severity('critical');
    await allure.allureId('AUTH-1');
    await allure.issue('https://jira.example.com/browse/AUTH-123', name: 'AUTH-123');
    await allure.tms('https://tms.example.com/cases/TMS-456', name: 'TMS-456');
  });
}

You can also declare metadata statically, without touching the test body. Inline markers in the test name are parsed and removed from the displayed name:

dart
test('checkout works @allure.id:123 @allure.label.owner:payments', () async {
  // ...
});

Supported markers are @allure.id:<value>, @allure.label.<name>:<value>, @allure.link.<type>:<url>, and @allure.name:<display name> (= works in place of :).

Ordinary package:test tags are reported as Allure tag labels. Reserved @allure.* tags are treated as inline metadata instead and do not become tag labels:

dart
test(
  'checkout works',
  () async {
    // ...
  },
  tags: ['smoke'],
);

Organize tests ​

Allure supports both behavior-based and suite-based hierarchies. For example:

dart
test('login works', () async {
  await allure.epic('Web interface');
  await allure.feature('Authentication');
  await allure.story('Login with username and password');

  await allure.parentSuite('UI tests');
  await allure.suite('Authentication');
  await allure.subSuite('Positive scenarios');
});

The adapters also derive suite labels from the group() hierarchy automatically. Explicit calls to allure.parentSuite(...), allure.suite(...), or allure.subSuite(...) override the automatically derived labels. See Configuration for the full list of automatic labels.

Divide a test into steps ​

Wrap parts of the test into named steps with allure.step(). Steps nest, record their own timing and status, and can carry parameters:

dart
test('login works', () async {
  await allure.step('open login page', (_) async {
    // ...
  });

  await allure.step('submit credentials', (step) async {
    await step.parameter('user', 'alice');
    await allure.step('fill the form', (_) async {
      // ...
    });
  });
});

If a step body throws, the step is reported as failed or broken, and the error is rethrown, so the test itself fails as usual.

To record an already-completed action without wrapping code, use allure.logStep():

dart
await allure.logStep('verify audit log');

Add parameters and attachments ​

Parameters and attachments are stored in the generated Allure results and rendered in the report:

dart
test('login works', () async {
  await allure.parameter('browser', 'firefox');
  await allure.parameter('password', 'qwerty', mode: allure.AllureParameterMode.masked);

  await allure.attachment(
    'request.json',
    '{"username":"demo","rememberMe":true}',
    contentType: 'application/json',
    fileExtension: 'json',
  );

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

Attachment content can be a String, a list of bytes, or any JSON-encodable object. By default, attachments added from inside a test are wrapped in an attachment step, so they keep their logical position between the surrounding steps; pass wrapInStep: false to attach them directly to the test or current step instead.

INFO

testWidgets bodies run on a fake-async zone, so an attachment call that does real I/O (attachmentPath, or attachment with stream content) must run inside tester.runAsync(...). Outside runAsync, the fake zone never pumps the real I/O callback and the test hangs.

Capture Flutter failures automatically ​

allure_flutter_test's installAllure() accepts two Flutter-only opt-in flags that install a process-wide hook the first time either is passed as true:

dart
installAllure(
  autoScreenshotOnFailure: true,
  autoAttachGoldenDiff: true,
);
  • autoScreenshotOnFailure captures a screenshot of the widget tree when a test fails and attaches it as screenshot-on-failure.
  • autoAttachGoldenDiff attaches the actual rendered image as golden-actual (plus, best-effort, the master and test images) whenever a matchesGoldenFile comparison fails.

Both hooks are best-effort — a capture failure never masks the original test failure — and monotonic: once enabled by any installAllure(...) call in the process, a later bare installAllure() call does not disable them. Enable them once, for example in test/flutter_test_config.dart. See Reference for details.

Report fixtures ​

When you use the drop-in imports, setUp, tearDown, setUpAll, and tearDownAll callbacks are reported as Allure fixtures, shown in the report alongside the tests they prepare:

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

void main() {
  group('authentication', () {
    setUp(() async {
      await allure.step('reset database', (_) async {
        // ...
      });
    });

    test('login works', () async {
      // ...
    });
  });
}

Steps and attachments created inside a fixture are attached to the fixture result. Labels and links declared inside a setUp or setUpAll fixture apply to the tests in its scope.

Skip tests ​

On the drop-in wrappers, a declaration-time skip: true (or a skip message) is converted into a runtime self-skip, so the test is still reported as skipped, not left out of the report:

dart
test('checkout applies a discount', () {
  // ...
}, skip: true);

With installAllure() and the original framework imports, the same declaration produces no Allure result at all, because the framework never runs setUp for a declaration-skipped test, and that's where the adapter schedules the result. Call markTestSkipped(...) from inside the test body instead if you need a skipped result without switching to the drop-in import:

dart
test('checkout applies a discount', () {
  markTestSkipped('temporarily disabled');
});

WARNING

A drop-in group(..., skip: true) is not forwarded to the underlying framework's own group skip — each nested test still runs far enough to self-skip individually. This means setUp, setUpAll, and tearDown fixtures inside a skipped group may still run, unlike a stock declaration-time group skip, which never runs the group's fixtures at all. Skip individual tests instead of the group if fixtures must not run.

Select tests via a test plan file ​

The adapters support the standard Allure test plan mechanism via the ALLURE_TESTPLAN_PATH environment variable.

Create a JSON file such as:

json
{
  "version": "1.0",
  "tests": [{ "id": "AUTH-1" }, { "selector": "test/auth_test.dart#authentication#login works" }]
}

Then run the tests with:

bash
ALLURE_TESTPLAN_PATH=./testplan.json dart test

Entries with id match tests that declare an Allure ID, for example via the @allure.id:AUTH-1 marker. Entries with selector match the test's full name: the test file path, the group names, and the test name, joined with #.

When the tests are declared through the drop-in test, group, or testWidgets wrappers, tests not included in the plan are declaration-skipped: the body does not run, and no Allure result is written. In suites that use installAllure() with the original framework imports, excluded tests still run, but their results are left out of allure-results.

Building a custom integration ​

If you need to integrate Allure with a custom Dart test runner or framework, use allure_dart_commons:

bash
dart pub add allure_dart_commons

At that level, you create a lifecycle, start a test case, and stop and write it when execution ends:

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',
  );
  // ... update metadata, add steps, and add attachments ...
  await lifecycle.stopTest(testUuid, status: AllureStatus.passed);
  await lifecycle.writeTest(testUuid);
}

See Reference for the runtime and lifecycle APIs, or Configuration for the supported environment variables and the allure-dart.yaml config file.

Pager
Previous pageReference
Next pageConfiguration
Powered by

Subscribe to our newsletter

Get product news you actually need, no spam.

Subscribe
Allure TestOps
  • Overview
  • Why choose us
  • Cloud
  • Self-hosted
  • Success Stories
Company
  • Documentation
  • Blog
  • About us
  • Contact
  • Events
© 2026 Qameta Software Inc. All rights reserved.
A Markdown version of this page is available at /docs/dart.md