askill
testing-flexible

testing-flexibleSafety 90Repository

Use when implementing features to write effective tests. Encourages test-first but allows prototyping.

0 stars
1.2k downloads
Updated 2/5/2026

Package Files

Loading files...
SKILL.md

Flexible Testing

Overview

Write tests for critical paths and complex logic. Test-first is encouraged but not mandatory.

Core principle: Tests should give you confidence, not slow you down.

When to Use

Strong recommendation (test-first):

  • Complex business logic
  • Edge cases and error handling
  • Security-critical code
  • Bug fixes (test reproduces bug first)
  • Public API surfaces

Optional (test-after or skip):

  • UI/view code that changes frequently
  • Prototype/exploration phase
  • Configuration and setup
  • Generated code
  • Simple CRUD operations

Two Modes

Production Mode (Default)

Write tests for critical functionality. Test-first encouraged.

1. Write failing test for critical behavior
2. Implement minimal code to pass
3. Add tests for edge cases
4. Refactor with confidence

Prototype Mode

Exploring ideas? Skip tests temporarily.

1. Build the prototype
2. Get feedback, iterate
3. Once design is stable: write tests
4. Or: throw away prototype, rebuild with tests

To enter prototype mode: Tell Claude "I'm prototyping" or "skip tests for now"

What to Test

Always Test

AreaWhy
Business logicCore value of your app
Data transformationsEasy to get wrong
API responsesContract with clients
Auth/permissionsSecurity critical
Error handlingUsers will hit edge cases

Consider Testing

AreaWhen
UI componentsWhen logic is complex
Integration pointsWhen external APIs involved
PerformanceWhen SLAs matter

Usually Skip

AreaWhy
UI layoutChanges frequently, hard to test
Third-party codeAlready tested
Trivial getters/settersNo logic to test
Generated codeTrust the generator

Test-First Pattern

When you do write test-first, follow RED-GREEN-REFACTOR:

RED - Failing Test

test('retries failed operations 3 times', async () => {
  let attempts = 0;
  const operation = () => {
    attempts++;
    if (attempts < 3) throw new Error('fail');
    return 'success';
  };

  const result = await retryOperation(operation);

  expect(result).toBe('success');
  expect(attempts).toBe(3);
});

GREEN - Make It Pass

async function retryOperation<T>(fn: () => Promise<T>): Promise<T> {
  for (let i = 0; i < 3; i++) {
    try {
      return await fn();
    } catch (e) {
      if (i === 2) throw e;
    }
  }
  throw new Error('unreachable');
}

REFACTOR - Clean Up

Once tests pass, improve the code while keeping tests green.

Swift/XCTest Specifics

Basic Test Structure

import XCTest
@testable import YourApp

final class GradingServiceTests: XCTestCase {

    func test_gradeReturnsScoreForValidImage() async throws {
        let service = GradingService()
        let result = try await service.grade(image: testImage)

        XCTAssertNotNil(result.score)
        XCTAssertGreaterThan(result.score!, 0)
    }

    func test_gradeThrowsForInvalidImage() async {
        let service = GradingService()

        do {
            _ = try await service.grade(image: Data())
            XCTFail("Expected error")
        } catch {
            // Expected
        }
    }
}

Testing Actors

func test_actorStateIsolated() async {
    let service = SyncService()

    // Actor methods are async
    await service.sync(item: testItem)

    let synced = await service.pendingItems
    XCTAssertTrue(synced.isEmpty)
}

Testing @Observable

func test_authStateUpdatesOnSignIn() async throws {
    let authService = AuthService()

    XCTAssertFalse(authService.isAuthenticated)

    try await authService.signIn(with: mockCredentials)

    XCTAssertTrue(authService.isAuthenticated)
}

TypeScript/Vitest Specifics

Basic Test Structure

import { describe, it, expect } from 'vitest'
import { gradeImage } from './grading'

describe('gradeImage', () => {
  it('returns score for valid image', async () => {
    const result = await gradeImage(testImageBase64)

    expect(result.score).toBeDefined()
    expect(result.score).toBeGreaterThan(0)
  })

  it('throws for invalid image', async () => {
    await expect(gradeImage('')).rejects.toThrow()
  })
})

Testing Edge Functions

import { createClient } from '@supabase/supabase-js'

describe('process-item function', () => {
  it('returns 401 without auth', async () => {
    const response = await fetch(`${FUNCTION_URL}/process-item`, {
      method: 'POST',
      body: JSON.stringify({ itemId: '123' })
    })

    expect(response.status).toBe(401)
  })
})

Good Tests

QualityGoodBad
FocusedOne behavior per testtest('validates, saves, and notifies')
ReadableClear name describes what's testedtest('test1')
IndependentNo shared state between testsTests fail in isolation
FastMilliseconds, not secondsSlow tests get skipped

When Tests Are Hard

If testing is painful, the design might be the problem:

SymptomLikely CauseFix
Need many mocksToo coupledDependency injection
Huge setupComplex object graphSimplify design
Flaky testsHidden state/timingMake dependencies explicit
Can't test in isolationGod objectsBreak into smaller units

Checklist Before Shipping

[ ] Critical paths have tests
[ ] Edge cases covered
[ ] Error cases handled
[ ] Tests pass
[ ] No flaky tests

Don't need 100% coverage. Need confidence in critical functionality.

Install

Download ZIP
Requires askill CLI v1.0+

AI Quality Score

95/100Analyzed 2/12/2026

An exceptional skill document that provides a balanced, pragmatic approach to testing. It includes clear triggers for different 'modes', high-quality code examples for multiple ecosystems (Swift and TypeScript), and excellent troubleshooting guidance for architectural issues.

90
100
90
95
95

Metadata

Licenseunknown
Version-
Updated2/5/2026
Publishermajiayu000

Tags

apici-cdllmsecuritytesting