A command-line tool for automating integration tests through declarative YAML configuration. Define your test flows in human-readable YAML files and execute them across local or remote environments. Currently supports Flutter with an extensible architecture for additional frameworks.
- Declarative Test Definition: Write integration tests in YAML with intuitive step-by-step actions
- Code Generation: Automatically generate Dart integration test files from YAML definitions
- Flexible Execution: Run tests locally or remotely with environment-specific configuration
- Lifecycle Hooks: Define custom hooks for system verification, preparation, and test lifecycle events
- Dependency Management: Verify system dependencies before test execution
- JSON Schema Support: Full schema validation for configuration and test files
- Rust (2024 edition or later)
- Cargo build tool
- Project-specific dependencies (e.g., Flutter SDK 3.29.2+ for Flutter projects)
Clone the repository and build the project:
git clone <repository-url>
cd playmaster
cargo build --release
The compiled binary will be available at ./target/release/playmaster
.
The tool provides three main commands:
playmaster gen
Generates integration test files from YAML feature test definitions in the feature_test/
directory. The output format depends on your project_type
configuration (e.g., Dart for Flutter projects).
playmaster schema
Generates JSON schema files for configuration and feature test validation. Schemas are output to src/schemas/generated/
:
config.json
- Main configuration schemafeature_test_schema.json
- Feature test definition schema
# Run tests locally (default)
playmaster run
# Run tests in local mode (explicit)
playmaster run --mode local
# Run tests in remote mode
playmaster run --mode remote
Executes the integration tests based on your configuration and feature test definitions.
Create a playmaster.yaml
in your project root directory:
project_type: flutter
dependencies:
- name: flutter
min_version: "3.29.2"
version_command: flutter --version | head -n 1 | awk '{print $2}'
hooks:
- name: Custom Hook
hook_type: prepare_system
command: "echo"
args: ["Running preparation hook"]
async: true
env:
TEST_ENV: 1
Configuration Schema: See config.json for the complete JSON schema.
Hooks execute at different lifecycle stages:
connect
- Establish connections to remote hostsverify_system
- Verify system prerequisitesprepare_system
- Prepare the system before testsbefore_all
- Run before all testsbefore_test
- Run before each individual testafter_test
- Run after each individual testafter_all
- Run after all tests complete
Create YAML test files in the feature_test/
directory:
PlayMaster supports two sources of variables for your feature tests:
- Global vars files: Any
*.vars.yaml
insidefeature_test/
- Local vars: A
vars:
section at the top of each*.test.yaml
These variables are simple flat key/value strings and can be referenced in test steps using the ${...}
syntax.
- Location: place them under
feature_test/
- File name format:
<Name>.vars.yaml
- At codegen time (
playmaster gen
), a Dart class is generated for each file inintegration_test/generated/vars.dart
.- Class name =
<Name>
converted to PascalCase - Each key becomes a
static const
string on that class
- Class name =
Example file feature_test/common.vars.yaml
(see sample at samples/flutter_sample_app/feature_test/common.vars.yaml
):
validEmail: "[email protected]"
This produces a Dart class similar to:
// in integration_test/generated/vars.dart
class Common {
static const validEmail = '[email protected]';
}
You can then reference it in tests as ${Common.validEmail}
.
Define a vars:
mapping at the top of your *.test.yaml
. Keys and values must be strings.
Example file feature_test/ftue.test.yaml
(excerpt; see sample at samples/flutter_sample_app/feature_test/ftue.test.yaml
):
name: First Time User Experience
description: >
Covers the FTUE flow, which is just the login for now
vars:
validPassword: "password123"
invalidPassword: "wrongpassword"
tests:
- name: Successful Login
description: Enters the correct username and password and logs in
steps:
- wait_for:
text: "Login"
- tap:
placeholder: "Email"
- type:
by:
placeholder: "Email"
value: "${Common.validEmail}" # from common.vars.yaml
- type:
by:
placeholder: "Password"
value: "${validPassword}" # from this file
- tap:
text: "Sign In"
- wait_for:
progress: linear
- wait_for:
text: "Welcome"
- match:
screenshot: "screenshot_welcome"
Feature Test Schema: See feature_test_schema.json for the complete JSON schema.
-
wait_for
text: "string"
- Wait for text to appeardelay: milliseconds
- Wait for a specific durationprogress: linear|radial
- Wait for progress indicator
-
tap
text: "string"
- Tap element by textplaceholder: "string"
- Tap element by placeholder text
-
type
by: { text: "string" }
- Type in element found by textby: { placeholder: "string" }
- Type in element found by placeholdervalue: "string"
- Value to type
-
match
text: "string"
- Assert text existsscreenshot: "name"
- Compare screenshot against golden file
- Use
${Common.key}
to read from a global vars file namedcommon.vars.yaml
(classCommon
). - Use
${localKey}
to read from the localvars:
block in the same.test.yaml
. - Vars are plain strings (no nested objects, arrays, or expressions).
playmaster/
├── src/
│ ├── code_gen/ # Test code generation from YAML
│ ├── code_run/ # Test execution logic
│ ├── hooks/ # Lifecycle hook implementations
│ ├── linux/ # Linux-specific utilities
│ ├── models/ # Data models (config, args, feature tests)
│ ├── schemas/ # JSON schema generation
│ │ └── generated/ # Generated JSON schemas
│ └── utils/ # Utility functions
├── samples/ # Example applications for different project types
│ └── flutter_sample_app/ # Example Flutter application
│ ├── feature_test/ # Example feature test definitions
│ └── playmaster.yaml # Sample configuration
├── Cargo.toml # Rust dependencies
└── README.md # This file
-
Set up your project structure:
your_project/ ├── playmaster.yaml └── feature_test/ └── login.test.yaml
-
Define your configuration (
playmaster.yaml
) -
Write feature tests in
feature_test/*.test.yaml
-
Generate schemas (optional, for IDE autocomplete):
playmaster schema
-
Generate Dart test files:
playmaster gen
-
Run the tests:
playmaster run --mode local
The following features are planned but not yet implemented:
- Remote Device Support: Full implementation of remote test execution on devices (e.g., GameOS devices)
- Remote Connection Management: Automated SSH/network connection handling for remote targets
- Device Discovery: Automatic discovery of test devices on LAN
- Multi-Resolution Testing: Run test suites across multiple screen resolutions automatically
- Parallel Test Execution: Run tests concurrently across multiple devices/resolutions
- LAN Test Orchestration: Coordinate test execution across multiple machines on local network
- Cloud Orchestration (Future): Cloud-based test coordination and scheduling
- Screenshot Comparison: Pixel-perfect screenshot matching for design validation
- Multi-Resolution Screenshots: Capture and compare screenshots across different resolutions
- Golden File Management: Tools for managing and updating golden screenshot files
- Test Reports: Generate comprehensive HTML/JSON test reports with:
- Test execution results
- Screenshot diffs and comparisons
- Performance metrics
- Historical trend analysis
- Service Management Hooks: Pre-test hooks for ensuring required services (e.g., playserve) are running
- Dependency Targeting: Specify and validate specific versions of dependencies for test runs
- Better Error Messages: Enhanced error reporting and debugging information
- Test Replay/Debug Mode: Step-through debugging for failed tests
- Additional Framework Support: Extend beyond Flutter (e.g., React Native, native mobile apps)
- Custom Action Plugins: Extensible action system for framework-specific test steps
- Environment Profiles: Named configuration profiles for different test environments
- Test Tagging: Tag tests for selective execution (smoke, regression, etc.)
- Retry Logic: Configurable retry strategies for flaky tests
Contributions in any of these areas are welcome! See the Contributing section below for guidelines.
Contributions are welcome! Please ensure:
- Code follows Rust best practices
- Tests pass before submitting PRs
- Documentation is updated for new features
For issues, questions, or contributions, please open an issue in the repository.