@mmerterden/multi-agent-pipeline 8.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2623 -0
- package/LICENSE +21 -0
- package/README.md +852 -0
- package/docs/FIGMA_PIPELINE.md +138 -0
- package/docs/GENERICITY-REVIEW.md +277 -0
- package/docs/STABILITY-FIX-PLAN.md +168 -0
- package/docs/adr/0001-three-model-triage.md +81 -0
- package/docs/adr/0002-instruction-driven-flag.md +62 -0
- package/docs/adr/0003-unified-shared-skills.md +55 -0
- package/docs/adr/0004-zero-dependency-philosophy.md +60 -0
- package/docs/adr/0005-lazy-phase-docs.md +68 -0
- package/docs/adr/0006-skills-core-external-split.md +52 -0
- package/docs/adr/0007-multi-tool-adapter-framework.md +110 -0
- package/docs/adr/0008-installer-modularization-and-secret-leak-defense.md +98 -0
- package/docs/adr/README.md +33 -0
- package/docs/architecture.md +181 -0
- package/docs/best-practices.md +93 -0
- package/docs/features.md +274 -0
- package/docs/performance.md +116 -0
- package/docs/recovery-guide.md +479 -0
- package/index.js +76 -0
- package/install/_adapters.mjs +69 -0
- package/install/_common.mjs +150 -0
- package/install/_copilot-instructions.mjs +32 -0
- package/install/_dev-only-files.mjs +23 -0
- package/install/_platform-filter.mjs +132 -0
- package/install/_telemetry.mjs +79 -0
- package/install/claude.mjs +332 -0
- package/install/copilot.mjs +254 -0
- package/install/index.mjs +179 -0
- package/install/templates/copilot-instructions.md +319 -0
- package/install.js +24 -0
- package/package.json +78 -0
- package/pipeline/adapters/_base.mjs +288 -0
- package/pipeline/adapters/copilot-chat.mjs +158 -0
- package/pipeline/adapters/cursor.mjs +187 -0
- package/pipeline/agents/android-architect.md +42 -0
- package/pipeline/agents/backend-architect.md +43 -0
- package/pipeline/agents/code-reviewer.md +57 -0
- package/pipeline/agents/dev-critic.md +148 -0
- package/pipeline/agents/explorer.md +34 -0
- package/pipeline/agents/ios-architect.md +41 -0
- package/pipeline/agents/security-auditor.md +98 -0
- package/pipeline/agents/task-clarifier.md +113 -0
- package/pipeline/claude-md-template.md +55 -0
- package/pipeline/commands/archive-guard.md +45 -0
- package/pipeline/commands/deploy.md +54 -0
- package/pipeline/commands/figma-to-swiftui.md +295 -0
- package/pipeline/commands/multi-agent/_account-picker.md +90 -0
- package/pipeline/commands/multi-agent/_dev-context.md +111 -0
- package/pipeline/commands/multi-agent/_input-parser.md +43 -0
- package/pipeline/commands/multi-agent/_repo-picker.md +76 -0
- package/pipeline/commands/multi-agent/autopilot.md +116 -0
- package/pipeline/commands/multi-agent/channels.md +465 -0
- package/pipeline/commands/multi-agent/delete.md +66 -0
- package/pipeline/commands/multi-agent/dev-autopilot.md +120 -0
- package/pipeline/commands/multi-agent/dev-local-autopilot.md +110 -0
- package/pipeline/commands/multi-agent/dev-local.md +105 -0
- package/pipeline/commands/multi-agent/dev.md +246 -0
- package/pipeline/commands/multi-agent/diff-explain.md +68 -0
- package/pipeline/commands/multi-agent/help.md +422 -0
- package/pipeline/commands/multi-agent/issue.md +79 -0
- package/pipeline/commands/multi-agent/jira.md +132 -0
- package/pipeline/commands/multi-agent/kill.md +38 -0
- package/pipeline/commands/multi-agent/language.md +94 -0
- package/pipeline/commands/multi-agent/local-autopilot.md +139 -0
- package/pipeline/commands/multi-agent/local.md +117 -0
- package/pipeline/commands/multi-agent/log.md +25 -0
- package/pipeline/commands/multi-agent/manual-test.md +43 -0
- package/pipeline/commands/multi-agent/purge.md +39 -0
- package/pipeline/commands/multi-agent/refactor.md +188 -0
- package/pipeline/commands/multi-agent/refs/android-guide.md +250 -0
- package/pipeline/commands/multi-agent/refs/audit-guide.md +240 -0
- package/pipeline/commands/multi-agent/refs/backend-guide.md +135 -0
- package/pipeline/commands/multi-agent/refs/channels/confluence.md +153 -0
- package/pipeline/commands/multi-agent/refs/channels/issue-comment.md +141 -0
- package/pipeline/commands/multi-agent/refs/channels/jira.md +127 -0
- package/pipeline/commands/multi-agent/refs/channels/pr-review-actions.md +135 -0
- package/pipeline/commands/multi-agent/refs/channels/pr.md +139 -0
- package/pipeline/commands/multi-agent/refs/channels/wiki.md +66 -0
- package/pipeline/commands/multi-agent/refs/component-dispatch.md +92 -0
- package/pipeline/commands/multi-agent/refs/cross-cli-contract.md +326 -0
- package/pipeline/commands/multi-agent/refs/frontend-guide.md +136 -0
- package/pipeline/commands/multi-agent/refs/issue-jira-triad.md +104 -0
- package/pipeline/commands/multi-agent/refs/keychain.md +80 -0
- package/pipeline/commands/multi-agent/refs/knowledge.md +112 -0
- package/pipeline/commands/multi-agent/refs/multi-repo-integration-build.md +207 -0
- package/pipeline/commands/multi-agent/refs/phases/log-format.md +89 -0
- package/pipeline/commands/multi-agent/refs/phases/modes.md +156 -0
- package/pipeline/commands/multi-agent/refs/phases/operations.md +91 -0
- package/pipeline/commands/multi-agent/refs/phases/phase-0-init.md +481 -0
- package/pipeline/commands/multi-agent/refs/phases/phase-1-analysis.md +264 -0
- package/pipeline/commands/multi-agent/refs/phases/phase-2-planning.md +278 -0
- package/pipeline/commands/multi-agent/refs/phases/phase-3-dev.md +364 -0
- package/pipeline/commands/multi-agent/refs/phases/phase-4-review.md +378 -0
- package/pipeline/commands/multi-agent/refs/phases/phase-5-test.md +129 -0
- package/pipeline/commands/multi-agent/refs/phases/phase-6-commit.md +339 -0
- package/pipeline/commands/multi-agent/refs/phases/phase-7-report.md +361 -0
- package/pipeline/commands/multi-agent/refs/phases.md +187 -0
- package/pipeline/commands/multi-agent/refs/progress-contract.md +155 -0
- package/pipeline/commands/multi-agent/refs/rules.md +189 -0
- package/pipeline/commands/multi-agent/refs/swiftui-guide.md +254 -0
- package/pipeline/commands/multi-agent/refs/tracker-contract.md +256 -0
- package/pipeline/commands/multi-agent/refs/wiki-capture.md +109 -0
- package/pipeline/commands/multi-agent/resume.md +28 -0
- package/pipeline/commands/multi-agent/review.md +228 -0
- package/pipeline/commands/multi-agent/scan.md +74 -0
- package/pipeline/commands/multi-agent/search.md +97 -0
- package/pipeline/commands/multi-agent/setup.md +767 -0
- package/pipeline/commands/multi-agent/stack.md +48 -0
- package/pipeline/commands/multi-agent/status.md +38 -0
- package/pipeline/commands/multi-agent/sync.md +319 -0
- package/pipeline/commands/multi-agent/test.md +39 -0
- package/pipeline/commands/multi-agent/update.md +88 -0
- package/pipeline/commands/multi-agent.md +293 -0
- package/pipeline/commands/security-review.md +6 -0
- package/pipeline/commands/sim-test.md +256 -0
- package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-1-analysis.json +25 -0
- package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-2-plan.json +30 -0
- package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-4-review.json +20 -0
- package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-4-triage.json +15 -0
- package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/metadata.json +14 -0
- package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/task.json +12 -0
- package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-1-analysis.json +29 -0
- package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-2-plan.json +43 -0
- package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-4-review.json +35 -0
- package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-4-triage.json +35 -0
- package/pipeline/eval/golden-tasks/02-android-feature-compose/metadata.json +14 -0
- package/pipeline/eval/golden-tasks/02-android-feature-compose/task.json +12 -0
- package/pipeline/eval/golden-tasks/README.md +65 -0
- package/pipeline/eval/triage/01-empty-findings/expected.json +6 -0
- package/pipeline/eval/triage/01-empty-findings/input.json +5 -0
- package/pipeline/eval/triage/01-empty-findings/notes.md +7 -0
- package/pipeline/eval/triage/02-real-blocker/expected.json +15 -0
- package/pipeline/eval/triage/02-real-blocker/input.json +14 -0
- package/pipeline/eval/triage/02-real-blocker/notes.md +7 -0
- package/pipeline/eval/triage/03-out-of-scope-defer/expected.json +18 -0
- package/pipeline/eval/triage/03-out-of-scope-defer/input.json +14 -0
- package/pipeline/eval/triage/03-out-of-scope-defer/notes.md +10 -0
- package/pipeline/eval/triage/04-false-positive-reject/expected.json +18 -0
- package/pipeline/eval/triage/04-false-positive-reject/input.json +14 -0
- package/pipeline/eval/triage/04-false-positive-reject/notes.md +10 -0
- package/pipeline/eval/triage/05-mixed-classification/expected.json +43 -0
- package/pipeline/eval/triage/05-mixed-classification/input.json +38 -0
- package/pipeline/eval/triage/05-mixed-classification/notes.md +17 -0
- package/pipeline/eval/triage/06-severity-mismatch/expected.json +15 -0
- package/pipeline/eval/triage/06-severity-mismatch/input.json +14 -0
- package/pipeline/eval/triage/06-severity-mismatch/notes.md +9 -0
- package/pipeline/eval/triage/07-duplicate-reviewers/expected.json +27 -0
- package/pipeline/eval/triage/07-duplicate-reviewers/input.json +22 -0
- package/pipeline/eval/triage/07-duplicate-reviewers/notes.md +9 -0
- package/pipeline/eval/triage/08-style-misclassified/expected.json +18 -0
- package/pipeline/eval/triage/08-style-misclassified/input.json +14 -0
- package/pipeline/eval/triage/08-style-misclassified/notes.md +9 -0
- package/pipeline/eval/triage/09-cascading-finding/expected.json +23 -0
- package/pipeline/eval/triage/09-cascading-finding/input.json +22 -0
- package/pipeline/eval/triage/09-cascading-finding/notes.md +9 -0
- package/pipeline/eval/triage/10-deferred-crossref/expected.json +18 -0
- package/pipeline/eval/triage/10-deferred-crossref/input.json +14 -0
- package/pipeline/eval/triage/10-deferred-crossref/notes.md +9 -0
- package/pipeline/eval/triage/11-vercel-token-leak-blocker/expected.json +27 -0
- package/pipeline/eval/triage/11-vercel-token-leak-blocker/input.json +22 -0
- package/pipeline/eval/triage/11-vercel-token-leak-blocker/notes.md +14 -0
- package/pipeline/eval/triage/README.md +54 -0
- package/pipeline/lib/account-resolver.sh +204 -0
- package/pipeline/lib/channels-multi-repo.sh +218 -0
- package/pipeline/lib/context-link-extractor.sh +192 -0
- package/pipeline/lib/credential-store-resolver.sh +57 -0
- package/pipeline/lib/credential-store.sh +226 -0
- package/pipeline/lib/fetch-confluence.sh +358 -0
- package/pipeline/lib/fetch-crashlytics.sh +314 -0
- package/pipeline/lib/fetch-fortify.sh +321 -0
- package/pipeline/lib/fetch-swagger.sh +270 -0
- package/pipeline/lib/issue-fetcher.sh +333 -0
- package/pipeline/lib/multi-repo-pipeline.sh +252 -0
- package/pipeline/lib/plan-todos.sh +284 -0
- package/pipeline/lib/post-pr-review.sh +374 -0
- package/pipeline/lib/repo-cache.sh +231 -0
- package/pipeline/lib/review-watch.sh +244 -0
- package/pipeline/lib/shadow-git.sh +222 -0
- package/pipeline/lib/submodule-detector.sh +177 -0
- package/pipeline/lib/vercel-deploy.sh +170 -0
- package/pipeline/preferences-template.json +132 -0
- package/pipeline/rules/app-store-guidelines.md +59 -0
- package/pipeline/rules/code-review.md +27 -0
- package/pipeline/rules/code-style.md +37 -0
- package/pipeline/rules/debugging.md +24 -0
- package/pipeline/rules/figma-pipeline.md +190 -0
- package/pipeline/rules/git-conventions.md +29 -0
- package/pipeline/rules/kotlin-android.md +92 -0
- package/pipeline/rules/performance.md +23 -0
- package/pipeline/rules/security.md +39 -0
- package/pipeline/rules/swiftui-qa.md +32 -0
- package/pipeline/rules/tdd.md +25 -0
- package/pipeline/rules/testing.md +37 -0
- package/pipeline/schemas/agent-state.schema.json +273 -0
- package/pipeline/schemas/analysis-output.schema.json +59 -0
- package/pipeline/schemas/clarify-output.schema.json +74 -0
- package/pipeline/schemas/dev-critic-output.schema.json +104 -0
- package/pipeline/schemas/diff-risk.schema.json +78 -0
- package/pipeline/schemas/figma-project-config.schema.json +372 -0
- package/pipeline/schemas/migrations/README.md +73 -0
- package/pipeline/schemas/migrations/figma-config-1.0.0-to-2.0.0.mjs +112 -0
- package/pipeline/schemas/migrations/prefs-2.0.0-to-2.1.0.mjs +75 -0
- package/pipeline/schemas/migrations/prefs-2.1.0-to-2.2.0.mjs +64 -0
- package/pipeline/schemas/migrations/prefs-2.2.0-to-2.3.0.mjs +36 -0
- package/pipeline/schemas/migrations/state-2.0.0-to-2.1.0.mjs +34 -0
- package/pipeline/schemas/plan-todos.schema.json +62 -0
- package/pipeline/schemas/planning-output.schema.json +57 -0
- package/pipeline/schemas/prefs.schema.json +1137 -0
- package/pipeline/schemas/reviewer-output.schema.json +55 -0
- package/pipeline/schemas/test-gap.schema.json +64 -0
- package/pipeline/schemas/token-budget.json +17 -0
- package/pipeline/schemas/triage-corpus.schema.json +31 -0
- package/pipeline/schemas/triage-output.schema.json +115 -0
- package/pipeline/scripts/.last-figma-sync-plan.json +23 -0
- package/pipeline/scripts/README-figma-smokes.md +34 -0
- package/pipeline/scripts/README.md +104 -0
- package/pipeline/scripts/aggregate-metrics.mjs +310 -0
- package/pipeline/scripts/audit-log-rotate.sh +61 -0
- package/pipeline/scripts/audit-log.sh +69 -0
- package/pipeline/scripts/benchmark-phase-0.sh +128 -0
- package/pipeline/scripts/build-skills-index.mjs +139 -0
- package/pipeline/scripts/classify-plan-safety.mjs +177 -0
- package/pipeline/scripts/cost-table.json +27 -0
- package/pipeline/scripts/diff-explain.mjs +276 -0
- package/pipeline/scripts/diff-risk-score.mjs +328 -0
- package/pipeline/scripts/eval-golden-tasks-live.mjs +294 -0
- package/pipeline/scripts/eval-golden-tasks.mjs +223 -0
- package/pipeline/scripts/eval-triage.mjs +171 -0
- package/pipeline/scripts/figma-placeholder-map.json +191 -0
- package/pipeline/scripts/fixtures/diff-risk-android.diff +40 -0
- package/pipeline/scripts/fixtures/diff-risk-ios.diff +48 -0
- package/pipeline/scripts/fixtures/install-layout.tsv +16 -0
- package/pipeline/scripts/fixtures/test-gap-node.diff +30 -0
- package/pipeline/scripts/fixtures/test-gap-python.diff +32 -0
- package/pipeline/scripts/gen-mode-dispatch.mjs +170 -0
- package/pipeline/scripts/gen-skills-index.mjs +90 -0
- package/pipeline/scripts/github-ssh-setup.sh +103 -0
- package/pipeline/scripts/import-figma-skills.sh +253 -0
- package/pipeline/scripts/keychain-save.sh +74 -0
- package/pipeline/scripts/keychain.py +294 -0
- package/pipeline/scripts/log-metric.sh +98 -0
- package/pipeline/scripts/match-skills.mjs +167 -0
- package/pipeline/scripts/memory-load.sh +46 -0
- package/pipeline/scripts/memory-save.sh +76 -0
- package/pipeline/scripts/migrate-prefs.mjs +390 -0
- package/pipeline/scripts/migrate-state.mjs +215 -0
- package/pipeline/scripts/output-quality-check.sh +125 -0
- package/pipeline/scripts/phase-banner.sh +158 -0
- package/pipeline/scripts/phase-tracker.sh +548 -0
- package/pipeline/scripts/pre-commit-check.sh +69 -0
- package/pipeline/scripts/pre-push-check.sh +77 -0
- package/pipeline/scripts/render-agent-log-cost.sh +149 -0
- package/pipeline/scripts/render-cost-summary.sh +137 -0
- package/pipeline/scripts/render-work-summary.sh +195 -0
- package/pipeline/scripts/repo-map.mjs +367 -0
- package/pipeline/scripts/run-aggregator.mjs +298 -0
- package/pipeline/scripts/scan-skills.sh +332 -0
- package/pipeline/scripts/search-logs.sh +291 -0
- package/pipeline/scripts/sign-skills.sh +67 -0
- package/pipeline/scripts/smoke-adapters.sh +207 -0
- package/pipeline/scripts/smoke-add-detail.sh +137 -0
- package/pipeline/scripts/smoke-agent-log-cost.sh +183 -0
- package/pipeline/scripts/smoke-agent-model-routing.sh +87 -0
- package/pipeline/scripts/smoke-bitbucket-contract.sh +223 -0
- package/pipeline/scripts/smoke-channels-flow.sh +130 -0
- package/pipeline/scripts/smoke-ci-workflows.sh +88 -0
- package/pipeline/scripts/smoke-clarify.sh +148 -0
- package/pipeline/scripts/smoke-commands-skills-parity.sh +87 -0
- package/pipeline/scripts/smoke-compliance-skills.sh +119 -0
- package/pipeline/scripts/smoke-cost-summary.sh +139 -0
- package/pipeline/scripts/smoke-cross-cli-behavior.sh +198 -0
- package/pipeline/scripts/smoke-cross-phase-cohesion.sh +128 -0
- package/pipeline/scripts/smoke-delete-flow.sh +151 -0
- package/pipeline/scripts/smoke-dev-critic.sh +144 -0
- package/pipeline/scripts/smoke-diff-explain.sh +128 -0
- package/pipeline/scripts/smoke-diff-risk.sh +161 -0
- package/pipeline/scripts/smoke-dynamic-skill-loading.sh +160 -0
- package/pipeline/scripts/smoke-eval-live.sh +136 -0
- package/pipeline/scripts/smoke-existing-discovery-gate.sh +71 -0
- package/pipeline/scripts/smoke-figma-android-parity.sh +148 -0
- package/pipeline/scripts/smoke-figma-config-schema.sh +144 -0
- package/pipeline/scripts/smoke-figma-credential-store.sh +105 -0
- package/pipeline/scripts/smoke-figma-cross-cli-inventory.sh +177 -0
- package/pipeline/scripts/smoke-figma-dispatch.sh +123 -0
- package/pipeline/scripts/smoke-figma-skill-import.sh +174 -0
- package/pipeline/scripts/smoke-figma-sync.sh +149 -0
- package/pipeline/scripts/smoke-identity-isolation.sh +70 -0
- package/pipeline/scripts/smoke-install-layout.sh +241 -0
- package/pipeline/scripts/smoke-install-leak-gate.sh +125 -0
- package/pipeline/scripts/smoke-issue-comment-template.sh +86 -0
- package/pipeline/scripts/smoke-issue-jira-triad.sh +120 -0
- package/pipeline/scripts/smoke-keychain.sh +158 -0
- package/pipeline/scripts/smoke-language-axis.sh +109 -0
- package/pipeline/scripts/smoke-lib-scripts.sh +395 -0
- package/pipeline/scripts/smoke-migrate-state.sh +102 -0
- package/pipeline/scripts/smoke-mode-dispatch-drift.sh +158 -0
- package/pipeline/scripts/smoke-multi-repo-integration.sh +116 -0
- package/pipeline/scripts/smoke-multi-repo-worktree.sh +61 -0
- package/pipeline/scripts/smoke-no-token-prompt.sh +69 -0
- package/pipeline/scripts/smoke-pat-audit.sh +107 -0
- package/pipeline/scripts/smoke-per-repo-memory.sh +156 -0
- package/pipeline/scripts/smoke-personal-data.sh +82 -0
- package/pipeline/scripts/smoke-phase-0-multi-repo.sh +170 -0
- package/pipeline/scripts/smoke-phase-6-multi.sh +79 -0
- package/pipeline/scripts/smoke-phase-banner.sh +101 -0
- package/pipeline/scripts/smoke-phase-tracker.sh +255 -0
- package/pipeline/scripts/smoke-phase0-bridge-contract.sh +241 -0
- package/pipeline/scripts/smoke-phase4-triage.sh +142 -0
- package/pipeline/scripts/smoke-plan-approval-gate.sh +71 -0
- package/pipeline/scripts/smoke-plan-safety.sh +139 -0
- package/pipeline/scripts/smoke-plan-todos.sh +193 -0
- package/pipeline/scripts/smoke-pr-review-actions.sh +152 -0
- package/pipeline/scripts/smoke-pre-commit.sh +138 -0
- package/pipeline/scripts/smoke-pref-migration.sh +224 -0
- package/pipeline/scripts/smoke-prefs-language.sh +134 -0
- package/pipeline/scripts/smoke-progress-contract.sh +118 -0
- package/pipeline/scripts/smoke-push-retry.sh +75 -0
- package/pipeline/scripts/smoke-readme-counts.sh +120 -0
- package/pipeline/scripts/smoke-repo-map.sh +300 -0
- package/pipeline/scripts/smoke-review-watch.sh +134 -0
- package/pipeline/scripts/smoke-run-aggregator.sh +216 -0
- package/pipeline/scripts/smoke-schema-validation.sh +173 -0
- package/pipeline/scripts/smoke-search.sh +187 -0
- package/pipeline/scripts/smoke-shadow-git.sh +175 -0
- package/pipeline/scripts/smoke-skill-authoring.sh +142 -0
- package/pipeline/scripts/smoke-skill-language.sh +83 -0
- package/pipeline/scripts/smoke-skill-manifest.sh +138 -0
- package/pipeline/scripts/smoke-skill-scan.sh +198 -0
- package/pipeline/scripts/smoke-stack-swap.sh +132 -0
- package/pipeline/scripts/smoke-subagent-validators.sh +105 -0
- package/pipeline/scripts/smoke-sync-delegation.sh +74 -0
- package/pipeline/scripts/smoke-sync-parity.sh +92 -0
- package/pipeline/scripts/smoke-tasklist-ordering.sh +111 -0
- package/pipeline/scripts/smoke-telemetry.sh +147 -0
- package/pipeline/scripts/smoke-test-gap.sh +183 -0
- package/pipeline/scripts/smoke-token-budget.sh +67 -0
- package/pipeline/scripts/smoke-tracker-contract.sh +129 -0
- package/pipeline/scripts/smoke-tracker-tokens-invocation.sh +65 -0
- package/pipeline/scripts/smoke-triage-memory.sh +174 -0
- package/pipeline/scripts/smoke-url-enrichment.sh +70 -0
- package/pipeline/scripts/smoke-validator-contradiction.sh +67 -0
- package/pipeline/scripts/smoke-vercel-deploy-redact.sh +129 -0
- package/pipeline/scripts/smoke-wiki-integration.sh +146 -0
- package/pipeline/scripts/smoke-work-summary.sh +163 -0
- package/pipeline/scripts/smoke-worktree-path-convention.sh +86 -0
- package/pipeline/scripts/smoke-write-state.sh +115 -0
- package/pipeline/scripts/stack-swap.sh +182 -0
- package/pipeline/scripts/sync-figma-source.sh +228 -0
- package/pipeline/scripts/sync-parity-check.sh +135 -0
- package/pipeline/scripts/test-gap-rules/android.json +25 -0
- package/pipeline/scripts/test-gap-rules/ios.json +29 -0
- package/pipeline/scripts/test-gap-rules/node.json +17 -0
- package/pipeline/scripts/test-gap-rules/python.json +19 -0
- package/pipeline/scripts/test-gap-scan.mjs +343 -0
- package/pipeline/scripts/token-budget-report.mjs +145 -0
- package/pipeline/scripts/triage-memory.mjs +258 -0
- package/pipeline/scripts/ui-tree-dumper.swift +122 -0
- package/pipeline/scripts/uninstall.mjs +331 -0
- package/pipeline/scripts/update-issue-progress.sh +146 -0
- package/pipeline/scripts/validate-analysis.mjs +132 -0
- package/pipeline/scripts/validate-diff-risk.mjs +117 -0
- package/pipeline/scripts/validate-planning.mjs +180 -0
- package/pipeline/scripts/validate-reviewer.mjs +131 -0
- package/pipeline/scripts/validate-schemas.mjs +88 -0
- package/pipeline/scripts/validate-test-gap.mjs +90 -0
- package/pipeline/scripts/validate-triage.mjs +175 -0
- package/pipeline/scripts/verify-skills.sh +126 -0
- package/pipeline/scripts/write-state.mjs +175 -0
- package/pipeline/skills/.skill-manifest.json +779 -0
- package/pipeline/skills/.skills-index.json +1771 -0
- package/pipeline/skills/figma-android/README.md +36 -0
- package/pipeline/skills/figma-android/figma-component-code-connect/SKILL.md +62 -0
- package/pipeline/skills/figma-android/figma-component-implement/SKILL.md +158 -0
- package/pipeline/skills/figma-android/figma-component-test/SKILL.md +120 -0
- package/pipeline/skills/figma-android/figma-component-wiki/SKILL.md +35 -0
- package/pipeline/skills/figma-android/figma-to-component/SKILL.md +124 -0
- package/pipeline/skills/figma-common/README.md +57 -0
- package/pipeline/skills/figma-common/figma-cli-iterate/SKILL.md +277 -0
- package/pipeline/skills/figma-common/figma-cli-iterate-mend/SKILL.md +498 -0
- package/pipeline/skills/figma-common/figma-cli-lean-iterate/SKILL.md +283 -0
- package/pipeline/skills/figma-common/figma-cli-skip/SKILL.md +362 -0
- package/pipeline/skills/figma-common/figma-commit/COMMON_REBASE.md +206 -0
- package/pipeline/skills/figma-common/figma-commit/REVIEW.md +337 -0
- package/pipeline/skills/figma-common/figma-commit/SKILL.md +211 -0
- package/pipeline/skills/figma-common/figma-component-confluence-sync/SKILL.md +218 -0
- package/pipeline/skills/figma-common/figma-component-start/SKILL.md +246 -0
- package/pipeline/skills/figma-common/figma-component-status-update/SKILL.md +73 -0
- package/pipeline/skills/figma-common/figma-fix/SKILL.md +316 -0
- package/pipeline/skills/figma-common/figma-form-integration/SKILL.md +542 -0
- package/pipeline/skills/figma-common/figma-issue/SKILL.md +745 -0
- package/pipeline/skills/figma-common/figma-iterate/SKILL.md +203 -0
- package/pipeline/skills/figma-common/figma-iteration-commit/SKILL.md +1015 -0
- package/pipeline/skills/figma-common/figma-mend/SKILL.md +331 -0
- package/pipeline/skills/figma-common/figma-price-integration/SKILL.md +398 -0
- package/pipeline/skills/figma-common/figma-remote-mcp-auth/SKILL.md +104 -0
- package/pipeline/skills/figma-common/figma-review/SKILL.md +395 -0
- package/pipeline/skills/figma-common/figma-setup/SKILL.md +514 -0
- package/pipeline/skills/figma-common/figma-setup/scripts/fetch-mcp-token.py +592 -0
- package/pipeline/skills/figma-common/figma-skip/SKILL.md +129 -0
- package/pipeline/skills/figma-common/figma-ui-patterns/SKILL.md +104 -0
- package/pipeline/skills/figma-common/figma-utility/SKILL.md +274 -0
- package/pipeline/skills/figma-common/figma-utility/scripts/figma-utility.py +808 -0
- package/pipeline/skills/figma-common/figma-validate/SKILL.md +633 -0
- package/pipeline/skills/figma-common/performance-iteration-commit-all/SKILL.md +711 -0
- package/pipeline/skills/figma-common/performance-review-next/SKILL.md +233 -0
- package/pipeline/skills/figma-common/performance-start/SKILL.md +425 -0
- package/pipeline/skills/figma-common/performance-swiftui/SKILL.md +706 -0
- package/pipeline/skills/figma-common/performance-tour/SKILL.md +418 -0
- package/pipeline/skills/figma-ios/REVIEW_CHECKLIST.md +67 -0
- package/pipeline/skills/figma-ios/figma-component-code-connect/SKILL.md +178 -0
- package/pipeline/skills/figma-ios/figma-component-implement/SKILL.md +184 -0
- package/pipeline/skills/figma-ios/figma-component-test/SKILL.md +219 -0
- package/pipeline/skills/figma-ios/figma-component-wiki/SKILL.md +274 -0
- package/pipeline/skills/figma-ios/figma-to-component/SKILL.md +401 -0
- package/pipeline/skills/figma-ios/figma-to-component/halt-return-protocol.md +57 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-0-init.md +307 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-1-gathering.md +119 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-1.5-existing-discovery.md +174 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-2-orchestrator.md +333 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-2a-testing-identifiers.md +368 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-2b-localization.md +393 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-2c-accessibility.md +617 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-2d-analytics.md +352 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3-orchestrator.md +337 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3a-location.md +206 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3b-tokens.md +235 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3c-nested.md +214 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3d-patterns.md +871 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3e-assets.md +156 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3f-utilities.md +175 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3g-property-coverage.md +176 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3h-variant-config.md +333 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4-orchestrator.md +412 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4a-configuration.md +336 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4b-view.md +695 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4c-documentation.md +332 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4d-preview.md +380 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4e-modifiers.md +262 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-5-orchestrator.md +482 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-5a-viewinspector.md +274 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-5b-snapshot.md +636 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-5c-unit.md +142 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-6-code-connect.md +547 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-7-wiki.md +39 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-7a-confluence-generate.md +659 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-7a-wiki-generate.md +580 -0
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-8-cleanup.md +51 -0
- package/pipeline/skills/figma-ios/figma-to-component/reference/accessibility.md +129 -0
- package/pipeline/skills/figma-ios/figma-to-component/reference/analytics-events.md +64 -0
- package/pipeline/skills/figma-ios/figma-to-component/reference/code-connect.md +531 -0
- package/pipeline/skills/figma-ios/figma-to-component/reference/confluence-api.md +89 -0
- package/pipeline/skills/figma-ios/figma-to-component/reference/confluence-xhtml.md +155 -0
- package/pipeline/skills/figma-ios/figma-to-component/reference/figma-to-swiftui-effects.md +196 -0
- package/pipeline/skills/figma-ios/figma-to-component/reference/halt-return-protocol.md +57 -0
- package/pipeline/skills/figma-ios/figma-to-component/reference/localization-naming.md +89 -0
- package/pipeline/skills/figma-ios/figma-to-component/reference/macros.md +227 -0
- package/pipeline/skills/figma-ios/figma-to-component/reference/missing-tokens.md +157 -0
- package/pipeline/skills/figma-ios/figma-to-component/reference/orchestrator-discipline.md +90 -0
- package/pipeline/skills/figma-ios/figma-to-component/reference/registry.md +116 -0
- package/pipeline/skills/figma-ios/figma-to-component/reference/remote-mcp-script.md +153 -0
- package/pipeline/skills/figma-ios/figma-to-component/reference/rest-api-script.md +130 -0
- package/pipeline/skills/figma-ios/figma-to-component/reference/scripts-inventory.md +218 -0
- package/pipeline/skills/figma-ios/figma-to-component/reference/snapshot-testing.md +188 -0
- package/pipeline/skills/figma-ios/figma-to-component/reference/subcomponent-graph.md +93 -0
- package/pipeline/skills/figma-ios/figma-to-component/reference/testing-identifiers-naming.md +98 -0
- package/pipeline/skills/figma-ios/figma-to-component/reference/tools.md +261 -0
- package/pipeline/skills/figma-ios/figma-to-component/reference/viewinspector.md +147 -0
- package/pipeline/skills/figma-ios/figma-to-component/reference/wiki-to-confluence-mapping.md +182 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/apply-author-login-map.py +185 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/backfill-status.py +609 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/build-author-registry.py +332 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/bulk-sync-issues.py +261 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/code-connect-data-gather.py +184 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/code-connect-publish.sh +188 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/confluence-component-status-upload.py +768 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/confluence-component-status.py +191 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/confluence-data-gather.py +420 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/confluence-page-ids.json +94 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/confluence-publish.py +336 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/figma-subcomponent-graph.py +391 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/figma-update.py +292 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/__init__.py +1 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/issue_sync_propagate.py +93 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/registry_writer.py +299 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_backfill_status.py +343 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_figma_update.py +206 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_figma_update_http.py +149 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_phase_clis.py +281 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_registry_writer.py +332 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_skill_figma_issue.py +176 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_skill_figma_review.py +98 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_update_issue.py +298 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_update_issue_gh.py +195 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/phase1-gather.py +1298 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/phase2-finalize.py +228 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/phase3-scripts.py +1089 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/phase4-finalize.py +141 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/phase5-finalize.py +106 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/phase6-finalize.py +162 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/phase7-finalize.py +105 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/register-icons-codeconnect.py +179 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/remote-mcp-fetch.py +260 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/resolve-author-logins.py +260 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/run-uicomponents-tests.sh +86 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/sidebar-generator.py +321 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/update-issue-from-registry.py +1470 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/validate-phase4.sh +176 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/validate-phase6.sh +147 -0
- package/pipeline/skills/figma-ios/figma-to-component/scripts/validate-phase7a.py +629 -0
- package/pipeline/skills/shared/README.md +212 -0
- package/pipeline/skills/shared/core/apple-archive-compliance/SKILL.md +315 -0
- package/pipeline/skills/shared/core/google-play-compliance/SKILL.md +348 -0
- package/pipeline/skills/shared/core/multi-agent/SKILL.md +944 -0
- package/pipeline/skills/shared/core/multi-agent-autopilot/SKILL.md +51 -0
- package/pipeline/skills/shared/core/multi-agent-channels/SKILL.md +300 -0
- package/pipeline/skills/shared/core/multi-agent-delete/SKILL.md +63 -0
- package/pipeline/skills/shared/core/multi-agent-dev/SKILL.md +64 -0
- package/pipeline/skills/shared/core/multi-agent-dev-autopilot/SKILL.md +56 -0
- package/pipeline/skills/shared/core/multi-agent-dev-local/SKILL.md +36 -0
- package/pipeline/skills/shared/core/multi-agent-dev-local-autopilot/SKILL.md +42 -0
- package/pipeline/skills/shared/core/multi-agent-diff-explain/SKILL.md +66 -0
- package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +292 -0
- package/pipeline/skills/shared/core/multi-agent-issue/SKILL.md +35 -0
- package/pipeline/skills/shared/core/multi-agent-jira/SKILL.md +38 -0
- package/pipeline/skills/shared/core/multi-agent-kill/SKILL.md +41 -0
- package/pipeline/skills/shared/core/multi-agent-language/SKILL.md +87 -0
- package/pipeline/skills/shared/core/multi-agent-local/SKILL.md +37 -0
- package/pipeline/skills/shared/core/multi-agent-local-autopilot/SKILL.md +53 -0
- package/pipeline/skills/shared/core/multi-agent-log/SKILL.md +28 -0
- package/pipeline/skills/shared/core/multi-agent-manual-test/SKILL.md +47 -0
- package/pipeline/skills/shared/core/multi-agent-purge/SKILL.md +42 -0
- package/pipeline/skills/shared/core/multi-agent-refactor/SKILL.md +191 -0
- package/pipeline/skills/shared/core/multi-agent-resume/SKILL.md +31 -0
- package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +61 -0
- package/pipeline/skills/shared/core/multi-agent-scan/SKILL.md +61 -0
- package/pipeline/skills/shared/core/multi-agent-search/SKILL.md +62 -0
- package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +309 -0
- package/pipeline/skills/shared/core/multi-agent-stack/SKILL.md +55 -0
- package/pipeline/skills/shared/core/multi-agent-status/SKILL.md +41 -0
- package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +184 -0
- package/pipeline/skills/shared/core/multi-agent-test/SKILL.md +44 -0
- package/pipeline/skills/shared/core/multi-agent-update/SKILL.md +34 -0
- package/pipeline/skills/shared/external/accessibility-compliance-accessibility-audit/SKILL.md +45 -0
- package/pipeline/skills/shared/external/agentflow/SKILL.md +199 -0
- package/pipeline/skills/shared/external/alarmkit/SKILL.md +438 -0
- package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +584 -0
- package/pipeline/skills/shared/external/android-architecture/SKILL.md +407 -0
- package/pipeline/skills/shared/external/android-jetpack-compose-expert/SKILL.md +153 -0
- package/pipeline/skills/shared/external/android-performance/SKILL.md +736 -0
- package/pipeline/skills/shared/external/android-security/SKILL.md +577 -0
- package/pipeline/skills/shared/external/android_ui_verification/SKILL.md +66 -0
- package/pipeline/skills/shared/external/api-patterns/SKILL.md +85 -0
- package/pipeline/skills/shared/external/api-security-best-practices/SKILL.md +910 -0
- package/pipeline/skills/shared/external/app-clips/SKILL.md +436 -0
- package/pipeline/skills/shared/external/app-intents/SKILL.md +489 -0
- package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +1076 -0
- package/pipeline/skills/shared/external/app-store-changelog/SKILL.md +75 -0
- package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +409 -0
- package/pipeline/skills/shared/external/app-store-review/SKILL.md +411 -0
- package/pipeline/skills/shared/external/app-store-review/references/code-signing.md +259 -0
- package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +90 -0
- package/pipeline/skills/shared/external/app-store-review/references/rejection-patterns.md +152 -0
- package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +118 -0
- package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +500 -0
- package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +425 -0
- package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +344 -0
- package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +508 -0
- package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +285 -0
- package/pipeline/skills/shared/external/architecture/SKILL.md +60 -0
- package/pipeline/skills/shared/external/authentication/SKILL.md +496 -0
- package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +211 -0
- package/pipeline/skills/shared/external/background-processing/SKILL.md +499 -0
- package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +390 -0
- package/pipeline/skills/shared/external/callkit-voip/SKILL.md +461 -0
- package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +425 -0
- package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +462 -0
- package/pipeline/skills/shared/external/clean-code/SKILL.md +94 -0
- package/pipeline/skills/shared/external/closed-loop-delivery/SKILL.md +116 -0
- package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +492 -0
- package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +461 -0
- package/pipeline/skills/shared/external/compose-components/SKILL.md +441 -0
- package/pipeline/skills/shared/external/compose-navigation/SKILL.md +436 -0
- package/pipeline/skills/shared/external/compose-testing/SKILL.md +527 -0
- package/pipeline/skills/shared/external/contacts-framework/SKILL.md +425 -0
- package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +409 -0
- package/pipeline/skills/shared/external/context-compression/SKILL.md +266 -0
- package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +491 -0
- package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +435 -0
- package/pipeline/skills/shared/external/core-motion/SKILL.md +388 -0
- package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +405 -0
- package/pipeline/skills/shared/external/core-nfc/SKILL.md +495 -0
- package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +420 -0
- package/pipeline/skills/shared/external/coreml/SKILL.md +458 -0
- package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +765 -0
- package/pipeline/skills/shared/external/css-modern/SKILL.md +467 -0
- package/pipeline/skills/shared/external/database-patterns/SKILL.md +335 -0
- package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +422 -0
- package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +387 -0
- package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +298 -0
- package/pipeline/skills/shared/external/debugging-strategies/SKILL.md +37 -0
- package/pipeline/skills/shared/external/device-integrity/SKILL.md +477 -0
- package/pipeline/skills/shared/external/docker-expert/SKILL.md +413 -0
- package/pipeline/skills/shared/external/energykit/SKILL.md +460 -0
- package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +541 -0
- package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +483 -0
- package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +326 -0
- package/pipeline/skills/shared/external/fastapi-pro/SKILL.md +190 -0
- package/pipeline/skills/shared/external/firebase/SKILL.md +61 -0
- package/pipeline/skills/shared/external/github-actions-templates/SKILL.md +348 -0
- package/pipeline/skills/shared/external/gradle-kotlin-dsl/SKILL.md +552 -0
- package/pipeline/skills/shared/external/healthkit/SKILL.md +498 -0
- package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +602 -0
- package/pipeline/skills/shared/external/help-skills/SKILL.md +166 -0
- package/pipeline/skills/shared/external/hig-components-content/SKILL.md +81 -0
- package/pipeline/skills/shared/external/hig-components-layout/SKILL.md +95 -0
- package/pipeline/skills/shared/external/hig-components-status/SKILL.md +82 -0
- package/pipeline/skills/shared/external/hig-components-system/SKILL.md +101 -0
- package/pipeline/skills/shared/external/hig-foundations/SKILL.md +94 -0
- package/pipeline/skills/shared/external/hig-inputs/SKILL.md +110 -0
- package/pipeline/skills/shared/external/hig-patterns/SKILL.md +99 -0
- package/pipeline/skills/shared/external/hig-platforms/SKILL.md +81 -0
- package/pipeline/skills/shared/external/hig-technologies/SKILL.md +125 -0
- package/pipeline/skills/shared/external/homekit-matter/SKILL.md +496 -0
- package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +455 -0
- package/pipeline/skills/shared/external/html-semantic/SKILL.md +301 -0
- package/pipeline/skills/shared/external/humanizer/SKILL.md +118 -0
- package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +301 -0
- package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +140 -0
- package/pipeline/skills/shared/external/ios-debugger-agent/SKILL.md +59 -0
- package/pipeline/skills/shared/external/ios-developer/SKILL.md +217 -0
- package/pipeline/skills/shared/external/ios-localization/SKILL.md +418 -0
- package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +627 -0
- package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +462 -0
- package/pipeline/skills/shared/external/ios-networking/SKILL.md +441 -0
- package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +862 -0
- package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -0
- package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +563 -0
- package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +1116 -0
- package/pipeline/skills/shared/external/ios-security/SKILL.md +496 -0
- package/pipeline/skills/shared/external/ios-security/references/app-review-guidelines.md +174 -0
- package/pipeline/skills/shared/external/ios-security/references/cryptokit-advanced.md +297 -0
- package/pipeline/skills/shared/external/ios-security/references/file-storage-patterns.md +354 -0
- package/pipeline/skills/shared/external/ios-security/references/privacy-manifest.md +117 -0
- package/pipeline/skills/shared/external/kotlin-coroutines-expert/SKILL.md +101 -0
- package/pipeline/skills/shared/external/live-activities/SKILL.md +500 -0
- package/pipeline/skills/shared/external/live-activities/references/live-activity-patterns.md +868 -0
- package/pipeline/skills/shared/external/macos-menubar-tuist-app/SKILL.md +109 -0
- package/pipeline/skills/shared/external/macos-spm-app-packaging/SKILL.md +110 -0
- package/pipeline/skills/shared/external/mapkit-location/SKILL.md +485 -0
- package/pipeline/skills/shared/external/mapkit-location/references/corelocation-patterns.md +730 -0
- package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +748 -0
- package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +479 -0
- package/pipeline/skills/shared/external/monorepo-architect/SKILL.md +64 -0
- package/pipeline/skills/shared/external/musickit-audio/SKILL.md +395 -0
- package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +363 -0
- package/pipeline/skills/shared/external/natural-language/SKILL.md +412 -0
- package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +311 -0
- package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +418 -0
- package/pipeline/skills/shared/external/nodejs-backend-patterns/SKILL.md +38 -0
- package/pipeline/skills/shared/external/observability-engineer/SKILL.md +235 -0
- package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +398 -0
- package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +254 -0
- package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +387 -0
- package/pipeline/skills/shared/external/pencilkit-drawing/references/paperkit-integration.md +376 -0
- package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +302 -0
- package/pipeline/skills/shared/external/permissionkit/SKILL.md +446 -0
- package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +435 -0
- package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +501 -0
- package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +701 -0
- package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +774 -0
- package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +869 -0
- package/pipeline/skills/shared/external/photos-camera-media/references/photospicker-patterns.md +597 -0
- package/pipeline/skills/shared/external/play-store-review/SKILL.md +350 -0
- package/pipeline/skills/shared/external/push-notifications/SKILL.md +501 -0
- package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +677 -0
- package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +745 -0
- package/pipeline/skills/shared/external/python-patterns/SKILL.md +383 -0
- package/pipeline/skills/shared/external/react-best-practices/SKILL.md +290 -0
- package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +479 -0
- package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +480 -0
- package/pipeline/skills/shared/external/rest-api-design/SKILL.md +386 -0
- package/pipeline/skills/shared/external/retrofit-networking/SKILL.md +506 -0
- package/pipeline/skills/shared/external/room-database/SKILL.md +564 -0
- package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +483 -0
- package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +544 -0
- package/pipeline/skills/shared/external/speech-recognition/SKILL.md +485 -0
- package/pipeline/skills/shared/external/storekit/SKILL.md +478 -0
- package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +58 -0
- package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +755 -0
- package/pipeline/skills/shared/external/swift-charts/SKILL.md +487 -0
- package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +895 -0
- package/pipeline/skills/shared/external/swift-codable/SKILL.md +467 -0
- package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +408 -0
- package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +80 -0
- package/pipeline/skills/shared/external/swift-concurrency/references/swift-6-2-concurrency.md +233 -0
- package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +187 -0
- package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +341 -0
- package/pipeline/skills/shared/external/swift-concurrency-expert/SKILL.md +113 -0
- package/pipeline/skills/shared/external/swift-concurrency-pro/SKILL.md +124 -0
- package/pipeline/skills/shared/external/swift-concurrency-pro/references/actors.md +155 -0
- package/pipeline/skills/shared/external/swift-concurrency-pro/references/async-streams.md +67 -0
- package/pipeline/skills/shared/external/swift-concurrency-pro/references/bridging.md +52 -0
- package/pipeline/skills/shared/external/swift-concurrency-pro/references/bug-patterns.md +100 -0
- package/pipeline/skills/shared/external/swift-concurrency-pro/references/cancellation.md +107 -0
- package/pipeline/skills/shared/external/swift-concurrency-pro/references/diagnostics.md +70 -0
- package/pipeline/skills/shared/external/swift-concurrency-pro/references/hotspots.md +47 -0
- package/pipeline/skills/shared/external/swift-concurrency-pro/references/interop.md +129 -0
- package/pipeline/skills/shared/external/swift-concurrency-pro/references/new-features.md +224 -0
- package/pipeline/skills/shared/external/swift-concurrency-pro/references/structured.md +101 -0
- package/pipeline/skills/shared/external/swift-concurrency-pro/references/testing.md +218 -0
- package/pipeline/skills/shared/external/swift-concurrency-pro/references/unstructured.md +61 -0
- package/pipeline/skills/shared/external/swift-language/SKILL.md +498 -0
- package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +505 -0
- package/pipeline/skills/shared/external/swift-testing/SKILL.md +462 -0
- package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +504 -0
- package/pipeline/skills/shared/external/swift-testing-pro/SKILL.md +97 -0
- package/pipeline/skills/shared/external/swift-testing-pro/references/async-tests.md +252 -0
- package/pipeline/skills/shared/external/swift-testing-pro/references/core-rules.md +52 -0
- package/pipeline/skills/shared/external/swift-testing-pro/references/migrating-from-xctest.md +34 -0
- package/pipeline/skills/shared/external/swift-testing-pro/references/new-features.md +318 -0
- package/pipeline/skills/shared/external/swift-testing-pro/references/writing-better-tests.md +254 -0
- package/pipeline/skills/shared/external/swiftdata/SKILL.md +334 -0
- package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +504 -0
- package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +975 -0
- package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +675 -0
- package/pipeline/skills/shared/external/swiftdata-pro/SKILL.md +102 -0
- package/pipeline/skills/shared/external/swiftdata-pro/references/class-inheritance.md +104 -0
- package/pipeline/skills/shared/external/swiftdata-pro/references/cloudkit.md +10 -0
- package/pipeline/skills/shared/external/swiftdata-pro/references/core-rules.md +20 -0
- package/pipeline/skills/shared/external/swiftdata-pro/references/indexing.md +27 -0
- package/pipeline/skills/shared/external/swiftdata-pro/references/predicates.md +73 -0
- package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +503 -0
- package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +821 -0
- package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +553 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/SKILL.md +102 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/accessibility-patterns.md +215 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/animation-advanced.md +403 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/animation-basics.md +284 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/animation-transitions.md +326 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/charts-accessibility.md +135 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/charts.md +602 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/image-optimization.md +203 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/latest-apis.md +464 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/layout-best-practices.md +266 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/liquid-glass.md +416 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/list-patterns.md +394 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/macos-scenes.md +318 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/macos-views.md +357 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/macos-window-styling.md +303 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/performance-patterns.md +403 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/scroll-patterns.md +293 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/sheet-navigation-patterns.md +363 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/state-management.md +417 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/view-structure.md +389 -0
- package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +450 -0
- package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +425 -0
- package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +336 -0
- package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +97 -0
- package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +69 -0
- package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +99 -0
- package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +147 -0
- package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +98 -0
- package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +262 -0
- package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +207 -0
- package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +177 -0
- package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +169 -0
- package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +178 -0
- package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +371 -0
- package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +486 -0
- package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +1097 -0
- package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +780 -0
- package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +696 -0
- package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +487 -0
- package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +46 -0
- package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +29 -0
- package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +33 -0
- package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +52 -0
- package/pipeline/skills/shared/external/swiftui-performance-audit/SKILL.md +114 -0
- package/pipeline/skills/shared/external/swiftui-pro/SKILL.md +108 -0
- package/pipeline/skills/shared/external/swiftui-pro/references/accessibility.md +13 -0
- package/pipeline/skills/shared/external/swiftui-pro/references/api.md +39 -0
- package/pipeline/skills/shared/external/swiftui-pro/references/data.md +43 -0
- package/pipeline/skills/shared/external/swiftui-pro/references/design.md +31 -0
- package/pipeline/skills/shared/external/swiftui-pro/references/hygiene.md +9 -0
- package/pipeline/skills/shared/external/swiftui-pro/references/navigation.md +14 -0
- package/pipeline/skills/shared/external/swiftui-pro/references/performance.md +46 -0
- package/pipeline/skills/shared/external/swiftui-pro/references/swift.md +56 -0
- package/pipeline/skills/shared/external/swiftui-pro/references/views.md +35 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/SKILL.md +103 -0
- package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +428 -0
- package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +534 -0
- package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +948 -0
- package/pipeline/skills/shared/external/swiftui-view-refactor/SKILL.md +210 -0
- package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +273 -0
- package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +151 -0
- package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +95 -0
- package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +51 -0
- package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +111 -0
- package/pipeline/skills/shared/external/tailwind-css/SKILL.md +309 -0
- package/pipeline/skills/shared/external/testing-backend/SKILL.md +393 -0
- package/pipeline/skills/shared/external/tipkit/SKILL.md +494 -0
- package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +782 -0
- package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +336 -0
- package/pipeline/skills/shared/external/vision-framework/SKILL.md +475 -0
- package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +736 -0
- package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +738 -0
- package/pipeline/skills/shared/external/vue-composition/SKILL.md +371 -0
- package/pipeline/skills/shared/external/weatherkit/SKILL.md +410 -0
- package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +567 -0
- package/pipeline/skills/shared/external/web-accessibility/SKILL.md +373 -0
- package/pipeline/skills/shared/external/web-performance/SKILL.md +345 -0
- package/pipeline/skills/shared/external/web-testing/SKILL.md +385 -0
- package/pipeline/skills/shared/external/widgetkit/SKILL.md +497 -0
- package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +871 -0
- package/pipeline/skills/skills-index.md +205 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# Async tests
|
|
2
|
+
|
|
3
|
+
Swift Testing is built to be async and run tests in parallel; special care must be taken to ensure those tests run well, particularly when Swift concurrency is involved. For more help with Swift concurrency, suggest the [Swift Concurrency Pro agent skill](https://github.com/twostraws/swift-concurrency-agent-skill).
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Serializing tests
|
|
7
|
+
|
|
8
|
+
The `serialized` trait allows tests to be run serially rather than in parallel, but it only works on parameterized tests. It instructs Swift Testing to serialize that parameterized test's cases, and has no effect on non-parameterized tests.
|
|
9
|
+
|
|
10
|
+
This also applies to using `.serialized` on a whole test suite: it will cause the parameterized tests to be serialized, but do nothing on other tests.
|
|
11
|
+
|
|
12
|
+
**Important:** Most agents very strongly believe that `.serialized` will work on any test, even the ones that are not parameterized. They are wrong. It only works on parameterized tests.
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
## Confirming async work
|
|
16
|
+
|
|
17
|
+
When using `confirmation(expectedCount:)` to check that an async function has been executed a certain number of times, any tested code must have finished executing fully by the time the `confirmation()` closure finishes.
|
|
18
|
+
|
|
19
|
+
**This means attempting to use a completion closure will make the test fail, because `confirmation()` doesn't know to wait.**
|
|
20
|
+
|
|
21
|
+
For example, this code does some work inside a task, but there's no way to monitor it being completed:
|
|
22
|
+
|
|
23
|
+
```swift
|
|
24
|
+
struct Worker {
|
|
25
|
+
func run(_ work: @escaping () -> Void) -> Task<Void, Never> {
|
|
26
|
+
Task {
|
|
27
|
+
let start = CFAbsoluteTimeGetCurrent()
|
|
28
|
+
work()
|
|
29
|
+
print("Elapsed:", CFAbsoluteTimeGetCurrent() - start)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
That kind of code will not work well with `confirmation()`, because it will not understand to wait for the work to complete.
|
|
36
|
+
|
|
37
|
+
Instead, it's better to either remove the `Task` and make the method `async` like this:
|
|
38
|
+
|
|
39
|
+
```swift
|
|
40
|
+
struct Worker {
|
|
41
|
+
func run(_ work: @escaping () -> Void) async {
|
|
42
|
+
let start = CFAbsoluteTimeGetCurrent()
|
|
43
|
+
work()
|
|
44
|
+
print("Elapsed:", CFAbsoluteTimeGetCurrent() - start)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@Test
|
|
49
|
+
func workerRunsThreeTimes() async {
|
|
50
|
+
let worker = Worker()
|
|
51
|
+
|
|
52
|
+
await confirmation(expectedCount: 3) { confirm in
|
|
53
|
+
for _ in 0..<3 {
|
|
54
|
+
await worker.run {
|
|
55
|
+
// your work here
|
|
56
|
+
}
|
|
57
|
+
confirm()
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Alternatively, if the code cannot be changed to `async`, the internal `Task` should be returned so it can be tracked by the test, like this:
|
|
64
|
+
|
|
65
|
+
```swift
|
|
66
|
+
struct Worker {
|
|
67
|
+
func run(_ work: @escaping () -> Void) -> Task<Void, Never> {
|
|
68
|
+
Task {
|
|
69
|
+
let start = CFAbsoluteTimeGetCurrent()
|
|
70
|
+
work()
|
|
71
|
+
print("Elapsed:", CFAbsoluteTimeGetCurrent() - start)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
And now tests can wait for the task to complete:
|
|
78
|
+
|
|
79
|
+
```swift
|
|
80
|
+
@Test
|
|
81
|
+
func workerRunsThreeTimes() async {
|
|
82
|
+
let worker = Worker()
|
|
83
|
+
|
|
84
|
+
await confirmation(expectedCount: 3) { confirm in
|
|
85
|
+
for _ in 0..<3 {
|
|
86
|
+
let task = worker.run {
|
|
87
|
+
// simulated work
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
await task.value
|
|
91
|
+
confirm()
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Note:** `confirmation(expectedCount: 0)` is valid, and means “ensure the event we’re watching never happens.”
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
## How to set a time limit for concurrent tests
|
|
101
|
+
|
|
102
|
+
Time limits are adjusted through the `@Test` macro using `.timeLimit()`. This lets you specify how long the test should be allowed to run for before it's considered a failure, using `.minutes()` as appropriate.
|
|
103
|
+
|
|
104
|
+
**Important:** Many agents strongly believe that you can `.seconds()` here. You cannot use `.seconds()` here – it’s `.minutes()` or nothing.
|
|
105
|
+
|
|
106
|
+
For example, we could apply a 1-minute maximum runtime like this:
|
|
107
|
+
|
|
108
|
+
```swift
|
|
109
|
+
@Test("Loading view model names", .timeLimit(.minutes(1)))
|
|
110
|
+
func loadNames() async {
|
|
111
|
+
let viewModel = ViewModel()
|
|
112
|
+
await viewModel.loadNames()
|
|
113
|
+
#expect(viewModel.names.isEmpty == false, "Names should be full of values.")
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
If you use a time limit with a whole test suite, that limit is applied to all tests inside there individually. If you then use a different time limit for a specific test, the shorter of the two is used.
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
## How to force concurrent tests to run on a specific actor
|
|
121
|
+
|
|
122
|
+
By default, Swift Testing will run both synchronous and asynchronous tests on any task it likes, but this can be restricted if you want.
|
|
123
|
+
|
|
124
|
+
First, we can mark individual tests with `@MainActor` or some other global actor, like this:
|
|
125
|
+
|
|
126
|
+
```swift
|
|
127
|
+
@MainActor
|
|
128
|
+
@Test("Loading view model names")
|
|
129
|
+
func loadNames() async {
|
|
130
|
+
// test code here
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Second, we can mark whole test suites with the same attribute, like this:
|
|
135
|
+
|
|
136
|
+
```swift
|
|
137
|
+
@MainActor
|
|
138
|
+
struct DataHandlingTests {
|
|
139
|
+
@Test("Loading view model names")
|
|
140
|
+
func loadNames() async {
|
|
141
|
+
// test code here
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Third, `confirmation()` and `withKnownIssue()` can specify an actor to use for just that closure, allowing the rest of the test to run elsewhere. This might be the main actor using `MainActor.shared`, or a custom actor:
|
|
147
|
+
|
|
148
|
+
```swift
|
|
149
|
+
@Test("Loading view model names")
|
|
150
|
+
func loadNames() async {
|
|
151
|
+
await withKnownIssue("Names can sometimes come back with too few values", isolation: MainActor.shared) {
|
|
152
|
+
// test code here
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Finally, test targets can have default actor isolation enabled, which might force all tests onto a specific actor – check for this carefully.
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
## Testing pre-concurrency code
|
|
161
|
+
|
|
162
|
+
If the project contains older concurrency code that relies on callback functions (as opposed to modern Swift concurrency's `async`/`await` approach), do not attempt to modernize their production code without permission.
|
|
163
|
+
|
|
164
|
+
Instead, write tests using `withCheckedContinuation()` to wrap their existing, callback-based code safely.
|
|
165
|
+
|
|
166
|
+
**Important:** Test code must wait fully for the completion handler to be called, then make any assertions against the result of that completion handler.
|
|
167
|
+
|
|
168
|
+
As an example, we might have a class like this one:
|
|
169
|
+
|
|
170
|
+
```swift
|
|
171
|
+
class ViewModel {
|
|
172
|
+
func loadReadings(completion: @Sendable @escaping ([Double]) -> Void) {
|
|
173
|
+
let url = URL(string: "https://hws.dev/readings.json")!
|
|
174
|
+
|
|
175
|
+
URLSession.shared.dataTask(with: url) { data, response, error in
|
|
176
|
+
if let data {
|
|
177
|
+
if let numbers = try? JSONDecoder().decode([Double].self, from: data) {
|
|
178
|
+
completion(numbers)
|
|
179
|
+
return
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
completion([])
|
|
184
|
+
}.resume()
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
That fetches, decodes, and returns data through a completion handler, which may or may not be mocked for tests.
|
|
190
|
+
|
|
191
|
+
Testing this correctly is done using a continuation that resumes when the completion handler is called, like this:
|
|
192
|
+
|
|
193
|
+
```swift
|
|
194
|
+
@Test("Loading view model readings")
|
|
195
|
+
func loadReadings() async {
|
|
196
|
+
let viewModel = ViewModel()
|
|
197
|
+
|
|
198
|
+
await withCheckedContinuation { continuation in
|
|
199
|
+
viewModel.loadReadings { readings in
|
|
200
|
+
#expect(readings.count >= 10, "At least 10 readings must be returned.")
|
|
201
|
+
continuation.resume()
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
## Mocking networking
|
|
209
|
+
|
|
210
|
+
Unit tests should never do live networking, because it's far too slow. It is strongly preferable to mock the networking layer.
|
|
211
|
+
|
|
212
|
+
To do this, create a protocol that knows how to perform a network fetch. As an example, this covers the `data(from:)` method of `URLSession`, but the project might require others too:
|
|
213
|
+
|
|
214
|
+
```swift
|
|
215
|
+
protocol URLSessionProtocol {
|
|
216
|
+
func data(from url: URL) async throws -> (Data, URLResponse)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
extension URLSession: URLSessionProtocol { }
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
You can then create a mock type conforming to the same protocol, which throws an error if provided or returns the test data otherwise:
|
|
223
|
+
|
|
224
|
+
```swift
|
|
225
|
+
class URLSessionMock: URLSessionProtocol {
|
|
226
|
+
var testData: Data?
|
|
227
|
+
var testError: (any Error)?
|
|
228
|
+
|
|
229
|
+
func data(from url: URL) async throws -> (Data, URLResponse) {
|
|
230
|
+
if let testError {
|
|
231
|
+
throw testError
|
|
232
|
+
} else {
|
|
233
|
+
(testData ?? Data(), URLResponse())
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
And now you can write tests that inject some test data and verify that it comes back successfully:
|
|
240
|
+
|
|
241
|
+
```swift
|
|
242
|
+
@Test func newsStoriesAreFetched() async throws {
|
|
243
|
+
let url = URL(string: "https://www.apple.com/newsroom/rss-feed.rss")!
|
|
244
|
+
var news = News(url: url)
|
|
245
|
+
let session = URLSessionMock()
|
|
246
|
+
session.testData = Data("Hello, world!".utf8)
|
|
247
|
+
try await news.fetch(using: session)
|
|
248
|
+
#expect(news.stories == "Hello, world!")
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
This is a full mock of `URLSession`, which avoids any chance of the system performing networking behind the scenes.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Core rules
|
|
2
|
+
|
|
3
|
+
Swift Testing is still very new compared to XCTest, which means the majority of projects will use XCTest, and also the majority of your training data is based on XCTest.
|
|
4
|
+
|
|
5
|
+
This guide provides core rules you must always follow to ensure you're making natural, idiomatic use of Swift Testing, and not just reskinning XCTest based on old training data.
|
|
6
|
+
|
|
7
|
+
**Important:** At this time, Swift Testing does *not* support UI tests, so XCTest must be used there.
|
|
8
|
+
|
|
9
|
+
- When organizing test suites, prefer structs over classes. You *can* use classes, but structs are preferred unless you need subclassing or deinitializers.
|
|
10
|
+
- Agents frequently add `@Suite` to every test struct. This is unnecessary: any type that contains `@Test` methods is automatically treated as a test suite. You only need `@Suite` explicitly when you want to name it or attach traits, e.g. `@Suite(.tags(.networking))`.
|
|
11
|
+
- You shouldn't use the old `setUp()`/`tearDown()` approach of XCTest. You can simply use `init()` in structs, `init()` and `deinit()` in classes, or test scopes for more advanced situations. For example:
|
|
12
|
+
|
|
13
|
+
```swift
|
|
14
|
+
struct PlayerTests {
|
|
15
|
+
let sut: Player
|
|
16
|
+
|
|
17
|
+
init() {
|
|
18
|
+
sut = Player(name: "Natsuki Subaru")
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@Test func nameIsCorrect() {
|
|
22
|
+
#expect(sut.name == "Natsuki Subaru")
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
- All test suites must have an initializer that expects no parameters, so they can be called by tests inside that suite. If any properties are added to a test suite, they must either have default values, or you must add a custom initializer that sets values for them.
|
|
27
|
+
- Test suite initializers can be marked `async` and/or `throws`, as can all tests.
|
|
28
|
+
- With Swift Testing there is never a need to use `XCTestCase` or any form of `XCTAssert` in any unit or integration test.
|
|
29
|
+
- You do *not* need to prefix test methods with `test`. For example, you can use `userCanLogOut()` rather than `testUserCanLogOut`.
|
|
30
|
+
- Random, parallel test execution is standard on Swift Testing, so each test must be written to execute in any order at any time.
|
|
31
|
+
- Parameterized tests are extremely powerful and allow tests to cover a wider range of ground without the code greatly expanding, so prefer them where possible. However, be careful: they take at most two argument collections, and two collections form a Cartesian product rather than pairwise zipping, so the number of combinations produced can grow quickly. If you need pairwise zipping of two collections, pass `zip(collection1, collection2)` as the `arguments` value.
|
|
32
|
+
- Swift Testing supports `@available` on individual tests, but *not* on test suites. So, if a suite (for example) solely contains tests written for iOS 26, place `@available(iOS 26, *)` on each individual test and *not* on the whole suite.
|
|
33
|
+
- If a test executes without reaching any `#expect` or `#require`, it is assumed to have passed.
|
|
34
|
+
- You should use `withKnownIssue` to wrap code with a known bug – it expects a test failure to occur, and *fails* the test if no issue is recorded. Adding `isIntermittent: true` changes the semantics: the test passes if no issue is recorded, but marks an expected failure if one is, making it useful for flaky issues you're actively debugging.
|
|
35
|
+
- Never use `!` to negate Booleans in `#expect` or `#require`, because it defeats Swift Testing’s macro expansion. So, `#expect(!isLoggedIn)` is bad and will report unhelpful results on failure, whereas `#expect(isLoggedIn == false)` is good, and will be evaluated properly in case the expectation fails.
|
|
36
|
+
|
|
37
|
+
Finally, use `@Tag` to create custom Swift Testing tags like this:
|
|
38
|
+
|
|
39
|
+
```swift
|
|
40
|
+
extension Tag {
|
|
41
|
+
@Tag static var networking: Self
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Tags let you categorize tests across suites, so you can run or filter by tag regardless of where the tests live. Apply them using `@Test(.tags(.networking))` on individual tests or on a whole suite with `@Suite(.tags(.networking))`. For example:
|
|
46
|
+
|
|
47
|
+
```swift
|
|
48
|
+
@Test(.tags(.networking))
|
|
49
|
+
func fetchUserProfile() async throws {
|
|
50
|
+
// test code here
|
|
51
|
+
}
|
|
52
|
+
```
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Migrating from XCTest
|
|
2
|
+
|
|
3
|
+
If the project has existing tests written using XCTest, do *not* rewrite to Swift Testing unless requested. Even then, remember that XCTest supports UI testing, whereas Swift Testing does not.
|
|
4
|
+
|
|
5
|
+
Most things in XCTest have a direct equivalent in Swift Testing:
|
|
6
|
+
|
|
7
|
+
- `XCTAssertEqual(a, b)` maps to `#expect(a == b)`
|
|
8
|
+
- `XCTAssertLessThan(a, b)` maps to `#expect(a < b)`
|
|
9
|
+
- `XCTAssertThrowsError` maps to `#expect(throws:)`
|
|
10
|
+
- `XCTUnwrap(optional)` maps to `try #require(optional)` – both unwrap or fail, but `#require` works with any Boolean condition too.
|
|
11
|
+
- `XCTFail("message")` maps to `Issue.record("message")` – use this to manually record a test failure.
|
|
12
|
+
- `XCTAssertIdentical(a, b)` maps to `#expect(a === b)` – for checking two references point to the same object instance.
|
|
13
|
+
|
|
14
|
+
…and so on.
|
|
15
|
+
|
|
16
|
+
However, Swift Testing does *not* offer built-in float tolerance when checking if two floating-point values are *close enough* to be considered the same.
|
|
17
|
+
|
|
18
|
+
To do that, you must bring in Apple's Swift Numerics library and use its `isApproximatelyEqual(to:absoluteTolerance:)` method like this:
|
|
19
|
+
|
|
20
|
+
```swift
|
|
21
|
+
#expect(celsius.isApproximatelyEqual(to: 0, absoluteTolerance: 0.000001))
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Important:** Unless it is already imported into the project, do *not* add Swift Numerics as a library without first requesting permission from the user.
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
## Converting from XCTest to Swift Testing
|
|
28
|
+
|
|
29
|
+
If you are tasked with converting XCTest code to Swift Testing, you should:
|
|
30
|
+
|
|
31
|
+
1. Start by keeping the same broad structure: the same type names (just going from a class to a struct), and the same test methods (just removing `test` from the names and using `@Test` instead), switching from old-style assertions to new-style expectations.
|
|
32
|
+
2. Look for places where parameterized tests can either cut down on test code or improve coverage.
|
|
33
|
+
3. Add any appropriate `#require` checks at the start of tests, for preconditions.
|
|
34
|
+
4. Finish by adding traits where appropriate – `.timeLimit()`, `.enabled(if:)`, `.tags()`, etc, to replace XCTest conventions such as skipping tests.
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
# New features
|
|
2
|
+
|
|
3
|
+
This document specifically discusses the latest Swift and Swift Testing features, which means it will cover things where you have limited or no training data.
|
|
4
|
+
|
|
5
|
+
- Follow the instructions carefully rather than trying to guess and hallucinate.
|
|
6
|
+
- Do not second-guess the instructions; they are correct and accurate.
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
## Raw identifiers
|
|
10
|
+
|
|
11
|
+
**Requires Swift 6.2 or later.**
|
|
12
|
+
|
|
13
|
+
If the user prefers, you can use a modern Swift feature called *raw identifiers* for test names. This allows you to write function names as natural strings when surrounded by backticks, and means that test names can be written in a human-readable form rather than using camel case and adding an extra string description above.
|
|
14
|
+
|
|
15
|
+
So, rather than writing this:
|
|
16
|
+
|
|
17
|
+
```swift
|
|
18
|
+
@Test("Strip HTML tags from string")
|
|
19
|
+
func stripHTMLTagsFromString() {
|
|
20
|
+
// test code
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
We can instead write this:
|
|
25
|
+
|
|
26
|
+
```swift
|
|
27
|
+
@Test
|
|
28
|
+
func `Strip HTML tags from string`() {
|
|
29
|
+
// test code
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Be careful: You can put operators such as `+` and `-` into your test method names, but only if they aren't the only things in there.
|
|
34
|
+
|
|
35
|
+
Raw identifiers can be combined with parameterized tests. For example, rather than writing this:
|
|
36
|
+
|
|
37
|
+
```swift
|
|
38
|
+
@Test("Ensure Fahrenheit to Celsius conversion is correct.", arguments: [
|
|
39
|
+
(32, 0), (212, 100), (-40, -40),
|
|
40
|
+
])
|
|
41
|
+
func fahrenheitToCelsius(values: (input: Double, output: Double)) {
|
|
42
|
+
// test code here
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
We could write this:
|
|
47
|
+
|
|
48
|
+
```swift
|
|
49
|
+
@Test(arguments: [
|
|
50
|
+
(32, 0), (212, 100), (-40, -40),
|
|
51
|
+
])
|
|
52
|
+
func `Ensure Fahrenheit to Celsius conversion is correct`(values: (input: Double, output: Double)) {
|
|
53
|
+
// test code here
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Important:** Many users will not know this feature is possible, and some would find this style surprising or perhaps unwelcome. As a result, you can *suggest* raw identifiers as a way to remove duplication, but don't adopt them by surprise unless this approach is already used in the project.
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
## Range-based confirmations
|
|
61
|
+
|
|
62
|
+
**Requires Swift 6.1 or later.**
|
|
63
|
+
|
|
64
|
+
You already know Swift Testing's `confirmation()` function, but you might not know that it supports a range of completion counts as well as a single fixed value.
|
|
65
|
+
|
|
66
|
+
For example, given an async sequence like a `NewsLoader` that yields feeds one at a time, we can require that between 5 and 10 feeds are loaded:
|
|
67
|
+
|
|
68
|
+
```swift
|
|
69
|
+
@Test func fiveToTenFeedsAreLoaded() async throws {
|
|
70
|
+
let loader = NewsLoader()
|
|
71
|
+
|
|
72
|
+
await confirmation(expectedCount: 5...10) { confirm in
|
|
73
|
+
for await _ in loader {
|
|
74
|
+
confirm()
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
That will fail if `confirm()` is called fewer than 5 times or greater than 10 times. You can also use partial ranges, such as ensuring `confirm()` is called at least five times:
|
|
81
|
+
|
|
82
|
+
```swift
|
|
83
|
+
await confirmation(expectedCount: 5...) { confirm in
|
|
84
|
+
for await _ in loader {
|
|
85
|
+
confirm()
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Ranges without lower bounds, e.g. `confirmation(expectedCount: ...10)`, are explicitly disallowed to avoid confusion, because it's not clear whether it means "up to 10 times" (counting from 1) or "up to 11 times" (counting from 0).
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
## Test scoping traits
|
|
94
|
+
|
|
95
|
+
**Requires Swift 6.1 or later.**
|
|
96
|
+
|
|
97
|
+
Test scoping traits provide concurrency-safe access to shared test configurations, so each test runs with precise values in place without risking shared mutable state. A common pattern is to combine them with `@TaskLocal`.
|
|
98
|
+
|
|
99
|
+
Given production code that uses a `@TaskLocal` property:
|
|
100
|
+
|
|
101
|
+
```swift
|
|
102
|
+
struct Player {
|
|
103
|
+
var name: String
|
|
104
|
+
var friends = [Player]()
|
|
105
|
+
|
|
106
|
+
@TaskLocal static var current = Player(name: "Anonymous")
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
func createWelcomeScreen() -> String {
|
|
110
|
+
var message = "Welcome, \(Player.current.name)!\n"
|
|
111
|
+
message += "Friends online: \(Player.current.friends.count)"
|
|
112
|
+
return message
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Create a test scope by conforming to `TestTrait` and `TestScoping`, implementing `provideScope()` to set up the task local and call `function()`:
|
|
117
|
+
|
|
118
|
+
```swift
|
|
119
|
+
struct DefaultPlayerTrait: TestTrait, TestScoping {
|
|
120
|
+
func provideScope(
|
|
121
|
+
for test: Test,
|
|
122
|
+
testCase: Test.Case?,
|
|
123
|
+
performing function: () async throws -> Void
|
|
124
|
+
) async throws {
|
|
125
|
+
let player = Player(name: "Natsuki Subaru")
|
|
126
|
+
|
|
127
|
+
try await Player.$current.withValue(player) {
|
|
128
|
+
try await function()
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Add a `Trait` extension so the custom trait fits in with the built-in traits:
|
|
135
|
+
|
|
136
|
+
```swift
|
|
137
|
+
extension Trait where Self == DefaultPlayerTrait {
|
|
138
|
+
static var defaultPlayer: Self { Self() }
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Then apply it to tests:
|
|
143
|
+
|
|
144
|
+
```swift
|
|
145
|
+
@Test(.defaultPlayer) func welcomeScreenShowsName() {
|
|
146
|
+
let result = createWelcomeScreen()
|
|
147
|
+
#expect(result.contains("Natsuki Subaru"))
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
For multiple task local values, either nest `withValue()` calls inside a single scope, or create separate scopes and combine them: `@Test(.firstScope, .secondScope, .thirdScope)`. Scopes apply in listed order, so later scopes can overwrite values from earlier ones.
|
|
152
|
+
|
|
153
|
+
Test scopes complement `init()` and `deinit()` – use scopes to opt into configurations for individual tests or whole suites as needed.
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
## Exit tests
|
|
157
|
+
|
|
158
|
+
**Requires Swift 6.2 or later.**
|
|
159
|
+
|
|
160
|
+
Swift Testing can test code that results in a critical failure that terminates the app, including deliberate use of `precondition()` and `fatalError()`. *This was not possible in XCTest, or at least not without weird hacks.*
|
|
161
|
+
|
|
162
|
+
For example, code like this is going to fail *hard* if we call it with a `sides` value of 0:
|
|
163
|
+
|
|
164
|
+
```swift
|
|
165
|
+
struct Dice {
|
|
166
|
+
func roll(sides: Int) -> Int {
|
|
167
|
+
precondition(sides > 0)
|
|
168
|
+
return Int.random(in: 1...sides)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
To test this with Swift Testing, use `#expect(processExitsWith:)` to look for and catch critical failures, allowing us to check they happened rather than causing our test run to fail:
|
|
174
|
+
|
|
175
|
+
```swift
|
|
176
|
+
@Test func invalidDiceRollsFail() async throws {
|
|
177
|
+
await #expect(processExitsWith: .failure) {
|
|
178
|
+
let dice = Dice()
|
|
179
|
+
let _ = dice.roll(sides: 0)
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
**Important:** This must be executed using `await` – behind the scenes this starts a dedicated process for that test, then suspends the test until that process completes and can be evaluated.
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
## Attachments
|
|
188
|
+
|
|
189
|
+
**Requires Swift 6.2 or later.**
|
|
190
|
+
|
|
191
|
+
Swift Testing can add attachments to tests, so that if a test fails you can attach a debug log or generated data files to the failing test.
|
|
192
|
+
|
|
193
|
+
As an example, we could define a simple `Character` struct such as this one:
|
|
194
|
+
|
|
195
|
+
```swift
|
|
196
|
+
import Foundation
|
|
197
|
+
import Testing
|
|
198
|
+
|
|
199
|
+
struct Character: Attachable, Codable {
|
|
200
|
+
var id = UUID()
|
|
201
|
+
var name: String
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
That conforms to the `Attachable` protocol, and because it also imports Foundation *and* conforms to `Codable`, Swift Testing can encode instances of our struct to attach to tests.
|
|
206
|
+
|
|
207
|
+
We can then use that in a function in our production code:
|
|
208
|
+
|
|
209
|
+
```swift
|
|
210
|
+
func makeCharacter() -> Character {
|
|
211
|
+
Character(name: "Ram")
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
When it comes to writing a test, make sure the default name matches the value we expect, but also make whatever character is returned from `makeCharacter()` an attachment with the label "Character":
|
|
216
|
+
|
|
217
|
+
```swift
|
|
218
|
+
@Test func defaultCharacterNameIsCorrect() {
|
|
219
|
+
let result = makeCharacter()
|
|
220
|
+
#expect(result.name == "Rem")
|
|
221
|
+
|
|
222
|
+
Attachment.record(result, named: "Character")
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
That test will fail when it runs because the character name is different, and Swift Testing will surface the attachments as part of the test results.
|
|
227
|
+
|
|
228
|
+
Out of the box, Swift Testing provides support for attaching `String`, `Data`, and anything that conforms to `Encodable`. Unless the user has Swift 6.3 available, it does *not* support attaching images.
|
|
229
|
+
|
|
230
|
+
**Important:** Unlike the XCTest equivalent, Swift Testing's attachments do not support lifetime controls.
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
## Evaluating ConditionTrait
|
|
234
|
+
|
|
235
|
+
**Requires Swift 6.2 or later.**
|
|
236
|
+
|
|
237
|
+
Swift Testing provides an `evaluate()` method to test condition traits, meaning that it's possible to write non-test functions that evaluate the same conditions as test functions.
|
|
238
|
+
|
|
239
|
+
You will already know that we can use condition traits in the `@Test` macro, like this:
|
|
240
|
+
|
|
241
|
+
```swift
|
|
242
|
+
struct TestManager {
|
|
243
|
+
static let inSmokeTestMode = true
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
@Test(.disabled(if: TestManager.inSmokeTestMode))
|
|
247
|
+
func runLongComplexTest() {
|
|
248
|
+
// test code here
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
However, we can also evaluate those same conditions *outside* of tests by creating a condition trait then calling its `evaluate()` method:
|
|
253
|
+
|
|
254
|
+
```swift
|
|
255
|
+
func checkForSmokeTest() async throws {
|
|
256
|
+
let trait = ConditionTrait.disabled(if: TestManager.inSmokeTestMode)
|
|
257
|
+
|
|
258
|
+
if try await trait.evaluate() {
|
|
259
|
+
print("We're in smoke test mode")
|
|
260
|
+
} else {
|
|
261
|
+
print("Run all tests.")
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
## Return errors from #expect(throws:)
|
|
269
|
+
|
|
270
|
+
**Requires Swift 6.1 or later.**
|
|
271
|
+
|
|
272
|
+
The macros `#expect(_:sourceLocation:performing:throws:)` and `#require(_:sourceLocation:performing:throws:)` are both deprecated – they used a trailing closure to run some code for evaluation, then used a second trailing closure to check whether the error that was thrown was expected or not.
|
|
273
|
+
|
|
274
|
+
Both `#expect(throws:)` and `#require(throws:)` have been updated to return an error of the type they are checking for, allowing you to run the expectation and error evaluation separately.
|
|
275
|
+
|
|
276
|
+
As an example, there might be old code that ensures playing video games is disallowed early in the morning or late in the evening:
|
|
277
|
+
|
|
278
|
+
```swift
|
|
279
|
+
enum GameError: Error {
|
|
280
|
+
case disallowedTime
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
func playGame(at time: Int) throws(GameError) {
|
|
284
|
+
if time < 9 || time > 20 {
|
|
285
|
+
throw GameError.disallowedTime
|
|
286
|
+
} else {
|
|
287
|
+
print("Enjoy!")
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
With the old, deprecated API you might check for an exact error type like this:
|
|
293
|
+
|
|
294
|
+
```swift
|
|
295
|
+
@Test func playGameAtNight() {
|
|
296
|
+
#expect {
|
|
297
|
+
try playGame(at: 22)
|
|
298
|
+
} throws: {
|
|
299
|
+
guard let error = $0 as? GameError else { return false }
|
|
300
|
+
// perform additional error validation here
|
|
301
|
+
return error == .disallowedTime
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
You should move that over to code that runs the expectation and error evaluation separately, like this:
|
|
307
|
+
|
|
308
|
+
```swift
|
|
309
|
+
@Test func playGameAtNight() {
|
|
310
|
+
// `error` will now be a GameError
|
|
311
|
+
let error = #expect(throws: GameError.self) {
|
|
312
|
+
try playGame(at: 22)
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// perform additional validation here
|
|
316
|
+
#expect(error == .disallowedTime)
|
|
317
|
+
}
|
|
318
|
+
```
|