@ngxtm/devkit 3.3.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/cli/index.js +59 -13
- package/cli/rules.js +248 -0
- 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,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: flutter-riverpod
|
|
3
|
+
version: 1.0.0
|
|
4
|
+
triggers: [riverpod, provider, state]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Riverpod
|
|
8
|
+
|
|
9
|
+
State management with Riverpod 2.x and code generation.
|
|
10
|
+
|
|
11
|
+
## Setup
|
|
12
|
+
|
|
13
|
+
```yaml
|
|
14
|
+
dependencies:
|
|
15
|
+
flutter_riverpod: ^2.4.0
|
|
16
|
+
riverpod_annotation: ^2.3.0
|
|
17
|
+
|
|
18
|
+
dev_dependencies:
|
|
19
|
+
riverpod_generator: ^2.3.0
|
|
20
|
+
build_runner: ^2.4.0
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Provider Types
|
|
24
|
+
|
|
25
|
+
```dart
|
|
26
|
+
// Simple value
|
|
27
|
+
@riverpod
|
|
28
|
+
String greeting(GreetingRef ref) => 'Hello';
|
|
29
|
+
|
|
30
|
+
// Async data
|
|
31
|
+
@riverpod
|
|
32
|
+
Future<User> user(UserRef ref) async {
|
|
33
|
+
return ref.watch(apiProvider).getUser();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Notifier for mutable state
|
|
37
|
+
@riverpod
|
|
38
|
+
class Counter extends _$Counter {
|
|
39
|
+
@override
|
|
40
|
+
int build() => 0;
|
|
41
|
+
|
|
42
|
+
void increment() => state++;
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Consumer Usage
|
|
47
|
+
|
|
48
|
+
```dart
|
|
49
|
+
class MyWidget extends ConsumerWidget {
|
|
50
|
+
@override
|
|
51
|
+
Widget build(BuildContext context, WidgetRef ref) {
|
|
52
|
+
final count = ref.watch(counterProvider);
|
|
53
|
+
return Text('$count');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Async Handling
|
|
59
|
+
|
|
60
|
+
```dart
|
|
61
|
+
ref.watch(userProvider).when(
|
|
62
|
+
data: (user) => UserCard(user),
|
|
63
|
+
loading: () => const CircularProgressIndicator(),
|
|
64
|
+
error: (e, st) => ErrorText(e.toString()),
|
|
65
|
+
);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Family Providers
|
|
69
|
+
|
|
70
|
+
```dart
|
|
71
|
+
@riverpod
|
|
72
|
+
Future<Post> post(PostRef ref, int id) async {
|
|
73
|
+
return ref.watch(apiProvider).getPost(id);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Usage
|
|
77
|
+
ref.watch(postProvider(42));
|
|
78
|
+
```
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Flutter Security
|
|
3
|
+
description: Security standards for Flutter applications based on OWASP Mobile.
|
|
4
|
+
metadata:
|
|
5
|
+
labels: [security, owasp, pii, encryption]
|
|
6
|
+
triggers:
|
|
7
|
+
files: ['lib/infrastructure/**', 'pubspec.yaml']
|
|
8
|
+
keywords: [secure_storage, obfuscate, jailbreak, pinning, PII, OWASP]
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Mobile Security
|
|
12
|
+
|
|
13
|
+
## **Priority: P0 (CRITICAL)**
|
|
14
|
+
|
|
15
|
+
Standards for basic mobile security and PII protection.
|
|
16
|
+
|
|
17
|
+
## Implementation Guidelines
|
|
18
|
+
|
|
19
|
+
- **Secure Storage**: Use `flutter_secure_storage` for tokens/PII. Never use `shared_preferences`.
|
|
20
|
+
- **Hardcoding**: Never store API keys or secrets in Dart code. Use `--dart-define` or `.env`.
|
|
21
|
+
- **Obfuscation**: Always release with `--obfuscate` and `--split-debug-info`.
|
|
22
|
+
- **SSL Pinning**: For high-security apps, use `dio_certificate_pinning`.
|
|
23
|
+
- **Root Detection**: Use `flutter_jailbreak_detection` for financial/sensitive applications.
|
|
24
|
+
- **PII Masking**: Mask sensitive data (email, phone) in logs and analytics.
|
|
25
|
+
|
|
26
|
+
## Reference & Examples
|
|
27
|
+
|
|
28
|
+
For SSL Pinning and Secure Storage implementation details:
|
|
29
|
+
See [references/REFERENCE.md](references/REFERENCE.md).
|
|
30
|
+
|
|
31
|
+
## Related Topics
|
|
32
|
+
|
|
33
|
+
layer-based-clean-architecture | performance
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Mobile Security Reference
|
|
2
|
+
|
|
3
|
+
Detailed implementation patterns for OWASP Mobile compliance.
|
|
4
|
+
|
|
5
|
+
## References
|
|
6
|
+
|
|
7
|
+
- [**Network Security**](network-security.md) - SSL Pinning and Security Headers.
|
|
8
|
+
- [**Secure Storage**](secure-storage-impl.md) - PII and Token management.
|
|
9
|
+
|
|
10
|
+
## **CI/CD Security Flag**
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
# Obfuscation during build
|
|
14
|
+
flutter build apk --obfuscate --split-debug-info=./debug-info
|
|
15
|
+
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Network Security & Certificate Pinning
|
|
2
|
+
|
|
3
|
+
## **SSL Pinning with Dio**
|
|
4
|
+
|
|
5
|
+
```dart
|
|
6
|
+
import 'package:dio/dio.dart';
|
|
7
|
+
import 'package:dio_certificate_pinning/dio_certificate_pinning.dart';
|
|
8
|
+
|
|
9
|
+
final dio = Dio();
|
|
10
|
+
dio.interceptors.add(CertificatePinningInterceptor(
|
|
11
|
+
allowedSHAFingerprints: [
|
|
12
|
+
"70:99:27:8B:54:4A:40:F5:30:DB:73:E3:64:36:0F:70:3D:09:A6:49",
|
|
13
|
+
],
|
|
14
|
+
));
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## **Security Headers Interceptor**
|
|
18
|
+
|
|
19
|
+
```dart
|
|
20
|
+
class SecurityInterceptor extends Interceptor {
|
|
21
|
+
@override
|
|
22
|
+
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
|
|
23
|
+
options.headers['X-Content-Type-Options'] = 'nosniff';
|
|
24
|
+
options.headers['X-Frame-Options'] = 'DENY';
|
|
25
|
+
super.onRequest(options, handler);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Flutter Testing Standards
|
|
3
|
+
description: Unit, widget, and integration testing using mocktail and bloc_test.
|
|
4
|
+
metadata:
|
|
5
|
+
labels: [testing, junit, mocktail, bloc_test, golden-tests]
|
|
6
|
+
triggers:
|
|
7
|
+
files: ['**/test/**.dart']
|
|
8
|
+
keywords: [test, group, expect, mocktail, blocTest, when, any]
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Testing Standards
|
|
12
|
+
|
|
13
|
+
## **Priority: P1 (HIGH)**
|
|
14
|
+
|
|
15
|
+
Ensuring code reliability through multi-layered testing strategies.
|
|
16
|
+
|
|
17
|
+
## Structure
|
|
18
|
+
|
|
19
|
+
```text
|
|
20
|
+
test/
|
|
21
|
+
├── unit/ # Business logic & mapping (Blocs, Repositories, UseCases)
|
|
22
|
+
├── widget/ # UI component behavior (Screens, Widgets)
|
|
23
|
+
└── integration/ # End-to-end flows
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Implementation Guidelines
|
|
27
|
+
|
|
28
|
+
- **Testing Pyramid**: Maintain ~70% Unit Tests, ~20% Widget Tests, ~10% Integration Tests.
|
|
29
|
+
- **Mocks**: Use `mocktail` for type-safe, boilerplate-free mocking.
|
|
30
|
+
- **Unit Tests**: Test logic in isolation. Verify all edge cases (Success, Failure, Exception).
|
|
31
|
+
- **Widget Tests**: Test high-value interactions (Button clicks, Error states, Loading indicators).
|
|
32
|
+
- **BLoC Tests**: Use `blocTest` to verify state emission sequences.
|
|
33
|
+
- **Code Coverage**: Aim for 80%+ coverage on Domain and Presentation (Logic) layers.
|
|
34
|
+
|
|
35
|
+
## Deep Dive References
|
|
36
|
+
|
|
37
|
+
- [Unit Testing Strategies](./references/unit-testing.md) (Test Data Builders, Mocktail)
|
|
38
|
+
- [Widget Testing Strategies](./references/widget-testing.md) (Robot Pattern)
|
|
39
|
+
- [Integration Testing](./references/integration-testing.md) (Shared Robots, Real Device)
|
|
40
|
+
- [Robot Pattern Implementation](./references/robot-pattern.md)
|
|
41
|
+
|
|
42
|
+
## Related Topics
|
|
43
|
+
|
|
44
|
+
layer-based-clean-architecture | dependency-injection | cicd
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Testing Standards Reference
|
|
2
|
+
|
|
3
|
+
Practical patterns for Unit, Widget, and Golden tests.
|
|
4
|
+
|
|
5
|
+
## References
|
|
6
|
+
|
|
7
|
+
- [**Unit Testing**](unit-testing.md) - Mocking, AAA pattern, Repository testing.
|
|
8
|
+
- [**Widget Testing**](widget-testing.md) - UI interactions, Finders, Pumping frames.
|
|
9
|
+
- [**BLoC Testing**](bloc-testing.md) - Using `blocTest` for state transitions.
|
|
10
|
+
|
|
11
|
+
## **Quick Assertions**
|
|
12
|
+
|
|
13
|
+
```dart
|
|
14
|
+
// Mocktail Stub
|
|
15
|
+
when(() => repository.fetchData()).thenAnswer((_) async => right(data));
|
|
16
|
+
|
|
17
|
+
// Expect Matchers
|
|
18
|
+
expect(state.isLoading, isTrue);
|
|
19
|
+
expect(find.text('Hello'), findsOneWidget);
|
|
20
|
+
verify(() => repository.fetchData()).called(1);
|
|
21
|
+
```
|
|
@@ -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
|
+
```
|