[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6NWMDBVMD4ATM7S2TTEDHCW":3,"skill-same:01M6NWMDBVMD4ATM7S2TTEDHCW":68},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":41,"linkOnly":42,"markdownContent":43,"markdownBody":44,"frontMatter":45,"refName":46,"commitSha":47,"skillDirectory":48,"forksCount":14,"repositoryHtmlUrl":49,"repositoryHomepageUrl":6,"ownerHtmlUrl":50,"ownerBlogUrl":51,"ownerDescription":52,"updatedAt":53,"install":54,"resources":67},"01M6NWMDBVMD4ATM7S2TTEDHCW","test-strategy",null,"Test pyramid decision matrix, coverage targets, when to write which test type, mock vs real dependency decisions, and test ROI analysis.","rubicanjr\u002FFinCognis","rubicanjr","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F234912519?v=4","01M6NT156NND8J474G34SB3923","Rubi","01M6NT15B70RWXE1N3YV0BZY8A",0,"MIT","https:\u002F\u002Fgithub.com\u002Frubicanjr\u002FFinCognis\u002Fblob\u002Fmain\u002Fskills\u002Ftest-strategy\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40],"test","strategy","test strategy","matrix","roi","which","decision matrix","roi analysis","targets","mock","type","dependency","coverage","write","decisions","decision","analysis","2026-11-10 10:12:30",false,"---\nname: test-strategy\ndescription: Test pyramid decision matrix, coverage targets, when to write which test type, mock vs real dependency decisions, and test ROI analysis.\n---\n\n# Test Strategy\n\n## Test Pyramid Ratio Guidance\n\n```\n        \u002F\\\n       \u002Fe2e\\         ~10% — critical user flows only\n      \u002F------\\\n     \u002F  integ  \\     ~20% — API contracts, DB interactions\n    \u002F------------\\\n   \u002F    unit      \\  ~70% — pure logic, transformations, edge cases\n  \u002F--------------\\\n```\n\nKeep the pyramid right-side-up. Inverting it (too many e2e) leads to slow, flaky CI.\n\n## Decision Matrix: Task Type → Test Type\n\n| Task Type | Test Type | Tool |\n|-----------|-----------|------|\n| Pure function \u002F utility | Unit | Jest \u002F Vitest |\n| API endpoint | Integration | Supertest \u002F httpx |\n| Critical user flow | E2E | Playwright |\n| Data transformation | Property-based | fast-check \u002F Hypothesis |\n| React\u002FVue component | Component | Testing Library |\n| CLI command | Integration | execa + assertions |\n| Database query | Integration (real DB) | jest + pg \u002F pytest |\n| Cron job \u002F scheduler | Unit (mocked time) | Jest fakeTimers |\n\n## Mock vs Real Dependency Decision Tree\n\n```\nIs it an external API (Stripe, Sendgrid, etc.)?\n  → YES: Always mock. Use recorded fixtures or MSW.\n\nIs it a database?\n  → Unit test context: mock (in-memory store or jest.fn())\n  → Integration test context: real DB (test container or local)\n\nIs it the file system?\n  → Mock with memfs or tmp dir, then clean up.\n\nIs it time \u002F Date.now()?\n  → Always mock. Use Jest fakeTimers or freezegun (Python).\n\nIs it a third-party SDK wrapper you wrote?\n  → Skip testing the wrapper itself, test your code's behavior.\n```\n\n## Coverage Targets by Project Type\n\n| Project Type | Branch Coverage | Notes |\n|-------------|----------------|-------|\n| Published library | 90%+ | Every exported function needs tests |\n| Production app | 80%+ | Focus on critical paths |\n| Internal tool | 70%+ | Happy path + main error cases |\n| Prototype \u002F spike | Skip | Throw it away anyway |\n| Generated code | Skip | Don't test codegen output |\n\n## Test Naming Conventions\n\n### Jest \u002F Vitest (describe + it)\n```typescript\ndescribe('calculateDiscount', () => {\n  it('returns 10% for gold members', () => { ... })\n  it('returns 0% when cart is empty', () => { ... })\n  it('throws when discount rate exceeds 100', () => { ... })\n})\n```\n\n### Given-When-Then (BDD style)\n```typescript\ndescribe('OrderService', () => {\n  describe('given a confirmed order', () => {\n    describe('when the user cancels', () => {\n      it('then it transitions to CANCELLED state', () => { ... })\n      it('then it sends a cancellation email', () => { ... })\n    })\n  })\n})\n```\n\n## When NOT to Test\n\n- Generated code (Prisma client, GraphQL types, protobuf outputs)\n- Third-party SDK wrappers with zero custom logic\n- Trivial getters\u002Fsetters (`getEmail() { return this.email }`)\n- Config files\n- Framework boilerplate (Next.js `_app.tsx`, Express server bootstrap)\n\n## Test Isolation Strategies\n\n### Transaction rollback (PostgreSQL)\n```typescript\nbeforeEach(async () => {\n  await db.query('BEGIN')\n})\n\nafterEach(async () => {\n  await db.query('ROLLBACK')\n})\n```\n\n### Cleanup hooks\n```typescript\nafterEach(() => {\n  jest.clearAllMocks()        \u002F\u002F clear call counts\n  jest.resetAllMocks()        \u002F\u002F reset return values\n  jest.restoreAllMocks()      \u002F\u002F restore spied originals\n})\n```\n\n### Test containers (real DB, isolated)\n```typescript\nimport { PostgreSqlContainer } from '@testcontainers\u002Fpostgresql'\n\nlet container: StartedPostgreSqlContainer\n\nbeforeAll(async () => {\n  container = await new PostgreSqlContainer().start()\n  process.env.DATABASE_URL = container.getConnectionUri()\n})\n\nafterAll(async () => {\n  await container.stop()\n})\n```\n\n## Flaky Test Triage\n\nWhen a test is flaky (passes\u002Ffails non-deterministically):\n\n1. Check for shared mutable state (global variables, singleton caches)\n2. Check for missing `await` on async calls\n3. Check for time-dependent assertions (`setTimeout`, `Date.now()`)\n4. Check for ordering dependencies (tests relying on previous test state)\n5. Add `--runInBand` to isolate and confirm\n\n## Mutation Testing (Stryker)\n\nMutation testing verifies that your tests actually catch bugs:\n\n```bash\nnpx stryker run\n```\n\n```json\n\u002F\u002F stryker.config.json\n{\n  \"mutator\": { \"excludedMutations\": [\"StringLiteral\"] },\n  \"thresholds\": { \"high\": 80, \"low\": 60, \"break\": 50 },\n  \"reporters\": [\"html\", \"progress\"]\n}\n```\n\nMutation score \u003C 60% means tests pass without catching real logic errors. Focus on the surviving mutants — each one is an untested code path.\n\n## Test ROI Analysis\n\nHigh ROI (write these first):\n- Business logic with branching conditions\n- Error handling paths\n- Data validation functions\n- State machine transitions\n\nLow ROI (write last or skip):\n- Simple CRUD with no custom logic\n- Pass-through adapters\n- Logging statements\n- UI cosmetic details\n","# Test Strategy\n\n## Test Pyramid Ratio Guidance\n\n```\n        \u002F\\\n       \u002Fe2e\\         ~10% — critical user flows only\n      \u002F------\\\n     \u002F  integ  \\     ~20% — API contracts, DB interactions\n    \u002F------------\\\n   \u002F    unit      \\  ~70% — pure logic, transformations, edge cases\n  \u002F--------------\\\n```\n\nKeep the pyramid right-side-up. Inverting it (too many e2e) leads to slow, flaky CI.\n\n## Decision Matrix: Task Type → Test Type\n\n| Task Type | Test Type | Tool |\n|-----------|-----------|------|\n| Pure function \u002F utility | Unit | Jest \u002F Vitest |\n| API endpoint | Integration | Supertest \u002F httpx |\n| Critical user flow | E2E | Playwright |\n| Data transformation | Property-based | fast-check \u002F Hypothesis |\n| React\u002FVue component | Component | Testing Library |\n| CLI command | Integration | execa + assertions |\n| Database query | Integration (real DB) | jest + pg \u002F pytest |\n| Cron job \u002F scheduler | Unit (mocked time) | Jest fakeTimers |\n\n## Mock vs Real Dependency Decision Tree\n\n```\nIs it an external API (Stripe, Sendgrid, etc.)?\n  → YES: Always mock. Use recorded fixtures or MSW.\n\nIs it a database?\n  → Unit test context: mock (in-memory store or jest.fn())\n  → Integration test context: real DB (test container or local)\n\nIs it the file system?\n  → Mock with memfs or tmp dir, then clean up.\n\nIs it time \u002F Date.now()?\n  → Always mock. Use Jest fakeTimers or freezegun (Python).\n\nIs it a third-party SDK wrapper you wrote?\n  → Skip testing the wrapper itself, test your code's behavior.\n```\n\n## Coverage Targets by Project Type\n\n| Project Type | Branch Coverage | Notes |\n|-------------|----------------|-------|\n| Published library | 90%+ | Every exported function needs tests |\n| Production app | 80%+ | Focus on critical paths |\n| Internal tool | 70%+ | Happy path + main error cases |\n| Prototype \u002F spike | Skip | Throw it away anyway |\n| Generated code | Skip | Don't test codegen output |\n\n## Test Naming Conventions\n\n### Jest \u002F Vitest (describe + it)\n```typescript\ndescribe('calculateDiscount', () => {\n  it('returns 10% for gold members', () => { ... })\n  it('returns 0% when cart is empty', () => { ... })\n  it('throws when discount rate exceeds 100', () => { ... })\n})\n```\n\n### Given-When-Then (BDD style)\n```typescript\ndescribe('OrderService', () => {\n  describe('given a confirmed order', () => {\n    describe('when the user cancels', () => {\n      it('then it transitions to CANCELLED state', () => { ... })\n      it('then it sends a cancellation email', () => { ... })\n    })\n  })\n})\n```\n\n## When NOT to Test\n\n- Generated code (Prisma client, GraphQL types, protobuf outputs)\n- Third-party SDK wrappers with zero custom logic\n- Trivial getters\u002Fsetters (`getEmail() { return this.email }`)\n- Config files\n- Framework boilerplate (Next.js `_app.tsx`, Express server bootstrap)\n\n## Test Isolation Strategies\n\n### Transaction rollback (PostgreSQL)\n```typescript\nbeforeEach(async () => {\n  await db.query('BEGIN')\n})\n\nafterEach(async () => {\n  await db.query('ROLLBACK')\n})\n```\n\n### Cleanup hooks\n```typescript\nafterEach(() => {\n  jest.clearAllMocks()        \u002F\u002F clear call counts\n  jest.resetAllMocks()        \u002F\u002F reset return values\n  jest.restoreAllMocks()      \u002F\u002F restore spied originals\n})\n```\n\n### Test containers (real DB, isolated)\n```typescript\nimport { PostgreSqlContainer } from '@testcontainers\u002Fpostgresql'\n\nlet container: StartedPostgreSqlContainer\n\nbeforeAll(async () => {\n  container = await new PostgreSqlContainer().start()\n  process.env.DATABASE_URL = container.getConnectionUri()\n})\n\nafterAll(async () => {\n  await container.stop()\n})\n```\n\n## Flaky Test Triage\n\nWhen a test is flaky (passes\u002Ffails non-deterministically):\n\n1. Check for shared mutable state (global variables, singleton caches)\n2. Check for missing `await` on async calls\n3. Check for time-dependent assertions (`setTimeout`, `Date.now()`)\n4. Check for ordering dependencies (tests relying on previous test state)\n5. Add `--runInBand` to isolate and confirm\n\n## Mutation Testing (Stryker)\n\nMutation testing verifies that your tests actually catch bugs:\n\n```bash\nnpx stryker run\n```\n\n```json\n\u002F\u002F stryker.config.json\n{\n  \"mutator\": { \"excludedMutations\": [\"StringLiteral\"] },\n  \"thresholds\": { \"high\": 80, \"low\": 60, \"break\": 50 },\n  \"reporters\": [\"html\", \"progress\"]\n}\n```\n\nMutation score \u003C 60% means tests pass without catching real logic errors. Focus on the surviving mutants — each one is an untested code path.\n\n## Test ROI Analysis\n\nHigh ROI (write these first):\n- Business logic with branching conditions\n- Error handling paths\n- Data validation functions\n- State machine transitions\n\nLow ROI (write last or skip):\n- Simple CRUD with no custom logic\n- Pass-through adapters\n- Logging statements\n- UI cosmetic details\n",{"name":5,"description":7},"main","70e1c350500ee750987420bbae48837afa906b7e","skills\u002Ftest-strategy","https:\u002F\u002Fgithub.com\u002Frubicanjr\u002FFinCognis","https:\u002F\u002Fgithub.com\u002Frubicanjr","linktr.ee\u002Ffinanskodu","Industrial Engineer & CIO @FinansKodu. Architecting AI-driven financial agents and autonomous workflows. 🏗️ Building systems, not just prompts.","2026-06-09 13:50:15",{"source":8,"skillName":5,"commands":55,"prompt":65,"zipAvailable":66},[56,59,62],{"tool":57,"command":58},"npx","npx skills add rubicanjr\u002FFinCognis --skill test-strategy",{"tool":60,"command":61},"bunx","bunx skills add rubicanjr\u002FFinCognis --skill test-strategy",{"tool":63,"command":64},"pnpm","pnpm dlx skills add rubicanjr\u002FFinCognis --skill test-strategy","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Frubicanjr\u002FFinCognis\u002Fblob\u002Fmain\u002Fskills\u002Ftest-strategy\u002FSKILL.md",true,[],[69,88,97,117,147,166],{"skillNo":70,"name":71,"nameZh":6,"description":72,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":73,"categories":74,"keywords":78,"publishedAt":41},"01M6NWS9DAXJTADT4T5MB49X8W","workflow-router","Goal-based workflow orchestration - routes tasks to specialist agents based on user goals","https:\u002F\u002Fgithub.com\u002Frubicanjr\u002FFinCognis\u002Fblob\u002Fmain\u002Fskills\u002Fworkflow-router\u002FSKILL.md",[75],{"categoryNo":76,"categoryName":77,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[79,80,81,82,83,84,85,86,87],"workflow router","workflow","router","orchestration","goals","goal","user","workflow orchestration","tasks",{"skillNo":89,"name":90,"nameZh":6,"description":91,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":92,"categories":93,"keywords":94,"publishedAt":41},"01M6NWS3RETSC0SHP16HP66E14","wiring","Wiring Verification","https:\u002F\u002Fgithub.com\u002Frubicanjr\u002FFinCognis\u002Fblob\u002Fmain\u002Fskills\u002Fwiring\u002FSKILL.md",[],[90,95,96],"verification","false",{"skillNo":98,"name":99,"nameZh":6,"description":100,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":101,"categories":102,"keywords":106,"publishedAt":41},"01M6NWS0XW9CVQZBDA1EGW0TWC","websocket-patterns","Connection management, room patterns, reconnection strategies, message buffering, and binary protocol design.","https:\u002F\u002Fgithub.com\u002Frubicanjr\u002FFinCognis\u002Fblob\u002Fmain\u002Fskills\u002Fwebsocket-patterns\u002Fskill.md",[103],{"categoryNo":104,"categoryName":105,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计",[107,108,109,110,111,112,113,114,115,116],"websocket","patterns","websocket patterns","design","protocol","management","message","strategies","binary","connection",{"skillNo":118,"name":119,"nameZh":6,"description":120,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":121,"categories":122,"keywords":127,"publishedAt":41},"01M6NWRDQDX9ZNETAWRRMQWV52","visual-verdict","Screenshot comparison QA for frontend development. Takes a screenshot of the current implementation, scores it across multiple visual dimensions, and returns a structured PASS\u002FREVISE\u002FFAIL verdict with concrete fixes. Use when implementing UI from a design reference or verifying visual correctness.","https:\u002F\u002Fgithub.com\u002Frubicanjr\u002FFinCognis\u002Fblob\u002Fmain\u002Fskills\u002Fvisual-verdict\u002FSKILL.md",[123,126],{"categoryNo":124,"categoryName":125,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000009","前端开发",{"categoryNo":76,"categoryName":77,"taxonomyType":21,"taxonomyTypeDesc":22},[128,129,130,131,132,133,134,135,136,137,138,139,140,110,141,142,143,144,145,146],"visual","verdict","visual verdict","ui","across","revise","comparison","correctness","implementing","for","fixes","dimensions","frontend","development","qa","screenshot","returns","use","frontend development",{"skillNo":148,"name":149,"nameZh":6,"description":150,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":151,"categories":152,"keywords":153,"publishedAt":41},"01M6NWR8HSNRS7MNDK2J02QYMN","verification-loop","Comprehensive verification system covering build, types, lint, tests, security, and diff review before a PR.","https:\u002F\u002Fgithub.com\u002Frubicanjr\u002FFinCognis\u002Fblob\u002Fmain\u002Fskills\u002Fverification-loop\u002FSKILL.md",[],[154,155,95,156,157,158,159,160,161,162,163,164,165],"verification loop","loop","lint","review","security","pr","system","diff","build","tests","diff review","types",{"skillNo":167,"name":168,"nameZh":6,"description":169,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":170,"categories":171,"keywords":172,"publishedAt":41},"01M6NWR4HHSFR0VR5EXFRWA747","vector-db-patterns","Embedding strategies, ANN algorithms, hybrid search, RAG chunking strategies, and reranking for semantic search and retrieval.","https:\u002F\u002Fgithub.com\u002Frubicanjr\u002FFinCognis\u002Fblob\u002Fmain\u002Fskills\u002Fvector-db-patterns\u002Fskill.md",[],[173,174,175,176,108,177,178,179,180,114,181,182,183,184,185,137,186,187],"vector db patterns","vector db","db","vector","semantic search","search","embedding strategies","algorithms","chunking","semantic","retrieval","embedding","Hybrid Search","hybrid","rag"]