test(e2e): add comprehensive E2E tests for listings, search, payments, subscriptions, admin
Expand Playwright E2E test coverage from 17 to 86 tests covering: - Listings CRUD (create, search, filter, detail, status update) - Search (text search, geo search, validation, Typesense fallback) - Payments (create, list transactions, auth guards) - Subscriptions (plans, create, quota, billing, usage metering) - Admin authorization guards (all endpoints reject non-admin users) Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
152
e2e/api/admin.spec.ts
Normal file
152
e2e/api/admin.spec.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
import { test, expect, registerUser } from '../fixtures';
|
||||
|
||||
/**
|
||||
* Admin API E2E tests.
|
||||
*
|
||||
* These tests verify that admin endpoints enforce proper authorization.
|
||||
* Full admin workflow tests require a seeded admin user with password
|
||||
* (see prisma/seed.ts — admin phone: 0900000001).
|
||||
*/
|
||||
test.describe('Admin API — Authorization', () => {
|
||||
let regularToken: string;
|
||||
|
||||
test.beforeAll(async ({ request }) => {
|
||||
const { accessToken } = await registerUser(request);
|
||||
regularToken = accessToken;
|
||||
});
|
||||
|
||||
test.describe('GET /admin/moderation — Moderation queue', () => {
|
||||
test('rejects unauthenticated request', async ({ request }) => {
|
||||
const res = await request.get('/admin/moderation');
|
||||
|
||||
expect(res.status()).toBe(401);
|
||||
});
|
||||
|
||||
test('rejects non-admin user', async ({ request }) => {
|
||||
const res = await request.get('/admin/moderation', {
|
||||
headers: { Authorization: `Bearer ${regularToken}` },
|
||||
});
|
||||
|
||||
expect(res.status()).toBe(403);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('POST /admin/moderation/approve — Approve listing', () => {
|
||||
test('rejects unauthenticated request', async ({ request }) => {
|
||||
const res = await request.post('/admin/moderation/approve', {
|
||||
data: { listingId: 'test-id' },
|
||||
});
|
||||
|
||||
expect(res.status()).toBe(401);
|
||||
});
|
||||
|
||||
test('rejects non-admin user', async ({ request }) => {
|
||||
const res = await request.post('/admin/moderation/approve', {
|
||||
data: { listingId: 'test-id' },
|
||||
headers: { Authorization: `Bearer ${regularToken}` },
|
||||
});
|
||||
|
||||
expect(res.status()).toBe(403);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('POST /admin/moderation/reject — Reject listing', () => {
|
||||
test('rejects unauthenticated request', async ({ request }) => {
|
||||
const res = await request.post('/admin/moderation/reject', {
|
||||
data: { listingId: 'test-id', reason: 'E2E test rejection reason' },
|
||||
});
|
||||
|
||||
expect(res.status()).toBe(401);
|
||||
});
|
||||
|
||||
test('rejects non-admin user', async ({ request }) => {
|
||||
const res = await request.post('/admin/moderation/reject', {
|
||||
data: { listingId: 'test-id', reason: 'E2E test rejection reason' },
|
||||
headers: { Authorization: `Bearer ${regularToken}` },
|
||||
});
|
||||
|
||||
expect(res.status()).toBe(403);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('POST /admin/users/ban — Ban user', () => {
|
||||
test('rejects unauthenticated request', async ({ request }) => {
|
||||
const res = await request.post('/admin/users/ban', {
|
||||
data: { userId: 'test-id', reason: 'E2E test ban reason text' },
|
||||
});
|
||||
|
||||
expect(res.status()).toBe(401);
|
||||
});
|
||||
|
||||
test('rejects non-admin user', async ({ request }) => {
|
||||
const res = await request.post('/admin/users/ban', {
|
||||
data: { userId: 'test-id', reason: 'E2E test ban reason text' },
|
||||
headers: { Authorization: `Bearer ${regularToken}` },
|
||||
});
|
||||
|
||||
expect(res.status()).toBe(403);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('POST /admin/subscriptions/adjust — Adjust subscription', () => {
|
||||
test('rejects unauthenticated request', async ({ request }) => {
|
||||
const res = await request.post('/admin/subscriptions/adjust', {
|
||||
data: {
|
||||
userId: 'test-id',
|
||||
newPlanTier: 'AGENT_PRO',
|
||||
reason: 'E2E test subscription adjustment',
|
||||
},
|
||||
});
|
||||
|
||||
expect(res.status()).toBe(401);
|
||||
});
|
||||
|
||||
test('rejects non-admin user', async ({ request }) => {
|
||||
const res = await request.post('/admin/subscriptions/adjust', {
|
||||
data: {
|
||||
userId: 'test-id',
|
||||
newPlanTier: 'AGENT_PRO',
|
||||
reason: 'E2E test subscription adjustment',
|
||||
},
|
||||
headers: { Authorization: `Bearer ${regularToken}` },
|
||||
});
|
||||
|
||||
expect(res.status()).toBe(403);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('GET /admin/dashboard — Dashboard stats', () => {
|
||||
test('rejects unauthenticated request', async ({ request }) => {
|
||||
const res = await request.get('/admin/dashboard');
|
||||
|
||||
expect(res.status()).toBe(401);
|
||||
});
|
||||
|
||||
test('rejects non-admin user', async ({ request }) => {
|
||||
const res = await request.get('/admin/dashboard', {
|
||||
headers: { Authorization: `Bearer ${regularToken}` },
|
||||
});
|
||||
|
||||
expect(res.status()).toBe(403);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('GET /admin/revenue — Revenue stats', () => {
|
||||
test('rejects unauthenticated request', async ({ request }) => {
|
||||
const res = await request.get('/admin/revenue', {
|
||||
params: { startDate: '2026-01-01', endDate: '2026-12-31' },
|
||||
});
|
||||
|
||||
expect(res.status()).toBe(401);
|
||||
});
|
||||
|
||||
test('rejects non-admin user', async ({ request }) => {
|
||||
const res = await request.get('/admin/revenue', {
|
||||
params: { startDate: '2026-01-01', endDate: '2026-12-31' },
|
||||
headers: { Authorization: `Bearer ${regularToken}` },
|
||||
});
|
||||
|
||||
expect(res.status()).toBe(403);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user