self_test 0.1.0 copy "self_test: ^0.1.0" to clipboard
self_test: ^0.1.0 copied to clipboard

Automated regression testing for Flutter through direct callback invocation. Run tests in live app environments without UI simulation.

self_test #

pub package

Automated regression testing for Flutter through direct callback invocation. Unlike traditional testing frameworks that simulate UI interactions, self_test invokes widget callbacks directly, providing fast and reliable testing for development and pre-production environments.

🤖 AI-Powered Testing: Pair with self_test_mcp to enable Claude and other AI agents to test your Flutter apps with Playwright feature parity - works on iOS, Android, Web, and Desktop!

Features #

Core Testing #

  • Direct Callback Invocation - Execute user actions by calling widget callbacks directly instead of injecting touch events
  • Runtime Testing - Run tests in live app environments without external test frameworks
  • Text Assertions - Built-in text validation for input fields
  • Memory Safe - Automatic registration/unregistration prevents memory leaks
  • Hot Restart Compatible - Works seamlessly with Flutter's hot restart
  • Test Scenarios - Define and run multi-step test scenarios with TestScenario

AI-Powered Testing (with MCP) #

  • 60+ Playwright-Equivalent Tools - Full feature parity with Playwright browser testing
  • State Management Inspection - Inspect and modify Riverpod, Bloc, and Provider state
  • Network Mocking - Mock HTTP responses, block requests, monitor traffic
  • Visual Regression - Golden file comparison for UI testing
  • Platform Mocking - Mock GPS, permissions, platform channels, sensors
  • Cross-Platform - Works on iOS, Android, Web (with or without bridge), Desktop
  • Bridgeless Web Testing - Test any Flutter web app via Playwright + semantics tree

Installation #

Core Package Only #

Add to your pubspec.yaml:

dependencies:
  self_test: ^0.1.0

Then run:

flutter pub get

With AI-Powered Testing (Optional) #

For AI agent integration with Claude Code:

  1. Install MCP server:

    git clone https://github.com/loonix/self_test
    cd self_test/packages/self_test_mcp
    npm install && npm run build
    ./scripts/setup-claude.sh
    
  2. Add bridge to your app:

    dependencies:
      self_test_bridge:
        git:
          url: https://github.com/loonix/self_test
          path: packages/self_test_bridge
    

See Architecture section below for details.

Sponsors #

Objais
Proudly sponsored by Objais

Quick Start #

1. Wrap Your App Root #

import 'package:self_test/self_test.dart';

void main() {
  runApp(SelfTestRoot(child: MyApp()));
}

2. Wrap Interactive Widgets #

SelfTestableWidget(
  id: 'username_field',
  onTextChange: (value) => setState(() => username = value),
  child: TextField(
    decoration: InputDecoration(labelText: 'Username'),
    onChanged: (value) => setState(() => username = value),
  ),
),

3. Run Tests #

SelfTestManager().enterText('username_field', 'john_doe');
SelfTestManager().trigger('login_button');
await SelfTestManager().waitForAnimations();

Usage #

Code Generation with Annotations #

For type-safe test controllers, annotate your callback methods:

import 'package:self_test/self_test.dart';

part 'login_form.self_test.g.dart';

class _LoginFormState extends State<LoginForm> {
  @SelfTestButton('login_btn')
  void onLoginPressed() { /* ... */ }

  @SelfTestInput('username_field')
  void onUsernameChanged(String value) { /* ... */ }

  @SelfTestInput('password_field')
  void onPasswordChanged(String value) { /* ... */ }
}

Generate the controller:

flutter pub run build_runner build

Use the generated controller:

final controller = LoginFormTestController();

controller.enterUsernameField('john_doe');
controller.enterPasswordField('secret123');
controller.tapLoginBtn();
controller.expectUsernameFieldText('john_doe');

Test Scenarios #

Define multi-step test scenarios:

final scenario = TestScenario(
  name: 'Login flow',
  steps: [
    TestStep.enterText('username_field', 'user@example.com'),
    TestStep.enterText('password_field', 'password123'),
    TestStep.tap('login_button'),
    TestStep.wait(Duration(milliseconds: 500)),
    TestStep.screenshot('after_login'),
  ],
);

final result = await scenario.run();
print(result.allPassed ? 'All steps passed' : 'Failed at step ${result.failedAtStep}');

Widget Testing #

Integrate with flutter_test:

testWidgets('Login flow test', (WidgetTester tester) async {
  SelfTestManager().setTestMode(true);

  await tester.pumpWidget(MyApp());
  await tester.pumpAndSettle();

  SelfTestManager().enterText('username_field', 'testuser');
  SelfTestManager().trigger('login_button');
  await tester.pump();

  expect(find.text('Login successful!'), findsOneWidget);
});

Enabling Self-Test Mode #

// In debug/profile builds
SelfTestManager().setSelfTestModeActive(true);
SelfTestManager().restartWidgetTree();

// In test environments
SelfTestManager().setTestMode(true);

API Reference #

SelfTestManager #

Singleton managing test nodes and actions.

Method Description
trigger(id) Tap a button by ID
enterText(id, text) Enter text in a field by ID
waitForAnimations() Wait for UI updates
restartWidgetTree() Force widget tree rebuild
captureScreenshot([name]) Capture a screenshot
registerTestNode(node) Register a test node
unregisterTestNode(id) Unregister a test node
setSelfTestModeActive(bool) Enable/disable in debug/profile
setTestMode(bool) Enable/disable in test environments

SelfTestableWidget #

