Requirements
- Target platform
- OpenClaw
- Install method
- Manual import
- Extraction
- Extract archive
- Prerequisites
- OpenClaw
- Primary doc
- SKILL.md
Unit, integration, and E2E testing patterns with framework-specific guidance. Use when asked to "write tests", "add test coverage", "testing strategy", "test this function", "create test suite", "fix flaky tests", or "improve test quality".
Unit, integration, and E2E testing patterns with framework-specific guidance. Use when asked to "write tests", "add test coverage", "testing strategy", "test this function", "create test suite", "fix flaky tests", or "improve test quality".
Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.
I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Then review README.md for any prerequisites, environment setup, or post-install checks. Tell me what you changed and call out any manual steps you could not complete.
I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Then review README.md for any prerequisites, environment setup, or post-install checks. Summarize what changed and any follow-up checks I should run.
Write tests that catch bugs, not tests that pass. โ Confidence through coverage, speed through isolation.
LevelRatioSpeedCostConfidenceScopeUnit~70%msLowLow (isolated)Single function/classIntegration~20%secondsMediumMediumModule boundaries, APIs, DBE2E~10%minutesHighHigh (realistic)Full user workflows Rule: If your E2E tests outnumber your unit tests, invert the pyramid.
PatternWhen to UseStructureArrange-Act-AssertDefault for all unit testsSetup, Execute, VerifyGiven-When-ThenBDD-style, behavior-focusedPrecondition, Action, OutcomeParameterizedSame logic, multiple inputsData-driven test casesSnapshotUI components, serialized outputCompare against saved baselineProperty-BasedMathematical invariantsGenerate random inputs, assert properties
The default structure for every unit test. Clear separation of setup, execution, and verification makes tests readable and maintainable. // Clean AAA structure test('calculates order total with tax', () => { // Arrange const items = [{ price: 10, qty: 2 }, { price: 5, qty: 1 }]; const taxRate = 0.08; // Act const total = calculateTotal(items, taxRate); // Assert expect(total).toBe(27.0); });
Use the right type of test double for the situation. Each serves a different purpose. DoublePurposeWhen to UseExampleStubReturns canned dataControl indirect inputjest.fn().mockReturnValue(42)MockVerifies interactionsAssert something was calledexpect(mock).toHaveBeenCalledWith('arg')SpyWraps real implementationObserve without replacingjest.spyOn(service, 'save')FakeWorking simplified implNeed realistic behaviorIn-memory database, fake HTTP server // Stub โ control indirect input const getUser = jest.fn().mockResolvedValue({ id: 1, name: 'Alice' }); // Spy โ observe without replacing const spy = jest.spyOn(logger, 'warn'); processInvalidInput(data); expect(spy).toHaveBeenCalledWith('Invalid input received'); // Fake โ lightweight substitute class FakeUserRepo implements UserRepository { private users = new Map<string, User>(); async save(user: User) { this.users.set(user.id, user); } async findById(id: string) { return this.users.get(id) ?? null; } }
Use parameterized tests when the same logic needs verification with multiple inputs. This eliminates copy-paste tests while providing comprehensive coverage. // Vitest/Jest test.each([ ['hello', 'HELLO'], ['world', 'WORLD'], ['', ''], ['123abc', '123ABC'], ])('toUpperCase(%s) returns %s', (input, expected) => { expect(input.toUpperCase()).toBe(expected); }); # pytest @pytest.mark.parametrize("input,expected", [ ("hello", "HELLO"), ("world", "WORLD"), ("", ""), ]) def test_to_upper(input, expected): assert input.upper() == expected // Go โ table-driven tests (idiomatic) func TestAdd(t *testing.T) { tests := []struct { name string a, b int expected int }{ {"positive", 2, 3, 5}, {"zero", 0, 0, 0}, {"negative", -1, -2, -3}, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { if got := Add(tc.a, tc.b); got != tc.expected { t.Errorf("Add(%d,%d) = %d, want %d", tc.a, tc.b, got, tc.expected) } }) } }
StrategyApproachTrade-offTransaction rollbackWrap each test in a transaction, rollback afterFast, but hides commit bugsFixtures/seedsLoad known data before suitePredictable, but brittle if schema changesFactory functionsGenerate data programmaticallyFlexible, but more setup codeTestcontainersSpin up real DB in DockerRealistic, but slower startup // Transaction rollback pattern (Prisma) beforeEach(async () => { await prisma.$executeRaw`BEGIN`; }); afterEach(async () => { await prisma.$executeRaw`ROLLBACK`; }); test('creates user in database', async () => { const user = await createUser({ name: 'Alice', email: 'a@b.com' }); const found = await prisma.user.findUnique({ where: { id: user.id } }); expect(found?.name).toBe('Alice'); });
// Supertest (Node.js) import request from 'supertest'; import { app } from '../src/app'; describe('POST /api/users', () => { it('creates a user and returns 201', async () => { const res = await request(app) .post('/api/users') .send({ name: 'Alice', email: 'alice@test.com' }) .expect(201); expect(res.body).toMatchObject({ id: expect.any(String), name: 'Alice', }); }); it('returns 400 for invalid email', async () => { await request(app) .post('/api/users') .send({ name: 'Alice', email: 'not-an-email' }) .expect(400); }); });
The fundamental rule: mock at system boundaries (external APIs, databases, file systems) and never mock internal domain logic. // BAD โ mocking internal implementation jest.mock('./utils/formatDate'); // Breaks on refactor // GOOD โ mocking external boundary jest.mock('./services/paymentGateway'); // Third-party API is the boundary
MockDon't MockHTTP APIs, external servicesPure functionsDatabase (in unit tests)Your own domain logicFile system, networkData transformationsTime/Date (Date.now)Simple calculationsEnvironment variablesInternal class methods
Structure code so dependencies can be swapped in tests. This is the single most impactful pattern for testable code. // Injectable dependencies โ easy to test class OrderService { constructor( private paymentGateway: PaymentGateway, private inventory: InventoryService, private notifier: NotificationService, ) {} async placeOrder(order: Order): Promise<OrderResult> { const stock = await this.inventory.check(order.items); if (!stock.available) return { status: 'out_of_stock' }; const payment = await this.paymentGateway.charge(order.total); if (!payment.success) return { status: 'payment_failed' }; await this.notifier.send(order.userId, 'Order confirmed'); return { status: 'confirmed', id: payment.transactionId }; } } // In tests โ inject fakes const service = new OrderService( new FakePaymentGateway(), new FakeInventory({ available: true }), new FakeNotifier(), );
FrameworkLanguageTypeTest RunnerAssertionJestJS/TSUnit/IntegrationBuilt-inexpect()VitestJS/TSUnit/IntegrationVite-nativeexpect() (Jest-compatible)PlaywrightJS/TS/PythonE2EBuilt-inexpect() / locatorsCypressJS/TSE2EBuilt-incy.should()pytestPythonUnit/IntegrationBuilt-inassertGo testingGoUnit/Integrationgo testt.Error() / testifyRustRustUnit/Integrationcargo testassert!() / assert_eq!()JUnit 5Java/KotlinUnit/IntegrationBuilt-inassertEquals()RSpecRubyUnit/IntegrationBuilt-inexpect().toPHPUnitPHPUnit/IntegrationBuilt-in$this->assert*()xUnitC#Unit/IntegrationBuilt-inAssert.Equal()
QualityRuleWhyDeterministicSame input produces same result, every timeFlaky tests erode trustIsolatedNo shared mutable state between testsOrder-dependent tests break in CIFastUnit: < 10ms, Integration: < 1s, E2E: < 30sSlow tests don't get runReadableTest name describes the scenario and expectationTests are documentationMaintainableChange one behavior, change one testBrittle tests slow developmentFocusedOne logical assertion per testFailures pinpoint the problem Naming convention: test_[unit]_[scenario]_[expected result] or should [do X] when [condition Y]
TargetWhenRationale80%+ line coverageBusiness logic, utilities, core domainHigh ROI โ catches most regressions90%+ branch coveragePayment processing, auth, security-criticalEdge cases matter here100% coverageAlmost never โ diminishing returnsGetter/setter tests add noise, not confidenceMutation testingCritical paths after coverage is highVerifies tests actually catch bugs
SkipReasonGenerated code (Prisma client, protobuf)Maintained by toolingThird-party library internalsNot your responsibilitySimple getters/settersNo logic to verifyConfiguration filesTest the behavior they configure insteadConsole.log / print statementsSide effects with no business value
src/ โโโ services/ โ โโโ order.service.ts โ โโโ order.service.test.ts # Co-located unit tests โโโ api/ โ โโโ routes/ โ โโโ orders.ts tests/ โโโ integration/ โ โโโ api/ โ โ โโโ orders.test.ts # API integration tests โ โโโ db/ โ โโโ order.repo.test.ts # DB integration tests โโโ e2e/ โ โโโ pages/ # Page objects โ โ โโโ checkout.page.ts โ โโโ specs/ โ โโโ checkout.spec.ts # E2E specs โโโ helpers/ โโโ factories.ts # Test data factories โโโ setup.ts # Global test setup Rule: Co-locate unit tests with source. Separate integration and E2E tests into dedicated directories.
Anti-PatternProblemFixTesting implementationTests break on refactor, not on bugsTest behavior and outputs, not internalsFlaky testsNon-deterministic failures erode CI trustRemove time/order/network dependenciesTest pollutionShared mutable state leaks between testsReset state in beforeEach / setUpSleeping in testssleep(2000) is slow and unreliableUse explicit waits, polling, or eventsGiant arrange50 lines of setup obscure intentExtract factories/builders/fixturesAssert-free testsTest runs but verifies nothingEvery test must assert or expectOvermockingMocking everything tests nothing realOnly mock external boundariesCopy-paste testsDuplicated tests diverge and rotUse parameterized tests or helpersTesting the frameworkVerifying library code worksTest your logic, trust dependenciesIgnoring test failuresskip, xit, @Disabled accumulateFix or delete โ never hoard skipped testsTight coupling to DBTests fail when schema changesUse repository pattern + fakes for unit testsOne giant testSingle test covers 10 scenariosSplit into focused, named testsNo test for bug fixRegression reappears laterEvery bug fix gets a regression test
NEVER test implementation details instead of behavior โ tests must verify what the code does, not how it does it NEVER use sleep() in tests โ use explicit waits, polling, events, or assertions that auto-retry NEVER share mutable state between tests โ each test sets up and tears down its own state NEVER write assert-free tests โ a test that asserts nothing proves nothing NEVER mock internal domain logic โ only mock at system boundaries (network, DB, filesystem, clock) NEVER skip tests without a linked issue and a plan to re-enable โ skipped tests rot into permanent gaps NEVER leave a test suite in a failing state โ fix it or remove it with justification before moving on NEVER chase 100% coverage as a goal โ coverage percentage is a tool, not a target; strong assertions on critical paths beat weak assertions everywhere
DoDon'tTest behavior, not implementationMock everything in sightWrite the test before fixing a bugSkip tests to ship fasterKeep tests fast and deterministicUse sleep() or shared stateUse factories for test dataCopy-paste setup across testsMock at system boundariesMock internal functionsName tests descriptivelyName tests test1, test2Run tests in CI on every pushOnly run tests locallyDelete or fix skipped testsLet @skip accumulate foreverUse parameterized tests for variantsDuplicate test codeInject dependencies for testabilityHard-code dependencies Remember: Tests are a safety net โ a fast, trustworthy suite lets you refactor fearlessly and ship with confidence.
Code helpers, APIs, CLIs, browser automation, testing, and developer operations.
Largest current source with strong distribution and engagement signals.