Files
flyer-crawler.projectium.com/docs/subagents/TESTER-GUIDE.md
Torben Sorensen eae0dbaa8e
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 19m11s
bugsink mcp and claude subagents - documentation and test fixes
2026-01-22 11:23:45 -08:00

11 KiB

Tester and Testwriter Subagent Guide

This guide covers two related but distinct subagents for testing in the Flyer Crawler project:

  • tester: Adversarial testing to find edge cases, race conditions, and vulnerabilities
  • testwriter: Creating comprehensive test suites for features and fixes

Understanding the Difference

Aspect tester testwriter
Purpose Find bugs and weaknesses Create test coverage
Approach Adversarial, exploratory Systematic, comprehensive
Output Bug reports, security findings Test files, test utilities
When to Use Before release, security review During development, refactoring

The tester Subagent

When to Use

Use the tester subagent when you need to:

  • Find edge cases that might cause failures
  • Identify race conditions in async code
  • Test security vulnerabilities
  • Stress test APIs or database queries
  • Validate error handling paths
  • Find memory leaks or performance issues

What the tester Knows

The tester subagent understands:

  • Common vulnerability patterns (SQL injection, XSS, CSRF)
  • Race condition scenarios in Node.js
  • Edge cases in data validation
  • Authentication and authorization bypasses
  • BullMQ queue edge cases
  • Database transaction isolation issues

Example Requests

Finding edge cases:

"Use the tester subagent to find edge cases in the flyer upload
endpoint. Consider file types, sizes, concurrent uploads, and
invalid data scenarios."

Security testing:

"Use the tester subagent to review the authentication flow for
security vulnerabilities, including JWT handling, session management,
and OAuth integration."

Race condition analysis:

"Use the tester subagent to identify potential race conditions in
the shopping list sharing feature where multiple users might modify
the same list simultaneously."

Sample Output from tester

The tester subagent typically produces:

  1. Vulnerability Reports

    • Issue description
    • Reproduction steps
    • Severity assessment
    • Recommended fix
  2. Edge Case Catalog

    • Input combinations to test
    • Expected vs actual behavior
    • Priority for fixing
  3. Test Scenarios

    • Detailed test cases for the testwriter
    • Setup and teardown requirements
    • Assertions to verify

The testwriter Subagent

When to Use

Use the testwriter subagent when you need to:

  • Write unit tests for new features
  • Add integration tests for API endpoints
  • Create end-to-end test scenarios
  • Improve test coverage for existing code
  • Write regression tests for bug fixes
  • Create test utilities and factories

What the testwriter Knows

The testwriter subagent understands:

  • Project testing stack (Vitest, Testing Library, Supertest)
  • Mock factory patterns (src/tests/utils/mockFactories.ts)
  • Test helper utilities (src/tests/utils/testHelpers.ts)
  • Database cleanup patterns
  • Integration test setup with globalSetup
  • Known testing issues documented in CLAUDE.md

Testing Framework Stack

Tool Version Purpose
Vitest 4.0.15 Test runner
@testing-library/react 16.3.0 Component testing
@testing-library/jest-dom 6.9.1 DOM assertions
supertest 7.1.4 API testing
msw 2.12.3 Network mocking

Test File Organization

src/
├── components/
│   └── *.test.tsx        # Component tests (colocated)
├── hooks/
│   └── *.test.ts         # Hook tests (colocated)
├── services/
│   └── *.test.ts         # Service tests (colocated)
├── routes/
│   └── *.test.ts         # Route handler tests (colocated)
└── tests/
    ├── integration/      # Integration tests
    └── e2e/              # End-to-end tests

Example Requests

Unit tests for a new feature:

"Use the testwriter subagent to create comprehensive unit tests
for the new StoreSearchService in src/services/storeSearchService.ts.
Include edge cases for empty results, partial matches, and pagination."

Integration tests for API:

"Use the testwriter subagent to add integration tests for the
POST /api/flyers endpoint, covering successful uploads, validation
errors, authentication requirements, and file size limits."

Regression test for bug fix:

"Use the testwriter subagent to create a regression test that
verifies the fix for issue #123 where duplicate flyer items were
created when uploading certain PDFs."

Test Patterns the testwriter Uses

Unit Test Pattern

// src/services/storeSearchService.test.ts
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { createMockStore, resetMockIds } from '@/tests/utils/mockFactories';

describe('StoreSearchService', () => {
  beforeEach(() => {
    resetMockIds(); // Ensure deterministic IDs
    vi.clearAllMocks();
  });

  describe('searchByName', () => {
    it('returns matching stores when query matches', async () => {
      const mockStore = createMockStore({ name: 'Test Mart' });
      // ... test implementation
    });

    it('returns empty array when no matches found', async () => {
      // ... test implementation
    });

    it('handles special characters in search query', async () => {
      // ... test implementation
    });
  });
});

