ワンクリックで
golden-test
Create Golden tests for an existing feature - Deterministic, convention-compliant golden test generation for feature pages
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Create Golden tests for an existing feature - Deterministic, convention-compliant golden test generation for feature pages
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
Create a new feature — implement a screen, add a page, scaffold a flow, implement an API spec (OpenAPI/Swagger), or build a new data layer + UI. Use for ANY prompt that mentions: feature, screen, page, API spec, swagger, openapi, implement, build from spec.
Create BLoC and Service unit tests for an existing feature - Deterministic, high-signal unit test generation
SOC 職業分類に基づく
| name | golden_test |
| description | Create Golden tests for an existing feature - Deterministic, convention-compliant golden test generation for feature pages |
This skill guides the AI agent in creating golden tests for Flutter feature pages, adhering strictly to the established architecture and patterns.
Reference implementation:
test/feature_profile/— this is the canonical example
To successfully execute this skill, the following inputs MUST be provided:
feature_profile or lib/feature_profile)Convention conformance > Visual coverage > Quantity
Every golden test must follow the exact patterns from the reference implementation. The agent must understand the infrastructure before generating any test.
Golden tests cover whole pages/screens only.
test/feature_<name>/view/The project uses the Alchemist package (package:alchemist/alchemist.dart).
test/flutter_test_config.dart_light / _dark suffix from the scenario name and routes the .png into goldens/light_theme/ or goldens/dark_theme/ProcreditFileComparator with 0% toleranceProI18n, I18n, GlobalMaterialLocalizations and DesignSystem.fromBrightness(Brightness.light) themeLocale('bg')You never specify a path to goldens/ manually. The scenario name + theme enum determine the output path automatically.
test/helpers/enums/app_themes.dartenum Themes {
light,
// dark, (currently disabled)
}
test/helpers/golden_helper.dartEvery golden renders across 7 devices:
| Device | Size | Pixel Ratio | Safe Area |
|---|---|---|---|
| iPhone SE (2nd gen) | 375×667 | 2.0 | top: 20 |
| Google Pixel 4a | 412×732 | 1.0 | none |
| iPhone 13 mini | 375×812 | 3.0 | top: 44, bottom: 34 |
| Google Pixel 5 | 393×851 | 2.75 | top: 24, bottom: 48 |
| Samsung Galaxy S20 | 412×915 | 3.0 | top: 24, bottom: 48 |
| Samsung Galaxy Tab S6 | 1280×800 | 2.0 | top: 24, bottom: 48 |
| Apple iPad Pro 12.9 | 1024×1366 | 2.0 | top: 24, bottom: 34 |
test/feature_<name>/
├── factory/ # Widget factories for golden tests
│ └── <page_name>_factory.dart
├── mock/ # Mockito mock factories + generated files
│ ├── <bloc_name>_mock.dart
│ └── <bloc_name>_mock.mocks.dart # Auto-generated by build_runner
└── view/ # Golden test files + generated images
├── goldens/
│ └── light_theme/
│ └── <scenario_name>.png # Auto-generated by --update-goldens
└── <page_name>_golden_test.dart
.png filesgoldens/dark_theme/ (when enabled)| Artifact | Pattern | Example |
|---|---|---|
| Golden test file | <page_snake_case>_golden_test.dart | profile_golden_test.dart |
| Factory file | <page_snake_case>_factory.dart | profile_factory.dart |
| Mock file | <bloc_snake_case>_mock.dart | profile_mock.dart |
| Generated mock | <bloc_snake_case>_mock.mocks.dart | profile_mock.mocks.dart |
| Golden image | <scenario_name>.png (auto-resolved) | profile_success.png |
The scenario name passed to Scenario(name: '...') becomes the golden filename.
<page_prefix>_<state>[_<variant>]
profile_, branch_network_page_)_success, _loading, _error)_light / _dark suffix is appended automatically — never add it yourself| Scenario Name | Meaning |
|---|---|
profile_success | default success state |
profile_success_toggled | success with biometrics/notifications enabled |
profile_loading | loading state |
profile_error | error state |
Before generating golden tests for any feature, the agent MUST:
lib/feature_<name>/views/ to identify the page and its UI stateslib/feature_<name>/di/ to identify all provider dependencieslib/feature_<name>/blocs/ to identify all BLoC state streamstest/feature_<name>/ to inventory existing test coveragetest/mocks/stubs.dart for available test datatest/mocks/ and test/base/ for existing shared mock factoriesIn test/feature_<name>/mock/<bloc>_mock.dart:
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:procredit/<feature>/blocs/<bloc>.dart';
import 'package:rx_bloc/rx_bloc.dart';
import 'package:rxdart/rxdart.dart';
import '<bloc>_mock.mocks.dart';
@GenerateMocks([<Bloc>BlocStates, <Bloc>BlocEvents, <Bloc>BlocType])
<Bloc>BlocType <bloc>MockFactory({
Result<MyDomainModel>? dataResult,
bool? someToggle,
// ... all state parameters
}) {
final blocMock = Mock<Bloc>BlocType();
final eventsMock = Mock<Bloc>BlocEvents();
final statesMock = Mock<Bloc>BlocStates();
when(blocMock.events).thenReturn(eventsMock);
when(blocMock.states).thenReturn(statesMock);
// Wire each state stream
when(statesMock.dataResult).thenAnswer(
(_) => dataResult != null ? Stream.value(dataResult) : const Stream.empty(),
);
when(statesMock.someToggle).thenAnswer(
(_) => someToggle != null ? Stream.value(someToggle) : const Stream.empty(),
);
// ... wire all remaining states ...
return blocMock;
}
@GenerateMocks goes in the mock file, never in the test or factory fileMissingStubError)const Stream.empty()dart run build_runner build after creating/modifying mock files| Stream type | Pattern |
|---|---|
| Simple fire-once (errors, loading) | Stream.value(x) or const Stream.empty() |
| States needing replay (dialogs, toggles) | .publishReplay(maxSize: 1)..connect() |
| States needing sharing | .share() or .shareReplay(maxSize: 1) |
In test/feature_<name>/factory/<page>_factory.dart:
import 'package:flutter/material.dart';
import 'package:flutter_rx_bloc/flutter_rx_bloc.dart';
import 'package:procredit/<feature>/blocs/<bloc>.dart';
import 'package:procredit/<feature>/views/<page>.dart';
import 'package:provider/provider.dart';
import 'package:rx_bloc/rx_bloc.dart';
import '../mock/<bloc>_mock.dart';
Widget <page>Factory({
Result<MyDomainModel>? dataResult,
bool? someToggle,
// ... all state parameters
}) => Scaffold(
body: MultiProvider(
providers: [
RxBlocProvider<MyFeatureBlocType>.value(
value: myFeatureMockFactory(
dataResult: dataResult,
someToggle: someToggle,
),
),
// ... all required providers
],
child: const <Page>(),
),
);
=> Scaffold(...)) — no block body, no local variablesScaffold bodyMultiProvider + RxBlocProvider<T>.valuepackage:mockito/mockito.dart../../mocks/stubs.dartwhen() / thenAnswer() / thenReturn() callsIn test/feature_<name>/view/<page>_golden_test.dart:
import 'package:procredit/base/models/...'; // Domain model imports as needed
import 'package:rx_bloc/rx_bloc.dart';
import '../../helpers/golden_helper.dart';
import '../../helpers/models/scenario.dart';
import '../../mocks/stubs.dart';
import '../factory/<page>_factory.dart';
void main() {
runGoldenTests([
generateDeviceBuilder(
widget: <page>Factory(
dataResult: Result.success(Stubs.mockModel),
),
scenario: Scenario(name: '<page>_success'),
),
generateDeviceBuilder(
widget: <page>Factory(
dataResult: Result.loading(),
),
scenario: Scenario(name: '<page>_loading'),
),
generateDeviceBuilder(
widget: <page>Factory(
dataResult: Result.error(Stubs.error),
),
scenario: Scenario(name: '<page>_error'),
),
]);
}
runGoldenTests(List<ScenarioBuilder>) — iterates over all Themes.values, calls goldenTest for each scenario+themegenerateDeviceBuilder(widget:, scenario:) — renders the widget across all 7 default devicescustomPumpBeforeTest, customDeviceHeight, localeIf the page requires global setup (e.g., isTest = true, VisibilityDetectorController), add a setUp() block before runGoldenTests:
void main() {
setUp(() {
isTest = true;
});
runGoldenTests([...]);
}
test/mocks/stubs.dartThis includes:
Stubs.profile, Stubs.error)ProfileModel.withDefaults() for default profile dataResult.success(data), Result.loading(), Result.error(Stubs.error) for state wrappersLoadingWithTag(loading: true) for loading statesstubs.dart firstFor every page, the agent MUST enumerate and cover:
| Dimension | Values |
|---|---|
| Data state | success, loading, error, empty (if applicable) |
| Interaction state | expanded/collapsed, toggled on/off, selected/unselected |
| Edge cases | missing optional data, overlay/modal visible |
| Theme | light (+ dark when enabled in Themes enum) |
| Locale | bg (default); add others only if layout visually differs |
Create one generateDeviceBuilder call per unique combination that produces a visually distinct render.
Do NOT create scenarios for combinations that render identically.
.png golden files@GenerateMocks inside a test file or factory filewhen() / thenAnswer() / thenReturn() calls inside a factory filepackage:mockito/mockito.dart in a factory filestubs.dart in a factory file{ return ... }) in a factory — use expression body (=>)_light or _dark suffix to scenario namesimport '../../helpers/golden_helper.dart';
import '../../helpers/models/scenario.dart';
import '../../mocks/stubs.dart';
import '../factory/<page>_factory.dart';
import 'package:rx_bloc/rx_bloc.dart'; // Result, LoadingWithTag
import 'package:flutter/material.dart';
import 'package:flutter_rx_bloc/flutter_rx_bloc.dart'; // RxBlocProvider
import 'package:provider/provider.dart'; // MultiProvider, Provider
import 'package:rx_bloc/rx_bloc.dart'; // Result, LoadingWithTag
import '../mock/<bloc>_mock.dart';
import 'package:mockito/annotations.dart'; // @GenerateMocks
import 'package:mockito/mockito.dart'; // when, thenReturn, thenAnswer
import 'package:rx_bloc/rx_bloc.dart';
import 'package:rxdart/rxdart.dart'; // share, shareReplay, publishReplay
import '../../mocks/stubs.dart'; // test data (ONLY in mock files)
Run build_runner to generate mock files:
dart run build_runner build --delete-conflicting-outputs
Generate golden images:
flutter test --update-goldens test/feature_<name>/view/<page>_golden_test.dart
Verify all scenarios pass:
flutter test test/feature_<name>/view/<page>_golden_test.dart
If the agent cannot clearly determine:
Then the agent MUST read the page source code and DI file before proceeding. Never guess.
By following these architecture and testing guidelines strictly, you will produce seamless, clean, scalable golden tests fully integrated into the pipeline.