[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6D28K5F5VC3PFW9K7WGR6F1":3,"skill-same:01M6D28K5F5VC3PFW9K7WGR6F1":70},{"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":26,"publishedAt":42,"linkOnly":43,"markdownContent":44,"markdownBody":45,"frontMatter":46,"refName":47,"commitSha":48,"skillDirectory":49,"forksCount":50,"repositoryHtmlUrl":51,"repositoryHomepageUrl":52,"ownerHtmlUrl":53,"ownerBlogUrl":52,"ownerDescription":54,"updatedAt":55,"install":56,"resources":69},"01M6D28K5F5VC3PFW9K7WGR6F1","testing",null,"Writing tests that earn their keep: what tests are for, choosing the level (unit, integration, end-to-end) by risk, testing behaviour through public surfaces, a new test that fails first for the right reason, determinism, speed, names that describe behaviour, reading the project's existing setup first, and reporting which test proves what. The principles and which skill holds each. Read before writing or changing tests.","enowdev\u002Fenowxcli","enowdev","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F179420349?v=4","01M6D1MVX2KC0X3Z9NESE7P22K","Enow Dev.","01M6D1MW1FMZGBDKWAJY4GQX81",67,"Apache-2.0","https:\u002F\u002Fgithub.com\u002Fenowdev\u002Fenowxcli\u002Fblob\u002Fmain\u002Fcrates\u002Fenowx-core\u002Fskills\u002Ftesting\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[5,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41],"writing","test","setup","writing tests","integration","reporting","risk","first","public","read","surfaces","speed","project","tests","end","2026-11-10 10:12:30",false,"---\nname: testing\ndescription: \"Writing tests that earn their keep: what tests are for, choosing the level (unit, integration, end-to-end) by risk, testing behaviour through public surfaces, a new test that fails first for the right reason, determinism, speed, names that describe behaviour, reading the project's existing setup first, and reporting which test proves what. The principles and which skill holds each. Read before writing or changing tests.\"\n---\n\n# Tests that earn their keep\n\nA generated test suite is easy to spot: tests that mirror the implementation\nline by line, a mock for every collaborator, assertions that cannot fail\n(`expect(result).toBeDefined()`), snapshot files nobody reads, `sleep(2000)`\nbefore an assertion, tests that pass alone and fail together, and 100%\ncoverage without a single edge case. It is green the day it is written and\nnever catches anything afterwards. This skill is the principles, the order\nof work, and which skill holds the detail for each part.\n\n## 1. What tests are for\n\n- **Protecting behaviour people rely on** (users, callers, other services),\n  so the code can change safely. A refactor keeps the tests green; a change\n  of behaviour turns them red. A test that breaks on every refactor protects\n  the implementation, not the behaviour.\n- **Executable documentation**: the names and cases say what the code does,\n  including the odd cases, and they cannot go out of date.\n- **Pinning fixed bugs**: every bug fixed gets a test that failed for the\n  reported reason (`testing-reproduce`).\n- A test is worth writing when the bug it can catch is likely or costly and\n  the test is cheap to run and keep. A test whose only way to fail is a\n  refactor costs more than it returns.\n- Tests are code: clear names, no dead helpers. But prefer readable over\n  clever: repeat a line of setup when it makes the test readable on its own.\n\n## 2. Read the project first\n\nBefore writing a test, find these, and match them:\n\n| Find | Where to look |\n|---|---|\n| Framework and runner | `package.json` scripts and devDependencies, `pyproject.toml` `[tool.pytest.ini_options]`, `_test.go` files, `Cargo.toml` dev-dependencies, `build.gradle` or `pom.xml`, test `*.csproj`, `Gemfile`, `composer.json` |\n| Where tests live, how they are named | colocated `*.test.ts`, `tests\u002F`, `test_*.py`, `*_test.go`, `#[cfg(test)]` modules and `tests\u002F`, `src\u002Ftest\u002Fjava`, `spec\u002F` |\n| Fixtures, factories, helpers | `conftest.py`, `test\u002Fhelpers`, `testutil`, `factories\u002F`, `spec\u002Fsupport`, a `renderWithProviders` |\n| How the database and services are provided | `docker-compose.yml`, Testcontainers setup, `.env.test`, in-memory fakes |\n| How CI runs them | `.github\u002Fworkflows\u002F`, `.gitlab-ci.yml`, `Makefile`, `justfile` |\n\nRun the existing suite once before changing anything and note what already\nfails, so an old failure is neither blamed on your change nor claimed fixed.\nUse the project's framework, assertion style, fixtures and naming; never add\na second test framework or assertion library.\n\nHow to run one test, by stack:\n\n```bash\nnpx vitest run src\u002Fcart.test.ts -t \"applies the discount\"\nnpx jest src\u002Fcart.test.ts -t \"applies the discount\"\nnpx playwright test e2e\u002Fcheckout.spec.ts:42\npytest tests\u002Ftest_cart.py::test_applies_discount\ngo test .\u002Fcart -run 'TestTotal\u002Fdiscount$' -count=1\ncargo test applies_discount            # or: cargo nextest run applies_discount\n.\u002Fgradlew test --tests 'shop.CartTest.appliesDiscount'\nmvn test -Dtest='CartTest#appliesDiscount'\ndotnet test --filter \"FullyQualifiedName~CartTests.AppliesDiscount\"\nbundle exec rspec spec\u002Fcart_spec.rb:42\nphp artisan test --filter=applies_discount\n```\n\n## 3. Choose the level by risk and cost\n\n| What is tested | Level | Skill |\n|---|---|---|\n| Calculations, parsing, validation rules, state machines, formatting | Unit | `testing-unit` |\n| An endpoint with its database, queries and constraints, serialisation, a client against a faked service, a job's effect | Integration | `testing-integration`, `backend-testing` |\n| A component's behaviour as the user sees it | Component | `frontend-testing` |\n| A journey that makes money or loses data (sign-up, checkout, the core task) | End to end | `testing-e2e` |\n| The agreement between services owned by different teams | Contract | `testing-integration` |\n\n- The test pyramid (many unit, fewer integration, few end-to-end tests) fits\n  logic-heavy code. The testing trophy (static checks at the base, most\n  tests at integration level, few end-to-end) fits web applications, where\n  the bugs live in the wiring between parts. In practice: pure logic gets\n  unit tests, anything that touches a database or the network gets\n  integration tests, and 5 to 20 journeys get end-to-end tests.\n- Choose the lowest level that can show the failure you care about: it is\n  faster, and its failure points at the cause.\n- Do not test what the type checker or linter already proves.\n- Speed budgets to aim for: a unit test in milliseconds and the unit suite\n  in seconds; the integration suite in a few minutes; end-to-end shards\n  under 10 to 15 minutes in CI.\n\n## 4. The rules for each test\n\n- **Arrange, act, assert**, separated by a blank line. One act per test.\n- **One behaviour per test.** Several assertions are fine when they describe\n  one outcome (the status and the body), not two behaviours.\n- **Assert on outcomes the caller sees**: a return value, a status and body,\n  rows in the database, a message published, text on screen. Not private\n  methods, internal call order or how many times a helper ran, unless the\n  call is the outcome (one charge, one email).\n- **Assertions that can fail**: the exact value (`toBe(9_000)`), not\n  `toBeTruthy()`; never an expected value computed with the code under test.\n- **Edge cases and failure paths**, not only the happy path: empty,\n  boundaries, invalid input, permissions, a failing dependency. The case\n  checklist is in `testing-unit`.\n- **Deterministic**: time frozen or injected, randomness seeded, the network\n  faked at the edge, time zone and locale fixed, no dependence on order.\n- **Fast**: no sleeps; expensive setup (a container) once per run.\n- **Independent**: each test creates its own data and runs alone, in any\n  order, in parallel.\n- **Names describe behaviour**: `refuses_a_payment_for_a_paid_order`,\n  `it(\"returns 404 for another user's order\")`, not `test_pay_2` or\n  `it(\"works\")`.\n- No `.only` or skipped tests committed; a skip carries a reason and an\n  issue link.\n\n```ts\n\u002F\u002F Mirrors the implementation: passes whatever the discount rule is.\nit(\"calls calculateDiscount\", () => {\n  const spy = vi.spyOn(pricing, \"calculateDiscount\");\n  checkout(cart);\n  expect(spy).toHaveBeenCalled();\n});\n\n\u002F\u002F States the rule, and fails when the rule breaks.\nit(\"gives 10% off orders of 100.00 or more\", () => {\n  const cart = cartWith({ subtotalCents: 10_000 });\n\n  const order = checkout(cart);\n\n  expect(order.discountCents).toBe(1_000);\n  expect(order.totalCents).toBe(9_000);\n});\n```\n\n## 5. Red first\n\n1. Write or change the test.\n2. Run it and watch it fail, and read why: it must fail on the assertion\n   about the behaviour, not on an import error, a typo, a missing fixture or\n   a timeout.\n3. Make the change. Run the test: it passes.\n4. Run the neighbouring tests, then the whole suite.\n\nA test added to code that already works (coverage, characterisation) is\nproved differently: break the code on purpose (flip a comparison, delete a\nline), see the test fail, restore. A test that cannot fail is worse than\nnone: it reports safety that is not there.\n\nMutation testing automates that check: the tool changes the code (`>` to\n`>=`, a call removed, a constant returned) and reruns the tests; a mutant\nthat survives marks an assertion gap. Run it on the module you changed:\n\n```bash\nnpx stryker run --incremental --mutate \"src\u002Fpricing\u002F**\u002F*.ts\"   # StrykerJS\ndotnet stryker                                                  # Stryker.NET\ncargo mutants -f src\u002Fpricing.rs                                 # or --in-diff pr.diff\nmutmut run && mutmut results                                    # Python\nmvn org.pitest:pitest-maven:mutationCoverage                    # PIT (Gradle: info.solidsoft.pitest)\nvendor\u002Fbin\u002Finfection --threads=max --git-diff-lines             # PHP\n```\n\n## 6. Coverage is a map, not a goal\n\n- Coverage shows what no test executes. Read the uncovered branches in the\n  code you changed and decide which matter: error paths and boundaries\n  usually do.\n- Executed is not checked: 100% line coverage with weak assertions proves\n  nothing. Mutation testing measures whether the assertions have teeth.\n- Prefer branch coverage to line coverage where the tool offers it.\n- Keep the project's threshold; never lower it and never add tests that run\n  code without asserting to reach it. Coverage of the changed lines is a\n  better gate than a global number (`testing-ci`).\n\n```bash\nnpx vitest run --coverage\npytest --cov=src --cov-branch --cov-report=term-missing\ngo test -coverprofile=cover.out .\u002F... && go tool cover -func=cover.out\ncargo llvm-cov --html\n```\n\n## 7. Report which test proves what\n\nDone means: the new tests fail without the change and pass with it, and the\nwhole existing suite passes (or its failures are named and shown to fail on\nthe base commit too). The report states:\n\n```\nAdded\n- tests\u002Forders\u002Ftest_pay.py::test_refuses_payment_for_paid_order: a second\n  payment returns 409 and creates no second charge (failed before the fix:\n  two charges)\nRan\n- pytest tests\u002Forders -q: 48 passed\n- pytest -q: 612 passed, 2 skipped (skips pre-existing)\nNot run\n- e2e: no browser available here\n```\n\nNever claim a suite passed that was not run; say plainly what could not be\nrun and why.\n\n## 8. Which skill for which job\n\n- `testing-unit`: finding cases, tables of cases, test doubles, property\n  tests, snapshots, each language's idioms.\n- `testing-integration`: real databases and HTTP, containers, isolation,\n  fakes at the network edge, contracts, migrations.\n- `testing-e2e`: journeys with Playwright, Maestro or Detox, locators,\n  signed-in state, traces.\n- `testing-reproduce`: a bug report turned into a failing test, shrinking,\n  `git bisect`.\n- `testing-flaky`: tests that pass and fail without a change: causes,\n  repeats, quarantine.\n- `testing-data`: factories, unique and seeded values, time, golden files,\n  no real personal data.\n- `testing-ci`: pipelines: order, sharding, caching, services, reports,\n  required checks.\n- `backend-testing`: server rules and endpoints through HTTP and a real\n  database.\n- `frontend-testing`: components with Testing Library, MSW, accessibility,\n  visual checks.\n- `mobile-testing`: app tests, the device matrix, Maestro, Detox, XCUITest,\n  Espresso.\n\n## Check it\n\n- The new test failed before the change (keep the output) and passes after.\n- One test, then its file, then the full suite, with the project's own\n  commands; counts recorded.\n- The new tests run in random order and repeatedly:\n  `vitest run --sequence.shuffle`, `pytest -p randomly` (pytest-randomly),\n  `go test -shuffle=on -count=5 -race`.\n- The diff has no `.only`, no unexplained skip, no `sleep` or\n  `waitForTimeout`, no real clock or network in the new tests.\n\n## Avoid\n\nTests that mirror the implementation; mocks of your own pure code, or of\nlibraries you do not own; assertions that cannot fail; large snapshots\nnobody reviews; sleeps; shared mutable fixtures; order dependence; the real\nnetwork or clock; skipping the red step; lowering thresholds, deleting or\nskipping failing tests to get green; claiming a pass that was not run.\n","# Tests that earn their keep\n\nA generated test suite is easy to spot: tests that mirror the implementation\nline by line, a mock for every collaborator, assertions that cannot fail\n(`expect(result).toBeDefined()`), snapshot files nobody reads, `sleep(2000)`\nbefore an assertion, tests that pass alone and fail together, and 100%\ncoverage without a single edge case. It is green the day it is written and\nnever catches anything afterwards. This skill is the principles, the order\nof work, and which skill holds the detail for each part.\n\n## 1. What tests are for\n\n- **Protecting behaviour people rely on** (users, callers, other services),\n  so the code can change safely. A refactor keeps the tests green; a change\n  of behaviour turns them red. A test that breaks on every refactor protects\n  the implementation, not the behaviour.\n- **Executable documentation**: the names and cases say what the code does,\n  including the odd cases, and they cannot go out of date.\n- **Pinning fixed bugs**: every bug fixed gets a test that failed for the\n  reported reason (`testing-reproduce`).\n- A test is worth writing when the bug it can catch is likely or costly and\n  the test is cheap to run and keep. A test whose only way to fail is a\n  refactor costs more than it returns.\n- Tests are code: clear names, no dead helpers. But prefer readable over\n  clever: repeat a line of setup when it makes the test readable on its own.\n\n## 2. Read the project first\n\nBefore writing a test, find these, and match them:\n\n| Find | Where to look |\n|---|---|\n| Framework and runner | `package.json` scripts and devDependencies, `pyproject.toml` `[tool.pytest.ini_options]`, `_test.go` files, `Cargo.toml` dev-dependencies, `build.gradle` or `pom.xml`, test `*.csproj`, `Gemfile`, `composer.json` |\n| Where tests live, how they are named | colocated `*.test.ts`, `tests\u002F`, `test_*.py`, `*_test.go`, `#[cfg(test)]` modules and `tests\u002F`, `src\u002Ftest\u002Fjava`, `spec\u002F` |\n| Fixtures, factories, helpers | `conftest.py`, `test\u002Fhelpers`, `testutil`, `factories\u002F`, `spec\u002Fsupport`, a `renderWithProviders` |\n| How the database and services are provided | `docker-compose.yml`, Testcontainers setup, `.env.test`, in-memory fakes |\n| How CI runs them | `.github\u002Fworkflows\u002F`, `.gitlab-ci.yml`, `Makefile`, `justfile` |\n\nRun the existing suite once before changing anything and note what already\nfails, so an old failure is neither blamed on your change nor claimed fixed.\nUse the project's framework, assertion style, fixtures and naming; never add\na second test framework or assertion library.\n\nHow to run one test, by stack:\n\n```bash\nnpx vitest run src\u002Fcart.test.ts -t \"applies the discount\"\nnpx jest src\u002Fcart.test.ts -t \"applies the discount\"\nnpx playwright test e2e\u002Fcheckout.spec.ts:42\npytest tests\u002Ftest_cart.py::test_applies_discount\ngo test .\u002Fcart -run 'TestTotal\u002Fdiscount$' -count=1\ncargo test applies_discount            # or: cargo nextest run applies_discount\n.\u002Fgradlew test --tests 'shop.CartTest.appliesDiscount'\nmvn test -Dtest='CartTest#appliesDiscount'\ndotnet test --filter \"FullyQualifiedName~CartTests.AppliesDiscount\"\nbundle exec rspec spec\u002Fcart_spec.rb:42\nphp artisan test --filter=applies_discount\n```\n\n## 3. Choose the level by risk and cost\n\n| What is tested | Level | Skill |\n|---|---|---|\n| Calculations, parsing, validation rules, state machines, formatting | Unit | `testing-unit` |\n| An endpoint with its database, queries and constraints, serialisation, a client against a faked service, a job's effect | Integration | `testing-integration`, `backend-testing` |\n| A component's behaviour as the user sees it | Component | `frontend-testing` |\n| A journey that makes money or loses data (sign-up, checkout, the core task) | End to end | `testing-e2e` |\n| The agreement between services owned by different teams | Contract | `testing-integration` |\n\n- The test pyramid (many unit, fewer integration, few end-to-end tests) fits\n  logic-heavy code. The testing trophy (static checks at the base, most\n  tests at integration level, few end-to-end) fits web applications, where\n  the bugs live in the wiring between parts. In practice: pure logic gets\n  unit tests, anything that touches a database or the network gets\n  integration tests, and 5 to 20 journeys get end-to-end tests.\n- Choose the lowest level that can show the failure you care about: it is\n  faster, and its failure points at the cause.\n- Do not test what the type checker or linter already proves.\n- Speed budgets to aim for: a unit test in milliseconds and the unit suite\n  in seconds; the integration suite in a few minutes; end-to-end shards\n  under 10 to 15 minutes in CI.\n\n## 4. The rules for each test\n\n- **Arrange, act, assert**, separated by a blank line. One act per test.\n- **One behaviour per test.** Several assertions are fine when they describe\n  one outcome (the status and the body), not two behaviours.\n- **Assert on outcomes the caller sees**: a return value, a status and body,\n  rows in the database, a message published, text on screen. Not private\n  methods, internal call order or how many times a helper ran, unless the\n  call is the outcome (one charge, one email).\n- **Assertions that can fail**: the exact value (`toBe(9_000)`), not\n  `toBeTruthy()`; never an expected value computed with the code under test.\n- **Edge cases and failure paths**, not only the happy path: empty,\n  boundaries, invalid input, permissions, a failing dependency. The case\n  checklist is in `testing-unit`.\n- **Deterministic**: time frozen or injected, randomness seeded, the network\n  faked at the edge, time zone and locale fixed, no dependence on order.\n- **Fast**: no sleeps; expensive setup (a container) once per run.\n- **Independent**: each test creates its own data and runs alone, in any\n  order, in parallel.\n- **Names describe behaviour**: `refuses_a_payment_for_a_paid_order`,\n  `it(\"returns 404 for another user's order\")`, not `test_pay_2` or\n  `it(\"works\")`.\n- No `.only` or skipped tests committed; a skip carries a reason and an\n  issue link.\n\n```ts\n\u002F\u002F Mirrors the implementation: passes whatever the discount rule is.\nit(\"calls calculateDiscount\", () => {\n  const spy = vi.spyOn(pricing, \"calculateDiscount\");\n  checkout(cart);\n  expect(spy).toHaveBeenCalled();\n});\n\n\u002F\u002F States the rule, and fails when the rule breaks.\nit(\"gives 10% off orders of 100.00 or more\", () => {\n  const cart = cartWith({ subtotalCents: 10_000 });\n\n  const order = checkout(cart);\n\n  expect(order.discountCents).toBe(1_000);\n  expect(order.totalCents).toBe(9_000);\n});\n```\n\n## 5. Red first\n\n1. Write or change the test.\n2. Run it and watch it fail, and read why: it must fail on the assertion\n   about the behaviour, not on an import error, a typo, a missing fixture or\n   a timeout.\n3. Make the change. Run the test: it passes.\n4. Run the neighbouring tests, then the whole suite.\n\nA test added to code that already works (coverage, characterisation) is\nproved differently: break the code on purpose (flip a comparison, delete a\nline), see the test fail, restore. A test that cannot fail is worse than\nnone: it reports safety that is not there.\n\nMutation testing automates that check: the tool changes the code (`>` to\n`>=`, a call removed, a constant returned) and reruns the tests; a mutant\nthat survives marks an assertion gap. Run it on the module you changed:\n\n```bash\nnpx stryker run --incremental --mutate \"src\u002Fpricing\u002F**\u002F*.ts\"   # StrykerJS\ndotnet stryker                                                  # Stryker.NET\ncargo mutants -f src\u002Fpricing.rs                                 # or --in-diff pr.diff\nmutmut run && mutmut results                                    # Python\nmvn org.pitest:pitest-maven:mutationCoverage                    # PIT (Gradle: info.solidsoft.pitest)\nvendor\u002Fbin\u002Finfection --threads=max --git-diff-lines             # PHP\n```\n\n## 6. Coverage is a map, not a goal\n\n- Coverage shows what no test executes. Read the uncovered branches in the\n  code you changed and decide which matter: error paths and boundaries\n  usually do.\n- Executed is not checked: 100% line coverage with weak assertions proves\n  nothing. Mutation testing measures whether the assertions have teeth.\n- Prefer branch coverage to line coverage where the tool offers it.\n- Keep the project's threshold; never lower it and never add tests that run\n  code without asserting to reach it. Coverage of the changed lines is a\n  better gate than a global number (`testing-ci`).\n\n```bash\nnpx vitest run --coverage\npytest --cov=src --cov-branch --cov-report=term-missing\ngo test -coverprofile=cover.out .\u002F... && go tool cover -func=cover.out\ncargo llvm-cov --html\n```\n\n## 7. Report which test proves what\n\nDone means: the new tests fail without the change and pass with it, and the\nwhole existing suite passes (or its failures are named and shown to fail on\nthe base commit too). The report states:\n\n```\nAdded\n- tests\u002Forders\u002Ftest_pay.py::test_refuses_payment_for_paid_order: a second\n  payment returns 409 and creates no second charge (failed before the fix:\n  two charges)\nRan\n- pytest tests\u002Forders -q: 48 passed\n- pytest -q: 612 passed, 2 skipped (skips pre-existing)\nNot run\n- e2e: no browser available here\n```\n\nNever claim a suite passed that was not run; say plainly what could not be\nrun and why.\n\n## 8. Which skill for which job\n\n- `testing-unit`: finding cases, tables of cases, test doubles, property\n  tests, snapshots, each language's idioms.\n- `testing-integration`: real databases and HTTP, containers, isolation,\n  fakes at the network edge, contracts, migrations.\n- `testing-e2e`: journeys with Playwright, Maestro or Detox, locators,\n  signed-in state, traces.\n- `testing-reproduce`: a bug report turned into a failing test, shrinking,\n  `git bisect`.\n- `testing-flaky`: tests that pass and fail without a change: causes,\n  repeats, quarantine.\n- `testing-data`: factories, unique and seeded values, time, golden files,\n  no real personal data.\n- `testing-ci`: pipelines: order, sharding, caching, services, reports,\n  required checks.\n- `backend-testing`: server rules and endpoints through HTTP and a real\n  database.\n- `frontend-testing`: components with Testing Library, MSW, accessibility,\n  visual checks.\n- `mobile-testing`: app tests, the device matrix, Maestro, Detox, XCUITest,\n  Espresso.\n\n## Check it\n\n- The new test failed before the change (keep the output) and passes after.\n- One test, then its file, then the full suite, with the project's own\n  commands; counts recorded.\n- The new tests run in random order and repeatedly:\n  `vitest run --sequence.shuffle`, `pytest -p randomly` (pytest-randomly),\n  `go test -shuffle=on -count=5 -race`.\n- The diff has no `.only`, no unexplained skip, no `sleep` or\n  `waitForTimeout`, no real clock or network in the new tests.\n\n## Avoid\n\nTests that mirror the implementation; mocks of your own pure code, or of\nlibraries you do not own; assertions that cannot fail; large snapshots\nnobody reviews; sleeps; shared mutable fixtures; order dependence; the real\nnetwork or clock; skipping the red step; lowering thresholds, deleting or\nskipping failing tests to get green; claiming a pass that was not run.\n",{"name":5,"description":7},"main","38293fe1b096e6bf3646c7344c38786ed688f464","crates\u002Fenowx-core\u002Fskills\u002Ftesting",21,"https:\u002F\u002Fgithub.com\u002Fenowdev\u002Fenowxcli","https:\u002F\u002Fenowx.ai","https:\u002F\u002Fgithub.com\u002Fenowdev","Pretending to be a Developer","2026-10-06 02:05:35",{"source":8,"skillName":5,"commands":57,"prompt":67,"zipAvailable":68},[58,61,64],{"tool":59,"command":60},"npx","npx skills add enowdev\u002Fenowxcli --skill testing",{"tool":62,"command":63},"bunx","bunx skills add enowdev\u002Fenowxcli --skill testing",{"tool":65,"command":66},"pnpm","pnpm dlx skills add enowdev\u002Fenowxcli --skill testing","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fenowdev\u002Fenowxcli\u002Fblob\u002Fmain\u002Fcrates\u002Fenowx-core\u002Fskills\u002Ftesting\u002FSKILL.md",true,[],[71,81,105,121,148,170],{"skillNo":72,"name":73,"nameZh":6,"description":74,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":75,"categories":76,"keywords":78,"publishedAt":42},"01M6D2HQYSQD9N7MTNDT4A7CBM","demo-skill","Project-scope demo skill for tests.","https:\u002F\u002Fgithub.com\u002Fenowdev\u002Fenowxcli\u002Fblob\u002Fmain\u002Fworkspace\u002F.agents\u002Fskills\u002Fdemo-skill\u002FSKILL.md",[77],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[79,80,40,39,36],"demo skill","demo",{"skillNo":82,"name":27,"nameZh":6,"description":83,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":84,"categories":85,"keywords":94,"publishedAt":42},"01M6D2HM0GCPM0TM2HPG9HHR2R","Writing words people read: the specific thing instead of claims, words to drop, sentences, interface copy (buttons, labels, errors, empty states, confirmations), page copy, notifications and emails, alt text and link text, numbers and dates, words that translate well, documentation and voice. Read before writing a page's copy, an interface's text or a document.","https:\u002F\u002Fgithub.com\u002Fenowdev\u002Fenowxcli\u002Fblob\u002Fmain\u002Fcrates\u002Fenowx-core\u002Fskills\u002Fwriting\u002FSKILL.md",[86,89],{"categoryNo":87,"categoryName":88,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000018","写作与文案",{"categoryNo":90,"categoryName":91,"taxonomyType":92,"taxonomyTypeDesc":93},"01JBSEEDCAT000000000000036","内容创作者","PROFESSION","适用职业",[27,95,96,97,98,99,36,100,101,102,103,104],"text","emails","empty","drop","document","page","voice","notifications","documentation","translate",{"skillNo":106,"name":107,"nameZh":6,"description":108,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":109,"categories":110,"keywords":114,"publishedAt":42},"01M6D2HG07YS49NM196Q0R3AZ8","ui","Designing or restyling an interface: direction, layout, type, colour, icons, components, states, responsive behaviour. Read before building a page, a screen or a set of components.","https:\u002F\u002Fgithub.com\u002Fenowdev\u002Fenowxcli\u002Fblob\u002Fmain\u002Fcrates\u002Fenowx-core\u002Fskills\u002Fui\u002FSKILL.md",[111],{"categoryNo":112,"categoryName":113,"taxonomyType":92,"taxonomyTypeDesc":93},"01JBSEEDCAT000000000000032","设计师",[107,115,116,117,118,100,119,36,120],"icons","components","SET","responsive","layout","before building",{"skillNo":122,"name":123,"nameZh":6,"description":124,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":125,"categories":126,"keywords":133,"publishedAt":42},"01M6D2HB59HZHWG1RYZDV4SJ91","ui-themes","Light and dark themes, and colour that holds in both: tokens with a value per theme, and what each kind of content needs to stay visible (icons, SVG drawings and line art, logos, photos, screenshots, charts, code, maps, borders, shadows, focus, form controls), switching without a flash, and checking both. Read before building a second theme or a theme toggle, and before any drawing, logo or chart on a page that has two themes.","https:\u002F\u002Fgithub.com\u002Fenowdev\u002Fenowxcli\u002Fblob\u002Fmain\u002Fcrates\u002Fenowx-core\u002Fskills\u002Fui-themes\u002FSKILL.md",[127,130],{"categoryNo":128,"categoryName":129,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":131,"categoryName":132,"taxonomyType":92,"taxonomyTypeDesc":93},"01JBSEEDCAT000000000000030","开发工程师",[107,134,135,136,137,138,139,140,141,36,120,142,100,143,144,145,115,146,147],"ui themes","switching","photos","tokens","drawing","focus","maps","Art","flash","code","Charts","content","screenshots","logo",{"skillNo":149,"name":150,"nameZh":6,"description":151,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":152,"categories":153,"keywords":157,"publishedAt":42},"01M6D2H5R5KRAE524C8QX0T7Q0","ui-structure","Structure before styling: the blueprint written before any interface code (the screen's job, the regions its kind of page needs, their order and why, the layout skeleton in numbers, the components and their states), the anatomy and order of a homepage, a dashboard, a list, a detail page, settings, a form, sign-in, pricing, docs, an article and a checkout, and how to turn the blueprint into code (tokens, layout primitives, components, sections, page). Read first, before building or rebuilding any page or screen.","https:\u002F\u002Fgithub.com\u002Fenowdev\u002Fenowxcli\u002Fblob\u002Fmain\u002Fcrates\u002Fenowx-core\u002Fskills\u002Fui-structure\u002FSKILL.md",[154,155,156],{"categoryNo":87,"categoryName":88,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":131,"categoryName":132,"taxonomyType":92,"taxonomyTypeDesc":93},{"categoryNo":90,"categoryName":91,"taxonomyType":92,"taxonomyTypeDesc":93},[158,107,159,116,160,161,143,162,163,164,119,137,165,166,167,36,120,100,168,169],"structure","ui structure","pricing","dashboard","Blueprint","article","anatomy","styling","primitives","list","why","how",{"skillNo":171,"name":172,"nameZh":6,"description":173,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":174,"categories":175,"keywords":181,"publishedAt":42},"01M6D2H0ZZBJG77MBGPZHA6MWD","ui-stack-vue","Building interfaces in Vue 3 and Nuxt: project layout, script setup with typed defineProps, defineEmits and defineModel, attribute fallthrough, slots and scoped slots, template refs, ref, reactive and computed, watch versus watchEffect, composables and VueUse, provide and inject, Pinia, keyed v-for, transitions, Nuxt 4 (app directory, pages, layouts, useFetch and useAsyncData keys, $fetch in handlers, server routes, runtime config, useSeoMeta, NuxtImg, middleware), VeeValidate forms, Reka UI and Nuxt UI, testing, vue-tsc, and the traps. Read when the project uses Vue or Nuxt.","https:\u002F\u002Fgithub.com\u002Fenowdev\u002Fenowxcli\u002Fblob\u002Fmain\u002Fcrates\u002Fenowx-core\u002Fskills\u002Fui-stack-vue\u002FSKILL.md",[176,177,180],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":178,"categoryName":179,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000009","前端开发",{"categoryNo":112,"categoryName":113,"taxonomyType":92,"taxonomyTypeDesc":93},[107,182,183,184,185,186,187,188,119,39,189,190,36,191,192,193,194,195,196,5],"vue","stack","ui stack vue","forms","pages","watch","runtime","transitions","fetch","pinia","nuxt","template","server","config","directory"]