semantic_gen

CI Publish Pub License: MIT

semantic_gen generates deterministic semantics wrappers for Flutter widgets so Selenium and other DOM-driven tools can discover them by stable labels. Annotate the widgets you care about (or configure the generator globally) and let build_runner do the rest at compile time.


๐Ÿš€ Quick Start

  1. Add the dependency to your Flutter package:

    dependencies:
      semantic_gen: ^0.2.3
    
    dev_dependencies:
      build_runner: ^2.7.1
    
  2. (Optional) Drop a semantic_gen.yaml next to your pubspec.yaml to tweak behaviour:

    enabled: true        # flip to false to turn the generator off
    prefix: test
    auto_wrap_widgets:
      - ElevatedButton
    
  3. Annotate a widget with @AutoTag and trigger code generation:

    flutter pub get
    dart run build_runner build -d
    
import 'package:semantic_gen/semantic_gen.dart';

@AutoTag('login')
class LoginButton extends StatelessWidget {
  const LoginButton({super.key});

  @override
  Widget build(BuildContext context) => const Text('Sign in');
}

The generator will automatically wrap the LoginButton with a Semantics widget, exposing a test:login:LoginButton label, making it Selenium-friendly.


๐Ÿงฉ Configuration

semantic_gen reads options from build.yaml first, then from an optional semantic_gen.yaml file that lives next to your pubspec.yaml. If neither provides a value, sensible defaults are used.

  • enabled (bool): set to false to disable wrapper generation without touching your source code.
  • prefix (string): customise the leading segment of every generated semantics label (defaults to test).
  • auto_wrap_widgets (list of strings): additional widget class names that should always receive wrappers.

To relocate the config file, specify config_path in build.yaml:

targets:
  $default:
    builders:
      semantic_gen:auto_tag_builder:
        options:
          config_path: tool/semantic_gen.yaml
        generate_for:
          - lib/**.dart

You can also enforce options directly in build.yaml (overriding anything in semantic_gen.yaml):

targets:
  $default:
    builders:
      semantic_gen:auto_tag_builder:
        options:
          enabled: false
          prefix: qa
          auto_wrap_widgets:
            - ElevatedButton
            - FilledButton

Environment-specific toggles

Because code generation happens during the build_runner step (before your app runs), --dart-define values are not visible to semantic_gen. To turn the generator on only for select build pipelines, drive it via configuration files and build_runner overrides instead:

  1. Keep generation disabled by default in semantic_gen.yaml:

    enabled: false
    
  2. Create an environment-specific override (for example semantic_gen.staging.yaml) that flips the flag and tweaks any other options you need:

    enabled: true
    prefix: staging
    
  3. In your staging build script, run:

    flutter pub run build_runner build --delete-conflicting-outputs \
      --define semantic_gen:auto_tag_builder=config_path=semantic_gen.staging.yaml
    

Production builds can omit the --define (or point it at a different file), keeping wrappers disabled. This approach ensures only the desired environments emit the generated semantics wrappers.


๐Ÿ”– Generated Wrappers & Annotations

  • Default coverage: Text, SelectableText, TextField, TextFormField, GestureDetector, InkWell, and common Material tap targets (e.g. ElevatedButton, FilledButton, OutlinedButton, TextButton, IconButton, FloatingActionButton, DropdownButton, MenuItemButton, PopupMenuButton, and the ListTile variants) are auto-wrapped with Semantics(label: 'test:auto:<TypeName>').
  • Custom classes: Annotate widgets with @AutoWrapWidgets(['ElevatedButton']) or use build.yaml to list additional types.
  • Explicit IDs: Apply @TestId('login-button') or testTag('checkout-button', child) when you need deterministic identifiers.
  • Runtime helper: testTag() exposes convenience parameters to mark buttons, text fields, and other semantics roles.

Refer to the API docs (dart doc) for full annotation behavior and generator options.


๐Ÿงช Example & Selenium Integration

The example/ app shows auto-tagging, manual tagging, and Selenium wiring. Launch it with:

flutter run -d chrome example

In Selenium, enable semantics DOM once per load and query by ARIA label:

const loginButton = driver.findElement(By.css('[aria-label="test:login-button"]'));
loginButton.click();

example/test_driver/selenium_demo.md documents the end-to-end setup, including enabling the Flutter semantics tree.


๐Ÿ› ๏ธ Developer Workflow

Task How
Format dart format .
Analyze flutter analyze && dart analyze
Generate code dart run build_runner build -d
Run tests dart test && flutter test test/runtime_test.dart
Quality gate pana .
Toggle semantics semantic_gen.yaml: enabled: false (or override in build.yaml)

Update semantic_gen.yaml or the builder options in build.yaml whenever you need to change prefixes, toggle coverage, or temporarily disable generation.


๐Ÿ’ก Contributing

  1. Fork and clone the repository.
  2. Install dependencies: flutter pub get.
  3. Make changes, keeping lint warnings at zero (flutter analyze).
  4. Regenerate code and tests as needed.
  5. Update README.md, CHANGELOG.md, and docs when APIs change.
  6. Run the full test suite (dart test test/vm and flutter test test/runtime_test.dart) and ensure pana . reports no actionable issues.

Submit a PR with a descriptive title, linked issue (if applicable), and screenshots or logs for visual changes.


๐Ÿ“ฆ Release Checklist

  • Update pubspec.yaml version and keep CHANGELOG.md in sync.
  • Verify documentation: dart doc and README sections.
  • Refresh screenshots/GIFs referenced in the README.
  • Run dart format, flutter analyze, dart test test/vm, flutter test test/runtime_test.dart, and pana ..
  • Execute flutter pub publish --dry-run and record the output in CI artifacts.
  • Tag the release (git tag v<version>) before publishing.
  • Push the release tag (v<version>) to trigger the automated Publish workflow configured via pub.dev's OIDC integration (no stored secrets required).

๐Ÿ“œ License

Released under the MIT License. See LICENSE for details.

Libraries

semantic_gen