@codyswann/lisa 1.0.0
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/LICENSE +21 -0
- package/README.md +867 -0
- package/all/copy-overwrite/.claude/README.md +205 -0
- package/all/copy-overwrite/.claude/agents/agent-architect.md +311 -0
- package/all/copy-overwrite/.claude/agents/codebase-analyzer.md +146 -0
- package/all/copy-overwrite/.claude/agents/codebase-locator.md +125 -0
- package/all/copy-overwrite/.claude/agents/codebase-pattern-finder.md +237 -0
- package/all/copy-overwrite/.claude/agents/git-history-analyzer.md +183 -0
- package/all/copy-overwrite/.claude/agents/hooks-expert.md +74 -0
- package/all/copy-overwrite/.claude/agents/skill-evaluator.md +246 -0
- package/all/copy-overwrite/.claude/agents/slash-command-architect.md +87 -0
- package/all/copy-overwrite/.claude/agents/web-search-researcher.md +112 -0
- package/all/copy-overwrite/.claude/commands/git/commit-and-submit-pr.md +8 -0
- package/all/copy-overwrite/.claude/commands/git/commit.md +44 -0
- package/all/copy-overwrite/.claude/commands/git/prune.md +34 -0
- package/all/copy-overwrite/.claude/commands/git/submit-pr.md +50 -0
- package/all/copy-overwrite/.claude/commands/jira/create.md +50 -0
- package/all/copy-overwrite/.claude/commands/jira/verify.md +34 -0
- package/all/copy-overwrite/.claude/commands/project/archive.md +8 -0
- package/all/copy-overwrite/.claude/commands/project/bootstrap.md +49 -0
- package/all/copy-overwrite/.claude/commands/project/complete-task.md +7 -0
- package/all/copy-overwrite/.claude/commands/project/debrief.md +65 -0
- package/all/copy-overwrite/.claude/commands/project/execute.md +94 -0
- package/all/copy-overwrite/.claude/commands/project/implement.md +42 -0
- package/all/copy-overwrite/.claude/commands/project/local-code-review.md +88 -0
- package/all/copy-overwrite/.claude/commands/project/lower-code-complexity.md +74 -0
- package/all/copy-overwrite/.claude/commands/project/plan.md +314 -0
- package/all/copy-overwrite/.claude/commands/project/research.md +248 -0
- package/all/copy-overwrite/.claude/commands/project/review.md +63 -0
- package/all/copy-overwrite/.claude/commands/project/setup.md +19 -0
- package/all/copy-overwrite/.claude/commands/project/verify.md +38 -0
- package/all/copy-overwrite/.claude/commands/pull-request/review.md +12 -0
- package/all/copy-overwrite/.claude/commands/rules/format-md.md +72 -0
- package/all/copy-overwrite/.claude/commands/sonarqube/check.md +6 -0
- package/all/copy-overwrite/.claude/commands/sonarqube/fix.md +3 -0
- package/all/copy-overwrite/.claude/hooks/README.md +301 -0
- package/all/copy-overwrite/.claude/hooks/notify-ntfy.sh +181 -0
- package/all/copy-overwrite/.claude/settings.json +41 -0
- package/all/copy-overwrite/.claude/settings.local.json.example +14 -0
- package/all/copy-overwrite/.claude/skills/coding-philosophy/SKILL.md +405 -0
- package/all/copy-overwrite/.claude/skills/coding-philosophy/references/function-structure.md +416 -0
- package/all/copy-overwrite/.claude/skills/coding-philosophy/references/immutable-patterns.md +316 -0
- package/all/copy-overwrite/.claude/skills/prompt-complexity-scorer/SKILL.md +118 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/LICENSE.txt +202 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/SKILL.md +210 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/scripts/__pycache__/quick_validate.cpython-312.pyc +0 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/scripts/init_skill.py +303 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/scripts/package_skill.py +110 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/scripts/quick_validate.py +65 -0
- package/all/copy-overwrite/CLAUDE.md +77 -0
- package/all/copy-overwrite/HUMAN.md +17 -0
- package/all/copy-overwrite/specs/.keep +0 -0
- package/all/create-only/PROJECT_RULES.md +0 -0
- package/cdk/merge/package.json +20 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +107 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/prompts.d.ts +45 -0
- package/dist/cli/prompts.d.ts.map +1 -0
- package/dist/cli/prompts.js +58 -0
- package/dist/cli/prompts.js.map +1 -0
- package/dist/core/config.d.ts +73 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +36 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +4 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/lisa.d.ts +81 -0
- package/dist/core/lisa.d.ts.map +1 -0
- package/dist/core/lisa.js +459 -0
- package/dist/core/lisa.js.map +1 -0
- package/dist/core/manifest.d.ts +58 -0
- package/dist/core/manifest.d.ts.map +1 -0
- package/dist/core/manifest.js +104 -0
- package/dist/core/manifest.js.map +1 -0
- package/dist/detection/detector.interface.d.ts +15 -0
- package/dist/detection/detector.interface.d.ts.map +1 -0
- package/dist/detection/detector.interface.js +2 -0
- package/dist/detection/detector.interface.js.map +1 -0
- package/dist/detection/detectors/cdk.d.ts +10 -0
- package/dist/detection/detectors/cdk.d.ts.map +1 -0
- package/dist/detection/detectors/cdk.js +34 -0
- package/dist/detection/detectors/cdk.js.map +1 -0
- package/dist/detection/detectors/expo.d.ts +10 -0
- package/dist/detection/detectors/expo.d.ts.map +1 -0
- package/dist/detection/detectors/expo.js +30 -0
- package/dist/detection/detectors/expo.js.map +1 -0
- package/dist/detection/detectors/nestjs.d.ts +10 -0
- package/dist/detection/detectors/nestjs.d.ts.map +1 -0
- package/dist/detection/detectors/nestjs.js +34 -0
- package/dist/detection/detectors/nestjs.js.map +1 -0
- package/dist/detection/detectors/npm-package.d.ts +13 -0
- package/dist/detection/detectors/npm-package.d.ts.map +1 -0
- package/dist/detection/detectors/npm-package.js +30 -0
- package/dist/detection/detectors/npm-package.js.map +1 -0
- package/dist/detection/detectors/typescript.d.ts +10 -0
- package/dist/detection/detectors/typescript.d.ts.map +1 -0
- package/dist/detection/detectors/typescript.js +25 -0
- package/dist/detection/detectors/typescript.js.map +1 -0
- package/dist/detection/index.d.ts +24 -0
- package/dist/detection/index.d.ts.map +1 -0
- package/dist/detection/index.js +57 -0
- package/dist/detection/index.js.map +1 -0
- package/dist/errors/index.d.ts +69 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +110 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/logging/console-logger.d.ts +12 -0
- package/dist/logging/console-logger.d.ts.map +1 -0
- package/dist/logging/console-logger.js +22 -0
- package/dist/logging/console-logger.js.map +1 -0
- package/dist/logging/index.d.ts +4 -0
- package/dist/logging/index.d.ts.map +1 -0
- package/dist/logging/index.js +3 -0
- package/dist/logging/index.js.map +1 -0
- package/dist/logging/logger.interface.d.ts +20 -0
- package/dist/logging/logger.interface.d.ts.map +1 -0
- package/dist/logging/logger.interface.js +2 -0
- package/dist/logging/logger.interface.js.map +1 -0
- package/dist/logging/silent-logger.d.ts +12 -0
- package/dist/logging/silent-logger.d.ts.map +1 -0
- package/dist/logging/silent-logger.js +21 -0
- package/dist/logging/silent-logger.js.map +1 -0
- package/dist/strategies/copy-contents.d.ts +14 -0
- package/dist/strategies/copy-contents.d.ts.map +1 -0
- package/dist/strategies/copy-contents.js +69 -0
- package/dist/strategies/copy-contents.js.map +1 -0
- package/dist/strategies/copy-overwrite.d.ts +14 -0
- package/dist/strategies/copy-overwrite.d.ts.map +1 -0
- package/dist/strategies/copy-overwrite.js +47 -0
- package/dist/strategies/copy-overwrite.js.map +1 -0
- package/dist/strategies/create-only.d.ts +13 -0
- package/dist/strategies/create-only.d.ts.map +1 -0
- package/dist/strategies/create-only.js +30 -0
- package/dist/strategies/create-only.js.map +1 -0
- package/dist/strategies/index.d.ts +31 -0
- package/dist/strategies/index.d.ts.map +1 -0
- package/dist/strategies/index.js +52 -0
- package/dist/strategies/index.js.map +1 -0
- package/dist/strategies/merge.d.ts +13 -0
- package/dist/strategies/merge.d.ts.map +1 -0
- package/dist/strategies/merge.js +60 -0
- package/dist/strategies/merge.js.map +1 -0
- package/dist/strategies/strategy.interface.d.ts +31 -0
- package/dist/strategies/strategy.interface.d.ts.map +1 -0
- package/dist/strategies/strategy.interface.js +2 -0
- package/dist/strategies/strategy.interface.js.map +1 -0
- package/dist/transaction/backup.d.ts +38 -0
- package/dist/transaction/backup.d.ts.map +1 -0
- package/dist/transaction/backup.js +97 -0
- package/dist/transaction/backup.js.map +1 -0
- package/dist/transaction/index.d.ts +4 -0
- package/dist/transaction/index.d.ts.map +1 -0
- package/dist/transaction/index.js +3 -0
- package/dist/transaction/index.js.map +1 -0
- package/dist/transaction/transaction.d.ts +34 -0
- package/dist/transaction/transaction.d.ts.map +1 -0
- package/dist/transaction/transaction.js +68 -0
- package/dist/transaction/transaction.js.map +1 -0
- package/dist/utils/file-operations.d.ts +29 -0
- package/dist/utils/file-operations.d.ts.map +1 -0
- package/dist/utils/file-operations.js +84 -0
- package/dist/utils/file-operations.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/json-utils.d.ts +22 -0
- package/dist/utils/json-utils.d.ts.map +1 -0
- package/dist/utils/json-utils.js +57 -0
- package/dist/utils/json-utils.js.map +1 -0
- package/dist/utils/path-utils.d.ts +21 -0
- package/dist/utils/path-utils.d.ts.map +1 -0
- package/dist/utils/path-utils.js +35 -0
- package/dist/utils/path-utils.js.map +1 -0
- package/eslint-plugin-code-organization/README.md +149 -0
- package/eslint-plugin-code-organization/__tests__/enforce-statement-order.test.js +468 -0
- package/eslint-plugin-code-organization/index.js +23 -0
- package/eslint-plugin-code-organization/package.json +10 -0
- package/eslint-plugin-code-organization/rules/enforce-statement-order.js +157 -0
- package/expo/copy-overwrite/.claude/skills/apollo-client/SKILL.md +238 -0
- package/expo/copy-overwrite/.claude/skills/apollo-client/references/mutation-patterns.md +360 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/SKILL.md +360 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/references/atomic-levels.md +417 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/references/folder-structure.md +257 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/references/gluestack-mapping.md +233 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/scripts/validate_atomic_structure.py +327 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/SKILL.md +299 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/references/examples.md +749 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/references/patterns.md +318 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/scripts/create_component.py +198 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/scripts/validate_component.py +207 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/SKILL.md +268 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/references/common-issues.md +619 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/references/file-extensions.md +340 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/references/platform-api.md +276 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/scripts/validate_cross_platform.py +414 -0
- package/expo/copy-overwrite/.claude/skills/directory-structure/SKILL.md +202 -0
- package/expo/copy-overwrite/.claude/skills/directory-structure/scripts/validate_structure.py +443 -0
- package/expo/copy-overwrite/.claude/skills/expo-env-config/SKILL.md +309 -0
- package/expo/copy-overwrite/.claude/skills/expo-env-config/references/validation-patterns.md +417 -0
- package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/SKILL.md +431 -0
- package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/references/official-docs.md +290 -0
- package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/scripts/generate-route.py +169 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/SKILL.md +411 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/references/color-tokens.md +343 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/references/component-mapping.md +307 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/references/spacing-scale.md +300 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/scripts/validate_styling.py +354 -0
- package/expo/copy-overwrite/.claude/skills/local-state/SKILL.md +362 -0
- package/expo/copy-overwrite/.claude/skills/local-state/references/async-storage.md +505 -0
- package/expo/copy-overwrite/.claude/skills/local-state/references/persistence-patterns.md +711 -0
- package/expo/copy-overwrite/.claude/skills/local-state/references/reactive-variables.md +446 -0
- package/expo/copy-overwrite/.claude/skills/playwright-selectors/SKILL.md +223 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/SKILL.md +319 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/references/async-patterns.md +420 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/references/expo-router-testing.md +556 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/references/mocking-patterns.md +590 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/references/query-priority.md +291 -0
- package/expo/copy-overwrite/.easignore.extra +2 -0
- package/expo/copy-overwrite/.mcp.json +33 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/README.md +234 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/__tests__/plugin-index.test.js +84 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/__tests__/require-memo-in-view.test.js +196 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/__tests__/single-component-per-file.test.js +289 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/index.js +32 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/package.json +10 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/enforce-component-structure.js +230 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/no-return-in-view.js +91 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/require-memo-in-view.js +178 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/single-component-per-file.js +238 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/README.md +260 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/index.js +29 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/package.json +10 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/rules/no-classname-outside-ui.js +51 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/rules/no-direct-rn-imports.js +55 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/rules/no-inline-styles.js +73 -0
- package/expo/copy-overwrite/eslint.config.mjs +560 -0
- package/expo/copy-overwrite/lighthouserc.js +194 -0
- package/expo/create-only/lighthouserc-config.json +28 -0
- package/expo/merge/package.json +132 -0
- package/lisa.sh +35 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/SKILL.md +176 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/advanced-features.md +527 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/project-patterns.md +483 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/quick-start.md +257 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/resolvers-mutations.md +413 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/types-scalars.md +513 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-rules/SKILL.md +536 -0
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/SKILL.md +275 -0
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/configuration-patterns.md +487 -0
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/entity-patterns.md +450 -0
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/observability-patterns.md +536 -0
- package/nestjs/merge/package.json +75 -0
- package/package.json +124 -0
- package/typescript/copy-contents/.husky/commit-msg +91 -0
- package/typescript/copy-contents/.husky/pre-commit +96 -0
- package/typescript/copy-contents/.husky/pre-push +211 -0
- package/typescript/copy-overwrite/.claude/hooks/format-on-edit.sh +74 -0
- package/typescript/copy-overwrite/.claude/hooks/install_pkgs.sh +59 -0
- package/typescript/copy-overwrite/.claude/hooks/lint-on-edit.sh +103 -0
- package/typescript/copy-overwrite/.claude/skills/jsdoc-best-practices/SKILL.md +388 -0
- package/typescript/copy-overwrite/.github/README.md +455 -0
- package/typescript/copy-overwrite/.github/dependabot.yml +40 -0
- package/typescript/copy-overwrite/.github/k6/BROWSER_TESTING_NOTE.md +129 -0
- package/typescript/copy-overwrite/.github/k6/INTEGRATION_GUIDE.md +354 -0
- package/typescript/copy-overwrite/.github/k6/README.md +386 -0
- package/typescript/copy-overwrite/.github/k6/SCENARIO_SELECTION_GUIDE.md +264 -0
- package/typescript/copy-overwrite/.github/k6/examples/customer-deploy-integration.yml +115 -0
- package/typescript/copy-overwrite/.github/k6/examples/data-driven-test.js +268 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/load.js +142 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/load.json +27 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/smoke.js +26 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/smoke.json +20 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/soak.js +244 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/soak.json +29 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/spike.js +180 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/spike.json +32 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/stress.js +206 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/stress.json +38 -0
- package/typescript/copy-overwrite/.github/k6/scripts/api-test.js +452 -0
- package/typescript/copy-overwrite/.github/k6/scripts/default-test.js +185 -0
- package/typescript/copy-overwrite/.github/k6/thresholds/normal.json +30 -0
- package/typescript/copy-overwrite/.github/k6/thresholds/relaxed.json +21 -0
- package/typescript/copy-overwrite/.github/k6/thresholds/strict.json +29 -0
- package/typescript/copy-overwrite/.github/workflows/build.yml +72 -0
- package/typescript/copy-overwrite/.github/workflows/ci.yml +49 -0
- package/typescript/copy-overwrite/.github/workflows/claude.yml +51 -0
- package/typescript/copy-overwrite/.github/workflows/create-github-issue-on-failure.yml +113 -0
- package/typescript/copy-overwrite/.github/workflows/create-jira-issue-on-failure.yml +195 -0
- package/typescript/copy-overwrite/.github/workflows/create-sentry-issue-on-failure.yml +267 -0
- package/typescript/copy-overwrite/.github/workflows/deploy.yml +228 -0
- package/typescript/copy-overwrite/.github/workflows/k6-load-test-README.md +230 -0
- package/typescript/copy-overwrite/.github/workflows/lighthouse.yml +68 -0
- package/typescript/copy-overwrite/.github/workflows/load-test.yml +282 -0
- package/typescript/copy-overwrite/.github/workflows/quality.yml +1737 -0
- package/typescript/copy-overwrite/.github/workflows/release.yml +1599 -0
- package/typescript/copy-overwrite/.gitleaksignore +28 -0
- package/typescript/copy-overwrite/.nvmrc +1 -0
- package/typescript/copy-overwrite/.prettierignore +23 -0
- package/typescript/copy-overwrite/.prettierrc.json +22 -0
- package/typescript/copy-overwrite/.versionrc +42 -0
- package/typescript/copy-overwrite/.yamllint +20 -0
- package/typescript/copy-overwrite/commitlint.config.js +11 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/README.md +149 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/__tests__/enforce-statement-order.test.js +468 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/index.js +23 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/package.json +10 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/rules/enforce-statement-order.js +157 -0
- package/typescript/copy-overwrite/eslint.config.mjs +390 -0
- package/typescript/copy-overwrite/eslint.ignore.config.json +57 -0
- package/typescript/copy-overwrite/eslint.thresholds.config.json +5 -0
- package/typescript/github-rulesets/base.json +106 -0
- package/typescript/merge/.claude/settings.json +28 -0
- package/typescript/merge/package.json +71 -0
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
# Async Testing Patterns
|
|
2
|
+
|
|
3
|
+
This reference covers best practices for handling asynchronous operations in tests.
|
|
4
|
+
|
|
5
|
+
## Core Async Utilities
|
|
6
|
+
|
|
7
|
+
### findBy Queries
|
|
8
|
+
|
|
9
|
+
`findBy` queries return a Promise that resolves when the element is found. They combine `getBy` with `waitFor`.
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
// Wait for element to appear (default timeout: 4500ms)
|
|
13
|
+
const alert = await screen.findByRole("alert");
|
|
14
|
+
|
|
15
|
+
// Custom timeout
|
|
16
|
+
const alert = await screen.findByRole("alert", {}, { timeout: 10000 });
|
|
17
|
+
|
|
18
|
+
// Wait for element with specific text
|
|
19
|
+
const message = await screen.findByText("Success!");
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
#### When to Use findBy
|
|
23
|
+
|
|
24
|
+
- After triggering an action that causes async state update
|
|
25
|
+
- When waiting for data to load
|
|
26
|
+
- When waiting for animations to complete
|
|
27
|
+
- When waiting for API responses
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
test("displays success message after form submission", async () => {
|
|
31
|
+
const user = userEvent.setup();
|
|
32
|
+
render(<ContactForm />);
|
|
33
|
+
|
|
34
|
+
await user.type(screen.getByLabelText("Email"), "test@example.com");
|
|
35
|
+
await user.press(screen.getByRole("button", { name: "Submit" }));
|
|
36
|
+
|
|
37
|
+
// Wait for success message to appear
|
|
38
|
+
expect(await screen.findByRole("alert")).toHaveTextContent("Message sent!");
|
|
39
|
+
});
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### waitFor Utility
|
|
43
|
+
|
|
44
|
+
`waitFor` repeatedly runs a callback until it stops throwing or times out.
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
import { waitFor } from "@testing-library/react-native";
|
|
48
|
+
|
|
49
|
+
// Wait for a mock to be called
|
|
50
|
+
await waitFor(() => {
|
|
51
|
+
expect(mockFunction).toHaveBeenCalled();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Wait for specific call arguments
|
|
55
|
+
await waitFor(() => {
|
|
56
|
+
expect(mockApi.post).toHaveBeenCalledWith("/submit", {
|
|
57
|
+
email: "test@example.com",
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
#### waitFor Configuration
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
await waitFor(
|
|
66
|
+
() => {
|
|
67
|
+
expect(element).toBeOnTheScreen();
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
timeout: 5000, // Max wait time (default: 4500ms)
|
|
71
|
+
interval: 100, // Check interval (default: 50ms)
|
|
72
|
+
onTimeout: error => {
|
|
73
|
+
// Custom error handling
|
|
74
|
+
console.log("Timed out waiting for element");
|
|
75
|
+
return error;
|
|
76
|
+
},
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### waitForElementToBeRemoved
|
|
82
|
+
|
|
83
|
+
Wait for an element to be removed from the screen.
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import { waitForElementToBeRemoved } from "@testing-library/react-native";
|
|
87
|
+
|
|
88
|
+
// Wait for loading indicator to disappear
|
|
89
|
+
await waitForElementToBeRemoved(() => screen.queryByRole("progressbar"));
|
|
90
|
+
|
|
91
|
+
// Alternative pattern
|
|
92
|
+
const loadingSpinner = screen.getByRole("progressbar");
|
|
93
|
+
await waitForElementToBeRemoved(loadingSpinner);
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Common Async Patterns
|
|
97
|
+
|
|
98
|
+
### Loading States
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
test("displays loading state then content", async () => {
|
|
102
|
+
render(<DataFetcher />);
|
|
103
|
+
|
|
104
|
+
// Assert loading state appears
|
|
105
|
+
expect(screen.getByRole("progressbar")).toBeOnTheScreen();
|
|
106
|
+
|
|
107
|
+
// Wait for loading to complete
|
|
108
|
+
await waitForElementToBeRemoved(() => screen.queryByRole("progressbar"));
|
|
109
|
+
|
|
110
|
+
// Assert content is now displayed
|
|
111
|
+
expect(screen.getByRole("list")).toBeOnTheScreen();
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Error States
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
test("displays error message when API fails", async () => {
|
|
119
|
+
mockApi.get.mockRejectedValue(new Error("Network error"));
|
|
120
|
+
const user = userEvent.setup();
|
|
121
|
+
render(<DataFetcher />);
|
|
122
|
+
|
|
123
|
+
await user.press(screen.getByRole("button", { name: "Fetch Data" }));
|
|
124
|
+
|
|
125
|
+
// Wait for error message
|
|
126
|
+
expect(await screen.findByRole("alert")).toHaveTextContent("Network error");
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Sequential Async Operations
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
test("completes multi-step wizard", async () => {
|
|
134
|
+
const user = userEvent.setup();
|
|
135
|
+
render(<Wizard />);
|
|
136
|
+
|
|
137
|
+
// Step 1
|
|
138
|
+
await user.type(screen.getByLabelText("Name"), "John Doe");
|
|
139
|
+
await user.press(screen.getByRole("button", { name: "Next" }));
|
|
140
|
+
|
|
141
|
+
// Wait for step 2 to load
|
|
142
|
+
expect(await screen.findByText("Step 2")).toBeOnTheScreen();
|
|
143
|
+
|
|
144
|
+
// Step 2
|
|
145
|
+
await user.type(screen.getByLabelText("Email"), "john@example.com");
|
|
146
|
+
await user.press(screen.getByRole("button", { name: "Submit" }));
|
|
147
|
+
|
|
148
|
+
// Wait for completion
|
|
149
|
+
expect(await screen.findByText("Success!")).toBeOnTheScreen();
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Debounced/Throttled Operations
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
jest.useFakeTimers();
|
|
157
|
+
|
|
158
|
+
test("debounced search executes after delay", async () => {
|
|
159
|
+
const user = userEvent.setup();
|
|
160
|
+
render(<SearchInput onSearch={mockSearch} />);
|
|
161
|
+
|
|
162
|
+
await user.type(screen.getByRole("textbox"), "query");
|
|
163
|
+
|
|
164
|
+
// Search not called yet (debounced)
|
|
165
|
+
expect(mockSearch).not.toHaveBeenCalled();
|
|
166
|
+
|
|
167
|
+
// Advance timers past debounce delay
|
|
168
|
+
jest.runAllTimers();
|
|
169
|
+
|
|
170
|
+
// Now search is called
|
|
171
|
+
await waitFor(() => {
|
|
172
|
+
expect(mockSearch).toHaveBeenCalledWith("query");
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Anti-Patterns
|
|
178
|
+
|
|
179
|
+
### Side Effects Inside waitFor
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
// Wrong - fireEvent inside waitFor
|
|
183
|
+
await waitFor(() => {
|
|
184
|
+
fireEvent.press(button);
|
|
185
|
+
expect(result).toBeOnTheScreen();
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// Correct - side effect before waitFor
|
|
189
|
+
fireEvent.press(button);
|
|
190
|
+
await waitFor(() => {
|
|
191
|
+
expect(result).toBeOnTheScreen();
|
|
192
|
+
});
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Multiple Assertions in waitFor
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
// Wrong - multiple assertions
|
|
199
|
+
await waitFor(() => {
|
|
200
|
+
expect(title).toBeOnTheScreen();
|
|
201
|
+
expect(subtitle).toBeOnTheScreen();
|
|
202
|
+
expect(button).toBeEnabled();
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
// Correct - wait for one, assert the rest synchronously
|
|
206
|
+
expect(await screen.findByRole("heading")).toBeOnTheScreen();
|
|
207
|
+
expect(screen.getByText("Subtitle")).toBeOnTheScreen();
|
|
208
|
+
expect(screen.getByRole("button")).toBeEnabled();
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Empty Callback in waitFor
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
// Wrong - empty callback
|
|
215
|
+
await waitFor(() => {});
|
|
216
|
+
|
|
217
|
+
// Correct - explicit assertion
|
|
218
|
+
await waitFor(() => {
|
|
219
|
+
expect(element).toBeOnTheScreen();
|
|
220
|
+
});
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Using waitFor When findBy Works
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
// Unnecessary - waitFor wrapping getBy
|
|
227
|
+
await waitFor(() => {
|
|
228
|
+
expect(screen.getByRole("alert")).toBeOnTheScreen();
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
// Better - use findBy directly
|
|
232
|
+
expect(await screen.findByRole("alert")).toBeOnTheScreen();
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Wrapping Render in act()
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
// Wrong - unnecessary act wrapper
|
|
239
|
+
await act(async () => {
|
|
240
|
+
render(<Component />);
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// Correct - render handles act internally
|
|
244
|
+
render(<Component />);
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Ignoring Return Value of Async Queries
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
// Wrong - not awaiting
|
|
251
|
+
screen.findByRole("alert");
|
|
252
|
+
expect(screen.getByRole("alert")).toBeOnTheScreen();
|
|
253
|
+
|
|
254
|
+
// Correct - await the findBy
|
|
255
|
+
await screen.findByRole("alert");
|
|
256
|
+
expect(screen.getByRole("alert")).toBeOnTheScreen();
|
|
257
|
+
|
|
258
|
+
// Or better - use the returned element
|
|
259
|
+
const alert = await screen.findByRole("alert");
|
|
260
|
+
expect(alert).toBeOnTheScreen();
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## userEvent and Async
|
|
264
|
+
|
|
265
|
+
### Setup with Fake Timers
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
jest.useFakeTimers();
|
|
269
|
+
|
|
270
|
+
test("user interaction with fake timers", async () => {
|
|
271
|
+
const user = userEvent.setup({
|
|
272
|
+
advanceTimers: jest.advanceTimersByTime,
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
render(<Component />);
|
|
276
|
+
await user.press(screen.getByRole("button", { name: "Click me" }));
|
|
277
|
+
|
|
278
|
+
// Assertions...
|
|
279
|
+
});
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Awaiting userEvent Actions
|
|
283
|
+
|
|
284
|
+
All userEvent methods are async and must be awaited:
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
const user = userEvent.setup();
|
|
288
|
+
|
|
289
|
+
// All interactions must be awaited
|
|
290
|
+
await user.press(button);
|
|
291
|
+
await user.type(input, "text");
|
|
292
|
+
await user.longPress(element);
|
|
293
|
+
await user.scroll(scrollView, { y: 100 });
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Sequential vs Parallel Interactions
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
// Sequential - wait for each action
|
|
300
|
+
await user.type(emailInput, "test@example.com");
|
|
301
|
+
await user.type(passwordInput, "password123");
|
|
302
|
+
await user.press(submitButton);
|
|
303
|
+
|
|
304
|
+
// Don't use Promise.all for user interactions
|
|
305
|
+
// Users can only do one thing at a time
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
## Apollo GraphQL Async Patterns
|
|
309
|
+
|
|
310
|
+
### Mocking Query Responses
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
const mocks = [
|
|
314
|
+
{
|
|
315
|
+
request: {
|
|
316
|
+
query: GET_USER,
|
|
317
|
+
variables: { id: "1" },
|
|
318
|
+
},
|
|
319
|
+
result: {
|
|
320
|
+
data: {
|
|
321
|
+
user: { id: "1", name: "John" },
|
|
322
|
+
},
|
|
323
|
+
},
|
|
324
|
+
},
|
|
325
|
+
];
|
|
326
|
+
|
|
327
|
+
test("displays user data", async () => {
|
|
328
|
+
render(
|
|
329
|
+
<MockedProvider mocks={mocks}>
|
|
330
|
+
<UserProfile userId="1" />
|
|
331
|
+
</MockedProvider>
|
|
332
|
+
);
|
|
333
|
+
|
|
334
|
+
// Wait for data to load
|
|
335
|
+
expect(await screen.findByText("John")).toBeOnTheScreen();
|
|
336
|
+
});
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Handling Loading and Error States
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
test("shows loading then data", async () => {
|
|
343
|
+
render(
|
|
344
|
+
<MockedProvider mocks={mocks}>
|
|
345
|
+
<UserProfile userId="1" />
|
|
346
|
+
</MockedProvider>
|
|
347
|
+
);
|
|
348
|
+
|
|
349
|
+
// Initially shows loading
|
|
350
|
+
expect(screen.getByRole("progressbar")).toBeOnTheScreen();
|
|
351
|
+
|
|
352
|
+
// After data loads
|
|
353
|
+
await waitForElementToBeRemoved(() => screen.queryByRole("progressbar"));
|
|
354
|
+
expect(screen.getByText("John")).toBeOnTheScreen();
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
test("shows error on failure", async () => {
|
|
358
|
+
const errorMocks = [
|
|
359
|
+
{
|
|
360
|
+
request: { query: GET_USER, variables: { id: "1" } },
|
|
361
|
+
error: new Error("Failed to fetch"),
|
|
362
|
+
},
|
|
363
|
+
];
|
|
364
|
+
|
|
365
|
+
render(
|
|
366
|
+
<MockedProvider mocks={errorMocks}>
|
|
367
|
+
<UserProfile userId="1" />
|
|
368
|
+
</MockedProvider>
|
|
369
|
+
);
|
|
370
|
+
|
|
371
|
+
expect(await screen.findByRole("alert")).toHaveTextContent("Failed to fetch");
|
|
372
|
+
});
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
## Timer Patterns
|
|
376
|
+
|
|
377
|
+
### Fake Timers Setup
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
beforeEach(() => {
|
|
381
|
+
jest.useFakeTimers();
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
afterEach(() => {
|
|
385
|
+
jest.useRealTimers();
|
|
386
|
+
});
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### Advancing Timers
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
// Advance by specific time
|
|
393
|
+
jest.advanceTimersByTime(1000);
|
|
394
|
+
|
|
395
|
+
// Run all pending timers
|
|
396
|
+
jest.runAllTimers();
|
|
397
|
+
|
|
398
|
+
// Run only pending timers (not new ones)
|
|
399
|
+
jest.runOnlyPendingTimers();
|
|
400
|
+
|
|
401
|
+
// Advance to next timer
|
|
402
|
+
jest.advanceTimersToNextTimer();
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
### Combining Timers with Async
|
|
406
|
+
|
|
407
|
+
```typescript
|
|
408
|
+
test("animation completes after delay", async () => {
|
|
409
|
+
render(<AnimatedComponent />);
|
|
410
|
+
|
|
411
|
+
expect(screen.getByTestId("animation")).toHaveStyle({ opacity: 0 });
|
|
412
|
+
|
|
413
|
+
// Advance past animation duration
|
|
414
|
+
jest.advanceTimersByTime(500);
|
|
415
|
+
|
|
416
|
+
await waitFor(() => {
|
|
417
|
+
expect(screen.getByTestId("animation")).toHaveStyle({ opacity: 1 });
|
|
418
|
+
});
|
|
419
|
+
});
|
|
420
|
+
```
|