# Freemansoft Flutter Adaptivecards Flutter Adaptive Cards Testing

> Flutter Adaptive Cards Testing Skill

- Skill: `tomevault-io/freemansoft-flutter-adaptivecards-flutter-adaptive-cards-tes` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add tomevault-io/freemansoft-flutter-adaptivecards-flutter-adaptive-cards-tes`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tomevault-io/freemansoft-flutter-adaptivecards-flutter-adaptive-cards-tes/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: tomevault-io (https://skillmd.com/u/tomevault-io)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tomevault-io/freemansoft-flutter-adaptivecards-flutter-adaptive-cards-tes

---


# Flutter Adaptive Cards Testing Skill

## Overview

All library tests live under:

```bash
packages/flutter_adaptive_cards_fs/test/
```

Tests are run **from that package directory**, not the monorepo root:

```bash
cd packages/flutter_adaptive_cards_fs
fvm flutter test                        # all tests
fvm flutter test test/golden_sample_test.dart  # specific file
fvm flutter test --tags golden          # only golden image tests
fvm flutter test --update-goldens       # regenerate golden images
```

---

## Key-First Testing (Mandatory)

To ensure tests are resilient to UI refactoring, **always locate widgets via
`generateWidgetKey()` / `generateAdaptiveWidgetKey()`** rather than hardcoded
`ValueKey` strings or text/type finders.

```dart
import 'package:flutter_adaptive_cards_fs/src/utils/utils.dart';

// Extract the element map from the card body before assertions
final elementMap = map['body'][0] as Map<String, dynamic>;

// [GOOD] Derived from the same map used to build the widget
expect(find.byKey(generateWidgetKey(elementMap)), findsOneWidget);

// [GOOD] Outer StatefulWidget wrapper
expect(find.byKey(generateAdaptiveWidgetKey(elementMap)), findsOneWidget);

// [GOOD] ChoiceSet item (suffix form)
expect(
  find.byKey(generateWidgetKey(elementMap, suffix: 'Choice 1')),
  findsOneWidget,
);

// [NEVER] Hard-coded string — breaks silently if the id format changes
// find.byKey(const ValueKey('submitButton'))    ← do NOT do this

// [AVOID] Brittle and broken by text changes
// find.text('Submit')

// [AVOID] Ambiguous in large cards
// find.byType(ElevatedButton)
```

> [!IMPORTANT]
> **Never** write `find.byKey(const ValueKey('someId'))` in tests.
> If the key format ever changes, string literals silently break whereas
> `generateWidgetKey()` calls continue to match the live implementation.

---

## Core Test Utilities — `test/utils/test_utils.dart`

Import this in every test file:

```dart
import 'utils/test_utils.dart';
```

### `getTestWidgetFromPath` & `getTestWidgetFromMap` — Primary Test Helpers

These helpers load an Adaptive Card (from a file or a Map) and return a fully-wrapped `MaterialApp`.

> [!IMPORTANT]
> **Mandatory Usage**: Always use these helpers instead of `RawAdaptiveCard.fromMap` or `AdaptiveCardsCanvas` directly. They ensure that:
>
> 1. **ID Injection**: Missing IDs are recursively injected into the JSON map.
> 2. **Context**: Necessary `ProviderScope` and `InheritedAdaptiveCardHandlers` are provided.
> 3. **UI Context**: The card is wrapped in a `MaterialApp`, `Scaffold`, and `RepaintBoundary`.

**Architecture Note**: These helpers automatically wrap the card in:

1. **MaterialApp & Scaffold**: Providing necessary theme and layout context.
2. **RepaintBoundary**: With an optional `key`, used to target specific regions for golden images.
3. **InheritedAdaptiveCardHandlers**: Injects mock handlers for `onSubmit`, `onExecute`, `onChange`, etc., if provided as arguments.

```dart
Widget getTestWidgetFromPath({
  required String path,           // relative to test/samples/
  Key? key,                       // targets the RepaintBoundary for Goldens
  // ... handlers
})

