Files
HOA_Financial_Platform/tests/api/accounts.api.spec.ts
JoeBot dfd1bccb89 feat: add Playwright E2E and API regression test suite
Production-ready test infrastructure with Page Object Model pattern,
reusable fixtures for auth/DB/test-data, and example tests covering
login flow, dashboard, accounts CRUD API, and visual regression.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 12:40:05 -04:00

141 lines
4.3 KiB
TypeScript

/**
* API regression tests for the Accounts endpoint.
*
* Tests CRUD operations on /api/accounts.
* Requires authentication — logs in first to get a Bearer token.
*/
import { test, expect } from '@playwright/test';
import { apiLogin, apiSwitchOrg, authHeaders } from '../fixtures/auth.fixture';
import { TEST_USERS, TEST_PREFIX } from '../fixtures/test-data';
const API_BASE = process.env.API_BASE_URL || 'http://localhost/api';
let accessToken: string;
test.beforeAll(async ({ request }) => {
// Login and switch to test org
const tokens = await apiLogin(request, TEST_USERS.treasurer);
if (tokens.organizations?.length > 0) {
const orgId = (tokens.organizations[0] as any).id;
try {
const switched = await apiSwitchOrg(request, tokens.accessToken, orgId);
accessToken = switched.accessToken;
} catch {
accessToken = tokens.accessToken;
}
} else {
accessToken = tokens.accessToken;
}
});
test.describe('GET /api/accounts', () => {
test('should return accounts list', async ({ request }) => {
const response = await request.get(`${API_BASE}/accounts`, {
headers: authHeaders(accessToken),
});
expect(response.status()).toBe(200);
const accounts = await response.json();
expect(Array.isArray(accounts)).toBe(true);
});
test('should return 401 without auth', async ({ request }) => {
const response = await request.get(`${API_BASE}/accounts`);
expect(response.status()).toBe(401);
});
test('should filter by fund type', async ({ request }) => {
const response = await request.get(`${API_BASE}/accounts?fundType=operating`, {
headers: authHeaders(accessToken),
});
expect(response.status()).toBe(200);
const accounts = await response.json();
expect(Array.isArray(accounts)).toBe(true);
});
});
test.describe('Accounts CRUD', () => {
let createdAccountId: string;
test('should create a new account', async ({ request }) => {
const response = await request.post(`${API_BASE}/accounts`, {
headers: authHeaders(accessToken),
data: {
name: `${TEST_PREFIX}Operating Checking`,
number: '1099',
accountType: 'asset',
fundType: 'operating',
description: 'E2E test account — safe to delete',
},
});
expect(response.status()).toBe(201);
const account = await response.json();
expect(account).toHaveProperty('id');
expect(account.name).toBe(`${TEST_PREFIX}Operating Checking`);
createdAccountId = account.id;
});
test('should get the created account', async ({ request }) => {
test.skip(!createdAccountId, 'No account was created');
const response = await request.get(`${API_BASE}/accounts/${createdAccountId}`, {
headers: authHeaders(accessToken),
});
expect(response.status()).toBe(200);
const account = await response.json();
expect(account.id).toBe(createdAccountId);
expect(account.name).toBe(`${TEST_PREFIX}Operating Checking`);
});
test('should update the account', async ({ request }) => {
test.skip(!createdAccountId, 'No account was created');
const response = await request.put(`${API_BASE}/accounts/${createdAccountId}`, {
headers: authHeaders(accessToken),
data: {
name: `${TEST_PREFIX}Updated Checking`,
description: 'Updated by E2E test',
},
});
expect(response.status()).toBe(200);
const account = await response.json();
expect(account.name).toBe(`${TEST_PREFIX}Updated Checking`);
});
test('should appear in accounts list', async ({ request }) => {
test.skip(!createdAccountId, 'No account was created');
const response = await request.get(`${API_BASE}/accounts`, {
headers: authHeaders(accessToken),
});
const accounts = await response.json();
const found = accounts.find((a: any) => a.id === createdAccountId);
expect(found).toBeTruthy();
expect(found.name).toBe(`${TEST_PREFIX}Updated Checking`);
});
});
test.describe('GET /api/accounts/trial-balance', () => {
test('should return trial balance data', async ({ request }) => {
const response = await request.get(`${API_BASE}/accounts/trial-balance`, {
headers: authHeaders(accessToken),
});
expect(response.status()).toBe(200);
const data = await response.json();
// Trial balance returns an object or array with debit/credit totals
expect(data).toBeDefined();
});
});