@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,319 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: testing-library
|
|
3
|
+
description: Enforces best practices for unit testing with Jest, @testing-library/react-native, and jest-expo in Expo projects. This skill should be used when writing, reviewing, or debugging unit tests to ensure tests are accessible, maintainable, and follow Testing Library guiding principles. Use this skill for test file creation, query selection, async handling, mocking patterns, and Expo Router testing.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Testing Library Best Practices
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
This skill enforces best practices for unit testing in Expo applications using Jest, `@testing-library/react-native`, and `jest-expo`. Tests should be **user-centric**, **accessible**, and **behavior-focused** rather than implementation-focused.
|
|
11
|
+
|
|
12
|
+
## Core Principles
|
|
13
|
+
|
|
14
|
+
### 1. Test User Behavior, Not Implementation
|
|
15
|
+
|
|
16
|
+
Focus on what the component does from a user's perspective, not how it achieves it internally.
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
// Correct - tests visible behavior
|
|
20
|
+
expect(screen.getByRole("button", { name: "Submit" })).toBeEnabled();
|
|
21
|
+
|
|
22
|
+
// Incorrect - tests implementation details
|
|
23
|
+
expect(component.state.isSubmitting).toBe(false);
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### 2. Use Accessible Queries
|
|
27
|
+
|
|
28
|
+
Queries should reflect how users and assistive technologies interact with the UI.
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
// Correct - uses accessible role and name
|
|
32
|
+
screen.getByRole("button", { name: /save changes/i });
|
|
33
|
+
|
|
34
|
+
// Incorrect - relies on implementation detail
|
|
35
|
+
screen.getByTestId("save-btn");
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 3. One Assertion Per Behavior
|
|
39
|
+
|
|
40
|
+
Each test should verify one behavior. Multiple assertions are acceptable when verifying different aspects of the same behavior.
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
// Correct - focused test
|
|
44
|
+
test("displays error message when submission fails", async () => {
|
|
45
|
+
render(<Form />);
|
|
46
|
+
await userEvent.press(screen.getByRole("button", { name: "Submit" }));
|
|
47
|
+
expect(await screen.findByRole("alert")).toHaveTextContent("Failed");
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Incorrect - testing multiple behaviors
|
|
51
|
+
test("form works correctly", async () => {
|
|
52
|
+
// Tests validation, submission, success, and error handling...
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 4. Prefer userEvent Over fireEvent
|
|
57
|
+
|
|
58
|
+
`userEvent` simulates realistic user interactions including the full event sequence.
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
// Correct - realistic interaction
|
|
62
|
+
const user = userEvent.setup();
|
|
63
|
+
await user.press(screen.getByRole("button", { name: "Submit" }));
|
|
64
|
+
|
|
65
|
+
// Less ideal - simplified event
|
|
66
|
+
fireEvent.press(screen.getByRole("button", { name: "Submit" }));
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Query Priority
|
|
70
|
+
|
|
71
|
+
Choose queries based on accessibility, following this priority order:
|
|
72
|
+
|
|
73
|
+
| Priority | Query | When to Use |
|
|
74
|
+
| -------- | ---------------- | --------------------------------------- |
|
|
75
|
+
| 1 | `getByRole` | Interactive elements, headings, buttons |
|
|
76
|
+
| 2 | `getByLabelText` | Form fields with labels |
|
|
77
|
+
| 3 | `getByText` | Non-interactive content, static text |
|
|
78
|
+
| 4 | `getByTestId` | Last resort when semantic queries fail |
|
|
79
|
+
|
|
80
|
+
For detailed query patterns, see [references/query-priority.md](references/query-priority.md).
|
|
81
|
+
|
|
82
|
+
## Async Testing Patterns
|
|
83
|
+
|
|
84
|
+
### Use findBy for Async Assertions
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
// Correct - waits for element to appear
|
|
88
|
+
expect(await screen.findByRole("alert")).toBeOnTheScreen();
|
|
89
|
+
|
|
90
|
+
// Incorrect - may fail if element appears async
|
|
91
|
+
expect(screen.getByRole("alert")).toBeOnTheScreen();
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Use waitFor for Side Effects
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
// Correct - assertion inside waitFor
|
|
98
|
+
await waitFor(() => {
|
|
99
|
+
expect(mockCallback).toHaveBeenCalledWith("success");
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Incorrect - side effect inside waitFor
|
|
103
|
+
await waitFor(() => {
|
|
104
|
+
fireEvent.press(button); // Never do this
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
For comprehensive async patterns, see [references/async-patterns.md](references/async-patterns.md).
|
|
109
|
+
|
|
110
|
+
## Mocking Patterns
|
|
111
|
+
|
|
112
|
+
### Required Global Mocks
|
|
113
|
+
|
|
114
|
+
These must be configured in `jest/setup-jest.ts`:
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
// AsyncStorage
|
|
118
|
+
jest.mock("@react-native-async-storage/async-storage", () =>
|
|
119
|
+
require("@react-native-async-storage/async-storage/jest/async-storage-mock")
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
// Expo Fonts (to avoid async icon assertions)
|
|
123
|
+
jest.mock("expo-font", () => ({
|
|
124
|
+
...jest.requireActual("expo-font"),
|
|
125
|
+
isLoaded: jest.fn(() => true),
|
|
126
|
+
}));
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
For complete mocking patterns, see [references/mocking-patterns.md](references/mocking-patterns.md).
|
|
130
|
+
|
|
131
|
+
## Expo Router Testing
|
|
132
|
+
|
|
133
|
+
Use `renderRouter` from `expo-router/testing-library` instead of `render` when testing components that use Expo Router.
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
import { renderRouter, screen } from "expo-router/testing-library";
|
|
137
|
+
|
|
138
|
+
test("navigates to player detail", async () => {
|
|
139
|
+
renderRouter({
|
|
140
|
+
index: () => <PlayerList />,
|
|
141
|
+
"players/[id]": () => <PlayerDetail />,
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
await userEvent.press(screen.getByRole("button", { name: "View Player" }));
|
|
145
|
+
expect(screen).toHavePathname("/players/123");
|
|
146
|
+
});
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
For Expo Router testing details, see [references/expo-router-testing.md](references/expo-router-testing.md).
|
|
150
|
+
|
|
151
|
+
## Test Structure
|
|
152
|
+
|
|
153
|
+
### File Organization
|
|
154
|
+
|
|
155
|
+
- Place test files in `__tests__/` directories, not alongside source files
|
|
156
|
+
- Never place tests inside the `app/` directory (Expo Router constraint)
|
|
157
|
+
- Use `.test.ts` or `.test.tsx` extensions
|
|
158
|
+
|
|
159
|
+
### AAA Pattern
|
|
160
|
+
|
|
161
|
+
Structure every test with Arrange-Act-Assert:
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
test("increments counter when button pressed", async () => {
|
|
165
|
+
// Arrange
|
|
166
|
+
const user = userEvent.setup();
|
|
167
|
+
render(<Counter initialCount={0} />);
|
|
168
|
+
|
|
169
|
+
// Act
|
|
170
|
+
await user.press(screen.getByRole("button", { name: "Increment" }));
|
|
171
|
+
|
|
172
|
+
// Assert
|
|
173
|
+
expect(screen.getByRole("text", { name: "Count: 1" })).toBeOnTheScreen();
|
|
174
|
+
});
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Descriptive Test Names
|
|
178
|
+
|
|
179
|
+
Use descriptive names that explain the expected behavior:
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
// Correct - describes behavior
|
|
183
|
+
test("displays validation error when email format is invalid", () => {});
|
|
184
|
+
test("disables submit button while form is submitting", () => {});
|
|
185
|
+
|
|
186
|
+
// Incorrect - vague or implementation-focused
|
|
187
|
+
test("email validation works", () => {});
|
|
188
|
+
test("sets isSubmitting to true", () => {});
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Jest Configuration
|
|
192
|
+
|
|
193
|
+
### Use jest-expo Universal Preset
|
|
194
|
+
|
|
195
|
+
Configure Jest to test across all Expo platforms:
|
|
196
|
+
|
|
197
|
+
```json
|
|
198
|
+
{
|
|
199
|
+
"jest": {
|
|
200
|
+
"preset": "jest-expo/universal"
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Use Fake Timers with userEvent
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
jest.useFakeTimers();
|
|
209
|
+
|
|
210
|
+
test("handles debounced input", async () => {
|
|
211
|
+
const user = userEvent.setup();
|
|
212
|
+
render(<SearchInput />);
|
|
213
|
+
|
|
214
|
+
await user.type(screen.getByRole("textbox"), "query");
|
|
215
|
+
jest.runAllTimers();
|
|
216
|
+
|
|
217
|
+
expect(await screen.findByText("Results")).toBeOnTheScreen();
|
|
218
|
+
});
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Anti-Patterns
|
|
222
|
+
|
|
223
|
+
### Never Test Implementation Details
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
// Wrong - testing internal state
|
|
227
|
+
expect(wrapper.state().isLoading).toBe(true);
|
|
228
|
+
|
|
229
|
+
// Wrong - testing component methods
|
|
230
|
+
expect(wrapper.instance().handleSubmit).toHaveBeenCalled();
|
|
231
|
+
|
|
232
|
+
// Correct - testing visible behavior
|
|
233
|
+
expect(screen.getByRole("progressbar")).toBeOnTheScreen();
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Never Use getByTestId as Default
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
// Wrong - using testID when semantic query exists
|
|
240
|
+
screen.getByTestId("submit-button");
|
|
241
|
+
|
|
242
|
+
// Correct - using accessible query
|
|
243
|
+
screen.getByRole("button", { name: "Submit" });
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Never Wrap render or fireEvent in act()
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
// Wrong - unnecessary act wrapper
|
|
250
|
+
await act(async () => {
|
|
251
|
+
render(<Component />);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// Correct - render already wraps in act
|
|
255
|
+
render(<Component />);
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Never Put Side Effects in waitFor
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
// Wrong - side effect in waitFor
|
|
262
|
+
await waitFor(() => {
|
|
263
|
+
fireEvent.press(button);
|
|
264
|
+
expect(result).toBeOnTheScreen();
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// Correct - side effect before waitFor
|
|
268
|
+
fireEvent.press(button);
|
|
269
|
+
await waitFor(() => {
|
|
270
|
+
expect(result).toBeOnTheScreen();
|
|
271
|
+
});
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Never Use Multiple Assertions in waitFor
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
// Wrong - multiple assertions
|
|
278
|
+
await waitFor(() => {
|
|
279
|
+
expect(title).toBeOnTheScreen();
|
|
280
|
+
expect(subtitle).toBeOnTheScreen();
|
|
281
|
+
expect(button).toBeEnabled();
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
// Correct - single assertion, chain with findBy
|
|
285
|
+
expect(await screen.findByRole("heading")).toBeOnTheScreen();
|
|
286
|
+
expect(screen.getByText("Subtitle")).toBeOnTheScreen();
|
|
287
|
+
expect(screen.getByRole("button")).toBeEnabled();
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Quick Reference
|
|
291
|
+
|
|
292
|
+
### Common Matchers
|
|
293
|
+
|
|
294
|
+
| Matcher | Purpose |
|
|
295
|
+
| --------------------- | ------------------------------- |
|
|
296
|
+
| `toBeOnTheScreen()` | Element is currently rendered |
|
|
297
|
+
| `toBeEnabled()` | Interactive element is enabled |
|
|
298
|
+
| `toBeDisabled()` | Interactive element is disabled |
|
|
299
|
+
| `toHaveTextContent()` | Element contains text |
|
|
300
|
+
| `toBeVisible()` | Element is visible to user |
|
|
301
|
+
| `toBeChecked()` | Checkbox/radio is checked |
|
|
302
|
+
|
|
303
|
+
### Query Variants
|
|
304
|
+
|
|
305
|
+
| Prefix | Returns | Throws on 0 | Throws on >1 | Async |
|
|
306
|
+
| ---------- | -------------------- | ----------- | ------------ | ----- |
|
|
307
|
+
| getBy | Element | Yes | Yes | No |
|
|
308
|
+
| queryBy | Element \| null | No | Yes | No |
|
|
309
|
+
| findBy | Promise\<Element\> | Yes | Yes | Yes |
|
|
310
|
+
| getAllBy | Element[] | Yes | No | No |
|
|
311
|
+
| queryAllBy | Element[] | No | No | No |
|
|
312
|
+
| findAllBy | Promise\<Element[]\> | Yes | No | Yes |
|
|
313
|
+
|
|
314
|
+
## References
|
|
315
|
+
|
|
316
|
+
- [Query Priority](references/query-priority.md) - Detailed query selection guidance
|
|
317
|
+
- [Async Patterns](references/async-patterns.md) - Comprehensive async testing patterns
|
|
318
|
+
- [Mocking Patterns](references/mocking-patterns.md) - Common mocking configurations
|
|
319
|
+
- [Expo Router Testing](references/expo-router-testing.md) - Testing with Expo Router
|