automation_keys_gen 0.1.5
automation_keys_gen: ^0.1.5 copied to clipboard
Enforces a consistent automation key contract for Flutter UI tests, with CLI validation and generated Markdown documentation.
automation_keys_gen #
A Flutter/Dart package that enforces a single, consistent automation key system.
Pub.dev: https://pub.dev/packages/automation_keys_gen
Repository: https://github.com/alpinnz/automation_keys_gen
Issues: https://github.com/alpinnz/automation_keys_gen/issues
Public API #
This package intentionally keeps its public surface small:
AutomationKeyHelper(mixin): the only supported way to generate keysAutomationKeyDescription(annotation): optional metadata used only to enrich generated documentation
Do not use
Key('...')/ValueKey('...')directly. The validator will fail.
Installation #
Add to your pubspec.yaml:
dev_dependencies:
automation_keys_gen: ^0.1.5
Configuration #
In your app's pubspec.yaml:
automation_keys_gen:
app_name: core
Rules:
- lowercase
snake_case- non-empty
Resolution order for appName:
appNameOverride(page-level override)automation_keys_gen.app_namefrompubspec.yaml- fallback:
app
Key pattern #
Canonical pattern:
{app}_{module}_{feature}_{screen?}_{type}_{name}
Usage (Widgets) #
Every page should mix in AutomationKeyHelper and provide context.
This example shows both:
- Declaration-level annotation (
@AutomationKeyDescription(...)) forpageKeyand reusable key variables. - Widget-level inline directive (
/// @AutomationKeyDescription: ...) directly above the widget line that calls...Key('...').
import 'package:automation_keys_gen/automation_keys_gen.dart';
import 'package:flutter/material.dart';
@AutomationKeyDescription('Catalog list page. Demonstrates pageKey + widget-level descriptions.')
class CatalogListPage extends StatelessWidget with AutomationKeyHelper {
const CatalogListPage({super.key});
@override
String get moduleName => 'catalog';
@override
String get featureName => 'list';
@override
Widget build(BuildContext context) {
@AutomationKeyDescription('Search input used to filter catalog items.')
final searchKey = inputKey('search');
return Scaffold(
key: pageKey,
appBar: AppBar(
/// @AutomationKeyDescription: Page title text in the AppBar.
title: Text('Catalog', key: textKey('page_title')),
),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextField(
key: searchKey,
decoration: const InputDecoration(labelText: 'Search'),
),
const SizedBox(height: 12),
/// @AutomationKeyDescription: Primary CTA button to open the item detail page.
ElevatedButton(
key: buttonKey('open_detail'),
onPressed: () {},
child: const Text('Open detail'),
),
],
),
),
);
}
}
Reusable widget rule #
Reusable widgets should not generate automation keys by themselves. Pass the key from the page instead:
final widget = ReusableInput(automationKey: inputKey('search'));
Description best practices #
You can document keys in two consistent ways:
- Declaration annotation (preferred for pages and reusable key variables)
-
Required for pages: put it on the page class to describe
pageKey.@AutomationKeyDescription('Catalog list screen.') class CatalogListPage extends StatelessWidget with AutomationKeyHelper { const CatalogListPage({super.key}); @override String get moduleName => 'catalog'; @override String get featureName => 'list'; @override Widget build(BuildContext context) => const SizedBox.shrink(); } -
Recommended for key variables you reuse multiple times in a build:
@AutomationKeyDescription('Primary submit button.') final submitKey = buttonKey('submit');
- Inline doc directive (preferred when you want description next to the widget)
Dart annotations cannot be attached to widget expressions, so for inline usage use:
/// @AutomationKeyDescription: Page title in the AppBar.
final appBar = AppBar(
title: Text('Catalog', key: textKey('page_title')),
);
CLI #
You can use either the full CLI commands (recommended for copy/paste) or the Makefile.
Full commands #
flutter pub get
flutter analyze
flutter test
dart run automation_keys_gen validate
dart run automation_keys_gen generate
Makefile shortcuts #
make validate
make generate
Outputs:
automation_keys.gen.md(success)automation_keys_errors.gen.md(when validation fails)
Best practices (consistent keys) #
Input field + helper/assistive text #
If a screen has both an input widget and helper/assistive text, keep selectors stable by:
- using
inputKey('email')for the actual input widget - giving the helper/assistive/error text its own key using an existing type that matches your UI (commonly
textKey('email_helper')orerrorStateKey('email_error'))
This avoids overloading one key for two different semantics.
Toast / snackbar / overlays #
Treat toast/snackbar as an overlay element. Prefer giving the root toast widget a key using:
bannerKey('toast_success')for success/info banners/toastserrorStateKey('toast_error')for error toasts- or
dialogKey(...)/bottomSheetKey(...)if your toast is implemented as a dialog/bottom sheet
If you use ScaffoldMessenger (SnackBar), attach the key to a widget inside the snackbar content (e.g. a Text or a wrapper Container) so your tests can reliably find it.
Makefile #
Common commands:
make get
make analyze
make test
make validate
make generate
make publish-dry-run