Spec Testing Framework
repository·main·Indexed 43 days ago
https://github.com/invertase/specA streamlined, type-safe testing framework for Dart and Flutter. It provides a declarative API for writing tests with improved IDE autocompletion and a Jest-inspired CLI tool featuring interactive watch mode, parallel execution, and CI integration via a GitHub Action.
What's inside Spec
- Spec is a streamlined testing framework for Dart and Flutter that builds on top of existing testing tools. It provides a more declarative, type-safe, and elegant testing environment designed to reduce errors and improve IDE autocompletion. Spec is available as both a CLI tool for running tests and a Dart package for writing them.
Overview of Spec
mainSpec is a streamlined testing framework for Dart and Flutter. It builds on top of existing Dart and Flutter testing tools to provide a more elegant testing environment. Spec is distributed as both a CLI tool for running tests and a Dart package for writing them.Use the Spec CLI to run tests
mainThe Spec CLI provides an intuitive testing output interface inspired by Jest. Key features include:
- Interactive Mode: Use
spec --watchto automatically re-run tests when source code changes and to specifically rerun only failed tests. - Parallel Execution: Run both Dart and Flutter tests in parallel with a single command.
- Multi-package Support: Run tests from multiple packages simultaneously using Melos.
To run your tests, use the
speccommand in your terminal.spec --watch- Interactive Mode: Use
Use the Spec GitHub Action
mainTo integrate Spec into your CI/CD pipeline, use the Spec GitHub action. Detailed configuration instructions are available on the action's marketplace page or in its dedicated repository.Write type-safe tests with the Spec package
mainThe
specpackage provides a declarative, type-safe API for writing tests, designed to improve IDE autocompletion and reduce errors compared to standard Dart testing syntax.Comparison
Standard Dart testing (not type-safe):
expect(value, equals(42)); await expectLater(Future.value(42), completion(equals(42)));With Spec (type-safe):
expect(value).toEqual(42); await expect(Future.value(42)).completion.toEqual(42);test('dart test example', () async { int value = 42; // Without spec - not type safe expect(value, equals(42)); await expectLater(Future.value(42), completion(equals(42))); // With spec - type safe expect(value).toEqual(42); await expect(Future.value(42)).completion.toEqual(42); });Install the Spec CLI
mainTo use the Spec CLI for running tests with an intuitive interface, activate it globally using the Dart package manager:
dart pub global activate spec_cliUse Spec matchers for testing Futures, Streams, and Functions
mainThe
specpackage provides declarative, type-safe matchers that extend standard Darttestmatchers. These are designed to improve readability and IDE autocompletion.Testing Futures
Use
.completionto assert the value resolved by a Future.Testing Streams
Use
.emitsto assert values, nullity, or errors emitted by a Stream.Testing Functions
Use
.returnsNormally()or.throwsto assert the behavior of a function call.import 'package:spec/spec.dart'; void main() { test('future example', () async { final future = Future.value(42); expect(future).toEqual(future); await expect(future).completion.toEqual(42); await expect(future).throws.isArgumentError(); }); test('stream example', () async { final stream = Stream.value(42); await expect(stream).emits.toEqual(42); await expect(stream).emits.isNull(); await expect(stream).emits.not.isNull(); await expect(stream).emitsError.isArgumentError(); }); test('function example', () { void throwsFn() => throw Error(); expect(throwsFn).returnsNormally(); expect(throwsFn).throws.isArgumentError(); }); }Interactive commands in `spec` watch mode
mainWhen running in
--watchmode, the CLI becomes interactive. You can use specific key presses to control the test runner:Watch Mode Controls
Key Action qStop the watch mode. wToggle the tooltip explaining available commands. fToggle "run failing tests only" mode. tStart editing the test name filter. gToggle --update-goldensmode.EnterIf tests are running: Stop them. If tests are idle: Restart them. Test Name Filter Editing
When in the test name filter editing mode (triggered by
t):- Characters: Type to append to the filter string.
Enter: Submit the filter and restart tests. |Escape: Abort the edit and return to watch mode. |Delete: Remove the last character from the filter string. |
Use Spec CLI interactive watch mode
mainSpec supports an interactive watch mode that automatically re-runs tests when source code changes. You can trigger manual runs or filter tests using keyboard shortcuts.
To start watch mode, use:
spec --watchWatch Mode Shortcuts:
f: Run only failed tests.t: Filter by a test name regex pattern.Enter: Trigger a test run.q: Quit watch mode.
Run tests with the Spec CLI
mainThe Spec CLI allows you to run Dart and Flutter tests in parallel with a single command. It provides a Jest-inspired output interface.
To run all tests in your project, use:
specAssert that a Future does not complete
mainThe
doesNotComplete()method allows you to match aFuturethat is expected to remain pending and never complete.Warning: This creates an asynchronous expectation. The
expect()call containing this matcher will return immediately, and execution will continue without waiting for the future to resolve or fail.expect(myFuture).doesNotComplete();Assert that a function returns normally
mainUse the
returnsNormally()extension method on anExpectation<Fn>to assert that a function call does not throw any exceptions. The function will be called exactly once, and any exceptions thrown will be swallowed by the matcher.Note: The function being tested must not take arguments. If you need to test a function with arguments, wrap it in an anonymous function (closure) first.
// Example: testing a function that takes no arguments expect(() => myFunc(), returnsNormally); // Example: testing a function with arguments using a wrapper expect(() => myFuncWithArgs(1, 2), returnsNormally);