shirokuma-docs 0.1.0-alpha.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/LICENSE +21 -0
- package/README.md +294 -0
- package/THIRD_PARTY_NOTICES.md +18 -0
- package/bin/shirokuma-docs +2 -0
- package/dist/analyzers/details-test-analysis.d.ts +31 -0
- package/dist/analyzers/details-test-analysis.d.ts.map +1 -0
- package/dist/analyzers/details-test-analysis.js +172 -0
- package/dist/analyzers/details-test-analysis.js.map +1 -0
- package/dist/analyzers/feature-map-builder.d.ts +20 -0
- package/dist/analyzers/feature-map-builder.d.ts.map +1 -0
- package/dist/analyzers/feature-map-builder.js +154 -0
- package/dist/analyzers/feature-map-builder.js.map +1 -0
- package/dist/analyzers/feature-map-references.d.ts +34 -0
- package/dist/analyzers/feature-map-references.d.ts.map +1 -0
- package/dist/analyzers/feature-map-references.js +249 -0
- package/dist/analyzers/feature-map-references.js.map +1 -0
- package/dist/analyzers/reference-analyzer.d.ts +95 -0
- package/dist/analyzers/reference-analyzer.d.ts.map +1 -0
- package/dist/analyzers/reference-analyzer.js +372 -0
- package/dist/analyzers/reference-analyzer.js.map +1 -0
- package/dist/commands/adr.d.ts +26 -0
- package/dist/commands/adr.d.ts.map +1 -0
- package/dist/commands/adr.js +129 -0
- package/dist/commands/adr.js.map +1 -0
- package/dist/commands/api-tools.d.ts +83 -0
- package/dist/commands/api-tools.d.ts.map +1 -0
- package/dist/commands/api-tools.js +771 -0
- package/dist/commands/api-tools.js.map +1 -0
- package/dist/commands/coverage.d.ts +139 -0
- package/dist/commands/coverage.d.ts.map +1 -0
- package/dist/commands/coverage.js +481 -0
- package/dist/commands/coverage.js.map +1 -0
- package/dist/commands/deps.d.ts +24 -0
- package/dist/commands/deps.d.ts.map +1 -0
- package/dist/commands/deps.js +211 -0
- package/dist/commands/deps.js.map +1 -0
- package/dist/commands/details-context.d.ts +38 -0
- package/dist/commands/details-context.d.ts.map +1 -0
- package/dist/commands/details-context.js +193 -0
- package/dist/commands/details-context.js.map +1 -0
- package/dist/commands/details-types.d.ts +315 -0
- package/dist/commands/details-types.d.ts.map +1 -0
- package/dist/commands/details-types.js +7 -0
- package/dist/commands/details-types.js.map +1 -0
- package/dist/commands/details.d.ts +24 -0
- package/dist/commands/details.d.ts.map +1 -0
- package/dist/commands/details.js +299 -0
- package/dist/commands/details.js.map +1 -0
- package/dist/commands/discussion-templates.d.ts +26 -0
- package/dist/commands/discussion-templates.d.ts.map +1 -0
- package/dist/commands/discussion-templates.js +270 -0
- package/dist/commands/discussion-templates.js.map +1 -0
- package/dist/commands/discussions.d.ts +31 -0
- package/dist/commands/discussions.d.ts.map +1 -0
- package/dist/commands/discussions.js +743 -0
- package/dist/commands/discussions.js.map +1 -0
- package/dist/commands/feature-map-types.d.ts +294 -0
- package/dist/commands/feature-map-types.d.ts.map +1 -0
- package/dist/commands/feature-map-types.js +8 -0
- package/dist/commands/feature-map-types.js.map +1 -0
- package/dist/commands/feature-map.d.ts +30 -0
- package/dist/commands/feature-map.d.ts.map +1 -0
- package/dist/commands/feature-map.js +137 -0
- package/dist/commands/feature-map.js.map +1 -0
- package/dist/commands/generate.d.ts +16 -0
- package/dist/commands/generate.d.ts.map +1 -0
- package/dist/commands/generate.js +88 -0
- package/dist/commands/generate.js.map +1 -0
- package/dist/commands/gh-discussions.d.ts +31 -0
- package/dist/commands/gh-discussions.d.ts.map +1 -0
- package/dist/commands/gh-discussions.js +743 -0
- package/dist/commands/gh-discussions.js.map +1 -0
- package/dist/commands/gh-issues-pr.d.ts +74 -0
- package/dist/commands/gh-issues-pr.d.ts.map +1 -0
- package/dist/commands/gh-issues-pr.js +417 -0
- package/dist/commands/gh-issues-pr.js.map +1 -0
- package/dist/commands/gh-issues.d.ts +90 -0
- package/dist/commands/gh-issues.d.ts.map +1 -0
- package/dist/commands/gh-issues.js +1297 -0
- package/dist/commands/gh-issues.js.map +1 -0
- package/dist/commands/gh-projects.d.ts +54 -0
- package/dist/commands/gh-projects.d.ts.map +1 -0
- package/dist/commands/gh-projects.js +966 -0
- package/dist/commands/gh-projects.js.map +1 -0
- package/dist/commands/gh-repo.d.ts +18 -0
- package/dist/commands/gh-repo.d.ts.map +1 -0
- package/dist/commands/gh-repo.js +253 -0
- package/dist/commands/gh-repo.js.map +1 -0
- package/dist/commands/github-data.d.ts +67 -0
- package/dist/commands/github-data.d.ts.map +1 -0
- package/dist/commands/github-data.js +361 -0
- package/dist/commands/github-data.js.map +1 -0
- package/dist/commands/i18n.d.ts +102 -0
- package/dist/commands/i18n.d.ts.map +1 -0
- package/dist/commands/i18n.js +829 -0
- package/dist/commands/i18n.js.map +1 -0
- package/dist/commands/impact.d.ts +14 -0
- package/dist/commands/impact.d.ts.map +1 -0
- package/dist/commands/impact.js +263 -0
- package/dist/commands/impact.js.map +1 -0
- package/dist/commands/init.d.ts +53 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +407 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/issues-pr.d.ts +74 -0
- package/dist/commands/issues-pr.d.ts.map +1 -0
- package/dist/commands/issues-pr.js +417 -0
- package/dist/commands/issues-pr.js.map +1 -0
- package/dist/commands/issues.d.ts +76 -0
- package/dist/commands/issues.d.ts.map +1 -0
- package/dist/commands/issues.js +1285 -0
- package/dist/commands/issues.js.map +1 -0
- package/dist/commands/link-docs.d.ts +21 -0
- package/dist/commands/link-docs.d.ts.map +1 -0
- package/dist/commands/link-docs.js +990 -0
- package/dist/commands/link-docs.js.map +1 -0
- package/dist/commands/lint-annotations.d.ts +28 -0
- package/dist/commands/lint-annotations.d.ts.map +1 -0
- package/dist/commands/lint-annotations.js +511 -0
- package/dist/commands/lint-annotations.js.map +1 -0
- package/dist/commands/lint-code.d.ts +26 -0
- package/dist/commands/lint-code.d.ts.map +1 -0
- package/dist/commands/lint-code.js +428 -0
- package/dist/commands/lint-code.js.map +1 -0
- package/dist/commands/lint-coverage.d.ts +33 -0
- package/dist/commands/lint-coverage.d.ts.map +1 -0
- package/dist/commands/lint-coverage.js +379 -0
- package/dist/commands/lint-coverage.js.map +1 -0
- package/dist/commands/lint-docs.d.ts +23 -0
- package/dist/commands/lint-docs.d.ts.map +1 -0
- package/dist/commands/lint-docs.js +338 -0
- package/dist/commands/lint-docs.js.map +1 -0
- package/dist/commands/lint-structure.d.ts +38 -0
- package/dist/commands/lint-structure.d.ts.map +1 -0
- package/dist/commands/lint-structure.js +350 -0
- package/dist/commands/lint-structure.js.map +1 -0
- package/dist/commands/lint-tests.d.ts +25 -0
- package/dist/commands/lint-tests.d.ts.map +1 -0
- package/dist/commands/lint-tests.js +105 -0
- package/dist/commands/lint-tests.js.map +1 -0
- package/dist/commands/lint-workflow.d.ts +36 -0
- package/dist/commands/lint-workflow.d.ts.map +1 -0
- package/dist/commands/lint-workflow.js +255 -0
- package/dist/commands/lint-workflow.js.map +1 -0
- package/dist/commands/overview.d.ts +21 -0
- package/dist/commands/overview.d.ts.map +1 -0
- package/dist/commands/overview.js +1300 -0
- package/dist/commands/overview.js.map +1 -0
- package/dist/commands/packages.d.ts +107 -0
- package/dist/commands/packages.d.ts.map +1 -0
- package/dist/commands/packages.js +308 -0
- package/dist/commands/packages.js.map +1 -0
- package/dist/commands/portal-nextjs.d.ts +23 -0
- package/dist/commands/portal-nextjs.d.ts.map +1 -0
- package/dist/commands/portal-nextjs.js +336 -0
- package/dist/commands/portal-nextjs.js.map +1 -0
- package/dist/commands/portal.d.ts +24 -0
- package/dist/commands/portal.d.ts.map +1 -0
- package/dist/commands/portal.js +16 -0
- package/dist/commands/portal.js.map +1 -0
- package/dist/commands/projects.d.ts +54 -0
- package/dist/commands/projects.d.ts.map +1 -0
- package/dist/commands/projects.js +969 -0
- package/dist/commands/projects.js.map +1 -0
- package/dist/commands/repo-pairs.d.ts +19 -0
- package/dist/commands/repo-pairs.d.ts.map +1 -0
- package/dist/commands/repo-pairs.js +529 -0
- package/dist/commands/repo-pairs.js.map +1 -0
- package/dist/commands/repo.d.ts +18 -0
- package/dist/commands/repo.d.ts.map +1 -0
- package/dist/commands/repo.js +253 -0
- package/dist/commands/repo.js.map +1 -0
- package/dist/commands/schema.d.ts +49 -0
- package/dist/commands/schema.d.ts.map +1 -0
- package/dist/commands/schema.js +830 -0
- package/dist/commands/schema.js.map +1 -0
- package/dist/commands/screenshots.d.ts +203 -0
- package/dist/commands/screenshots.d.ts.map +1 -0
- package/dist/commands/screenshots.js +1234 -0
- package/dist/commands/screenshots.js.map +1 -0
- package/dist/commands/search-index.d.ts +83 -0
- package/dist/commands/search-index.d.ts.map +1 -0
- package/dist/commands/search-index.js +389 -0
- package/dist/commands/search-index.js.map +1 -0
- package/dist/commands/session.d.ts +153 -0
- package/dist/commands/session.d.ts.map +1 -0
- package/dist/commands/session.js +1243 -0
- package/dist/commands/session.js.map +1 -0
- package/dist/commands/test-cases-types.d.ts +154 -0
- package/dist/commands/test-cases-types.d.ts.map +1 -0
- package/dist/commands/test-cases-types.js +7 -0
- package/dist/commands/test-cases-types.js.map +1 -0
- package/dist/commands/test-cases.d.ts +28 -0
- package/dist/commands/test-cases.d.ts.map +1 -0
- package/dist/commands/test-cases.js +192 -0
- package/dist/commands/test-cases.js.map +1 -0
- package/dist/commands/typedoc.d.ts +21 -0
- package/dist/commands/typedoc.d.ts.map +1 -0
- package/dist/commands/typedoc.js +192 -0
- package/dist/commands/typedoc.js.map +1 -0
- package/dist/commands/update-skills.d.ts +56 -0
- package/dist/commands/update-skills.d.ts.map +1 -0
- package/dist/commands/update-skills.js +599 -0
- package/dist/commands/update-skills.js.map +1 -0
- package/dist/generators/details-entity-pages.d.ts +40 -0
- package/dist/generators/details-entity-pages.d.ts.map +1 -0
- package/dist/generators/details-entity-pages.js +301 -0
- package/dist/generators/details-entity-pages.js.map +1 -0
- package/dist/generators/details-html.d.ts +23 -0
- package/dist/generators/details-html.d.ts.map +1 -0
- package/dist/generators/details-html.js +324 -0
- package/dist/generators/details-html.js.map +1 -0
- package/dist/generators/details-module-page.d.ts +33 -0
- package/dist/generators/details-module-page.d.ts.map +1 -0
- package/dist/generators/details-module-page.js +408 -0
- package/dist/generators/details-module-page.js.map +1 -0
- package/dist/generators/details-styles.d.ts +39 -0
- package/dist/generators/details-styles.d.ts.map +1 -0
- package/dist/generators/details-styles.js +409 -0
- package/dist/generators/details-styles.js.map +1 -0
- package/dist/generators/feature-map-html.d.ts +66 -0
- package/dist/generators/feature-map-html.d.ts.map +1 -0
- package/dist/generators/feature-map-html.js +569 -0
- package/dist/generators/feature-map-html.js.map +1 -0
- package/dist/generators/feature-map-styles.d.ts +39 -0
- package/dist/generators/feature-map-styles.d.ts.map +1 -0
- package/dist/generators/feature-map-styles.js +449 -0
- package/dist/generators/feature-map-styles.js.map +1 -0
- package/dist/generators/test-cases-hierarchy.d.ts +21 -0
- package/dist/generators/test-cases-hierarchy.d.ts.map +1 -0
- package/dist/generators/test-cases-hierarchy.js +336 -0
- package/dist/generators/test-cases-hierarchy.js.map +1 -0
- package/dist/generators/test-cases-main.d.ts +20 -0
- package/dist/generators/test-cases-main.d.ts.map +1 -0
- package/dist/generators/test-cases-main.js +439 -0
- package/dist/generators/test-cases-main.js.map +1 -0
- package/dist/generators/test-cases-styles.d.ts +64 -0
- package/dist/generators/test-cases-styles.d.ts.map +1 -0
- package/dist/generators/test-cases-styles.js +1277 -0
- package/dist/generators/test-cases-styles.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +517 -0
- package/dist/index.js.map +1 -0
- package/dist/lint/annotation-lint.d.ts +198 -0
- package/dist/lint/annotation-lint.d.ts.map +1 -0
- package/dist/lint/annotation-lint.js +510 -0
- package/dist/lint/annotation-lint.js.map +1 -0
- package/dist/lint/annotation-types.d.ts +161 -0
- package/dist/lint/annotation-types.d.ts.map +1 -0
- package/dist/lint/annotation-types.js +31 -0
- package/dist/lint/annotation-types.js.map +1 -0
- package/dist/lint/code-types.d.ts +135 -0
- package/dist/lint/code-types.d.ts.map +1 -0
- package/dist/lint/code-types.js +25 -0
- package/dist/lint/code-types.js.map +1 -0
- package/dist/lint/coverage-types.d.ts +128 -0
- package/dist/lint/coverage-types.d.ts.map +1 -0
- package/dist/lint/coverage-types.js +24 -0
- package/dist/lint/coverage-types.js.map +1 -0
- package/dist/lint/docs-types.d.ts +214 -0
- package/dist/lint/docs-types.d.ts.map +1 -0
- package/dist/lint/docs-types.js +18 -0
- package/dist/lint/docs-types.js.map +1 -0
- package/dist/lint/formatters/index.d.ts +14 -0
- package/dist/lint/formatters/index.d.ts.map +1 -0
- package/dist/lint/formatters/index.js +28 -0
- package/dist/lint/formatters/index.js.map +1 -0
- package/dist/lint/formatters/json.d.ts +11 -0
- package/dist/lint/formatters/json.d.ts.map +1 -0
- package/dist/lint/formatters/json.js +12 -0
- package/dist/lint/formatters/json.js.map +1 -0
- package/dist/lint/formatters/summary.d.ts +11 -0
- package/dist/lint/formatters/summary.d.ts.map +1 -0
- package/dist/lint/formatters/summary.js +37 -0
- package/dist/lint/formatters/summary.js.map +1 -0
- package/dist/lint/formatters/terminal.d.ts +11 -0
- package/dist/lint/formatters/terminal.d.ts.map +1 -0
- package/dist/lint/formatters/terminal.js +99 -0
- package/dist/lint/formatters/terminal.js.map +1 -0
- package/dist/lint/index.d.ts +18 -0
- package/dist/lint/index.d.ts.map +1 -0
- package/dist/lint/index.js +103 -0
- package/dist/lint/index.js.map +1 -0
- package/dist/lint/rules/annotation-required.d.ts +35 -0
- package/dist/lint/rules/annotation-required.d.ts.map +1 -0
- package/dist/lint/rules/annotation-required.js +127 -0
- package/dist/lint/rules/annotation-required.js.map +1 -0
- package/dist/lint/rules/code-rules.d.ts +12 -0
- package/dist/lint/rules/code-rules.d.ts.map +1 -0
- package/dist/lint/rules/code-rules.js +11 -0
- package/dist/lint/rules/code-rules.js.map +1 -0
- package/dist/lint/rules/describe-coverage.d.ts +8 -0
- package/dist/lint/rules/describe-coverage.d.ts.map +1 -0
- package/dist/lint/rules/describe-coverage.js +43 -0
- package/dist/lint/rules/describe-coverage.js.map +1 -0
- package/dist/lint/rules/duplicate-testdoc.d.ts +8 -0
- package/dist/lint/rules/duplicate-testdoc.d.ts.map +1 -0
- package/dist/lint/rules/duplicate-testdoc.js +38 -0
- package/dist/lint/rules/duplicate-testdoc.js.map +1 -0
- package/dist/lint/rules/index.d.ts +29 -0
- package/dist/lint/rules/index.d.ts.map +1 -0
- package/dist/lint/rules/index.js +55 -0
- package/dist/lint/rules/index.js.map +1 -0
- package/dist/lint/rules/server-action-structure.d.ts +37 -0
- package/dist/lint/rules/server-action-structure.d.ts.map +1 -0
- package/dist/lint/rules/server-action-structure.js +151 -0
- package/dist/lint/rules/server-action-structure.js.map +1 -0
- package/dist/lint/rules/skipped-test-report.d.ts +11 -0
- package/dist/lint/rules/skipped-test-report.d.ts.map +1 -0
- package/dist/lint/rules/skipped-test-report.js +31 -0
- package/dist/lint/rules/skipped-test-report.js.map +1 -0
- package/dist/lint/rules/structure-rules.d.ts +67 -0
- package/dist/lint/rules/structure-rules.d.ts.map +1 -0
- package/dist/lint/rules/structure-rules.js +615 -0
- package/dist/lint/rules/structure-rules.js.map +1 -0
- package/dist/lint/rules/testdoc-japanese.d.ts +8 -0
- package/dist/lint/rules/testdoc-japanese.d.ts.map +1 -0
- package/dist/lint/rules/testdoc-japanese.js +31 -0
- package/dist/lint/rules/testdoc-japanese.js.map +1 -0
- package/dist/lint/rules/testdoc-min-length.d.ts +8 -0
- package/dist/lint/rules/testdoc-min-length.d.ts.map +1 -0
- package/dist/lint/rules/testdoc-min-length.js +31 -0
- package/dist/lint/rules/testdoc-min-length.js.map +1 -0
- package/dist/lint/rules/testdoc-required.d.ts +8 -0
- package/dist/lint/rules/testdoc-required.d.ts.map +1 -0
- package/dist/lint/rules/testdoc-required.js +27 -0
- package/dist/lint/rules/testdoc-required.js.map +1 -0
- package/dist/lint/rules/workflow-branch-naming.d.ts +20 -0
- package/dist/lint/rules/workflow-branch-naming.d.ts.map +1 -0
- package/dist/lint/rules/workflow-branch-naming.js +85 -0
- package/dist/lint/rules/workflow-branch-naming.js.map +1 -0
- package/dist/lint/rules/workflow-commit-format.d.ts +27 -0
- package/dist/lint/rules/workflow-commit-format.d.ts.map +1 -0
- package/dist/lint/rules/workflow-commit-format.js +92 -0
- package/dist/lint/rules/workflow-commit-format.js.map +1 -0
- package/dist/lint/rules/workflow-issue-fields.d.ts +24 -0
- package/dist/lint/rules/workflow-issue-fields.d.ts.map +1 -0
- package/dist/lint/rules/workflow-issue-fields.js +89 -0
- package/dist/lint/rules/workflow-issue-fields.js.map +1 -0
- package/dist/lint/rules/workflow-main-protection.d.ts +32 -0
- package/dist/lint/rules/workflow-main-protection.d.ts.map +1 -0
- package/dist/lint/rules/workflow-main-protection.js +114 -0
- package/dist/lint/rules/workflow-main-protection.js.map +1 -0
- package/dist/lint/structure-types.d.ts +216 -0
- package/dist/lint/structure-types.d.ts.map +1 -0
- package/dist/lint/structure-types.js +96 -0
- package/dist/lint/structure-types.js.map +1 -0
- package/dist/lint/types.d.ts +154 -0
- package/dist/lint/types.d.ts.map +1 -0
- package/dist/lint/types.js +21 -0
- package/dist/lint/types.js.map +1 -0
- package/dist/lint/workflow-types.d.ts +90 -0
- package/dist/lint/workflow-types.d.ts.map +1 -0
- package/dist/lint/workflow-types.js +7 -0
- package/dist/lint/workflow-types.js.map +1 -0
- package/dist/md/analyzer/index.d.ts +46 -0
- package/dist/md/analyzer/index.d.ts.map +1 -0
- package/dist/md/analyzer/index.js +288 -0
- package/dist/md/analyzer/index.js.map +1 -0
- package/dist/md/builder/index.d.ts +91 -0
- package/dist/md/builder/index.d.ts.map +1 -0
- package/dist/md/builder/index.js +446 -0
- package/dist/md/builder/index.js.map +1 -0
- package/dist/md/cli/analyze.d.ts +11 -0
- package/dist/md/cli/analyze.d.ts.map +1 -0
- package/dist/md/cli/analyze.js +118 -0
- package/dist/md/cli/analyze.js.map +1 -0
- package/dist/md/cli/build.d.ts +11 -0
- package/dist/md/cli/build.d.ts.map +1 -0
- package/dist/md/cli/build.js +74 -0
- package/dist/md/cli/build.js.map +1 -0
- package/dist/md/cli/extract.d.ts +25 -0
- package/dist/md/cli/extract.d.ts.map +1 -0
- package/dist/md/cli/extract.js +230 -0
- package/dist/md/cli/extract.js.map +1 -0
- package/dist/md/cli/index.d.ts +3 -0
- package/dist/md/cli/index.d.ts.map +1 -0
- package/dist/md/cli/index.js +99 -0
- package/dist/md/cli/index.js.map +1 -0
- package/dist/md/cli/lint.d.ts +11 -0
- package/dist/md/cli/lint.d.ts.map +1 -0
- package/dist/md/cli/lint.js +165 -0
- package/dist/md/cli/lint.js.map +1 -0
- package/dist/md/cli/list.d.ts +16 -0
- package/dist/md/cli/list.d.ts.map +1 -0
- package/dist/md/cli/list.js +85 -0
- package/dist/md/cli/list.js.map +1 -0
- package/dist/md/cli/program.d.ts +11 -0
- package/dist/md/cli/program.d.ts.map +1 -0
- package/dist/md/cli/program.js +104 -0
- package/dist/md/cli/program.js.map +1 -0
- package/dist/md/cli/validate.d.ts +8 -0
- package/dist/md/cli/validate.d.ts.map +1 -0
- package/dist/md/cli/validate.js +82 -0
- package/dist/md/cli/validate.js.map +1 -0
- package/dist/md/constants.d.ts +69 -0
- package/dist/md/constants.d.ts.map +1 -0
- package/dist/md/constants.js +69 -0
- package/dist/md/constants.js.map +1 -0
- package/dist/md/extractor/index.d.ts +57 -0
- package/dist/md/extractor/index.d.ts.map +1 -0
- package/dist/md/extractor/index.js +359 -0
- package/dist/md/extractor/index.js.map +1 -0
- package/dist/md/index.d.ts +26 -0
- package/dist/md/index.d.ts.map +1 -0
- package/dist/md/index.js +30 -0
- package/dist/md/index.js.map +1 -0
- package/dist/md/linter/index.d.ts +20 -0
- package/dist/md/linter/index.d.ts.map +1 -0
- package/dist/md/linter/index.js +412 -0
- package/dist/md/linter/index.js.map +1 -0
- package/dist/md/linter/token-optimizer.d.ts +66 -0
- package/dist/md/linter/token-optimizer.d.ts.map +1 -0
- package/dist/md/linter/token-optimizer.js +292 -0
- package/dist/md/linter/token-optimizer.js.map +1 -0
- package/dist/md/lister/index.d.ts +42 -0
- package/dist/md/lister/index.d.ts.map +1 -0
- package/dist/md/lister/index.js +317 -0
- package/dist/md/lister/index.js.map +1 -0
- package/dist/md/parser/heading-numbers.d.ts +43 -0
- package/dist/md/parser/heading-numbers.d.ts.map +1 -0
- package/dist/md/parser/heading-numbers.js +97 -0
- package/dist/md/parser/heading-numbers.js.map +1 -0
- package/dist/md/parser/section-meta.d.ts +50 -0
- package/dist/md/parser/section-meta.d.ts.map +1 -0
- package/dist/md/parser/section-meta.js +212 -0
- package/dist/md/parser/section-meta.js.map +1 -0
- package/dist/md/parser/template.d.ts +56 -0
- package/dist/md/parser/template.d.ts.map +1 -0
- package/dist/md/parser/template.js +122 -0
- package/dist/md/parser/template.js.map +1 -0
- package/dist/md/plugins/loader.d.ts +15 -0
- package/dist/md/plugins/loader.d.ts.map +1 -0
- package/dist/md/plugins/loader.js +80 -0
- package/dist/md/plugins/loader.js.map +1 -0
- package/dist/md/plugins/normalize-headings.d.ts +43 -0
- package/dist/md/plugins/normalize-headings.d.ts.map +1 -0
- package/dist/md/plugins/normalize-headings.js +51 -0
- package/dist/md/plugins/normalize-headings.js.map +1 -0
- package/dist/md/plugins/normalize-whitespace.d.ts +46 -0
- package/dist/md/plugins/normalize-whitespace.d.ts.map +1 -0
- package/dist/md/plugins/normalize-whitespace.js +86 -0
- package/dist/md/plugins/normalize-whitespace.js.map +1 -0
- package/dist/md/plugins/remove-badges.d.ts +36 -0
- package/dist/md/plugins/remove-badges.d.ts.map +1 -0
- package/dist/md/plugins/remove-badges.js +59 -0
- package/dist/md/plugins/remove-badges.js.map +1 -0
- package/dist/md/plugins/remove-comments.d.ts +27 -0
- package/dist/md/plugins/remove-comments.d.ts.map +1 -0
- package/dist/md/plugins/remove-comments.js +40 -0
- package/dist/md/plugins/remove-comments.js.map +1 -0
- package/dist/md/plugins/remove-duplicates.d.ts +40 -0
- package/dist/md/plugins/remove-duplicates.d.ts.map +1 -0
- package/dist/md/plugins/remove-duplicates.js +72 -0
- package/dist/md/plugins/remove-duplicates.js.map +1 -0
- package/dist/md/plugins/remove-internal-links.d.ts +38 -0
- package/dist/md/plugins/remove-internal-links.d.ts.map +1 -0
- package/dist/md/plugins/remove-internal-links.js +66 -0
- package/dist/md/plugins/remove-internal-links.js.map +1 -0
- package/dist/md/plugins/strip-heading-numbers.d.ts +35 -0
- package/dist/md/plugins/strip-heading-numbers.d.ts.map +1 -0
- package/dist/md/plugins/strip-heading-numbers.js +59 -0
- package/dist/md/plugins/strip-heading-numbers.js.map +1 -0
- package/dist/md/plugins/strip-section-meta.d.ts +37 -0
- package/dist/md/plugins/strip-section-meta.d.ts.map +1 -0
- package/dist/md/plugins/strip-section-meta.js +62 -0
- package/dist/md/plugins/strip-section-meta.js.map +1 -0
- package/dist/md/types/config.d.ts +748 -0
- package/dist/md/types/config.d.ts.map +1 -0
- package/dist/md/types/config.js +156 -0
- package/dist/md/types/config.js.map +1 -0
- package/dist/md/types/document.d.ts +37 -0
- package/dist/md/types/document.d.ts.map +1 -0
- package/dist/md/types/document.js +2 -0
- package/dist/md/types/document.js.map +1 -0
- package/dist/md/types/validation.d.ts +107 -0
- package/dist/md/types/validation.d.ts.map +1 -0
- package/dist/md/types/validation.js +2 -0
- package/dist/md/types/validation.js.map +1 -0
- package/dist/md/utils/code-blocks.d.ts +136 -0
- package/dist/md/utils/code-blocks.d.ts.map +1 -0
- package/dist/md/utils/code-blocks.js +178 -0
- package/dist/md/utils/code-blocks.js.map +1 -0
- package/dist/md/utils/config.d.ts +10 -0
- package/dist/md/utils/config.d.ts.map +1 -0
- package/dist/md/utils/config.js +99 -0
- package/dist/md/utils/config.js.map +1 -0
- package/dist/md/utils/file-collector.d.ts +78 -0
- package/dist/md/utils/file-collector.d.ts.map +1 -0
- package/dist/md/utils/file-collector.js +100 -0
- package/dist/md/utils/file-collector.js.map +1 -0
- package/dist/md/utils/markdown.d.ts +18 -0
- package/dist/md/utils/markdown.d.ts.map +1 -0
- package/dist/md/utils/markdown.js +93 -0
- package/dist/md/utils/markdown.js.map +1 -0
- package/dist/md/utils/remark.d.ts +91 -0
- package/dist/md/utils/remark.d.ts.map +1 -0
- package/dist/md/utils/remark.js +125 -0
- package/dist/md/utils/remark.js.map +1 -0
- package/dist/md/utils/tokens.d.ts +9 -0
- package/dist/md/utils/tokens.d.ts.map +1 -0
- package/dist/md/utils/tokens.js +31 -0
- package/dist/md/utils/tokens.js.map +1 -0
- package/dist/md/validator/index.d.ts +40 -0
- package/dist/md/validator/index.d.ts.map +1 -0
- package/dist/md/validator/index.js +289 -0
- package/dist/md/validator/index.js.map +1 -0
- package/dist/parsers/details-jsdoc.d.ts +46 -0
- package/dist/parsers/details-jsdoc.d.ts.map +1 -0
- package/dist/parsers/details-jsdoc.js +262 -0
- package/dist/parsers/details-jsdoc.js.map +1 -0
- package/dist/parsers/details-zod.d.ts +22 -0
- package/dist/parsers/details-zod.d.ts.map +1 -0
- package/dist/parsers/details-zod.js +145 -0
- package/dist/parsers/details-zod.js.map +1 -0
- package/dist/parsers/drizzle-schema.d.ts +92 -0
- package/dist/parsers/drizzle-schema.d.ts.map +1 -0
- package/dist/parsers/drizzle-schema.js +376 -0
- package/dist/parsers/drizzle-schema.js.map +1 -0
- package/dist/parsers/feature-map-tags.d.ts +45 -0
- package/dist/parsers/feature-map-tags.d.ts.map +1 -0
- package/dist/parsers/feature-map-tags.js +292 -0
- package/dist/parsers/feature-map-tags.js.map +1 -0
- package/dist/parsers/feature-map-type-extraction.d.ts +62 -0
- package/dist/parsers/feature-map-type-extraction.d.ts.map +1 -0
- package/dist/parsers/feature-map-type-extraction.js +347 -0
- package/dist/parsers/feature-map-type-extraction.js.map +1 -0
- package/dist/parsers/feature-map-utils.d.ts +34 -0
- package/dist/parsers/feature-map-utils.d.ts.map +1 -0
- package/dist/parsers/feature-map-utils.js +101 -0
- package/dist/parsers/feature-map-utils.js.map +1 -0
- package/dist/parsers/jsdoc-common.d.ts +209 -0
- package/dist/parsers/jsdoc-common.d.ts.map +1 -0
- package/dist/parsers/jsdoc-common.js +655 -0
- package/dist/parsers/jsdoc-common.js.map +1 -0
- package/dist/parsers/jsdoc.d.ts +76 -0
- package/dist/parsers/jsdoc.d.ts.map +1 -0
- package/dist/parsers/jsdoc.js +238 -0
- package/dist/parsers/jsdoc.js.map +1 -0
- package/dist/parsers/screenshot-annotations.d.ts +96 -0
- package/dist/parsers/screenshot-annotations.d.ts.map +1 -0
- package/dist/parsers/screenshot-annotations.js +227 -0
- package/dist/parsers/screenshot-annotations.js.map +1 -0
- package/dist/parsers/test-annotations.d.ts +46 -0
- package/dist/parsers/test-annotations.d.ts.map +1 -0
- package/dist/parsers/test-annotations.js +393 -0
- package/dist/parsers/test-annotations.js.map +1 -0
- package/dist/parsers/test-categorization.d.ts +42 -0
- package/dist/parsers/test-categorization.d.ts.map +1 -0
- package/dist/parsers/test-categorization.js +182 -0
- package/dist/parsers/test-categorization.js.map +1 -0
- package/dist/parsers/zod-schema.d.ts +105 -0
- package/dist/parsers/zod-schema.d.ts.map +1 -0
- package/dist/parsers/zod-schema.js +270 -0
- package/dist/parsers/zod-schema.js.map +1 -0
- package/dist/utils/action-inference.d.ts +23 -0
- package/dist/utils/action-inference.d.ts.map +1 -0
- package/dist/utils/action-inference.js +36 -0
- package/dist/utils/action-inference.js.map +1 -0
- package/dist/utils/app-inference.d.ts +31 -0
- package/dist/utils/app-inference.d.ts.map +1 -0
- package/dist/utils/app-inference.js +41 -0
- package/dist/utils/app-inference.js.map +1 -0
- package/dist/utils/auto-infer.d.ts +93 -0
- package/dist/utils/auto-infer.d.ts.map +1 -0
- package/dist/utils/auto-infer.js +184 -0
- package/dist/utils/auto-infer.js.map +1 -0
- package/dist/utils/config.d.ts +709 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +504 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/file.d.ts +46 -0
- package/dist/utils/file.d.ts.map +1 -0
- package/dist/utils/file.js +103 -0
- package/dist/utils/file.js.map +1 -0
- package/dist/utils/formatters.d.ts +111 -0
- package/dist/utils/formatters.d.ts.map +1 -0
- package/dist/utils/formatters.js +164 -0
- package/dist/utils/formatters.js.map +1 -0
- package/dist/utils/gh-config.d.ts +99 -0
- package/dist/utils/gh-config.d.ts.map +1 -0
- package/dist/utils/gh-config.js +247 -0
- package/dist/utils/gh-config.js.map +1 -0
- package/dist/utils/github.d.ts +98 -0
- package/dist/utils/github.d.ts.map +1 -0
- package/dist/utils/github.js +295 -0
- package/dist/utils/github.js.map +1 -0
- package/dist/utils/html.d.ts +107 -0
- package/dist/utils/html.d.ts.map +1 -0
- package/dist/utils/html.js +376 -0
- package/dist/utils/html.js.map +1 -0
- package/dist/utils/i18n.d.ts +40 -0
- package/dist/utils/i18n.d.ts.map +1 -0
- package/dist/utils/i18n.js +148 -0
- package/dist/utils/i18n.js.map +1 -0
- package/dist/utils/logger.d.ts +20 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +49 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/project-fields.d.ts +71 -0
- package/dist/utils/project-fields.d.ts.map +1 -0
- package/dist/utils/project-fields.js +318 -0
- package/dist/utils/project-fields.js.map +1 -0
- package/dist/utils/repo-pairs.d.ts +94 -0
- package/dist/utils/repo-pairs.d.ts.map +1 -0
- package/dist/utils/repo-pairs.js +196 -0
- package/dist/utils/repo-pairs.js.map +1 -0
- package/dist/utils/route-inference.d.ts +81 -0
- package/dist/utils/route-inference.d.ts.map +1 -0
- package/dist/utils/route-inference.js +137 -0
- package/dist/utils/route-inference.js.map +1 -0
- package/dist/utils/setup-check.d.ts +34 -0
- package/dist/utils/setup-check.d.ts.map +1 -0
- package/dist/utils/setup-check.js +136 -0
- package/dist/utils/setup-check.js.map +1 -0
- package/dist/utils/shirokumaignore.d.ts +55 -0
- package/dist/utils/shirokumaignore.d.ts.map +1 -0
- package/dist/utils/shirokumaignore.js +94 -0
- package/dist/utils/shirokumaignore.js.map +1 -0
- package/dist/utils/skills-repo.d.ts +309 -0
- package/dist/utils/skills-repo.d.ts.map +1 -0
- package/dist/utils/skills-repo.js +704 -0
- package/dist/utils/skills-repo.js.map +1 -0
- package/dist/utils/status-workflow.d.ts +54 -0
- package/dist/utils/status-workflow.d.ts.map +1 -0
- package/dist/utils/status-workflow.js +103 -0
- package/dist/utils/status-workflow.js.map +1 -0
- package/dist/validators/frontmatter.d.ts +41 -0
- package/dist/validators/frontmatter.d.ts.map +1 -0
- package/dist/validators/frontmatter.js +117 -0
- package/dist/validators/frontmatter.js.map +1 -0
- package/dist/validators/link-checker.d.ts +48 -0
- package/dist/validators/link-checker.d.ts.map +1 -0
- package/dist/validators/link-checker.js +108 -0
- package/dist/validators/link-checker.js.map +1 -0
- package/dist/validators/markdown-structure.d.ts +50 -0
- package/dist/validators/markdown-structure.d.ts.map +1 -0
- package/dist/validators/markdown-structure.js +253 -0
- package/dist/validators/markdown-structure.js.map +1 -0
- package/i18n/cli/en.json +155 -0
- package/i18n/cli/ja.json +155 -0
- package/i18n/discussion/en.json +191 -0
- package/i18n/discussion/ja.json +191 -0
- package/package.json +111 -0
- package/plugin/.claude-plugin/marketplace.json +25 -0
- package/plugin/shirokuma-hooks/.claude-plugin/plugin.json +17 -0
- package/plugin/shirokuma-hooks/hooks/blocked-commands.json +41 -0
- package/plugin/shirokuma-hooks/hooks/hooks.json +24 -0
- package/plugin/shirokuma-hooks/hooks/scripts/backup-handover.sh +65 -0
- package/plugin/shirokuma-hooks/hooks/scripts/block-destructive-commands.sh +87 -0
- package/plugin/shirokuma-skills-en/.claude-plugin/plugin.json +21 -0
- package/plugin/shirokuma-skills-en/rules/best-practices-first.md +154 -0
- package/plugin/shirokuma-skills-en/rules/config-authoring-flow.md +39 -0
- package/plugin/shirokuma-skills-en/rules/git-commit-style.md +58 -0
- package/plugin/shirokuma-skills-en/rules/github/.gitkeep +0 -0
- package/plugin/shirokuma-skills-en/rules/github/branch-workflow.md +313 -0
- package/plugin/shirokuma-skills-en/rules/github/discussions-usage.md +129 -0
- package/plugin/shirokuma-skills-en/rules/github/output-language.md +14 -0
- package/plugin/shirokuma-skills-en/rules/github/pr-review-response.md +37 -0
- package/plugin/shirokuma-skills-en/rules/github/project-items.md +276 -0
- package/plugin/shirokuma-skills-en/rules/memory-operations.md +38 -0
- package/plugin/shirokuma-skills-en/rules/nextjs/known-issues.md +59 -0
- package/plugin/shirokuma-skills-en/rules/nextjs/lib-structure.md +48 -0
- package/plugin/shirokuma-skills-en/rules/nextjs/radix-ui-hydration.md +30 -0
- package/plugin/shirokuma-skills-en/rules/nextjs/server-actions.md +50 -0
- package/plugin/shirokuma-skills-en/rules/nextjs/tailwind-v4.md +43 -0
- package/plugin/shirokuma-skills-en/rules/nextjs/tech-stack.md +43 -0
- package/plugin/shirokuma-skills-en/rules/nextjs/testing.md +66 -0
- package/plugin/shirokuma-skills-en/rules/output-destinations.md +112 -0
- package/plugin/shirokuma-skills-en/rules/shirokuma-docs/cli-invocation.md +15 -0
- package/plugin/shirokuma-skills-en/rules/shirokuma-docs/plugin-cache.md +54 -0
- package/plugin/shirokuma-skills-en/rules/shirokuma-docs/shirokuma-annotations.md +78 -0
- package/plugin/shirokuma-skills-en/rules/skill-authoring.md +168 -0
- package/plugin/shirokuma-skills-en/skills/.gitkeep +0 -0
- package/plugin/shirokuma-skills-en/skills/best-practices-researching/SKILL.md +144 -0
- package/plugin/shirokuma-skills-en/skills/claude-config-reviewing/SKILL.md +210 -0
- package/plugin/shirokuma-skills-en/skills/codebase-rule-discovery/SKILL.md +208 -0
- package/plugin/shirokuma-skills-en/skills/codebase-rule-discovery/patterns/discovery-categories.md +191 -0
- package/plugin/shirokuma-skills-en/skills/codebase-rule-discovery/templates/convention-proposal.md +138 -0
- package/plugin/shirokuma-skills-en/skills/codebase-rule-discovery/templates/rule-proposal.md +148 -0
- package/plugin/shirokuma-skills-en/skills/codebase-rule-discovery/workflows/analyze-codebase.md +212 -0
- package/plugin/shirokuma-skills-en/skills/committing-on-issue/SKILL.md +227 -0
- package/plugin/shirokuma-skills-en/skills/creating-pr-on-issue/SKILL.md +225 -0
- package/plugin/shirokuma-skills-en/skills/ending-session/SKILL.md +232 -0
- package/plugin/shirokuma-skills-en/skills/ending-session/templates/handover-template.md +75 -0
- package/plugin/shirokuma-skills-en/skills/frontend-designing/SKILL.md +271 -0
- package/plugin/shirokuma-skills-en/skills/frontend-designing/reference/reference.md +544 -0
- package/plugin/shirokuma-skills-en/skills/github-project-setup/SKILL.md +206 -0
- package/plugin/shirokuma-skills-en/skills/github-project-setup/reference/custom-fields.md +42 -0
- package/plugin/shirokuma-skills-en/skills/github-project-setup/reference/issue-types.md +85 -0
- package/plugin/shirokuma-skills-en/skills/github-project-setup/reference/labels.md +86 -0
- package/plugin/shirokuma-skills-en/skills/github-project-setup/reference/status-options.md +69 -0
- package/plugin/shirokuma-skills-en/skills/github-project-setup/scripts/locales/en.json +35 -0
- package/plugin/shirokuma-skills-en/skills/github-project-setup/scripts/locales/ja.json +35 -0
- package/plugin/shirokuma-skills-en/skills/github-project-setup/scripts/setup-project.py +226 -0
- package/plugin/shirokuma-skills-en/skills/managing-agents/SKILL.md +290 -0
- package/plugin/shirokuma-skills-en/skills/managing-agents/best-practices-advanced.md +326 -0
- package/plugin/shirokuma-skills-en/skills/managing-agents/best-practices.md +276 -0
- package/plugin/shirokuma-skills-en/skills/managing-agents/design-patterns.md +574 -0
- package/plugin/shirokuma-skills-en/skills/managing-agents/documentation-structure.md +214 -0
- package/plugin/shirokuma-skills-en/skills/managing-agents/examples.md +558 -0
- package/plugin/shirokuma-skills-en/skills/managing-agents/reference.md +522 -0
- package/plugin/shirokuma-skills-en/skills/managing-agents/templates/complex-agent.md +69 -0
- package/plugin/shirokuma-skills-en/skills/managing-agents/templates/creator-checker-pair.md +149 -0
- package/plugin/shirokuma-skills-en/skills/managing-agents/templates/simple-agent.md +43 -0
- package/plugin/shirokuma-skills-en/skills/managing-github-items/SKILL.md +50 -0
- package/plugin/shirokuma-skills-en/skills/managing-github-items/reference/create-item.md +82 -0
- package/plugin/shirokuma-skills-en/skills/managing-github-items/reference/create-spec.md +68 -0
- package/plugin/shirokuma-skills-en/skills/managing-github-items/reference/github-operations.md +163 -0
- package/plugin/shirokuma-skills-en/skills/managing-output-styles/SKILL.md +237 -0
- package/plugin/shirokuma-skills-en/skills/managing-output-styles/examples.md +762 -0
- package/plugin/shirokuma-skills-en/skills/managing-output-styles/reference.md +417 -0
- package/plugin/shirokuma-skills-en/skills/managing-plugins/SKILL.md +397 -0
- package/plugin/shirokuma-skills-en/skills/managing-plugins/examples-advanced.md +562 -0
- package/plugin/shirokuma-skills-en/skills/managing-plugins/examples.md +552 -0
- package/plugin/shirokuma-skills-en/skills/managing-plugins/reference.md +786 -0
- package/plugin/shirokuma-skills-en/skills/managing-rules/SKILL.md +365 -0
- package/plugin/shirokuma-skills-en/skills/managing-rules/templates/path-rule.md.template +27 -0
- package/plugin/shirokuma-skills-en/skills/managing-rules/templates/rule.md.template +15 -0
- package/plugin/shirokuma-skills-en/skills/managing-rules/templates/tech-stack.md.template +32 -0
- package/plugin/shirokuma-skills-en/skills/managing-skills/README.md +377 -0
- package/plugin/shirokuma-skills-en/skills/managing-skills/SKILL.md +418 -0
- package/plugin/shirokuma-skills-en/skills/managing-skills/architecture.md +1009 -0
- package/plugin/shirokuma-skills-en/skills/managing-skills/best-practices-testing.md +354 -0
- package/plugin/shirokuma-skills-en/skills/managing-skills/best-practices-writing.md +325 -0
- package/plugin/shirokuma-skills-en/skills/managing-skills/best-practices.md +334 -0
- package/plugin/shirokuma-skills-en/skills/managing-skills/examples.md +1024 -0
- package/plugin/shirokuma-skills-en/skills/managing-skills/reference-output-patterns.md +89 -0
- package/plugin/shirokuma-skills-en/skills/managing-skills/reference-platform.md +482 -0
- package/plugin/shirokuma-skills-en/skills/managing-skills/reference-workflows.md +98 -0
- package/plugin/shirokuma-skills-en/skills/managing-skills/reference.md +747 -0
- package/plugin/shirokuma-skills-en/skills/managing-skills/scripts/LICENSE.txt +191 -0
- package/plugin/shirokuma-skills-en/skills/managing-skills/scripts/init_skill.py +184 -0
- package/plugin/shirokuma-skills-en/skills/managing-skills/scripts/package_skill.py +109 -0
- package/plugin/shirokuma-skills-en/skills/managing-skills/scripts/quick_validate.py +128 -0
- package/plugin/shirokuma-skills-en/skills/managing-skills/updating-skills.md +675 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/SKILL.md +316 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/patterns/better-auth.md +185 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/patterns/code-patterns.md +335 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/patterns/coding-conventions.md +324 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/patterns/csp.md +97 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/patterns/csrf-protection.md +153 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/patterns/documentation.md +220 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/patterns/drizzle-orm.md +314 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/patterns/e2e-testing.md +826 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/patterns/image-optimization.md +227 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/patterns/radix-ui-hydration.md +79 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/patterns/rate-limiting.md +188 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/patterns/tailwind-v4.md +43 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/patterns/testing.md +298 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/reference/checklists.md +76 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/reference/large-scale.md +141 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/reference/reference.md +171 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/reference/report-template.md +53 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/templates/README.md +108 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/templates/component.test.tsx.template +245 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/templates/delete-button.tsx.template +86 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/templates/form-component.tsx.template +142 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/templates/messages-split/common.json.template +46 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/templates/messages-split/errors.json.template +29 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/templates/messages-split/feature.json.template +46 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/templates/messages-split/index.ts.template +26 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/templates/page-edit.tsx.template +43 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/templates/page-list.tsx.template +133 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/templates/page-new.tsx.template +27 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/templates/server-action-split/index.ts.template +19 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/templates/server-action-split/mutations.ts.template +196 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/templates/server-action-split/queries.ts.template +134 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/templates/server-action-split/types.ts.template +60 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/templates/server-action.md +345 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/templates/server-action.test.ts.template +267 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/templates/server-action.ts.template +218 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/templates/translations.ja.json.template +35 -0
- package/plugin/shirokuma-skills-en/skills/nextjs-vibe-coding/templates/translations.json.template +35 -0
- package/plugin/shirokuma-skills-en/skills/planning-on-issue/SKILL.md +310 -0
- package/plugin/shirokuma-skills-en/skills/project-config-generator/SKILL.md +301 -0
- package/plugin/shirokuma-skills-en/skills/project-config-generator/templates/discussion-templates/en/adr.yml +75 -0
- package/plugin/shirokuma-skills-en/skills/project-config-generator/templates/discussion-templates/en/handovers.yml +62 -0
- package/plugin/shirokuma-skills-en/skills/project-config-generator/templates/discussion-templates/en/knowledge.yml +66 -0
- package/plugin/shirokuma-skills-en/skills/project-config-generator/templates/discussion-templates/en/research.yml +71 -0
- package/plugin/shirokuma-skills-en/skills/project-config-generator/templates/discussion-templates/ja/adr.yml +75 -0
- package/plugin/shirokuma-skills-en/skills/project-config-generator/templates/discussion-templates/ja/handovers.yml +62 -0
- package/plugin/shirokuma-skills-en/skills/project-config-generator/templates/discussion-templates/ja/knowledge.yml +66 -0
- package/plugin/shirokuma-skills-en/skills/project-config-generator/templates/discussion-templates/ja/research.yml +71 -0
- package/plugin/shirokuma-skills-en/skills/project-config-generator/templates/github-discussions.md.template +161 -0
- package/plugin/shirokuma-skills-en/skills/project-config-generator/templates/known-issues.md.template +54 -0
- package/plugin/shirokuma-skills-en/skills/project-config-generator/templates/lib-structure.md.template +73 -0
- package/plugin/shirokuma-skills-en/skills/project-config-generator/templates/tech-stack.md.template +51 -0
- package/plugin/shirokuma-skills-en/skills/publishing/SKILL.md +227 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/SKILL.md +506 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/criteria/code-quality.md +303 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/criteria/coding-conventions.md +419 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/criteria/security.md +266 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/criteria/testing.md +439 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/docs/setup/auth-setup.md +295 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/docs/setup/database-setup.md +284 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/docs/setup/infra-setup.md +222 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/docs/setup/project-init.md +176 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/docs/setup/styling-setup.md +324 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/docs/workflows/annotation-consistency.md +256 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/docs/workflows/shirokuma-docs-verification.md +219 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/patterns/account-lockout.md +177 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/patterns/audit-logging.md +374 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/patterns/better-auth.md +185 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/patterns/code-quality.md +281 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/patterns/docs-management.md +123 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/patterns/drizzle-orm.md +314 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/patterns/e2e-testing.md +922 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/patterns/i18n.md +245 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/patterns/jsdoc.md +250 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/patterns/nextjs-patterns.md +559 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/patterns/radix-ui-hydration.md +79 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/patterns/server-actions-structure.md +272 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/patterns/server-actions.md +445 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/patterns/tailwind-v4.md +43 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/roles/code.md +184 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/roles/docs.md +79 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/roles/nextjs.md +105 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/roles/plan.md +109 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/roles/security.md +124 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/roles/testing.md +180 -0
- package/plugin/shirokuma-skills-en/skills/reviewing-on-issue/templates/report.md +121 -0
- package/plugin/shirokuma-skills-en/skills/showing-github/SKILL.md +276 -0
- package/plugin/shirokuma-skills-en/skills/showing-github/reference/github-operations.md +163 -0
- package/plugin/shirokuma-skills-en/skills/starting-session/SKILL.md +114 -0
- package/plugin/shirokuma-skills-en/skills/working-on-issue/SKILL.md +261 -0
- package/plugin/shirokuma-skills-ja/.claude-plugin/plugin.json +21 -0
- package/plugin/shirokuma-skills-ja/rules/best-practices-first.md +43 -0
- package/plugin/shirokuma-skills-ja/rules/config-authoring-flow.md +39 -0
- package/plugin/shirokuma-skills-ja/rules/git-commit-style.md +21 -0
- package/plugin/shirokuma-skills-ja/rules/github/branch-workflow.md +64 -0
- package/plugin/shirokuma-skills-ja/rules/github/discussions-usage.md +129 -0
- package/plugin/shirokuma-skills-ja/rules/github/output-language.md +14 -0
- package/plugin/shirokuma-skills-ja/rules/github/pr-review-response.md +37 -0
- package/plugin/shirokuma-skills-ja/rules/github/project-items.md +164 -0
- package/plugin/shirokuma-skills-ja/rules/memory-operations.md +38 -0
- package/plugin/shirokuma-skills-ja/rules/nextjs/known-issues.md +59 -0
- package/plugin/shirokuma-skills-ja/rules/nextjs/lib-structure.md +48 -0
- package/plugin/shirokuma-skills-ja/rules/nextjs/radix-ui-hydration.md +30 -0
- package/plugin/shirokuma-skills-ja/rules/nextjs/server-actions.md +50 -0
- package/plugin/shirokuma-skills-ja/rules/nextjs/tailwind-v4.md +43 -0
- package/plugin/shirokuma-skills-ja/rules/nextjs/tech-stack.md +43 -0
- package/plugin/shirokuma-skills-ja/rules/nextjs/testing.md +66 -0
- package/plugin/shirokuma-skills-ja/rules/output-destinations.md +95 -0
- package/plugin/shirokuma-skills-ja/rules/shirokuma-docs/cli-invocation.md +15 -0
- package/plugin/shirokuma-skills-ja/rules/shirokuma-docs/plugin-cache.md +54 -0
- package/plugin/shirokuma-skills-ja/rules/shirokuma-docs/shirokuma-annotations.md +78 -0
- package/plugin/shirokuma-skills-ja/rules/skill-authoring.md +184 -0
- package/plugin/shirokuma-skills-ja/skills/best-practices-researching/SKILL.md +144 -0
- package/plugin/shirokuma-skills-ja/skills/claude-config-reviewing/SKILL.md +210 -0
- package/plugin/shirokuma-skills-ja/skills/codebase-rule-discovery/SKILL.md +217 -0
- package/plugin/shirokuma-skills-ja/skills/codebase-rule-discovery/patterns/discovery-categories.md +150 -0
- package/plugin/shirokuma-skills-ja/skills/codebase-rule-discovery/templates/convention-proposal.md +138 -0
- package/plugin/shirokuma-skills-ja/skills/codebase-rule-discovery/templates/rule-proposal.md +148 -0
- package/plugin/shirokuma-skills-ja/skills/codebase-rule-discovery/workflows/analyze-codebase.md +211 -0
- package/plugin/shirokuma-skills-ja/skills/committing-on-issue/SKILL.md +227 -0
- package/plugin/shirokuma-skills-ja/skills/creating-pr-on-issue/SKILL.md +187 -0
- package/plugin/shirokuma-skills-ja/skills/ending-session/SKILL.md +230 -0
- package/plugin/shirokuma-skills-ja/skills/ending-session/templates/handover-template.md +75 -0
- package/plugin/shirokuma-skills-ja/skills/frontend-designing/SKILL.md +270 -0
- package/plugin/shirokuma-skills-ja/skills/frontend-designing/reference/reference.md +533 -0
- package/plugin/shirokuma-skills-ja/skills/github-project-setup/SKILL.md +206 -0
- package/plugin/shirokuma-skills-ja/skills/github-project-setup/reference/custom-fields.md +42 -0
- package/plugin/shirokuma-skills-ja/skills/github-project-setup/reference/issue-types.md +84 -0
- package/plugin/shirokuma-skills-ja/skills/github-project-setup/reference/labels.md +85 -0
- package/plugin/shirokuma-skills-ja/skills/github-project-setup/reference/status-options.md +69 -0
- package/plugin/shirokuma-skills-ja/skills/github-project-setup/scripts/locales/en.json +35 -0
- package/plugin/shirokuma-skills-ja/skills/github-project-setup/scripts/locales/ja.json +35 -0
- package/plugin/shirokuma-skills-ja/skills/github-project-setup/scripts/setup-project.py +226 -0
- package/plugin/shirokuma-skills-ja/skills/managing-agents/SKILL.md +289 -0
- package/plugin/shirokuma-skills-ja/skills/managing-agents/best-practices-advanced.md +318 -0
- package/plugin/shirokuma-skills-ja/skills/managing-agents/best-practices.md +267 -0
- package/plugin/shirokuma-skills-ja/skills/managing-agents/design-patterns.md +473 -0
- package/plugin/shirokuma-skills-ja/skills/managing-agents/documentation-structure.md +170 -0
- package/plugin/shirokuma-skills-ja/skills/managing-agents/examples.md +324 -0
- package/plugin/shirokuma-skills-ja/skills/managing-agents/reference.md +464 -0
- package/plugin/shirokuma-skills-ja/skills/managing-agents/templates/complex-agent.md +69 -0
- package/plugin/shirokuma-skills-ja/skills/managing-agents/templates/creator-checker-pair.md +149 -0
- package/plugin/shirokuma-skills-ja/skills/managing-agents/templates/simple-agent.md +43 -0
- package/plugin/shirokuma-skills-ja/skills/managing-github-items/SKILL.md +50 -0
- package/plugin/shirokuma-skills-ja/skills/managing-github-items/reference/create-item.md +82 -0
- package/plugin/shirokuma-skills-ja/skills/managing-github-items/reference/create-spec.md +68 -0
- package/plugin/shirokuma-skills-ja/skills/managing-github-items/reference/github-operations.md +163 -0
- package/plugin/shirokuma-skills-ja/skills/managing-output-styles/SKILL.md +233 -0
- package/plugin/shirokuma-skills-ja/skills/managing-output-styles/examples.md +751 -0
- package/plugin/shirokuma-skills-ja/skills/managing-output-styles/reference.md +307 -0
- package/plugin/shirokuma-skills-ja/skills/managing-plugins/SKILL.md +327 -0
- package/plugin/shirokuma-skills-ja/skills/managing-plugins/examples-advanced.md +398 -0
- package/plugin/shirokuma-skills-ja/skills/managing-plugins/examples.md +383 -0
- package/plugin/shirokuma-skills-ja/skills/managing-plugins/reference.md +382 -0
- package/plugin/shirokuma-skills-ja/skills/managing-rules/SKILL.md +354 -0
- package/plugin/shirokuma-skills-ja/skills/managing-rules/templates/path-rule.md.template +27 -0
- package/plugin/shirokuma-skills-ja/skills/managing-rules/templates/rule.md.template +15 -0
- package/plugin/shirokuma-skills-ja/skills/managing-rules/templates/tech-stack.md.template +32 -0
- package/plugin/shirokuma-skills-ja/skills/managing-skills/README.md +377 -0
- package/plugin/shirokuma-skills-ja/skills/managing-skills/SKILL.md +413 -0
- package/plugin/shirokuma-skills-ja/skills/managing-skills/architecture.md +1009 -0
- package/plugin/shirokuma-skills-ja/skills/managing-skills/best-practices-testing.md +354 -0
- package/plugin/shirokuma-skills-ja/skills/managing-skills/best-practices-writing.md +325 -0
- package/plugin/shirokuma-skills-ja/skills/managing-skills/best-practices.md +334 -0
- package/plugin/shirokuma-skills-ja/skills/managing-skills/examples.md +1024 -0
- package/plugin/shirokuma-skills-ja/skills/managing-skills/reference-output-patterns.md +89 -0
- package/plugin/shirokuma-skills-ja/skills/managing-skills/reference-platform.md +482 -0
- package/plugin/shirokuma-skills-ja/skills/managing-skills/reference-workflows.md +98 -0
- package/plugin/shirokuma-skills-ja/skills/managing-skills/reference.md +747 -0
- package/plugin/shirokuma-skills-ja/skills/managing-skills/scripts/LICENSE.txt +191 -0
- package/plugin/shirokuma-skills-ja/skills/managing-skills/scripts/init_skill.py +184 -0
- package/plugin/shirokuma-skills-ja/skills/managing-skills/scripts/package_skill.py +109 -0
- package/plugin/shirokuma-skills-ja/skills/managing-skills/scripts/quick_validate.py +128 -0
- package/plugin/shirokuma-skills-ja/skills/managing-skills/updating-skills.md +675 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/SKILL.md +315 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/patterns/better-auth.md +185 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/patterns/code-patterns.md +335 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/patterns/coding-conventions.md +323 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/patterns/csp.md +97 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/patterns/csrf-protection.md +153 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/patterns/documentation.md +220 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/patterns/drizzle-orm.md +314 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/patterns/e2e-testing.md +826 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/patterns/image-optimization.md +227 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/patterns/radix-ui-hydration.md +79 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/patterns/rate-limiting.md +188 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/patterns/tailwind-v4.md +43 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/patterns/testing.md +298 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/reference/checklists.md +76 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/reference/large-scale.md +141 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/reference/reference.md +171 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/reference/report-template.md +53 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/templates/README.md +108 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/templates/component.test.tsx.template +245 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/templates/delete-button.tsx.template +86 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/templates/form-component.tsx.template +142 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/templates/messages-split/common.json.template +46 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/templates/messages-split/errors.json.template +29 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/templates/messages-split/feature.json.template +46 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/templates/messages-split/index.ts.template +26 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/templates/page-edit.tsx.template +43 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/templates/page-list.tsx.template +133 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/templates/page-new.tsx.template +27 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/templates/server-action-split/index.ts.template +19 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/templates/server-action-split/mutations.ts.template +196 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/templates/server-action-split/queries.ts.template +134 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/templates/server-action-split/types.ts.template +60 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/templates/server-action.md +345 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/templates/server-action.test.ts.template +267 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/templates/server-action.ts.template +218 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/templates/translations.ja.json.template +35 -0
- package/plugin/shirokuma-skills-ja/skills/nextjs-vibe-coding/templates/translations.json.template +35 -0
- package/plugin/shirokuma-skills-ja/skills/planning-on-issue/SKILL.md +310 -0
- package/plugin/shirokuma-skills-ja/skills/project-config-generator/SKILL.md +289 -0
- package/plugin/shirokuma-skills-ja/skills/project-config-generator/templates/discussion-templates/en/adr.yml +75 -0
- package/plugin/shirokuma-skills-ja/skills/project-config-generator/templates/discussion-templates/en/handovers.yml +62 -0
- package/plugin/shirokuma-skills-ja/skills/project-config-generator/templates/discussion-templates/en/knowledge.yml +66 -0
- package/plugin/shirokuma-skills-ja/skills/project-config-generator/templates/discussion-templates/en/research.yml +71 -0
- package/plugin/shirokuma-skills-ja/skills/project-config-generator/templates/discussion-templates/ja/adr.yml +75 -0
- package/plugin/shirokuma-skills-ja/skills/project-config-generator/templates/discussion-templates/ja/handovers.yml +62 -0
- package/plugin/shirokuma-skills-ja/skills/project-config-generator/templates/discussion-templates/ja/knowledge.yml +66 -0
- package/plugin/shirokuma-skills-ja/skills/project-config-generator/templates/discussion-templates/ja/research.yml +71 -0
- package/plugin/shirokuma-skills-ja/skills/project-config-generator/templates/github-discussions.md.template +161 -0
- package/plugin/shirokuma-skills-ja/skills/project-config-generator/templates/known-issues.md.template +54 -0
- package/plugin/shirokuma-skills-ja/skills/project-config-generator/templates/lib-structure.md.template +73 -0
- package/plugin/shirokuma-skills-ja/skills/project-config-generator/templates/tech-stack.md.template +51 -0
- package/plugin/shirokuma-skills-ja/skills/publishing/SKILL.md +227 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/SKILL.md +506 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/criteria/code-quality.md +303 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/criteria/coding-conventions.md +419 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/criteria/security.md +266 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/criteria/testing.md +431 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/docs/setup/auth-setup.md +295 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/docs/setup/database-setup.md +284 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/docs/setup/infra-setup.md +222 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/docs/setup/project-init.md +176 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/docs/setup/styling-setup.md +324 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/docs/workflows/annotation-consistency.md +256 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/docs/workflows/shirokuma-docs-verification.md +219 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/patterns/account-lockout.md +177 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/patterns/audit-logging.md +364 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/patterns/better-auth.md +185 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/patterns/code-quality.md +244 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/patterns/docs-management.md +95 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/patterns/drizzle-orm.md +314 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/patterns/e2e-testing.md +826 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/patterns/i18n.md +242 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/patterns/jsdoc.md +247 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/patterns/nextjs-patterns.md +421 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/patterns/radix-ui-hydration.md +79 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/patterns/server-actions-structure.md +272 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/patterns/server-actions.md +399 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/patterns/tailwind-v4.md +43 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/roles/code.md +181 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/roles/docs.md +79 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/roles/nextjs.md +105 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/roles/plan.md +109 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/roles/security.md +124 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/roles/testing.md +180 -0
- package/plugin/shirokuma-skills-ja/skills/reviewing-on-issue/templates/report.md +121 -0
- package/plugin/shirokuma-skills-ja/skills/showing-github/SKILL.md +276 -0
- package/plugin/shirokuma-skills-ja/skills/showing-github/reference/github-operations.md +163 -0
- package/plugin/shirokuma-skills-ja/skills/starting-session/SKILL.md +93 -0
- package/plugin/shirokuma-skills-ja/skills/working-on-issue/SKILL.md +208 -0
- package/portal/app/api-tools/api-tools-client.tsx +411 -0
- package/portal/app/api-tools/api-tools-document.tsx +240 -0
- package/portal/app/api-tools/page.tsx +56 -0
- package/portal/app/api-tools/swagger-view.tsx +114 -0
- package/portal/app/apps/[appId]/[type]/[module]/[item]/item-tabs-client.tsx +71 -0
- package/portal/app/apps/[appId]/[type]/[module]/[item]/page.tsx +1422 -0
- package/portal/app/apps/[appId]/[type]/[module]/page.tsx +373 -0
- package/portal/app/apps/[appId]/feature-map/feature-map-app-document.tsx +298 -0
- package/portal/app/apps/[appId]/feature-map/page.tsx +224 -0
- package/portal/app/apps/[appId]/i18n/page.tsx +139 -0
- package/portal/app/apps/[appId]/test-cases/page.tsx +840 -0
- package/portal/app/apps/[appId]/tools/[tool]/page.tsx +351 -0
- package/portal/app/apps/[appId]/tools/api-tools-client.tsx +429 -0
- package/portal/app/apps/[appId]/tools/page.tsx +119 -0
- package/portal/app/db-schema/[db]/[table]/page.tsx +235 -0
- package/portal/app/db-schema/[db]/diagram/page.tsx +81 -0
- package/portal/app/db-schema/[db]/page.tsx +148 -0
- package/portal/app/db-schema/db-schema-document.tsx +100 -0
- package/portal/app/db-schema/diagram/client.tsx +211 -0
- package/portal/app/db-schema/diagram/page.tsx +20 -0
- package/portal/app/db-schema/page.tsx +145 -0
- package/portal/app/db-schema/table-detail-document.tsx +710 -0
- package/portal/app/db-schema/table-detail.tsx +747 -0
- package/portal/app/db-schema/table-list-document.tsx +224 -0
- package/portal/app/db-schema/table-list.tsx +247 -0
- package/portal/app/details/[type]/[module]/[item]/item-tabs-client.tsx +71 -0
- package/portal/app/details/[type]/[module]/[item]/page.tsx +1286 -0
- package/portal/app/details/[type]/[module]/page.tsx +884 -0
- package/portal/app/feature-map/feature-map-client.tsx +681 -0
- package/portal/app/feature-map/feature-map-document.tsx +313 -0
- package/portal/app/feature-map/page.tsx +438 -0
- package/portal/app/globals.css +205 -0
- package/portal/app/i18n/[...namespace]/page.tsx +190 -0
- package/portal/app/i18n/i18n-client.tsx +369 -0
- package/portal/app/i18n/page.tsx +339 -0
- package/portal/app/layout.tsx +37 -0
- package/portal/app/overview/page.tsx +65 -0
- package/portal/app/packages/[packageId]/page.tsx +201 -0
- package/portal/app/packages/page.tsx +148 -0
- package/portal/app/page.tsx +568 -0
- package/portal/app/test-cases/[file]/[line]/page.tsx +455 -0
- package/portal/app/test-cases/[file]/[line]/test-detail-document.tsx +335 -0
- package/portal/app/test-cases/[file]/page.tsx +323 -0
- package/portal/app/test-cases/[file]/test-file-document.tsx +335 -0
- package/portal/app/test-cases/page.tsx +546 -0
- package/portal/app/test-cases/test-cases-document.tsx +384 -0
- package/portal/components/code-block.tsx +57 -0
- package/portal/components/document/doc-params-table.tsx +71 -0
- package/portal/components/document/doc-section.tsx +133 -0
- package/portal/components/document/doc-table.tsx +119 -0
- package/portal/components/document/index.ts +9 -0
- package/portal/components/drawflow-er-diagram.tsx +607 -0
- package/portal/components/interactive-er-diagram.tsx +228 -0
- package/portal/components/layout/app-sidebar.tsx +490 -0
- package/portal/components/layout/er-sidebar.tsx +116 -0
- package/portal/components/layout/global-header.tsx +117 -0
- package/portal/components/layout/layout-content.tsx +48 -0
- package/portal/components/markdown-content.tsx +120 -0
- package/portal/components/mermaid-diagram.tsx +83 -0
- package/portal/components/reactflow-er-diagram.tsx +475 -0
- package/portal/components/search-dialog.tsx +268 -0
- package/portal/components/shared/coverage-score-bar.tsx +144 -0
- package/portal/components/swagger/endpoint-accordion.tsx +117 -0
- package/portal/components/swagger/index.ts +7 -0
- package/portal/components/swagger/method-badge.tsx +55 -0
- package/portal/components/swagger/params-table.tsx +78 -0
- package/portal/components/tabs-with-hash.tsx +43 -0
- package/portal/components/test/index.ts +2 -0
- package/portal/components/test/test-bdd-card.tsx +192 -0
- package/portal/components/test/test-matrix.tsx +242 -0
- package/portal/components/ui/accordion.tsx +66 -0
- package/portal/components/ui/badge.tsx +46 -0
- package/portal/components/ui/breadcrumb.tsx +109 -0
- package/portal/components/ui/button.tsx +62 -0
- package/portal/components/ui/card.tsx +92 -0
- package/portal/components/ui/collapsible.tsx +33 -0
- package/portal/components/ui/dialog.tsx +118 -0
- package/portal/components/ui/progress.tsx +28 -0
- package/portal/components/ui/scroll-area.tsx +58 -0
- package/portal/components/ui/sheet.tsx +139 -0
- package/portal/components/ui/table.tsx +116 -0
- package/portal/components/ui/tabs.tsx +66 -0
- package/portal/components.json +21 -0
- package/portal/lib/constants/test-categories.ts +186 -0
- package/portal/lib/data-loader.ts +1181 -0
- package/portal/lib/db-schema-utils.ts +182 -0
- package/portal/lib/format.ts +43 -0
- package/portal/lib/hooks/use-hash-tab.ts +144 -0
- package/portal/lib/path-utils.ts +25 -0
- package/portal/lib/search-index-generator.ts +214 -0
- package/portal/lib/search.ts +126 -0
- package/portal/lib/sidebar-context.tsx +111 -0
- package/portal/lib/types.ts +740 -0
- package/portal/lib/utils.ts +6 -0
- package/portal/next.config.ts +21 -0
- package/portal/package.json +45 -0
- package/portal/postcss.config.mjs +8 -0
- package/portal/tsconfig.json +41 -0
- package/portal/types/drawflow.d.ts +80 -0
- package/templates/README.md +73 -0
- package/templates/coverage.html +367 -0
- package/templates/dark-theme.css +443 -0
- package/templates/discussion/adr.yml.hbs +65 -0
- package/templates/discussion/handovers.yml.hbs +57 -0
- package/templates/discussion/knowledge.yml.hbs +60 -0
- package/templates/discussion/reports.yml.hbs +68 -0
- package/templates/discussion/research.yml.hbs +61 -0
|
@@ -0,0 +1,922 @@
|
|
|
1
|
+
# E2E Testing Patterns
|
|
2
|
+
|
|
3
|
+
Related: [testing.md](../criteria/testing.md), [better-auth.md](better-auth.md)
|
|
4
|
+
|
|
5
|
+
## Directory Organization (App-Based)
|
|
6
|
+
|
|
7
|
+
Organize E2E tests by app in monorepo projects:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
tests/e2e/
|
|
11
|
+
├── admin/ # Admin app tests
|
|
12
|
+
│ ├── auth/
|
|
13
|
+
│ ├── posts/
|
|
14
|
+
│ └── settings/
|
|
15
|
+
├── public/ # Public app tests
|
|
16
|
+
│ ├── blog/
|
|
17
|
+
│ ├── comments/
|
|
18
|
+
│ └── search/
|
|
19
|
+
├── shared/ # Cross-app tests (rare)
|
|
20
|
+
│ └── seo.test.ts
|
|
21
|
+
└── helpers/ # Shared test utilities
|
|
22
|
+
├── database.ts
|
|
23
|
+
├── fixtures.ts
|
|
24
|
+
└── auth.ts
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**Playwright Configuration**:
|
|
28
|
+
```typescript
|
|
29
|
+
// playwright.config.ts
|
|
30
|
+
export default defineConfig({
|
|
31
|
+
projects: [
|
|
32
|
+
{ name: "admin", testDir: "./tests/e2e/admin", use: { baseURL: "https://admin-test.local.test" } },
|
|
33
|
+
{ name: "public", testDir: "./tests/e2e/public", use: { baseURL: "https://public-test.local.test" } },
|
|
34
|
+
],
|
|
35
|
+
})
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Benefits**: Clear ownership, parallel execution, easier maintenance, targeted CI/CD.
|
|
39
|
+
|
|
40
|
+
## Test Environment Isolation
|
|
41
|
+
|
|
42
|
+
Use separate test database and hosts:
|
|
43
|
+
|
|
44
|
+
| Environment | Host | Database |
|
|
45
|
+
|-------------|------|----------|
|
|
46
|
+
| Development | admin.local.test | blogcms_dev |
|
|
47
|
+
| E2E Test | admin-test.local.test | blogcms_test |
|
|
48
|
+
|
|
49
|
+
### Configuration
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
// playwright.config.ts
|
|
53
|
+
export default defineConfig({
|
|
54
|
+
use: {
|
|
55
|
+
baseURL: "http://admin-test.local.test", // Test-specific host
|
|
56
|
+
},
|
|
57
|
+
webServer: undefined, // Use external server
|
|
58
|
+
})
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Global Setup
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
// tests/global-setup.ts
|
|
65
|
+
export default async function globalSetup() {
|
|
66
|
+
// Reset test database before all tests
|
|
67
|
+
execSync(`DATABASE_URL="${TEST_DB_URL}" pnpm --filter @repo/database db:push`)
|
|
68
|
+
execSync(`DATABASE_URL="${TEST_DB_URL}" pnpm --filter @repo/database db:seed`)
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Rate Limiting for Tests
|
|
73
|
+
|
|
74
|
+
Better Auth rate limiting blocks E2E tests. Relax for development:
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
// lib/auth.ts
|
|
78
|
+
rateLimit: {
|
|
79
|
+
window: 15 * 60,
|
|
80
|
+
max: process.env.NODE_ENV === "production" ? 5 : 1000, // Relaxed for dev/test
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Multi-Step Auth Flow Timeouts
|
|
85
|
+
|
|
86
|
+
Admin login includes multiple API calls (signIn -> get-session -> check-admin):
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
// Increase timeout for multi-step flows
|
|
90
|
+
await expect(page).toHaveURL(/\/$/, { timeout: 15000 })
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Loading State Testing
|
|
94
|
+
|
|
95
|
+
Use Promise-based blocking to reliably test loading states:
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
test("should show loading state during login", async ({ page }) => {
|
|
99
|
+
let resolveRequest: () => void
|
|
100
|
+
const requestPromise = new Promise<void>((resolve) => {
|
|
101
|
+
resolveRequest = resolve
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
// Block the request to keep loading state visible
|
|
105
|
+
await page.route("**/api/auth/sign-in/**", async (route) => {
|
|
106
|
+
await requestPromise
|
|
107
|
+
await route.continue()
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
// Fill form
|
|
111
|
+
await page.getByLabel("Email").fill("test@example.com")
|
|
112
|
+
await page.getByLabel("Password").fill("password")
|
|
113
|
+
|
|
114
|
+
// Get button reference before clicking
|
|
115
|
+
const submitButton = page.getByRole("button", { name: /Log in/i })
|
|
116
|
+
await submitButton.click()
|
|
117
|
+
|
|
118
|
+
// Verify loading state - button text changes!
|
|
119
|
+
const loadingButton = page.getByRole("button", { name: /Logging in/i })
|
|
120
|
+
await expect(loadingButton).toBeVisible()
|
|
121
|
+
await expect(loadingButton).toBeDisabled()
|
|
122
|
+
|
|
123
|
+
// Release request to complete
|
|
124
|
+
resolveRequest!()
|
|
125
|
+
})
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Button Text During Loading
|
|
129
|
+
|
|
130
|
+
Button locators need to account for text changes:
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
// Before click: "Log in"
|
|
134
|
+
// During loading: "Logging in..."
|
|
135
|
+
|
|
136
|
+
// WRONG: Original locator fails during loading state
|
|
137
|
+
await expect(submitButton).toBeDisabled() // Fails - locator can't find element
|
|
138
|
+
|
|
139
|
+
// CORRECT: Use new locator for loading state
|
|
140
|
+
const loadingButton = page.getByRole("button", { name: /Logging in/i })
|
|
141
|
+
await expect(loadingButton).toBeDisabled()
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Test Order Dependencies
|
|
145
|
+
|
|
146
|
+
When tests modify shared state (like passwords), handle order dependencies:
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
test("should work after password change", async ({ page }) => {
|
|
150
|
+
// Try multiple passwords if previous test changed it
|
|
151
|
+
const passwords = [originalPassword, newPassword]
|
|
152
|
+
let loggedIn = false
|
|
153
|
+
|
|
154
|
+
for (const password of passwords) {
|
|
155
|
+
await page.getByLabel("Password").fill(password)
|
|
156
|
+
await page.getByRole("button", { name: /Log in/i }).click()
|
|
157
|
+
|
|
158
|
+
// Check if login succeeded
|
|
159
|
+
if (page.url().includes("/dashboard")) {
|
|
160
|
+
loggedIn = true
|
|
161
|
+
break
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
expect(loggedIn).toBe(true)
|
|
166
|
+
})
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## i18n in E2E Tests
|
|
170
|
+
|
|
171
|
+
Handle both languages in assertions:
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
// Match either English or Japanese
|
|
175
|
+
await expect(page.getByRole("button", { name: /Log in|ログイン/i })).toBeVisible()
|
|
176
|
+
await expect(page.getByText(/Invalid email or password|認証エラー/i)).toBeVisible()
|
|
177
|
+
|
|
178
|
+
// Link text varies by language
|
|
179
|
+
await expect(page.getByRole("link", { name: /Forgot password\?|パスワードをお忘れですか/i })).toBeVisible()
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Semantic Locators
|
|
183
|
+
|
|
184
|
+
Prefer semantic locators over CSS selectors:
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
// Good: Semantic locators
|
|
188
|
+
await page.getByLabel("Email").fill("test@example.com")
|
|
189
|
+
await page.getByRole("button", { name: /Submit/i }).click()
|
|
190
|
+
await page.getByText("Success message").toBeVisible()
|
|
191
|
+
|
|
192
|
+
// Avoid: CSS selectors
|
|
193
|
+
await page.locator("#email-input").fill("test@example.com")
|
|
194
|
+
await page.locator(".submit-button").click()
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Test Isolation
|
|
198
|
+
|
|
199
|
+
Clear state between tests:
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
test.beforeEach(async ({ page, context }) => {
|
|
203
|
+
// Clear cookies for test isolation
|
|
204
|
+
await context.clearCookies()
|
|
205
|
+
// Clear rate limits
|
|
206
|
+
await redisHelper.clearRateLimits("ratelimit:*")
|
|
207
|
+
// Navigate to starting page
|
|
208
|
+
await page.goto("/login")
|
|
209
|
+
})
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Database Fixtures (TestDatabaseClient)
|
|
213
|
+
|
|
214
|
+
Direct database access for E2E test data management:
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
// tests/helpers/database.ts
|
|
218
|
+
import { Pool, PoolClient } from "pg"
|
|
219
|
+
|
|
220
|
+
const TEST_DATABASE_URL = "postgresql://postgres:password@localhost:5432/blogcms_test"
|
|
221
|
+
const pool = new Pool({ connectionString: TEST_DATABASE_URL, max: 5 })
|
|
222
|
+
|
|
223
|
+
export class TestDatabaseClient {
|
|
224
|
+
private client: PoolClient | null = null
|
|
225
|
+
|
|
226
|
+
async connect(): Promise<void> { this.client = await pool.connect() }
|
|
227
|
+
async disconnect(): Promise<void> { this.client?.release(); this.client = null }
|
|
228
|
+
|
|
229
|
+
async query<T = any>(sql: string, params?: any[]): Promise<T[]> {
|
|
230
|
+
if (!this.client) throw new Error("Not connected")
|
|
231
|
+
return (await this.client.query(sql, params)).rows as T[]
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async clearTable(tableName: string): Promise<void> {
|
|
235
|
+
const allowed = ["posts", "comments", "categories", "tags", "users"]
|
|
236
|
+
if (!allowed.includes(tableName)) throw new Error("Table not allowed")
|
|
237
|
+
await this.query(`TRUNCATE TABLE "${tableName}" CASCADE`)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
async clearAllPosts(): Promise<void> {
|
|
241
|
+
await this.query("TRUNCATE TABLE posts CASCADE")
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
async createComment(data: {
|
|
245
|
+
postId: string; authorId: string; content: string;
|
|
246
|
+
approved?: boolean; parentId?: string | null; deletedAt?: Date | null
|
|
247
|
+
}): Promise<{ id: string }> {
|
|
248
|
+
const result = await this.query<{ id: string }>(
|
|
249
|
+
`INSERT INTO comments (id, post_id, author_id, content, approved, parent_id, deleted_at, created_at, updated_at)
|
|
250
|
+
VALUES (gen_random_uuid(), $1, $2, $3, $4, $5, $6, NOW(), NOW()) RETURNING id`,
|
|
251
|
+
[data.postId, data.authorId, data.content, data.approved ?? false, data.parentId || null, data.deletedAt || null]
|
|
252
|
+
)
|
|
253
|
+
return result[0]
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export const testDb = new TestDatabaseClient()
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Empty State Testing Pattern
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
import { testDb, seedTestDatabase } from "../helpers/database"
|
|
264
|
+
|
|
265
|
+
test.describe("Post List Empty State", () => {
|
|
266
|
+
test.beforeAll(async () => {
|
|
267
|
+
await testDb.connect()
|
|
268
|
+
await testDb.clearAllPosts()
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
test.afterAll(async () => {
|
|
272
|
+
await testDb.disconnect()
|
|
273
|
+
await seedTestDatabase() // Restore for other tests
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
test("should display empty state", async ({ page }) => {
|
|
277
|
+
await page.goto("/posts")
|
|
278
|
+
await expect(page.getByText(/No posts|投稿がありません/i)).toBeVisible()
|
|
279
|
+
})
|
|
280
|
+
})
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
## Serial Test Execution
|
|
284
|
+
|
|
285
|
+
Use `test.describe.serial` for tests that modify shared state:
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
test.describe.serial("Comment Moderation", () => {
|
|
289
|
+
test("should approve a pending comment", async ({ page }) => {
|
|
290
|
+
await page.goto("/comments?filter=pending")
|
|
291
|
+
const initialCount = await page.locator("table tbody tr").count()
|
|
292
|
+
await page.locator("button[title='Approve'], button[title='承認']").first().click()
|
|
293
|
+
await page.waitForLoadState("networkidle")
|
|
294
|
+
const newCount = await page.locator("table tbody tr").count()
|
|
295
|
+
expect(newCount).toBeLessThan(initialCount)
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
test("should delete a comment", async ({ page }) => {
|
|
299
|
+
// Runs after approval test
|
|
300
|
+
})
|
|
301
|
+
})
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## Icon Button Testing
|
|
305
|
+
|
|
306
|
+
For icon-only buttons with `title` attribute:
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
// Find by title attribute (both languages)
|
|
310
|
+
const restoreButton = page.locator("button[title='Restore'], button[title='復元']").first()
|
|
311
|
+
await expect(restoreButton).toBeVisible({ timeout: 5000 })
|
|
312
|
+
await restoreButton.click()
|
|
313
|
+
|
|
314
|
+
// For buttons with confirmation dialog
|
|
315
|
+
const deleteButton = page.locator("button[title='Permanently Delete'], button[title='完全削除']").first()
|
|
316
|
+
await deleteButton.click()
|
|
317
|
+
await page.getByRole("button", { name: /Permanently Delete|完全削除/i }).click() // Confirm
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## Network Interception
|
|
321
|
+
|
|
322
|
+
Intercept and mock network requests:
|
|
323
|
+
|
|
324
|
+
```typescript
|
|
325
|
+
// Mock API response
|
|
326
|
+
await page.route("**/api/posts", async (route) => {
|
|
327
|
+
await route.fulfill({
|
|
328
|
+
status: 200,
|
|
329
|
+
contentType: "application/json",
|
|
330
|
+
body: JSON.stringify({ posts: [] }),
|
|
331
|
+
})
|
|
332
|
+
})
|
|
333
|
+
|
|
334
|
+
// Delay response to test loading states
|
|
335
|
+
await page.route("**/api/slow", async (route) => {
|
|
336
|
+
await new Promise(resolve => setTimeout(resolve, 2000))
|
|
337
|
+
await route.continue()
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
// Fail request to test error handling
|
|
341
|
+
await page.route("**/api/fail", async (route) => {
|
|
342
|
+
await route.abort("failed")
|
|
343
|
+
})
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
## Debugging Tips
|
|
347
|
+
|
|
348
|
+
```typescript
|
|
349
|
+
// Take screenshot on failure
|
|
350
|
+
test.afterEach(async ({ page }, testInfo) => {
|
|
351
|
+
if (testInfo.status !== testInfo.expectedStatus) {
|
|
352
|
+
await page.screenshot({ path: `screenshots/${testInfo.title}.png` })
|
|
353
|
+
}
|
|
354
|
+
})
|
|
355
|
+
|
|
356
|
+
// Enable tracing for debugging
|
|
357
|
+
test.use({ trace: "retain-on-failure" })
|
|
358
|
+
|
|
359
|
+
// Visual debugging
|
|
360
|
+
await page.pause() // Opens Playwright Inspector
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
## Anti-Patterns
|
|
364
|
+
|
|
365
|
+
### Timeout-Based Waiting
|
|
366
|
+
|
|
367
|
+
```typescript
|
|
368
|
+
// Bad: Arbitrary timeout
|
|
369
|
+
await page.waitForTimeout(3000)
|
|
370
|
+
await page.click("button")
|
|
371
|
+
|
|
372
|
+
// Good: Wait for specific condition
|
|
373
|
+
await expect(page.getByRole("button")).toBeEnabled()
|
|
374
|
+
await page.getByRole("button").click()
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### Hard-Coded Test Data
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
// Bad: Hard-coded credentials scattered in tests
|
|
381
|
+
await page.getByLabel("Email").fill("admin@example.com")
|
|
382
|
+
|
|
383
|
+
// Good: Use fixtures
|
|
384
|
+
import { TEST_USERS } from "../fixtures/test-users"
|
|
385
|
+
await page.getByLabel("Email").fill(TEST_USERS.admin.email)
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### Testing Internal Implementation
|
|
389
|
+
|
|
390
|
+
```typescript
|
|
391
|
+
// Bad: Testing internal state
|
|
392
|
+
expect(page.evaluate(() => window.__internalState)).toBe(...)
|
|
393
|
+
|
|
394
|
+
// Good: Test user-visible behavior
|
|
395
|
+
await expect(page.getByText("Success")).toBeVisible()
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
### Force Click and Direct URL Navigation
|
|
399
|
+
|
|
400
|
+
```typescript
|
|
401
|
+
// Bad: Bypassing UI interaction
|
|
402
|
+
await link.click({ force: true }) // Hides real UI issues
|
|
403
|
+
await page.goto(`/posts/${slug}`) // Skips navigation testing
|
|
404
|
+
|
|
405
|
+
// Good: Fix the UI issue or use viewport adjustment
|
|
406
|
+
test.use({ viewport: { width: 375, height: 667 } }) // Mobile view
|
|
407
|
+
await link.click() // Normal click works
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### Conditional test.skip() When Data Exists
|
|
411
|
+
|
|
412
|
+
```typescript
|
|
413
|
+
// Bad: Skip when seed data should exist
|
|
414
|
+
const link = page.getByRole("link", { name: /Read more/i }).first()
|
|
415
|
+
test.skip(!(await link.isVisible()), "No posts found")
|
|
416
|
+
|
|
417
|
+
// Good: Assert that seed data exists
|
|
418
|
+
const link = page.getByRole("link", { name: /Read more/i }).first()
|
|
419
|
+
await expect(link).toBeVisible({ timeout: 10000 })
|
|
420
|
+
await link.click()
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
## Sidebar Overlay Handling
|
|
424
|
+
|
|
425
|
+
When sidebar overlaps content on desktop, use mobile viewport:
|
|
426
|
+
|
|
427
|
+
```typescript
|
|
428
|
+
test.describe("Feature requiring main content click", () => {
|
|
429
|
+
// Mobile viewport hides sidebar
|
|
430
|
+
test.use({ viewport: { width: 375, height: 667 } })
|
|
431
|
+
|
|
432
|
+
test("should click link in main content", async ({ page }) => {
|
|
433
|
+
await page.goto("/posts")
|
|
434
|
+
const link = page.getByRole("link", { name: /Read more/i }).first()
|
|
435
|
+
await expect(link).toBeVisible()
|
|
436
|
+
await link.click() // Works without sidebar interference
|
|
437
|
+
})
|
|
438
|
+
})
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
## Selector Patterns for shadcn/ui Components
|
|
442
|
+
|
|
443
|
+
### Password Input (type="password")
|
|
444
|
+
|
|
445
|
+
Password inputs are NOT `textbox` role in accessibility tree:
|
|
446
|
+
|
|
447
|
+
```typescript
|
|
448
|
+
// Bad: type="password" is not textbox
|
|
449
|
+
await page.getByRole("textbox", { name: /Password/i }).fill("...")
|
|
450
|
+
|
|
451
|
+
// Good: Use locator for password inputs
|
|
452
|
+
await page.locator('input[type="password"]').first().fill("...")
|
|
453
|
+
|
|
454
|
+
// Or use label association if unique
|
|
455
|
+
await page.getByLabel(/^Password$/i).fill("...")
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
### Combobox/Select Components
|
|
459
|
+
|
|
460
|
+
```typescript
|
|
461
|
+
// shadcn Select component
|
|
462
|
+
const select = page.getByRole("combobox").first()
|
|
463
|
+
await select.click()
|
|
464
|
+
await page.getByRole("option").first().click()
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
### Switch Component
|
|
468
|
+
|
|
469
|
+
```typescript
|
|
470
|
+
const publishSwitch = page.getByRole("switch", { name: /Published/i })
|
|
471
|
+
await expect(publishSwitch).not.toBeChecked()
|
|
472
|
+
await publishSwitch.click()
|
|
473
|
+
await expect(publishSwitch).toBeChecked()
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
### Pagination Component
|
|
477
|
+
|
|
478
|
+
```typescript
|
|
479
|
+
const pagination = page.getByRole("navigation", { name: "pagination" })
|
|
480
|
+
await expect(pagination).toBeVisible()
|
|
481
|
+
const nextButton = pagination.getByRole("link", { name: /next|次/i })
|
|
482
|
+
await nextButton.click()
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
## OpenGraph Meta Tag Testing
|
|
486
|
+
|
|
487
|
+
Use correct property names (NOT `og:article:*`):
|
|
488
|
+
|
|
489
|
+
```typescript
|
|
490
|
+
// Correct OpenGraph article properties
|
|
491
|
+
const publishedTime = page.locator('meta[property="article:published_time"]')
|
|
492
|
+
const modifiedTime = page.locator('meta[property="article:modified_time"]')
|
|
493
|
+
const author = page.locator('meta[property="article:author"]')
|
|
494
|
+
|
|
495
|
+
// Standard OG properties
|
|
496
|
+
const ogTitle = page.locator('meta[property="og:title"]')
|
|
497
|
+
const ogType = page.locator('meta[property="og:type"]')
|
|
498
|
+
const ogLocale = page.locator('meta[property="og:locale"]')
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
## Test Fixtures Pattern
|
|
502
|
+
|
|
503
|
+
Create reusable fixtures for test data:
|
|
504
|
+
|
|
505
|
+
```typescript
|
|
506
|
+
// tests/helpers/fixtures.ts
|
|
507
|
+
import { testDb } from "./database"
|
|
508
|
+
|
|
509
|
+
export interface MetadataTestFixtures {
|
|
510
|
+
category: { id: string; name: string; slug: string }
|
|
511
|
+
tag: { id: string; name: string; slug: string }
|
|
512
|
+
post: { id: string; title: string; slug: string }
|
|
513
|
+
authorId: string
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
export async function createMetadataTestFixtures(): Promise<MetadataTestFixtures> {
|
|
517
|
+
await testDb.connect()
|
|
518
|
+
|
|
519
|
+
// Get admin user
|
|
520
|
+
const [admin] = await testDb.query<{ id: string }>(
|
|
521
|
+
"SELECT id FROM users WHERE email = $1",
|
|
522
|
+
["admin@example.com"]
|
|
523
|
+
)
|
|
524
|
+
|
|
525
|
+
// Create category
|
|
526
|
+
const [category] = await testDb.query<{ id: string; name: string; slug: string }>(
|
|
527
|
+
`INSERT INTO categories (id, name, slug, created_at, updated_at)
|
|
528
|
+
VALUES (gen_random_uuid(), $1, $2, NOW(), NOW()) RETURNING id, name, slug`,
|
|
529
|
+
[`Test Category ${Date.now()}`, `test-category-${Date.now()}`]
|
|
530
|
+
)
|
|
531
|
+
|
|
532
|
+
// Create post
|
|
533
|
+
const [post] = await testDb.query<{ id: string; title: string; slug: string }>(
|
|
534
|
+
`INSERT INTO posts (id, title, slug, content, published, published_at, author_id, category_id, created_at, updated_at)
|
|
535
|
+
VALUES (gen_random_uuid(), $1, $2, $3, true, NOW(), $4, $5, NOW(), NOW())
|
|
536
|
+
RETURNING id, title, slug`,
|
|
537
|
+
[`Test Post ${Date.now()}`, `test-post-${Date.now()}`, "Test content", admin.id, category.id]
|
|
538
|
+
)
|
|
539
|
+
|
|
540
|
+
await testDb.disconnect()
|
|
541
|
+
return { category, tag, post, authorId: admin.id }
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
export async function cleanupMetadataTestFixtures(fixtures: MetadataTestFixtures | null): Promise<void> {
|
|
545
|
+
if (!fixtures) return
|
|
546
|
+
await testDb.connect()
|
|
547
|
+
await testDb.query("DELETE FROM posts WHERE id = $1", [fixtures.post.id])
|
|
548
|
+
await testDb.query("DELETE FROM categories WHERE id = $1", [fixtures.category.id])
|
|
549
|
+
await testDb.disconnect()
|
|
550
|
+
}
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
### Using Fixtures in Tests
|
|
554
|
+
|
|
555
|
+
```typescript
|
|
556
|
+
let testFixtures: MetadataTestFixtures | null = null
|
|
557
|
+
|
|
558
|
+
test.beforeAll(async () => {
|
|
559
|
+
testFixtures = await createMetadataTestFixtures()
|
|
560
|
+
})
|
|
561
|
+
|
|
562
|
+
test.afterAll(async () => {
|
|
563
|
+
await cleanupMetadataTestFixtures(testFixtures)
|
|
564
|
+
testFixtures = null
|
|
565
|
+
})
|
|
566
|
+
|
|
567
|
+
test("should have correct metadata", async ({ page }) => {
|
|
568
|
+
await page.goto(`/posts/${testFixtures!.post.slug}`)
|
|
569
|
+
// Test metadata...
|
|
570
|
+
})
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
## Prefer Seed Data Over Fixtures
|
|
574
|
+
|
|
575
|
+
When possible, use seed data instead of creating fixtures:
|
|
576
|
+
|
|
577
|
+
```typescript
|
|
578
|
+
// Good: Use seed data (150 posts exist)
|
|
579
|
+
test("should navigate to post detail", async ({ page }) => {
|
|
580
|
+
await page.goto("/posts")
|
|
581
|
+
const readMoreLink = page.getByRole("link", { name: /Read more/i }).first()
|
|
582
|
+
await expect(readMoreLink).toBeVisible({ timeout: 10000 })
|
|
583
|
+
await readMoreLink.click()
|
|
584
|
+
await expect(page).toHaveURL(/\/posts\/[^/]+$/)
|
|
585
|
+
})
|
|
586
|
+
|
|
587
|
+
// Only use fixtures when:
|
|
588
|
+
// - Testing specific data conditions
|
|
589
|
+
// - ISR cache prevents seeing new data immediately
|
|
590
|
+
// - Need isolated test data that won't affect other tests
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
## Comment Section Testing
|
|
594
|
+
|
|
595
|
+
```typescript
|
|
596
|
+
test.describe("Comment functionality", () => {
|
|
597
|
+
test.use({ viewport: { width: 375, height: 667 } }) // Mobile to avoid sidebar
|
|
598
|
+
|
|
599
|
+
test("guest should see login prompt", async ({ page }) => {
|
|
600
|
+
await page.goto("/posts")
|
|
601
|
+
const readMoreLink = page.getByRole("link", { name: /続きを読む|Read more/i }).first()
|
|
602
|
+
await expect(readMoreLink).toBeVisible()
|
|
603
|
+
await readMoreLink.click()
|
|
604
|
+
|
|
605
|
+
// Scroll to comment section
|
|
606
|
+
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight))
|
|
607
|
+
|
|
608
|
+
// Verify login prompt (i18n)
|
|
609
|
+
await expect(page.getByText(/コメントするにはログイン|Please login to comment/i)).toBeVisible()
|
|
610
|
+
})
|
|
611
|
+
|
|
612
|
+
test("authenticated user should see comment form", async ({ page }) => {
|
|
613
|
+
// Login first
|
|
614
|
+
await page.goto("/login")
|
|
615
|
+
await page.getByRole("textbox", { name: /Email|メール/i }).fill(TEST_USERS.user.email)
|
|
616
|
+
await page.getByLabel(/^Password$|^パスワード$/i).fill(TEST_USERS.user.password)
|
|
617
|
+
await page.getByRole("button", { name: /Login|ログイン/i }).click()
|
|
618
|
+
await expect(page).toHaveURL(/\/$/, { timeout: 15000 })
|
|
619
|
+
|
|
620
|
+
// Navigate to post
|
|
621
|
+
await page.goto("/posts")
|
|
622
|
+
const readMoreLink = page.getByRole("link", { name: /続きを読む|Read more/i }).first()
|
|
623
|
+
await readMoreLink.click()
|
|
624
|
+
await page.waitForLoadState("networkidle")
|
|
625
|
+
|
|
626
|
+
// Scroll to comment section
|
|
627
|
+
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight))
|
|
628
|
+
|
|
629
|
+
// Verify comment form
|
|
630
|
+
const commentInput = page.getByPlaceholder(/コメントを入力|Enter your comment/i)
|
|
631
|
+
await expect(commentInput).toBeVisible({ timeout: 15000 })
|
|
632
|
+
})
|
|
633
|
+
})
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
## Mailpit Email Testing Integration
|
|
637
|
+
|
|
638
|
+
Use the Mailpit helper for email verification flows:
|
|
639
|
+
|
|
640
|
+
```typescript
|
|
641
|
+
import { mailpit } from "../helpers/mailpit"
|
|
642
|
+
|
|
643
|
+
test.describe("Password Reset Flow", () => {
|
|
644
|
+
test("should send password reset email", async ({ page }) => {
|
|
645
|
+
// Clear all emails before test
|
|
646
|
+
await mailpit.deleteAllMessages()
|
|
647
|
+
|
|
648
|
+
// Request password reset
|
|
649
|
+
await page.goto("/forgot-password")
|
|
650
|
+
await page.getByLabel("Email").fill("user@example.com")
|
|
651
|
+
await page.getByRole("button", { name: /Send Reset Link/i }).click()
|
|
652
|
+
|
|
653
|
+
// Wait for success message
|
|
654
|
+
await expect(page.getByText(/Check your email/i)).toBeVisible()
|
|
655
|
+
|
|
656
|
+
// Verify email was sent
|
|
657
|
+
const messages = await mailpit.getMessages()
|
|
658
|
+
expect(messages.length).toBe(1)
|
|
659
|
+
expect(messages[0].to[0].address).toBe("user@example.com")
|
|
660
|
+
expect(messages[0].subject).toMatch(/Password Reset/i)
|
|
661
|
+
|
|
662
|
+
// Extract verification link
|
|
663
|
+
const verifyLink = extractVerificationLink(messages[0].body)
|
|
664
|
+
expect(verifyLink).toBeTruthy()
|
|
665
|
+
|
|
666
|
+
// Navigate to verification link
|
|
667
|
+
await page.goto(verifyLink)
|
|
668
|
+
await expect(page.getByText(/Enter new password/i)).toBeVisible()
|
|
669
|
+
})
|
|
670
|
+
|
|
671
|
+
test("should verify email for new user", async ({ page }) => {
|
|
672
|
+
await mailpit.deleteAllMessages()
|
|
673
|
+
|
|
674
|
+
// Register new user
|
|
675
|
+
await page.goto("/register")
|
|
676
|
+
const testEmail = `test-${Date.now()}@example.com`
|
|
677
|
+
await page.getByLabel("Email").fill(testEmail)
|
|
678
|
+
await page.getByLabel("Password").fill("Test@Pass123")
|
|
679
|
+
await page.getByRole("button", { name: /Sign Up/i }).click()
|
|
680
|
+
|
|
681
|
+
// Get verification email
|
|
682
|
+
const messages = await mailpit.getMessages()
|
|
683
|
+
expect(messages.length).toBe(1)
|
|
684
|
+
|
|
685
|
+
const emailBody = messages[0].body
|
|
686
|
+
const verifyLink = extractVerificationLink(emailBody)
|
|
687
|
+
|
|
688
|
+
// Click verification link
|
|
689
|
+
await page.goto(verifyLink)
|
|
690
|
+
await expect(page.getByText(/Email verified/i)).toBeVisible()
|
|
691
|
+
})
|
|
692
|
+
})
|
|
693
|
+
|
|
694
|
+
function extractVerificationLink(body: string): string {
|
|
695
|
+
const match = body.match(/https?:\/\/[^\s<>"]+\/verify[^\s<>"]*/)
|
|
696
|
+
return match ? match[0] : ""
|
|
697
|
+
}
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
### Mailpit Helper API
|
|
701
|
+
|
|
702
|
+
```typescript
|
|
703
|
+
// tests/helpers/mailpit.ts
|
|
704
|
+
interface MailpitMessage {
|
|
705
|
+
id: string
|
|
706
|
+
from: { address: string; name: string }
|
|
707
|
+
to: Array<{ address: string; name: string }>
|
|
708
|
+
subject: string
|
|
709
|
+
body: string
|
|
710
|
+
html: string
|
|
711
|
+
created: string
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
class MailpitHelper {
|
|
715
|
+
private baseUrl = "http://mailpit:8025/api/v1"
|
|
716
|
+
|
|
717
|
+
async getMessages(): Promise<MailpitMessage[]> {
|
|
718
|
+
const response = await fetch(`${this.baseUrl}/messages`)
|
|
719
|
+
const data = await response.json()
|
|
720
|
+
return data.messages || []
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
async getMessage(id: string): Promise<MailpitMessage> {
|
|
724
|
+
const response = await fetch(`${this.baseUrl}/message/${id}`)
|
|
725
|
+
return await response.json()
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
async deleteAllMessages(): Promise<void> {
|
|
729
|
+
await fetch(`${this.baseUrl}/messages`, { method: "DELETE" })
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
export const mailpit = new MailpitHelper()
|
|
734
|
+
```
|
|
735
|
+
|
|
736
|
+
## Redis Test Helper Integration
|
|
737
|
+
|
|
738
|
+
Clear rate limits and lockouts between tests:
|
|
739
|
+
|
|
740
|
+
```typescript
|
|
741
|
+
import { redisHelper } from "../helpers/redis"
|
|
742
|
+
|
|
743
|
+
test.describe("Login Rate Limiting", () => {
|
|
744
|
+
test.beforeEach(async () => {
|
|
745
|
+
// Clear all test state before each test
|
|
746
|
+
await redisHelper.clearAllTestState()
|
|
747
|
+
})
|
|
748
|
+
|
|
749
|
+
test("should lock account after 5 failed attempts", async ({ page }) => {
|
|
750
|
+
await page.goto("/login")
|
|
751
|
+
|
|
752
|
+
// Attempt 5 failed logins
|
|
753
|
+
for (let i = 0; i < 5; i++) {
|
|
754
|
+
await page.getByLabel("Email").fill("user@example.com")
|
|
755
|
+
await page.getByLabel("Password").fill("wrongpassword")
|
|
756
|
+
await page.getByRole("button", { name: /Log in/i }).click()
|
|
757
|
+
await expect(page.getByText(/Invalid credentials/i)).toBeVisible()
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
// 6th attempt should show lockout message
|
|
761
|
+
await page.getByLabel("Email").fill("user@example.com")
|
|
762
|
+
await page.getByLabel("Password").fill("wrongpassword")
|
|
763
|
+
await page.getByRole("button", { name: /Log in/i }).click()
|
|
764
|
+
await expect(page.getByText(/Account locked/i)).toBeVisible()
|
|
765
|
+
})
|
|
766
|
+
|
|
767
|
+
test("should allow login after clearing lockout", async ({ page }) => {
|
|
768
|
+
// Simulate account lockout
|
|
769
|
+
await page.goto("/login")
|
|
770
|
+
for (let i = 0; i < 6; i++) {
|
|
771
|
+
await page.getByLabel("Email").fill("user@example.com")
|
|
772
|
+
await page.getByLabel("Password").fill("wrongpassword")
|
|
773
|
+
await page.getByRole("button", { name: /Log in/i }).click()
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// Clear rate limits via helper
|
|
777
|
+
await redisHelper.clearRateLimits()
|
|
778
|
+
|
|
779
|
+
// Should now allow login with correct password
|
|
780
|
+
await page.getByLabel("Email").fill("user@example.com")
|
|
781
|
+
await page.getByLabel("Password").fill("User@Test2024!")
|
|
782
|
+
await page.getByRole("button", { name: /Log in/i }).click()
|
|
783
|
+
await expect(page).toHaveURL(/\/$/, { timeout: 15000 })
|
|
784
|
+
})
|
|
785
|
+
})
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
### Redis Helper API
|
|
789
|
+
|
|
790
|
+
```typescript
|
|
791
|
+
// tests/helpers/redis.ts
|
|
792
|
+
import { createClient, RedisClientType } from "redis"
|
|
793
|
+
|
|
794
|
+
class RedisTestHelper {
|
|
795
|
+
private client: RedisClientType | null = null
|
|
796
|
+
|
|
797
|
+
async connect(): Promise<void> {
|
|
798
|
+
this.client = createClient({ url: process.env.REDIS_URL })
|
|
799
|
+
await this.client.connect()
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
async disconnect(): Promise<void> {
|
|
803
|
+
await this.client?.quit()
|
|
804
|
+
this.client = null
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
/** Clear all rate limits (ratelimit:*, account-lockout:*) */
|
|
808
|
+
async clearRateLimits(): Promise<void> {
|
|
809
|
+
if (!this.client) throw new Error("Not connected")
|
|
810
|
+
const keys = await this.client.keys("ratelimit:*")
|
|
811
|
+
const lockoutKeys = await this.client.keys("account-lockout:*")
|
|
812
|
+
const allKeys = [...keys, ...lockoutKeys]
|
|
813
|
+
if (allKeys.length > 0) {
|
|
814
|
+
await this.client.del(allKeys)
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
/** Clear all test-related state (rate limits, lockouts, sessions) */
|
|
819
|
+
async clearAllTestState(): Promise<void> {
|
|
820
|
+
if (!this.client) throw new Error("Not connected")
|
|
821
|
+
await this.clearRateLimits()
|
|
822
|
+
// Add other cleanup as needed
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
export const redisHelper = new RedisTestHelper()
|
|
827
|
+
```
|
|
828
|
+
|
|
829
|
+
## Request Blocking for Loading States (Advanced)
|
|
830
|
+
|
|
831
|
+
Use Promise-based request blocking to reliably test loading states:
|
|
832
|
+
|
|
833
|
+
```typescript
|
|
834
|
+
test("should show loading state during form submission", async ({ page }) => {
|
|
835
|
+
let resolveRequest: () => void
|
|
836
|
+
const requestPromise = new Promise<void>((resolve) => {
|
|
837
|
+
resolveRequest = resolve
|
|
838
|
+
})
|
|
839
|
+
|
|
840
|
+
// Block API request to keep loading state visible
|
|
841
|
+
await page.route("**/api/posts", async (route) => {
|
|
842
|
+
await requestPromise
|
|
843
|
+
await route.continue()
|
|
844
|
+
})
|
|
845
|
+
|
|
846
|
+
await page.goto("/posts/new")
|
|
847
|
+
await page.getByLabel("Title").fill("Test Post")
|
|
848
|
+
await page.getByLabel("Content").fill("Test content")
|
|
849
|
+
|
|
850
|
+
// Get button reference before clicking
|
|
851
|
+
const submitButton = page.getByRole("button", { name: /Publish/i })
|
|
852
|
+
await submitButton.click()
|
|
853
|
+
|
|
854
|
+
// Verify loading state - button text changes to "Publishing..."
|
|
855
|
+
const loadingButton = page.getByRole("button", { name: /Publishing/i })
|
|
856
|
+
await expect(loadingButton).toBeVisible()
|
|
857
|
+
await expect(loadingButton).toBeDisabled()
|
|
858
|
+
|
|
859
|
+
// Release request to complete
|
|
860
|
+
resolveRequest!()
|
|
861
|
+
|
|
862
|
+
// Verify success
|
|
863
|
+
await expect(page).toHaveURL(/\/posts\/[^/]+$/, { timeout: 10000 })
|
|
864
|
+
})
|
|
865
|
+
```
|
|
866
|
+
|
|
867
|
+
### Multiple Request Blocking Pattern
|
|
868
|
+
|
|
869
|
+
```typescript
|
|
870
|
+
test("should show loading for multi-step operation", async ({ page }) => {
|
|
871
|
+
let resolveStep1: () => void
|
|
872
|
+
let resolveStep2: () => void
|
|
873
|
+
|
|
874
|
+
const step1Promise = new Promise<void>(r => { resolveStep1 = r })
|
|
875
|
+
const step2Promise = new Promise<void>(r => { resolveStep2 = r })
|
|
876
|
+
|
|
877
|
+
// Block first API call
|
|
878
|
+
await page.route("**/api/validate", async (route) => {
|
|
879
|
+
await step1Promise
|
|
880
|
+
await route.continue()
|
|
881
|
+
})
|
|
882
|
+
|
|
883
|
+
// Block second API call
|
|
884
|
+
await page.route("**/api/submit", async (route) => {
|
|
885
|
+
await step2Promise
|
|
886
|
+
await route.continue()
|
|
887
|
+
})
|
|
888
|
+
|
|
889
|
+
await page.getByRole("button", { name: /Submit/i }).click()
|
|
890
|
+
|
|
891
|
+
// Step 1: Validating
|
|
892
|
+
await expect(page.getByText(/Validating/i)).toBeVisible()
|
|
893
|
+
resolveStep1!()
|
|
894
|
+
|
|
895
|
+
// Step 2: Submitting
|
|
896
|
+
await expect(page.getByText(/Submitting/i)).toBeVisible()
|
|
897
|
+
resolveStep2!()
|
|
898
|
+
|
|
899
|
+
// Complete
|
|
900
|
+
await expect(page.getByText(/Success/i)).toBeVisible()
|
|
901
|
+
})
|
|
902
|
+
```
|
|
903
|
+
|
|
904
|
+
## Playwright Version Info
|
|
905
|
+
|
|
906
|
+
### Playwright 1.58 (Latest)
|
|
907
|
+
|
|
908
|
+
- **Browsers**: Chromium 145.0, Firefox 146.0.1, WebKit 26.0
|
|
909
|
+
- **HTML Report**: Timeline display in merge reports
|
|
910
|
+
- **Breaking Changes**: `_react`/`_vue` selectors removed, `:light` selector engine removed, `devtools` launch option removed
|
|
911
|
+
|
|
912
|
+
### Playwright 1.57
|
|
913
|
+
|
|
914
|
+
- **Chrome for Testing**: Switched from Chromium to Chrome for Testing builds (both headed/headless)
|
|
915
|
+
- **Speedboard**: Added test execution time sorted tab in HTML report
|
|
916
|
+
- **Deprecated**: `page.accessibility` (removed after 3-year deprecation period)
|
|
917
|
+
- **New Features**: `testConfig.tag`, worker console events, locator descriptions
|
|
918
|
+
|
|
919
|
+
### Playwright 1.56
|
|
920
|
+
|
|
921
|
+
- **Playwright Agents**: LLM-powered test generation and repair agents (planner, generator, healer)
|
|
922
|
+
- **New Methods**: `page.consoleMessages()`, `page.pageErrors()`, `page.requests()`
|