Widget getTestWidgetFromMap({
  required Map<String, dynamic> map,
  required String title,
  Key? key,
  // ... handlers
})
```

---

## Widget Key Generation Patterns

All widgets use deterministic `ValueKey`s generated by two functions from
`package:flutter_adaptive_cards_fs/src/utils/utils.dart`.

| Widget Type        | Generator call                                      | Produced key            |
| ------------------ | --------------------------------------------------- | ----------------------- |
| **Card Wrapper**   | `generateAdaptiveWidgetKey(elementMap)`             | `ValueKey('{id}_adaptive')` |
| **Input Content**  | `generateWidgetKey(elementMap)`                     | `ValueKey('{id}')`      |
| **ChoiceSet Item** | `generateWidgetKey(elementMap, suffix: 'Choice 1')` | `ValueKey('{id}_Choice 1')` |
| **Modal Search**   | `generateWidgetKey(elementMap)`                     | Same id as input field  |

### Canonical test pattern

```dart
import 'package:flutter_adaptive_cards_fs/src/utils/utils.dart';

// 1. Define the card map
final Map<String, dynamic> map = {
  'type': 'AdaptiveCard',
  'body': [
    {'type': 'Input.Text', 'id': 'myField', 'label': 'Name'},
  ],
};

// 2. Pump the widget
await tester.pumpWidget(getTestWidgetFromMap(map: map, title: 'Test'));
await tester.pumpAndSettle();

// 3. Extract element map — the single source of truth for keys
final fieldMap = map['body'][0] as Map<String, dynamic>;

// 4. Find widgets
expect(find.byKey(generateAdaptiveWidgetKey(fieldMap)), findsOneWidget); // wrapper
expect(find.byKey(generateWidgetKey(fieldMap)), findsOneWidget);          // input

// 5. Interact
await tester.enterText(find.byKey(generateWidgetKey(fieldMap)), 'hello');
```

> **Reference**: See [AdaptiveWidget-Key-Generation.md](../../../../doc/AdaptiveWidget-Key-Generation.md)
> for the full key contract and automatic ID injection rules.

---

## Golden Image Tests

### Canonical Environment (Linux)

> [!WARNING]
> **Golden image pixels are platform-specific.** This project organizes golden images into platform-specific subdirectories:
>
> - `test/gold_files/linux/`: Project-wide source of truth (CI generated).
> - `test/gold_files/macos/`: Local verification images.
>
> **Updating Goldens**: Should primarily be done via CI (for Linux results). Use `getGoldenPath(filename)` to dynamically resolve the path.

### Standard Golden Pattern

```dart
testWidgets('My Card Golden', (tester) async {
  // 1. Fixed viewport
  RendererBinding.instance.renderViews.first.configuration =
      TestViewConfiguration.fromView(
        size: const Size(500, 700),
        view: PlatformDispatcher.instance.implicitView!,
      );

  const key = ValueKey('paint');

  // 2. Load and Pump
  await tester.pumpWidget(getTestWidgetFromPath(path: 'my_card.json', key: key));
  await tester.pumpAndSettle();

  // 3. Compare (Note: targets the key, uses dynamic platform path)
  await expectLater(
    find.byKey(key),
    matchesGoldenFile(getGoldenPath('my_card-base.png')),
  );
}, tags: ['golden']);
```

### Local Golden Generation for Visual Verifications

You can generate goldens on your local machine for visual verification purposes, but they will not be used for CI testing and they should not be comitted to the repository.

```bash
cd packages/flutter_adaptive_cards_fs
flutter test --update-goldens --tags golden
```

> **Warning:** Golden image pixels are platform-specific. macOS-generated
> goldens may not match Linux CI exactly. The project uses `dart_test.yaml`
> to manage this. Check `test/analysis_options.yaml` for any tag restrictions.

### Running Only Non-Golden Tests (Faster Iteration)

The local AI agents should always run the tests with the `--exclude-tags golden` flag to speed up the test execution and because local execution of golden tests will fail due to the platform aliasing issues.

```bash
flutter test --exclude-tags golden
```

---

## Test Sample Files

Sample JSON cards live in `test/samples/`.
Always add a new sample JSON when implementing a feature or fixing a bug to enable regression testing and designer validation.

1. Create `test/samples/feature_name.json`.
2. Reference via `getTestWidgetFromPath(path: 'feature_name.json')`.

---
> Source: [freemansoft/Flutter-AdaptiveCards](https://github.com/freemansoft/Flutter-AdaptiveCards) — distributed by [TomeVault](https://tomevault.io).
<!-- tomevault:4.0:skill_md:2026-05-22 -->