SelfTestableWidget({
  required String id,
  required Widget child,
  VoidCallback? onTap,
  ValueSetter<String>? onTextChange,
})

Annotations #

@SelfTestButton(String id)  // For tappable widgets
@SelfTestInput(String id)   // For text input widgets

Architecture #

The self_test ecosystem consists of three components:

┌─────────────────────────────────────────────────────────────────┐
│                      AI Agent (Claude)                           │
└─────────────────────────────┬───────────────────────────────────┘
                              │ MCP Protocol
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                   self_test_mcp Server                           │
│  • 60+ Playwright-equivalent tools                               │
│  • Actions: tap, type, scroll, drag                             │
│  • Assertions: expect, visual regression                        │
│  • State inspection: Riverpod, Bloc, Provider                   │
│  • Network mocking & monitoring                                 │
└─────────────────────────────┬───────────────────────────────────┘
                              │ WebSocket
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                Flutter App + self_test_bridge                    │
│  • Receives commands from MCP                                    │
│  • Executes via self_test callbacks                             │
│  • Works on iOS, Android, Web, Desktop                          │
└─────────────────────────────────────────────────────────────────┘

Components #

Package Description When to Use
self_test (this package) Core testing framework with direct callback invocation Always - enables runtime testing in your Flutter app
self_test_bridge WebSocket bridge connecting MCP to Flutter When using AI-powered testing with Claude
self_test_mcp MCP server with 60+ tools for AI agents When using AI agents for automated testing

AI-Powered Testing with MCP #

The self_test MCP (Model Context Protocol) server enables AI agents like Claude to test your Flutter apps with Playwright feature parity.

Platform Support #

Platform Bridge Required How It Works
iOS ✅ Yes Bridge runs WebSocket server on device, MCP connects
Android ✅ Yes Bridge runs WebSocket server on device, MCP connects
Web (with bridge) ✅ Yes Bridge embedded in web app, MCP connects
Web (bridgeless) ❌ No MCP uses Playwright + Flutter semantics tree
Desktop ✅ Yes Bridge runs WebSocket server in app, MCP connects

Quick Start with MCP #

1. Install MCP Server

cd packages/self_test_mcp
npm install && npm run build

# Add to Claude Code automatically
./scripts/setup-claude.sh

Or manually add to ~/.claude/settings.json:

{
  "mcpServers": {
    "flutter-self-test": {
      "command": "node",
      "args": ["/path/to/self_test_mcp/dist/index.js"],
      "env": {
        "FLUTTER_APP_HOST": "localhost",
        "FLUTTER_APP_PORT": "9999"
      }
    }
  }
}

2. Add Bridge to Flutter App

Add to pubspec.yaml:

dependencies:
  self_test_bridge:
    git:
      url: https://github.com/loonix/self_test
      path: packages/self_test_bridge

Add to main.dart:

import 'package:flutter/foundation.dart';
import 'package:self_test_bridge/self_test_bridge.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Start bridge in debug mode only
  if (kDebugMode) {
    final bridge = SelfTestBridge(port: 9999);
    await bridge.start();
  }

  runApp(SelfTestRoot(child: MyApp()));
}

3. Test with Claude

Open Claude Code and ask:

Test the login flow in my Flutter app:
1. Enter username "test@example.com"
2. Enter password "password123"
3. Tap login button
4. Verify we navigated to the dashboard

Claude will use the MCP tools to interact with your app!

Web-External Mode (No Bridge Required!) #

Test any Flutter web app without code changes using Playwright:

# Configure for web-external mode
export BRIDGE_MODE=web-external
export FLUTTER_APP_URL=https://your-app.com
export PLAYWRIGHT_HEADLESS=false

# Run MCP server
npm start

Perfect for:

  • Production web apps
  • Third-party Flutter apps
  • CI/CD smoke tests
  • Quick exploratory testing

Available MCP Tools #

The MCP server provides 60+ tools with Playwright feature parity:

Locators & Queries:

  • flutter_snapshot - Get widget tree
  • flutter_get_by_role - Find by semantic role
  • flutter_get_by_text - Find by text content

Actions:

  • flutter_tap, flutter_type, flutter_clear, flutter_scroll
  • flutter_drag, flutter_hover, flutter_focus
  • flutter_long_press, flutter_double_tap

Assertions:

  • flutter_expect - Assert widget state (toBeVisible, toHaveText, etc.)
  • flutter_expect_screenshot - Visual regression testing

State Management:

  • flutter_get_state - Inspect Riverpod/Bloc/Provider state
  • flutter_dispatch_action - Dispatch events/actions
  • flutter_watch_state - Subscribe to state changes

Network:

  • flutter_mock_http - Mock API responses
  • flutter_block_http - Block requests
  • flutter_network_log - Monitor network traffic

Platform Mocking:

  • flutter_set_geolocation - Mock GPS
  • flutter_set_permission - Mock permissions
  • flutter_mock_channel - Mock platform channels

[See full tool list in packages/self_test_mcp/README.md]

Ecosystem #

Contributing #

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests
  5. Run the test suite: flutter test
  6. Submit a pull request

License #

Copyright (c) 2025-2026 Ari Silva, Daniel Carneiro. All rights reserved.

This software may be used and modified in your own products and services, but may not be sold or redistributed as a standalone product. See the LICENSE file for details.

0
likes
140
points
10
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Automated regression testing for Flutter through direct callback invocation. Run tests in live app environments without UI simulation.

Repository (GitHub)
View/report issues

Topics

#testing #flutter #regression #automation

License

unknown (license)

Dependencies

analyzer, build, dart_style, flutter, meta, source_gen

More

Packages that depend on self_test