Jest testing patterns — test structure, mocking, async testing, snapshot
99
99%
Does it follow best practices?
Impact
99%
1.26xAverage score across 6 eval scenarios
Passed
No known issues
The billing team has a PaymentService that processes charges through an external payment gateway. A junior engineer wrote a starter test file but left it incomplete — it covers only the most basic happy path and is missing coverage for validation logic and error scenarios.
Your task is to extend the existing test file to achieve thorough coverage. The PaymentService has an internal validateAmount method that sanity-checks the charge amount before contacting the gateway. The team wants tests that verify this internal validation is called correctly during payment processing, without replacing the real implementation entirely, so any bugs introduced into validateAmount would still be caught.
Extend (or rewrite if necessary) the test file at src/billing/__tests__/paymentService.test.ts with a complete test suite.
Tests should cover at minimum:
src/billing/paymentService.tsimport { GatewayClient } from '../gateway/gatewayClient';
export class PaymentService {
constructor(private readonly gateway: GatewayClient) {}
async charge(userId: string, amount: number): Promise<{ transactionId: string }> {
this.validateAmount(amount);
const result = await this.gateway.processCharge({ userId, amount });
return { transactionId: result.id };
}
validateAmount(amount: number): void {
if (amount <= 0) {
throw new Error('Amount must be greater than zero');
}
}
}src/gateway/gatewayClient.tsexport interface ChargeRequest {
userId: string;
amount: number;
}
export interface ChargeResult {
id: string;
status: string;
}
export class GatewayClient {
async processCharge(req: ChargeRequest): Promise<ChargeResult> {
throw new Error('Not implemented');
}
}src/billing/__tests__/paymentService.test.ts (starter file — extend this)import { PaymentService } from '../paymentService';
import { GatewayClient } from '../../gateway/gatewayClient';
jest.mock('../../gateway/gatewayClient');
const mockProcessCharge = GatewayClient.prototype.processCharge as jest.MockedFunction<
typeof GatewayClient.prototype.processCharge
>;
describe('PaymentService', () => {
let service: PaymentService;
let gateway: GatewayClient;
beforeEach(() => {
jest.clearAllMocks();
gateway = new GatewayClient();
service = new PaymentService(gateway);
});
describe('charge', () => {
it('returns a transaction id on success', async () => {
mockProcessCharge.mockResolvedValueOnce({ id: 'txn_001', status: 'success' });
const result = await service.charge('user_1', 50);
expect(result.transactionId).toBe('txn_001');
});
});
});