@ngxtm/devkit 3.4.0 → 3.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -1
- package/rules/README.md +141 -0
- package/rules/dart/best-practices/SKILL.md +23 -0
- package/rules/dart/language/SKILL.md +52 -0
- package/rules/dart/tooling/SKILL.md +43 -0
- package/rules/dotnet/aspnet-core/SKILL.md +92 -0
- package/rules/dotnet/aspnet-core/references/REFERENCE.md +335 -0
- package/rules/dotnet/best-practices/SKILL.md +101 -0
- package/rules/dotnet/best-practices/references/REFERENCE.md +256 -0
- package/rules/dotnet/blazor/SKILL.md +146 -0
- package/rules/dotnet/blazor/references/REFERENCE.md +392 -0
- package/rules/dotnet/language/SKILL.md +82 -0
- package/rules/dotnet/language/references/REFERENCE.md +222 -0
- package/rules/dotnet/patterns.rule.md +388 -0
- package/rules/dotnet/razor-pages/SKILL.md +124 -0
- package/rules/dotnet/razor-pages/references/REFERENCE.md +321 -0
- package/rules/dotnet/security/SKILL.md +89 -0
- package/rules/dotnet/security/references/REFERENCE.md +295 -0
- package/rules/dotnet/tooling/SKILL.md +92 -0
- package/rules/dotnet/tooling/references/REFERENCE.md +300 -0
- package/rules/flutter/auto-route-navigation/SKILL.md +43 -0
- package/rules/flutter/auto-route-navigation/references/REFERENCE.md +19 -0
- package/rules/flutter/auto-route-navigation/references/router-config.md +62 -0
- package/rules/flutter/bloc-state-management/SKILL.md +64 -0
- package/rules/flutter/bloc-state-management/references/REFERENCE.md +20 -0
- package/rules/flutter/bloc-state-management/references/auth-bloc-example.md +52 -0
- package/rules/flutter/bloc-state-management/references/equatable-usage.md +56 -0
- package/rules/flutter/bloc-state-management/references/property-based-state.md +68 -0
- package/rules/flutter/bloc.rule.md +76 -0
- package/rules/flutter/cicd/SKILL.md +48 -0
- package/rules/flutter/cicd/references/advanced-workflow.md +66 -0
- package/rules/flutter/cicd/references/fastlane.md +139 -0
- package/rules/flutter/cicd/references/github-actions.md +59 -0
- package/rules/flutter/dependency-injection/SKILL.md +42 -0
- package/rules/flutter/dependency-injection/references/REFERENCE.md +15 -0
- package/rules/flutter/dependency-injection/references/modules.md +37 -0
- package/rules/flutter/error-handling/SKILL.md +32 -0
- package/rules/flutter/error-handling/references/REFERENCE.md +19 -0
- package/rules/flutter/error-handling/references/error-mapping.md +31 -0
- package/rules/flutter/feature-based-clean-architecture/SKILL.md +46 -0
- package/rules/flutter/feature-based-clean-architecture/references/REFERENCE.md +14 -0
- package/rules/flutter/feature-based-clean-architecture/references/folder-structure.md +36 -0
- package/rules/flutter/getx-navigation/SKILL.md +70 -0
- package/rules/flutter/getx-navigation/references/app-pages.md +40 -0
- package/rules/flutter/getx-navigation/references/middleware-example.md +29 -0
- package/rules/flutter/getx-state-management/SKILL.md +76 -0
- package/rules/flutter/getx-state-management/references/binding-example.md +32 -0
- package/rules/flutter/getx-state-management/references/reactive-vs-simple.md +39 -0
- package/rules/flutter/go-router-navigation/SKILL.md +57 -0
- package/rules/flutter/idiomatic-flutter/SKILL.md +20 -0
- package/rules/flutter/layer-based-clean-architecture/SKILL.md +50 -0
- package/rules/flutter/layer-based-clean-architecture/references/REFERENCE.md +60 -0
- package/rules/flutter/layer-based-clean-architecture/references/repository-mapping.md +50 -0
- package/rules/flutter/localization/SKILL.md +50 -0
- package/rules/flutter/localization/references/REFERENCE.md +48 -0
- package/rules/flutter/localization/references/sheet-loader.md +33 -0
- package/rules/flutter/navigator-v1-navigation/SKILL.md +71 -0
- package/rules/flutter/navigator-v1-navigation/references/on-generate-route.md +48 -0
- package/rules/flutter/performance/SKILL.md +24 -0
- package/rules/flutter/retrofit-networking/SKILL.md +51 -0
- package/rules/flutter/retrofit-networking/references/REFERENCE.md +19 -0
- package/rules/flutter/retrofit-networking/references/token-refresh.md +40 -0
- package/rules/flutter/riverpod-state-management/SKILL.md +53 -0
- package/rules/flutter/riverpod-state-management/references/architecture.md +124 -0
- package/rules/flutter/riverpod-state-management/references/best-practices.md +89 -0
- package/rules/flutter/riverpod-state-management/references/testing.md +73 -0
- package/rules/flutter/riverpod.rule.md +78 -0
- package/rules/flutter/security/SKILL.md +33 -0
- package/rules/flutter/security/references/REFERENCE.md +15 -0
- package/rules/flutter/security/references/network-security.md +28 -0
- package/rules/flutter/testing/SKILL.md +44 -0
- package/rules/flutter/testing/references/REFERENCE.md +21 -0
- package/rules/flutter/testing/references/bloc-testing.md +38 -0
- package/rules/flutter/testing/references/integration-testing.md +128 -0
- package/rules/flutter/testing/references/robot-pattern.md +82 -0
- package/rules/flutter/testing/references/unit-testing.md +130 -0
- package/rules/flutter/testing/references/widget-testing.md +120 -0
- package/rules/flutter/widgets/SKILL.md +37 -0
- package/rules/golang/chi-router/SKILL.md +219 -0
- package/rules/golang/chi-router/references/REFERENCE.md +13 -0
- package/rules/golang/chi-router/references/routing-patterns.md +205 -0
- package/rules/golang/cobra-cli/SKILL.md +227 -0
- package/rules/golang/cobra-cli/references/REFERENCE.md +13 -0
- package/rules/golang/cobra-cli/references/command-patterns.md +224 -0
- package/rules/golang/core/SKILL.md +210 -0
- package/rules/golang/core/references/REFERENCE.md +14 -0
- package/rules/golang/core/references/concurrency-patterns.md +114 -0
- package/rules/golang/core/references/error-handling.md +87 -0
- package/rules/golang/echo-framework/SKILL.md +215 -0
- package/rules/golang/echo-framework/references/REFERENCE.md +14 -0
- package/rules/golang/echo-framework/references/middleware-patterns.md +141 -0
- package/rules/golang/echo-framework/references/routing-patterns.md +140 -0
- package/rules/golang/ent-orm/SKILL.md +239 -0
- package/rules/golang/ent-orm/references/REFERENCE.md +13 -0
- package/rules/golang/ent-orm/references/schema-patterns.md +255 -0
- package/rules/golang/fiber-framework/SKILL.md +196 -0
- package/rules/golang/fiber-framework/references/REFERENCE.md +13 -0
- package/rules/golang/fiber-framework/references/routing-patterns.md +191 -0
- package/rules/golang/gin-framework/SKILL.md +205 -0
- package/rules/golang/gin-framework/references/REFERENCE.md +14 -0
- package/rules/golang/gin-framework/references/middleware-patterns.md +119 -0
- package/rules/golang/gorm-orm/SKILL.md +196 -0
- package/rules/golang/gorm-orm/references/REFERENCE.md +14 -0
- package/rules/golang/gorm-orm/references/model-definitions.md +167 -0
- package/rules/golang/gorm-orm/references/query-patterns.md +161 -0
- package/rules/golang/grpc/SKILL.md +231 -0
- package/rules/golang/grpc/references/REFERENCE.md +13 -0
- package/rules/golang/grpc/references/service-patterns.md +276 -0
- package/rules/golang/testify/SKILL.md +239 -0
- package/rules/golang/testify/references/REFERENCE.md +13 -0
- package/rules/golang/testify/references/assert-patterns.md +170 -0
- package/rules/golang/validator/SKILL.md +234 -0
- package/rules/golang/validator/references/REFERENCE.md +13 -0
- package/rules/golang/validator/references/validation-tags.md +211 -0
- package/rules/golang/viper-config/SKILL.md +244 -0
- package/rules/golang/viper-config/references/REFERENCE.md +13 -0
- package/rules/golang/viper-config/references/config-loading.md +181 -0
- package/rules/golang/wire-di/SKILL.md +243 -0
- package/rules/golang/wire-di/references/REFERENCE.md +13 -0
- package/rules/golang/wire-di/references/provider-patterns.md +193 -0
- package/rules/golang/zap-logging/SKILL.md +203 -0
- package/rules/golang/zap-logging/references/REFERENCE.md +13 -0
- package/rules/golang/zap-logging/references/logger-config.md +165 -0
- package/rules/java/build-gradle/SKILL.md +92 -0
- package/rules/java/build-gradle/references/REFERENCE.md +14 -0
- package/rules/java/build-gradle/references/kotlin-dsl.md +118 -0
- package/rules/java/build-gradle/references/task-configuration.md +132 -0
- package/rules/java/build-maven/SKILL.md +86 -0
- package/rules/java/build-maven/references/REFERENCE.md +14 -0
- package/rules/java/build-maven/references/dependency-management.md +111 -0
- package/rules/java/build-maven/references/lifecycle-phases.md +114 -0
- package/rules/java/graalvm-native/SKILL.md +105 -0
- package/rules/java/graalvm-native/references/REFERENCE.md +12 -0
- package/rules/java/java-collections-streams/SKILL.md +148 -0
- package/rules/java/java-collections-streams/references/REFERENCE.md +15 -0
- package/rules/java/java-collections-streams/references/collectors-patterns.md +178 -0
- package/rules/java/java-collections-streams/references/stream-pipelines.md +165 -0
- package/rules/java/java-concurrency/SKILL.md +187 -0
- package/rules/java/java-concurrency/references/REFERENCE.md +17 -0
- package/rules/java/java-concurrency/references/completable-future.md +165 -0
- package/rules/java/java-concurrency/references/executor-patterns.md +176 -0
- package/rules/java/java-concurrency/references/virtual-threads.md +190 -0
- package/rules/java/java-core-language/SKILL.md +121 -0
- package/rules/java/java-core-language/references/REFERENCE.md +15 -0
- package/rules/java/java-core-language/references/jvm-memory-model.md +160 -0
- package/rules/java/java-core-language/references/modern-java-features.md +168 -0
- package/rules/java/java-project-structure/SKILL.md +195 -0
- package/rules/java/java-project-structure/references/REFERENCE.md +15 -0
- package/rules/java/java-project-structure/references/maven-project-layout.md +199 -0
- package/rules/java/java-project-structure/references/module-system.md +159 -0
- package/rules/java/micronaut-core/SKILL.md +99 -0
- package/rules/java/micronaut-core/references/REFERENCE.md +12 -0
- package/rules/java/micronaut-reactive/SKILL.md +68 -0
- package/rules/java/micronaut-reactive/references/REFERENCE.md +12 -0
- package/rules/java/quarkus-core/SKILL.md +85 -0
- package/rules/java/quarkus-core/references/REFERENCE.md +12 -0
- package/rules/java/quarkus-reactive/SKILL.md +67 -0
- package/rules/java/quarkus-reactive/references/REFERENCE.md +12 -0
- package/rules/java/spring-batch/SKILL.md +102 -0
- package/rules/java/spring-batch/references/REFERENCE.md +12 -0
- package/rules/java/spring-boot-architecture/SKILL.md +206 -0
- package/rules/java/spring-boot-architecture/references/REFERENCE.md +15 -0
- package/rules/java/spring-boot-architecture/references/auto-configuration.md +158 -0
- package/rules/java/spring-boot-architecture/references/configuration-properties.md +202 -0
- package/rules/java/spring-boot-web/SKILL.md +217 -0
- package/rules/java/spring-boot-web/references/REFERENCE.md +17 -0
- package/rules/java/spring-cloud/SKILL.md +109 -0
- package/rules/java/spring-cloud/references/REFERENCE.md +13 -0
- package/rules/java/spring-data-jpa/SKILL.md +241 -0
- package/rules/java/spring-data-jpa/references/REFERENCE.md +16 -0
- package/rules/java/spring-security/SKILL.md +161 -0
- package/rules/java/spring-security/references/REFERENCE.md +16 -0
- package/rules/java/spring-security/references/jwt-auth-flow.md +213 -0
- package/rules/java/testing-junit-mockito/SKILL.md +135 -0
- package/rules/java/testing-junit-mockito/references/REFERENCE.md +15 -0
- package/rules/java/testing-junit-mockito/references/junit5-patterns.md +159 -0
- package/rules/java/testing-junit-mockito/references/mockito-patterns.md +148 -0
- package/rules/java/testing-junit-mockito/references/spring-boot-testing.md +152 -0
- package/rules/javascript/best-practices/SKILL.md +64 -0
- package/rules/javascript/best-practices/references/REFERENCE.md +91 -0
- package/rules/javascript/language/SKILL.md +71 -0
- package/rules/javascript/language/references/REFERENCE.md +106 -0
- package/rules/javascript/tooling/SKILL.md +60 -0
- package/rules/javascript/tooling/references/REFERENCE.md +107 -0
- package/rules/metadata.json +54 -0
- package/rules/nestjs/api-standards/SKILL.md +47 -0
- package/rules/nestjs/api-standards/references/pagination-wrapper.md +87 -0
- package/rules/nestjs/architecture/SKILL.md +68 -0
- package/rules/nestjs/architecture/references/dynamic-module.md +53 -0
- package/rules/nestjs/caching/SKILL.md +51 -0
- package/rules/nestjs/caching/references/REFERENCE.md +13 -0
- package/rules/nestjs/caching/references/cache-patterns.md +183 -0
- package/rules/nestjs/configuration/SKILL.md +41 -0
- package/rules/nestjs/configuration/references/REFERENCE.md +13 -0
- package/rules/nestjs/configuration/references/config-patterns.md +184 -0
- package/rules/nestjs/controllers-services/SKILL.md +63 -0
- package/rules/nestjs/controllers-services/references/REFERENCE.md +14 -0
- package/rules/nestjs/controllers-services/references/controller-patterns.md +119 -0
- package/rules/nestjs/controllers-services/references/service-patterns.md +129 -0
- package/rules/nestjs/database/SKILL.md +102 -0
- package/rules/nestjs/database/references/REFERENCE.md +14 -0
- package/rules/nestjs/database/references/typeorm-patterns.md +156 -0
- package/rules/nestjs/deployment/SKILL.md +36 -0
- package/rules/nestjs/deployment/references/REFERENCE.md +13 -0
- package/rules/nestjs/deployment/references/deployment-patterns.md +140 -0
- package/rules/nestjs/documentation/SKILL.md +64 -0
- package/rules/nestjs/documentation/references/REFERENCE.md +13 -0
- package/rules/nestjs/documentation/references/swagger-patterns.md +139 -0
- package/rules/nestjs/error-handling/SKILL.md +55 -0
- package/rules/nestjs/error-handling/references/REFERENCE.md +13 -0
- package/rules/nestjs/error-handling/references/exception-filters.md +152 -0
- package/rules/nestjs/file-uploads/SKILL.md +35 -0
- package/rules/nestjs/file-uploads/references/REFERENCE.md +13 -0
- package/rules/nestjs/file-uploads/references/upload-patterns.md +125 -0
- package/rules/nestjs/observability/SKILL.md +39 -0
- package/rules/nestjs/observability/references/REFERENCE.md +13 -0
- package/rules/nestjs/observability/references/logging-metrics.md +175 -0
- package/rules/nestjs/performance/SKILL.md +60 -0
- package/rules/nestjs/performance/references/REFERENCE.md +13 -0
- package/rules/nestjs/performance/references/performance-patterns.md +107 -0
- package/rules/nestjs/real-time/SKILL.md +45 -0
- package/rules/nestjs/real-time/references/REFERENCE.md +13 -0
- package/rules/nestjs/real-time/references/websocket-patterns.md +121 -0
- package/rules/nestjs/scheduling/SKILL.md +39 -0
- package/rules/nestjs/scheduling/references/REFERENCE.md +13 -0
- package/rules/nestjs/scheduling/references/scheduling-patterns.md +137 -0
- package/rules/nestjs/search/SKILL.md +41 -0
- package/rules/nestjs/search/references/REFERENCE.md +13 -0
- package/rules/nestjs/search/references/search-patterns.md +137 -0
- package/rules/nestjs/security/SKILL.md +87 -0
- package/rules/nestjs/security/references/REFERENCE.md +14 -0
- package/rules/nestjs/security/references/authentication.md +151 -0
- package/rules/nestjs/testing/SKILL.md +40 -0
- package/rules/nestjs/testing/references/REFERENCE.md +14 -0
- package/rules/nestjs/testing/references/unit-testing.md +179 -0
- package/rules/nestjs/transport/SKILL.md +45 -0
- package/rules/nestjs/transport/references/REFERENCE.md +13 -0
- package/rules/nestjs/transport/references/microservices-patterns.md +170 -0
- package/rules/nextjs/app-router/SKILL.md +46 -0
- package/rules/nextjs/app-router/references/REFERENCE.md +14 -0
- package/rules/nextjs/app-router/references/routing-patterns.md +182 -0
- package/rules/nextjs/architecture/SKILL.md +44 -0
- package/rules/nextjs/architecture/references/fsd-structure.md +77 -0
- package/rules/nextjs/authentication/SKILL.md +29 -0
- package/rules/nextjs/authentication/references/auth-implementation.md +73 -0
- package/rules/nextjs/caching/SKILL.md +66 -0
- package/rules/nextjs/caching/references/REFERENCE.md +13 -0
- package/rules/nextjs/caching/references/cache-strategies.md +168 -0
- package/rules/nextjs/data-access-layer/SKILL.md +33 -0
- package/rules/nextjs/data-access-layer/references/patterns.md +66 -0
- package/rules/nextjs/data-fetching/SKILL.md +59 -0
- package/rules/nextjs/data-fetching/references/REFERENCE.md +13 -0
- package/rules/nextjs/data-fetching/references/fetch-patterns.md +160 -0
- package/rules/nextjs/internationalization/SKILL.md +105 -0
- package/rules/nextjs/internationalization/references/REFERENCE.md +13 -0
- package/rules/nextjs/internationalization/references/i18n-patterns.md +180 -0
- package/rules/nextjs/optimization/SKILL.md +64 -0
- package/rules/nextjs/optimization/references/REFERENCE.md +13 -0
- package/rules/nextjs/optimization/references/optimization-patterns.md +190 -0
- package/rules/nextjs/rendering/SKILL.md +91 -0
- package/rules/nextjs/rendering/references/REFERENCE.md +13 -0
- package/rules/nextjs/rendering/references/rendering-modes.md +163 -0
- package/rules/nextjs/server-actions/SKILL.md +46 -0
- package/rules/nextjs/server-actions/references/REFERENCE.md +13 -0
- package/rules/nextjs/server-actions/references/action-patterns.md +188 -0
- package/rules/nextjs/server-components/SKILL.md +52 -0
- package/rules/nextjs/server-components/references/REFERENCE.md +13 -0
- package/rules/nextjs/server-components/references/component-patterns.md +175 -0
- package/rules/nextjs/state-management/SKILL.md +73 -0
- package/rules/nextjs/state-management/references/REFERENCE.md +13 -0
- package/rules/nextjs/state-management/references/state-patterns.md +218 -0
- package/rules/nextjs/styling/SKILL.md +31 -0
- package/rules/nextjs/styling/references/implementation.md +56 -0
- package/rules/react/component-patterns/SKILL.md +66 -0
- package/rules/react/component-patterns/references/REFERENCE.md +126 -0
- package/rules/react/hooks/SKILL.md +60 -0
- package/rules/react/hooks/references/REFERENCE.md +132 -0
- package/rules/react/hooks.rule.md +79 -0
- package/rules/react/performance/SKILL.md +69 -0
- package/rules/react/performance/references/REFERENCE.md +143 -0
- package/rules/react/security/SKILL.md +46 -0
- package/rules/react/security/references/REFERENCE.md +170 -0
- package/rules/react/state-management/SKILL.md +56 -0
- package/rules/react/state-management/references/REFERENCE.md +137 -0
- package/rules/react/testing/SKILL.md +45 -0
- package/rules/react/testing/references/REFERENCE.md +149 -0
- package/rules/react/tooling/SKILL.md +39 -0
- package/rules/react/typescript/SKILL.md +53 -0
- package/rules/rust/actix-web/SKILL.md +160 -0
- package/rules/rust/actix-web/references/REFERENCE.md +13 -0
- package/rules/rust/actix-web/references/handler-patterns.md +198 -0
- package/rules/rust/async-graphql/SKILL.md +228 -0
- package/rules/rust/async-graphql/references/REFERENCE.md +13 -0
- package/rules/rust/async-graphql/references/schema-patterns.md +215 -0
- package/rules/rust/axum/SKILL.md +161 -0
- package/rules/rust/axum/references/REFERENCE.md +14 -0
- package/rules/rust/axum/references/handler-patterns.md +97 -0
- package/rules/rust/bevy/SKILL.md +206 -0
- package/rules/rust/bevy/references/REFERENCE.md +13 -0
- package/rules/rust/bevy/references/ecs-patterns.md +226 -0
- package/rules/rust/clap/SKILL.md +217 -0
- package/rules/rust/clap/references/REFERENCE.md +13 -0
- package/rules/rust/clap/references/derive-patterns.md +205 -0
- package/rules/rust/core/SKILL.md +154 -0
- package/rules/rust/core/references/REFERENCE.md +14 -0
- package/rules/rust/core/references/error-handling.md +92 -0
- package/rules/rust/diesel-orm/SKILL.md +176 -0
- package/rules/rust/diesel-orm/references/REFERENCE.md +13 -0
- package/rules/rust/diesel-orm/references/schema-patterns.md +206 -0
- package/rules/rust/rocket/SKILL.md +182 -0
- package/rules/rust/rocket/references/REFERENCE.md +13 -0
- package/rules/rust/rocket/references/handler-patterns.md +209 -0
- package/rules/rust/sea-orm/SKILL.md +230 -0
- package/rules/rust/sea-orm/references/REFERENCE.md +13 -0
- package/rules/rust/sea-orm/references/entity-patterns.md +221 -0
- package/rules/rust/serde-serialization/SKILL.md +150 -0
- package/rules/rust/serde-serialization/references/REFERENCE.md +13 -0
- package/rules/rust/serde-serialization/references/serialization-patterns.md +199 -0
- package/rules/rust/sqlx-database/SKILL.md +140 -0
- package/rules/rust/sqlx-database/references/REFERENCE.md +13 -0
- package/rules/rust/sqlx-database/references/query-patterns.md +210 -0
- package/rules/rust/tauri/SKILL.md +180 -0
- package/rules/rust/tauri/references/REFERENCE.md +13 -0
- package/rules/rust/tauri/references/command-patterns.md +209 -0
- package/rules/rust/tokio-runtime/SKILL.md +167 -0
- package/rules/rust/tokio-runtime/references/REFERENCE.md +14 -0
- package/rules/rust/tokio-runtime/references/async-patterns.md +137 -0
- package/rules/rust/tokio-runtime/references/synchronization.md +152 -0
- package/rules/rust/tonic/SKILL.md +231 -0
- package/rules/rust/tonic/references/REFERENCE.md +13 -0
- package/rules/rust/tonic/references/service-patterns.md +213 -0
- package/rules/rust/tracing/SKILL.md +214 -0
- package/rules/rust/tracing/references/REFERENCE.md +13 -0
- package/rules/rust/tracing/references/instrumentation.md +187 -0
- package/rules/typescript/best-practices/SKILL.md +108 -0
- package/rules/typescript/best-practices/references/REFERENCE.md +68 -0
- package/rules/typescript/language/SKILL.md +72 -0
- package/rules/typescript/language/references/REFERENCE.md +67 -0
- package/rules/typescript/patterns.rule.md +85 -0
- package/rules/typescript/security/SKILL.md +59 -0
- package/rules/typescript/security/references/REFERENCE.md +113 -0
- package/rules/typescript/tooling/SKILL.md +52 -0
- package/rules/typescript/tooling/references/REFERENCE.md +110 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# BLoC Testing with `bloc_test`
|
|
2
|
+
|
|
3
|
+
`blocTest` ensures your events trigger the correct sequence of states.
|
|
4
|
+
|
|
5
|
+
## **Success Scenario**
|
|
6
|
+
|
|
7
|
+
```dart
|
|
8
|
+
blocTest<AuthBloc, AuthState>(
|
|
9
|
+
'emits [loading, authenticated] when login is successful',
|
|
10
|
+
build: () {
|
|
11
|
+
// Stub the repository
|
|
12
|
+
when(() => mockAuthRepo.login(any(), any()))
|
|
13
|
+
.thenAnswer((_) async => Right(mockUser));
|
|
14
|
+
return AuthBloc(mockAuthRepo);
|
|
15
|
+
},
|
|
16
|
+
act: (bloc) => bloc.add(const AuthEvent.loginPressed('test@email.com', 'pass123')),
|
|
17
|
+
expect: () => [
|
|
18
|
+
const AuthState.loading(),
|
|
19
|
+
AuthState.authenticated(mockUser),
|
|
20
|
+
],
|
|
21
|
+
verify: (_) {
|
|
22
|
+
verify(() => mockAuthRepo.login('test@email.com', 'pass123')).called(1);
|
|
23
|
+
},
|
|
24
|
+
);
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## **Best Practices & Pitfalls**
|
|
28
|
+
|
|
29
|
+
- **Do not mock based on State**: Do not use values in the BLoC state to mock data or verify calls. This is unreliable because it tracks the number of times a state is emitted (which can happen multiple times) rather than verifying the actual event trigger. Always verify the downstream Dependency/Service call in the `verify` block.
|
|
30
|
+
- **Initial State verification**
|
|
31
|
+
|
|
32
|
+
Always ensure your BLoC doesn't emit anything just by being created unless specified.
|
|
33
|
+
|
|
34
|
+
```dart
|
|
35
|
+
test('initial state is AuthState.initial', () {
|
|
36
|
+
expect(AuthBloc(mockRepo).state, const AuthState.initial());
|
|
37
|
+
});
|
|
38
|
+
```
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Advanced Integration Testing
|
|
2
|
+
|
|
3
|
+
Expert strategies for running "hard" tests (Native, Network, Time) reliably on CI.
|
|
4
|
+
|
|
5
|
+
## The Core Problem
|
|
6
|
+
|
|
7
|
+
Standard flutter `integration_test` struggles with:
|
|
8
|
+
|
|
9
|
+
1. **Native UI**: Permission dialogs, Notifications, Dark Mode toggles.
|
|
10
|
+
2. **WebViews**: Logging in via 3rd party identity providers.
|
|
11
|
+
3. **Flakiness**: `pumpAndSettle` hanging on infinite animations.
|
|
12
|
+
|
|
13
|
+
## Recommended Tool: Patrol
|
|
14
|
+
|
|
15
|
+
[Patrol](https://pub.dev/packages/patrol) extends Flutter's testing capabilities to interact with the OS.
|
|
16
|
+
|
|
17
|
+
### Why Patrol?
|
|
18
|
+
|
|
19
|
+
- **Native Interactions**: `$.native.tap()` to query OS/native views.
|
|
20
|
+
- **Improved Finders**: `$(#email)` instead of `find.byKey(Key('email'))`.
|
|
21
|
+
- **Better Waiters**: `waitUntilVisible()` handles spinners correctly (unlike `pumpAndSettle`).
|
|
22
|
+
|
|
23
|
+
### Setup
|
|
24
|
+
|
|
25
|
+
1. Add dependency: `dev_dependencies: patrol: ^3.0.0`
|
|
26
|
+
2. Create test file: `integration_test/app_test.dart`
|
|
27
|
+
|
|
28
|
+
```dart
|
|
29
|
+
import 'package:patrol/patrol.dart';
|
|
30
|
+
|
|
31
|
+
void main() {
|
|
32
|
+
patrolTest(
|
|
33
|
+
'Login and accept permissions',
|
|
34
|
+
nativeAutomation: true, // Enable native controls
|
|
35
|
+
($) async {
|
|
36
|
+
await $.pumpWidgetAndSettle(MyApp());
|
|
37
|
+
|
|
38
|
+
// 1. Flutter Interaction (Concise Syntax)
|
|
39
|
+
await $(#emailField).enterText('user@test.com');
|
|
40
|
+
await $(#passwordField).enterText('password123');
|
|
41
|
+
await $('Login').tap();
|
|
42
|
+
|
|
43
|
+
// 2. Native Interaction (The Killer Feature)
|
|
44
|
+
if (await $.native.isPermissionDialogVisible()) {
|
|
45
|
+
await $.native.grantPermissionWhenInUse();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// 3. WebViews (if needed)
|
|
49
|
+
// await $.native.tap(Selector(text: 'Accept Cookies'));
|
|
50
|
+
},
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Strategy 1: Real Environment (End-to-End)
|
|
56
|
+
|
|
57
|
+
Run tests against a real staging/dev backend to verify the full system. Do **not** mock the HTTP client in Integration Tests unless strictly necessary for hermeticity.
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# Run with Patrol
|
|
61
|
+
patrol test -t integration_test/app_test.dart --dart-define=ENV=staging
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
```dart
|
|
65
|
+
// main.dart
|
|
66
|
+
void main() {
|
|
67
|
+
final env = String.fromEnvironment('ENV', defaultValue: 'prod');
|
|
68
|
+
runApp(MyApp(config: Config.fromEnv(env)));
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Strategy 2: Robust Waiters
|
|
73
|
+
|
|
74
|
+
Avoid `pumpAndSettle()` for any screen with a `CircularProgressIndicator` or Lottie animation, as it will timeout waiting for the "animation" to settle.
|
|
75
|
+
|
|
76
|
+
**Use Patrol's `waitUntilVisible`**:
|
|
77
|
+
|
|
78
|
+
```dart
|
|
79
|
+
// BAD
|
|
80
|
+
// await $.pumpAndSettle(); // Times out if a spinner is running
|
|
81
|
+
|
|
82
|
+
// GOOD
|
|
83
|
+
await $('Welcome Home').waitUntilVisible(timeout: Duration(seconds: 10));
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Legacy (If not using Patrol)**:
|
|
87
|
+
You must write a custom extension to pump frames manually.
|
|
88
|
+
|
|
89
|
+
```dart
|
|
90
|
+
extension PumpUntilFound on WidgetTester {
|
|
91
|
+
Future<void> pumpUntilFound(Finder finder) async {
|
|
92
|
+
while (!any(finder)) {
|
|
93
|
+
await pump(const Duration(milliseconds: 100));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Strategy 3: Handling Long Delays
|
|
100
|
+
|
|
101
|
+
For flows involving long waits (e.g., "Verification code expires in 5 minutes"), waiting real time is impractical.
|
|
102
|
+
|
|
103
|
+
**Approach**: Configure the app to use shorter durations in non-production environments.
|
|
104
|
+
|
|
105
|
+
```dart
|
|
106
|
+
// Code
|
|
107
|
+
class TimerWidget extends StatelessWidget {
|
|
108
|
+
final Duration duration; // Configurable
|
|
109
|
+
const TimerWidget({this.duration = const Duration(minutes: 5)});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Test
|
|
113
|
+
await $.pumpWidget(TimerWidget(duration: Duration(seconds: 1)));
|
|
114
|
+
await $('Resend Code').waitUntilVisible(); // Done instantly
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Strategy 4: Debugging Failures
|
|
118
|
+
|
|
119
|
+
Patrol automatically handles taking screenshots on failure if configured, but you can also do it manually.
|
|
120
|
+
|
|
121
|
+
```dart
|
|
122
|
+
// Patrol automatically captures screenshots on failure in `patrol test` output.
|
|
123
|
+
// No boilerplate needed.
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Related Topics
|
|
127
|
+
|
|
128
|
+
[Robot Pattern](./robot-pattern.md) | [Github Actions](../../cicd/references/github-actions.md)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Robot Pattern (Page Object Model)
|
|
2
|
+
|
|
3
|
+
For maintainable widget and integration tests, decouple the "what" (business logic/asserts) from the "how" (finding widgets).
|
|
4
|
+
|
|
5
|
+
## Why?
|
|
6
|
+
|
|
7
|
+
- **Readability**: Tests read like user stories.
|
|
8
|
+
- **Reusability**: One Robot works for both **Widget Tests** and **Integration Tests** (shared API).
|
|
9
|
+
- **Resilience**: If a widget key changes, you update only the Robot, not 50 tests.
|
|
10
|
+
|
|
11
|
+
## Directory Structure
|
|
12
|
+
|
|
13
|
+
Place robots in `test/robots/` so they can be imported by `test/widget/` and `integration_test/` folders.
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
test/
|
|
17
|
+
robots/
|
|
18
|
+
login_robot.dart
|
|
19
|
+
widget/
|
|
20
|
+
login_test.dart
|
|
21
|
+
integration_test/
|
|
22
|
+
full_app_test.dart
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Example
|
|
26
|
+
|
|
27
|
+
### The Robot Class (`test/robots/login_robot.dart`)
|
|
28
|
+
|
|
29
|
+
```dart
|
|
30
|
+
import 'package:flutter/material.dart';
|
|
31
|
+
import 'package:flutter_test/flutter_test.dart';
|
|
32
|
+
|
|
33
|
+
class LoginRobot {
|
|
34
|
+
final WidgetTester tester;
|
|
35
|
+
|
|
36
|
+
LoginRobot(this.tester);
|
|
37
|
+
|
|
38
|
+
// Finders (Private)
|
|
39
|
+
final _emailField = find.byKey(const Key('emailKey'));
|
|
40
|
+
final _passwordField = find.byKey(const Key('passwordKey'));
|
|
41
|
+
final _loginButton = find.byType(ElevatedButton);
|
|
42
|
+
|
|
43
|
+
// Actions
|
|
44
|
+
Future<void> enterEmail(String email) async {
|
|
45
|
+
await tester.enterText(_emailField, email);
|
|
46
|
+
await tester.pump();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
Future<void> enterPassword(String password) async {
|
|
50
|
+
await tester.enterText(_passwordField, password);
|
|
51
|
+
await tester.pump();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
Future<void> tapLogin() async {
|
|
55
|
+
await tester.tap(_loginButton);
|
|
56
|
+
await tester.pumpAndSettle();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Assertions
|
|
60
|
+
void expectErrorShown() {
|
|
61
|
+
expect(find.text('Invalid credentials'), findsOneWidget);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### The Test (`test/widget/login_screen_test.dart`)
|
|
67
|
+
|
|
68
|
+
```dart
|
|
69
|
+
testWidgets('Login failure flow', (tester) async {
|
|
70
|
+
// 1. Init
|
|
71
|
+
await tester.pumpWidget(myApp());
|
|
72
|
+
final robot = LoginRobot(tester);
|
|
73
|
+
|
|
74
|
+
// 2. Interact (Readable DSL)
|
|
75
|
+
await robot.enterEmail('bad@email.com');
|
|
76
|
+
await robot.enterPassword('wrong');
|
|
77
|
+
await robot.tapLogin();
|
|
78
|
+
|
|
79
|
+
// 3. Verify
|
|
80
|
+
robot.expectErrorShown();
|
|
81
|
+
});
|
|
82
|
+
```
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Unit Testing Strategies
|
|
2
|
+
|
|
3
|
+
Unit tests verify the smallest parts of your application (functions, methods, classes) in isolation.
|
|
4
|
+
|
|
5
|
+
## Core Rules
|
|
6
|
+
|
|
7
|
+
1. **Isolation**: External dependencies (API, Database, SharedPreferences) **must** be mocked.
|
|
8
|
+
2. **Scope**: One test file per source file (e.g., `user_repository.dart` -> `user_repository_test.dart`).
|
|
9
|
+
3. **Arrange-Act-Assert (AAA)**: Follow this structure strictly.
|
|
10
|
+
|
|
11
|
+
## Advanced Techniques
|
|
12
|
+
|
|
13
|
+
### 1. Test Data Builders
|
|
14
|
+
|
|
15
|
+
Avoid hardcoding large objects in every test. Use a Builder pattern to generate valid default data with overrides.
|
|
16
|
+
|
|
17
|
+
```dart
|
|
18
|
+
class UserBuilder {
|
|
19
|
+
String _id = '1';
|
|
20
|
+
String _name = 'Default User';
|
|
21
|
+
|
|
22
|
+
UserBuilder withId(String id) {
|
|
23
|
+
_id = id;
|
|
24
|
+
return this;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
User build() => User(id: _id, name: _name);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Usage in test
|
|
31
|
+
final user = UserBuilder().withId('99').build();
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 2. Mocking with Mocktail
|
|
35
|
+
|
|
36
|
+
We prefer `mocktail` over `mockito` for its null-safety and simplicity.
|
|
37
|
+
|
|
38
|
+
```dart
|
|
39
|
+
import 'package:mocktail/mocktail.dart';
|
|
40
|
+
import 'package:test/test.dart';
|
|
41
|
+
|
|
42
|
+
// 1. Create Mock
|
|
43
|
+
class MockUserRepository extends Mock implements UserRepository {}
|
|
44
|
+
|
|
45
|
+
void main() {
|
|
46
|
+
late MockUserRepository mockRepo;
|
|
47
|
+
late GetUserProfileUseCase useCase;
|
|
48
|
+
|
|
49
|
+
setUp(() {
|
|
50
|
+
mockRepo = MockUserRepository();
|
|
51
|
+
useCase = GetUserProfileUseCase(mockRepo);
|
|
52
|
+
|
|
53
|
+
// Register fallback values if needed
|
|
54
|
+
registerFallbackValue(User.empty());
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// 2. Test Group
|
|
58
|
+
group('GetUserProfileUseCase', () {
|
|
59
|
+
test('should return User when repository succeeds', () async {
|
|
60
|
+
// ARRANGE
|
|
61
|
+
final user = UserBuilder().build();
|
|
62
|
+
when(() => mockRepo.getUser('1')).thenAnswer((_) async => Right(user));
|
|
63
|
+
|
|
64
|
+
// ACT
|
|
65
|
+
final result = await useCase('1');
|
|
66
|
+
|
|
67
|
+
// ASSERT
|
|
68
|
+
expect(result, Right(user));
|
|
69
|
+
verify(() => mockRepo.getUser('1')).called(1);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test('should return Failure when repository fails', () async {
|
|
73
|
+
// ARRANGE
|
|
74
|
+
when(() => mockRepo.getUser(any())).thenThrow(ServerException());
|
|
75
|
+
|
|
76
|
+
// ACT
|
|
77
|
+
final call = useCase('1');
|
|
78
|
+
|
|
79
|
+
// ASSERT
|
|
80
|
+
expect(call, throwsA(isA<ServerException>()));
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Best Practices & Anti-Patterns (DCM)
|
|
87
|
+
|
|
88
|
+
Avoid common testing mistakes identified by Dart Code Metrics.
|
|
89
|
+
|
|
90
|
+
### 1. Assertions are Mandatory
|
|
91
|
+
|
|
92
|
+
Never write a test that just "runs" without verifying anything.
|
|
93
|
+
|
|
94
|
+
```dart
|
|
95
|
+
// BAD
|
|
96
|
+
test('fetchUser runs', () async {
|
|
97
|
+
await repo.fetchUser();
|
|
98
|
+
// ❌ No assertion - test passes even if logic is broken
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// GOOD
|
|
102
|
+
test('fetchUser returns data', () async {
|
|
103
|
+
final result = await repo.fetchUser();
|
|
104
|
+
expect(result, isNotNull); // ✅ Always verify result
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### 2. Use Proper Matchers
|
|
109
|
+
|
|
110
|
+
Use specific matchers for better error messages.
|
|
111
|
+
|
|
112
|
+
```dart
|
|
113
|
+
// BAD
|
|
114
|
+
expect(list.length, 1); // Message: "Expected: <1> Actual: <0>"
|
|
115
|
+
|
|
116
|
+
// GOOD
|
|
117
|
+
expect(list, hasLength(1)); // Message: "Expected: list with length <1> Actual: list with length <0> [...]"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### 3. Async Expectations
|
|
121
|
+
|
|
122
|
+
When testing Streams or Futures validation, use `expectLater` to ensure the test waits.
|
|
123
|
+
|
|
124
|
+
```dart
|
|
125
|
+
// BAD
|
|
126
|
+
expect(stream, emits(1)); // Might finish test before stream emits
|
|
127
|
+
|
|
128
|
+
// GOOD
|
|
129
|
+
await expectLater(stream, emits(1));
|
|
130
|
+
```
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Widget Testing Strategies
|
|
2
|
+
|
|
3
|
+
Widget tests verify the UI and interaction of valid widgets in a simulated environment (headless).
|
|
4
|
+
|
|
5
|
+
## Core Rules
|
|
6
|
+
|
|
7
|
+
1. **Wrapper**: Always wrap widgets in `MaterialApp`/`CupertinoApp` to provide Theme/Navigator context.
|
|
8
|
+
2. **Pump**:
|
|
9
|
+
- `pump()`: Triggers a frame.
|
|
10
|
+
- `pumpAndSettle()`: Wait for all animations to complete.
|
|
11
|
+
3. **Finders**: Use semantic finders (`find.text`, `find.byKey`, `find.byType`) to locate elements.
|
|
12
|
+
|
|
13
|
+
## Advanced: The Robot Pattern
|
|
14
|
+
|
|
15
|
+
For complex screens, avoid scattering `find.by...` references throughout your tests. Use a **Robot** to encapsulate UI interactions.
|
|
16
|
+
|
|
17
|
+
Reference: [Robot Pattern Implementation](./robot-pattern.md)
|
|
18
|
+
|
|
19
|
+
### Updated Example: Testing a Login Screen
|
|
20
|
+
|
|
21
|
+
```dart
|
|
22
|
+
import 'package:flutter_test/flutter_test.dart';
|
|
23
|
+
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
24
|
+
import 'package:mocktail/mocktail.dart';
|
|
25
|
+
import 'robots/login_robot.dart'; // Import your robot
|
|
26
|
+
|
|
27
|
+
void main() {
|
|
28
|
+
late MockAuthBloc mockAuthBloc;
|
|
29
|
+
|
|
30
|
+
setUp(() {
|
|
31
|
+
mockAuthBloc = MockAuthBloc();
|
|
32
|
+
when(() => mockAuthBloc.state).thenReturn(AuthInitial());
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
Widget createWidget() {
|
|
36
|
+
return MaterialApp(
|
|
37
|
+
home: BlocProvider<AuthBloc>.value(
|
|
38
|
+
value: mockAuthBloc,
|
|
39
|
+
child: LoginScreen(),
|
|
40
|
+
),
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
testWidgets('shows loading indicator when state is Loading', (tester) async {
|
|
45
|
+
// ARRANGE
|
|
46
|
+
when(() => mockAuthBloc.state).thenReturn(AuthLoading());
|
|
47
|
+
final robot = LoginRobot(tester);
|
|
48
|
+
|
|
49
|
+
// ACT
|
|
50
|
+
await tester.pumpWidget(createWidget());
|
|
51
|
+
|
|
52
|
+
// ASSERT
|
|
53
|
+
robot.expectLoadingVisible();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
testWidgets('triggers login event on button tap', (tester) async {
|
|
57
|
+
// ARRANGE
|
|
58
|
+
final robot = LoginRobot(tester);
|
|
59
|
+
await tester.pumpWidget(createWidget());
|
|
60
|
+
|
|
61
|
+
// ACT
|
|
62
|
+
await robot.enterEmail('test@example.com');
|
|
63
|
+
await robot.enterPassword('password123');
|
|
64
|
+
await robot.tapLogin();
|
|
65
|
+
|
|
66
|
+
// ASSERT
|
|
67
|
+
verify(() => mockAuthBloc.add(LoginSubmitted(
|
|
68
|
+
email: 'test@example.com',
|
|
69
|
+
password: 'password123'
|
|
70
|
+
))).called(1);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Handling Screen Variability
|
|
76
|
+
|
|
77
|
+
One of the most common mistakes is testing only on the default 800x600 surface.
|
|
78
|
+
|
|
79
|
+
### 1. Multi-Screen Golden Tests
|
|
80
|
+
|
|
81
|
+
Use `golden_toolkit` to verify responsive layouts across multiple devices.
|
|
82
|
+
|
|
83
|
+
```dart
|
|
84
|
+
testGoldens('Login Screen responsive layout', (tester) async {
|
|
85
|
+
final builder = DeviceBuilder()
|
|
86
|
+
..overrideDevicesForAllScenarios(devices: [
|
|
87
|
+
Device.phone,
|
|
88
|
+
Device.iphone11,
|
|
89
|
+
Device.tabletPortrait,
|
|
90
|
+
Device.tabletLandscape,
|
|
91
|
+
])
|
|
92
|
+
..addScenario(
|
|
93
|
+
widget: LoginScreen(),
|
|
94
|
+
name: 'Default State',
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
await tester.pumpDeviceBuilder(builder);
|
|
98
|
+
await screenMatchesGolden(tester, 'login_screen_responsive');
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 2. Manual Screen Resizing
|
|
103
|
+
|
|
104
|
+
If not using goldens, explicitly force screen sizes to test overflows.
|
|
105
|
+
|
|
106
|
+
```dart
|
|
107
|
+
testWidgets('Login on small screen', (tester) async {
|
|
108
|
+
// Set Surface Size to a small phone
|
|
109
|
+
tester.binding.window.physicalSizeTestValue = Size(320, 480);
|
|
110
|
+
tester.binding.window.devicePixelRatioTestValue = 1.0;
|
|
111
|
+
addTearDown(tester.binding.window.clearPhysicalSizeTestValue);
|
|
112
|
+
|
|
113
|
+
await tester.pumpWidget(createWidget());
|
|
114
|
+
|
|
115
|
+
// Verify no overflow errors
|
|
116
|
+
expect(tester.takeException(), isNull);
|
|
117
|
+
// Using a custom finder to check if something is visible only on scroll
|
|
118
|
+
await tester.scrollUntilVisible(find.text('Login'), 50);
|
|
119
|
+
});
|
|
120
|
+
```
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Flutter UI Widgets
|
|
3
|
+
description: Principles for maintainable UI components.
|
|
4
|
+
metadata:
|
|
5
|
+
labels: [ui, widgets]
|
|
6
|
+
triggers:
|
|
7
|
+
files: ['**_page.dart', '**_screen.dart', '**/widgets/**']
|
|
8
|
+
keywords: [StatelessWidget, const, Theme, ListView]
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# UI & Widgets (P1)
|
|
12
|
+
|
|
13
|
+
- **State**: Use `StatelessWidget` by default. `StatefulWidget` only for local state/controllers.
|
|
14
|
+
- **Composition**: Extract UI into small, atomic `const` widgets.
|
|
15
|
+
- **Theming**: Use `Theme.of(context)`. No hardcoded colors.
|
|
16
|
+
- **Layout**: Use `Flex` + `Gap/SizedBox`.
|
|
17
|
+
- **Specialized**:
|
|
18
|
+
- `SelectionArea`: For multi-widget text selection.
|
|
19
|
+
- `InteractiveViewer`: For zoom/pan.
|
|
20
|
+
- `ListWheelScrollView`: For pickers.
|
|
21
|
+
- `IntrinsicWidth/Height`: Avoid unless strictly required.
|
|
22
|
+
- **Large Lists**: Always use `ListView.builder`.
|
|
23
|
+
|
|
24
|
+
```dart
|
|
25
|
+
class AppButton extends StatelessWidget {
|
|
26
|
+
final String label;
|
|
27
|
+
final VoidCallback onPressed;
|
|
28
|
+
const AppButton({super.key, required this.label, required this.onPressed});
|
|
29
|
+
|
|
30
|
+
@override
|
|
31
|
+
Widget build(BuildContext context) => ElevatedButton(onPressed: onPressed, child: Text(label));
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Related Topics
|
|
36
|
+
|
|
37
|
+
performance | testing
|