Integration Test Pattern

// src/tests/integration/stores.integration.test.ts
import supertest from 'supertest';
import { createAndLoginUser, cleanupDb } from '@/tests/utils/testHelpers';

describe('Stores API', () => {
  let request: ReturnType<typeof supertest>;
  let authToken: string;
  let testUserId: string;

  beforeAll(async () => {
    const app = (await import('../../../server')).default;
    request = supertest(app);
    const { token, userId } = await createAndLoginUser(request);
    authToken = token;
    testUserId = userId;
  });

  afterAll(async () => {
    await cleanupDb({ users: [testUserId] });
  });

  describe('GET /api/stores', () => {
    it('returns list of stores', async () => {
      const response = await request.get('/api/stores').set('Authorization', `Bearer ${authToken}`);

      expect(response.status).toBe(200);
      expect(response.body.data.stores).toBeInstanceOf(Array);
    });
  });
});

Component Test Pattern

// src/components/StoreCard.test.tsx
import { describe, it, expect, vi } from 'vitest';
import { renderWithProviders, screen } from '@/tests/utils/renderWithProviders';
import { createMockStore } from '@/tests/utils/mockFactories';
import { StoreCard } from './StoreCard';

describe('StoreCard', () => {
  it('renders store name and location count', () => {
    const store = createMockStore({
      name: 'Test Store',
      location_count: 5
    });

    renderWithProviders(<StoreCard store={store} />);

    expect(screen.getByText('Test Store')).toBeInTheDocument();
    expect(screen.getByText('5 locations')).toBeInTheDocument();
  });

  it('calls onSelect when clicked', async () => {
    const store = createMockStore();
    const handleSelect = vi.fn();

    renderWithProviders(<StoreCard store={store} onSelect={handleSelect} />);

    await userEvent.click(screen.getByText(store.name));

    expect(handleSelect).toHaveBeenCalledWith(store);
  });
});

Test Execution Environment

Critical Requirement

ALL tests MUST be executed inside the dev container (Linux environment)

Tests that pass on Windows but fail on Linux are considered broken tests.

Running Tests

# From Windows host - run in container
podman exec -it flyer-crawler-dev npm run test:unit
podman exec -it flyer-crawler-dev npm run test:integration

# Inside dev container
npm run test:unit
npm run test:integration

# Run specific test file
npm test -- --run src/services/storeService.test.ts

Test Commands Reference

Command Description
npm test All unit tests
npm run test:unit Unit tests only
npm run test:integration Integration tests (requires DB/Redis)
npm run test:coverage Tests with coverage report

Known Testing Issues

The testwriter subagent is aware of these documented issues:

1. Vitest globalSetup Context Isolation

Vitest's globalSetup runs in a separate Node.js context. Mocks and spies do NOT share instances with test files.

Impact: BullMQ worker service mocks don't work in integration tests.

Solution: Use .todo() for affected tests or create test-only API endpoints.

2. Cleanup Queue Timing

The cleanup worker may process jobs before tests can verify them.

Solution:

const { cleanupQueue } = await import('../../services/queues.server');
await cleanupQueue.drain();
await cleanupQueue.pause();
// ... run test ...
await cleanupQueue.resume();

3. Cache Stale After Direct SQL

Direct database inserts bypass cache invalidation.

Solution:

await cacheService.invalidateFlyers();

4. Unique Filenames Required

File upload tests need unique filenames to avoid collisions.

Solution:

const filename = `test-${Date.now()}-${Math.round(Math.random() * 1e9)}.jpg`;

Test Coverage Guidelines

When Writing Tests

  1. Unit Tests (required for all new code):

    • Pure functions and utilities
    • React components
    • Custom hooks
    • Service methods
    • Repository methods
  2. Integration Tests (required for API changes):

    • New API endpoints
    • Authentication flows
    • Middleware behavior
  3. E2E Tests (for critical paths):

    • User registration/login
    • Flyer upload workflow
    • Admin operations

Test Isolation

  1. Reset mock IDs in beforeEach()
  2. Use unique test data (timestamps, UUIDs)
  3. Clean up after tests with cleanupDb()
  4. Don't share state between tests

Combining tester and testwriter

A typical workflow for thorough testing:

  1. Development: Write code with basic tests using testwriter
  2. Edge Cases: Use tester to identify edge cases and vulnerabilities
  3. Coverage: Use testwriter to add tests for identified edge cases
  4. Review: Use code-reviewer to verify test quality

Example Combined Workflow

1. "Use testwriter to create initial tests for the new discount
   calculation feature"

2. "Use tester to find edge cases in the discount calculation -
   consider rounding errors, negative values, percentage limits,
   and currency precision"

3. "Use testwriter to add tests for the edge cases identified:
   - Rounding to 2 decimal places
   - Negative discount values
   - Discounts over 100%
   - Very small amounts (under $0.01)"