Write, extend, and run Jest unit/integration tests for POSCursor (Expo RN + WatermelonDB LokiJS). Use when adding services/screens/hooks, fixing failing Jest tests, following TDD, or choosing mocks/createTestDatabase patterns. Do not use for Playwright E2E or the full release matrix — use systematic-test-matrix instead.
73
92%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Passed
No findings from the security scan
| Need | Skill |
|---|---|
| Author/fix Jest unit or service tests | This skill (testing) |
| Full QA ladder (tsc → Jest buckets → Playwright → export smoke) | systematic-test-matrix |
| Deploy after green QA | deploy-poscursor |
| Sync engine debugging | sync-debug |
As of 2026-09-11 (local npx jest --no-coverage):
| Metric | Value |
|---|---|
| Suites | ~193 |
| Tests | ~1554 |
| Typical wall time | ~50–60s (maxWorkers: 2) |
| Playwright | Separate; under tests/ (ignored by Jest) |
Prefer targeted Jest while iterating. Use the matrix only for release confidence.
| Layer | Tech |
|---|---|
| Runner | jest-expo (jest.config.js) |
| Setup | src/jest-setup.ts |
| Assertions | @testing-library/jest-native/extend-expect |
| Test DB | LokiJS via createTestDatabase() in src/__tests__/test-utils.ts |
| Timeout | 15s (testTimeout) |
| Workers | maxWorkers: 2 |
| Coverage | src/**/*.{js,jsx,ts,tsx} excl. .d.ts, mocks/, assets/, generatedAppUpdates.ts |
src/jest-setup.ts blocks production Supabase via isProductionSupabaseUrl(). If EXPO_PUBLIC_SUPABASE_URL points at production, tests throw immediately.
Use .env.test or rely on fallbacks set in setup:
EXPO_PUBLIC_SUPABASE_URL=https://example.supabase.co
EXPO_PUBLIC_SUPABASE_ANON_KEY=dummy-keyNever point Jest at jetfarm-placeholder-db (production). Playwright has its own safety check in playwright.config.ts.
__tests__/Name.test.ts(x)).Co-locate tests:
src/services/__tests__/ (or src/services/<area>/__tests__/)src/database/models/__tests__/src/hooks/__tests__/src/components/__tests__/app/(role)/…/__tests__/Prefer constructor/Database injection when the service supports it:
import { createTestDatabase } from '../../__tests__/test-utils';
import { Database } from '@nozbe/watermelondb';
import { ActionLogService } from '../ActionLogService';
let database: Database;
let service: ActionLogService;
beforeEach(() => {
database = createTestDatabase();
service = new ActionLogService(database);
jest.clearAllMocks();
});databaseWhen the class imports database from src/database, mock the module and inject LokiJS (see MonthlyClosingService.test.ts):
jest.mock('../../database', () => {
const { createTestDatabase } = jest.requireActual('../../__tests__/test-utils');
return { database: createTestDatabase() };
});
import { database } from '../../database';
beforeEach(async () => {
await database.write(async () => {
const rows = await database.get('financial_snapshots').query().fetch();
for (const row of rows) await row.destroyPermanently();
});
jest.clearAllMocks();
});Avoid unsafeResetDatabase() on LokiJS — it can hang/destroy the adapter. Delete rows manually instead.
Use @testing-library/react-native. Mock navigation, auth, and heavy children:
import { render, fireEvent, waitFor } from '@testing-library/react-native';
jest.mock('expo-router', () => ({
useRouter: () => ({ push: jest.fn(), back: jest.fn(), replace: jest.fn() }),
}));
jest.mock('../../../src/store/AuthContext', () => ({
useAuth: () => ({
user: { id: 'user-1', email: 'cashier@poscursor.com' },
branchId: 'branch-1',
}),
}));Reference: app/(cashier)/__tests__/returns.test.tsx.
Auto-mock src/database/supabase via src/database/__mocks__/supabase.ts (chainable .from().select()…). Do not hit live networks in unit tests.
__mocks__/)src/database/__mocks__/index.ts — global databasesrc/database/__mocks__/supabase.ts — Supabase client stubsrc/jest-setup.ts)react-native-gesture-handler, expo-blur, react-native-safe-area-context@expo/vector-icons, @react-native-async-storage/async-storagereact-native-reanimated, react-native-worklets / worklets-corenativewind (cssInterop, styled, …)jest.mock('../AuthService', () => ({
AuthService: { getCurrentUserId: jest.fn().mockResolvedValue('user-123') },
}));
jest.mock('../../components/AppToast', () => ({ show: jest.fn() }));# Fast full suite (preferred day-to-day)
npx jest --no-coverage
# One file
npx jest src/services/__tests__/CashService.test.ts --no-coverage
# One file with focused coverage
npx jest src/services/__tests__/CashService.test.ts --coverage --collectCoverageFrom="src/services/CashService.ts"
# Bucket
npx jest src/services/__tests__/ --no-coverage
npx jest "app/(cashier)/__tests__/" --no-coverage
# npm script (same runner; may include coverage depending on invocation)
npm test -- --no-coverageWindows tip: quote paths with parentheses, e.g. "app/(admin)/reports/__tests__/".
Directories with real *.test.* files (matrix script discovers these dynamically):
| Bucket | Approx. files |
|---|---|
src/services/__tests__ | ~89 |
src/utils/__tests__ | ~21 |
src/components/__tests__ | ~15 |
app/(admin)/settings/__tests__ | ~7 |
app/(admin)/reports/__tests__ | ~7 |
src/hooks/__tests__ | ~6 |
app/(cashier)/__tests__ | ~5 |
src/services/cic/__tests__ | ~5 |
app/(admin)/accounting/__tests__ | ~5 |
+ models, store(s), config, constants, modules, other app/(*) | … |
Also: regression files outside __tests__ folders (e.g. src/database/supabaseMigrations.regression.test.ts) still match Jest testMatch and run in the full suite.
High-value services still thin/untested (exclude configs/fixtures):
BusinessUnitService.tsDividendService.tsMarketplaceOrderService.ts / MarketplacePayoutService.ts / MarketplaceProductService.ts / MarketplaceSalesPostingService.ts / MarketplaceStoreService.tscic/CicFormatterService.tsWhen asked to “improve test coverage,” start here with TDD, not blanket snapshot churn.
babel.config.js disables NativeWind transform when NODE_ENV=test.@babel/plugin-proposal-decorators (legacy) + babel-plugin-transform-typescript-metadata — do not remove for WatermelonDB.testPathIgnorePatterns excludes <rootDir>/tests/ (Playwright) and src/__tests__/test-utils.ts.unsafeResetDatabase().npx jest <path> --no-coverage.references/patterns.md../systematic-test-matrix/SKILL.mdzazakia/JetFarm
bdf360f
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.