Files
goodgo-platform/e2e/api/subscriptions.spec.ts
Ho Ngoc Hai da10ac64c6 test(e2e): update all E2E specs for latest API and fixtures
Update 17 E2E test files including admin, auth, inquiries, listings,
payments, search, subscriptions, and MCP specs. Update listings fixture
and global setup to align with latest schema changes.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-11 01:40:45 +07:00

205 lines
6.9 KiB
TypeScript

import { test, expect, registerUser } from '../fixtures';
test.describe('Subscriptions API', () => {
let accessToken: string;
test.beforeAll(async ({ request }) => {
const { accessToken: token } = await registerUser(request);
accessToken = token;
});
test.describe('GET /subscriptions/plans — List plans', () => {
test('returns all available subscription plans', async ({ request }) => {
const res = await request.get('subscriptions/plans');
expect(res.status()).toBe(200);
const body = await res.json();
expect(Array.isArray(body)).toBeTruthy();
expect(body.length).toBeGreaterThan(0);
// Verify plan structure
const plan = body[0];
expect(plan).toHaveProperty('tier');
expect(plan).toHaveProperty('name');
expect(plan).toHaveProperty('priceMonthlyVND');
});
test('includes FREE tier in plans', async ({ request }) => {
const res = await request.get('subscriptions/plans');
const body = await res.json();
const freePlan = body.find((p: { tier: string }) => p.tier === 'FREE');
expect(freePlan).toBeDefined();
});
});
test.describe('GET /subscriptions/plans/:tier — Get specific plan', () => {
test('returns plan details for FREE tier', async ({ request }) => {
const res = await request.get('subscriptions/plans/FREE');
expect(res.status()).toBe(200);
const body = await res.json();
expect(body.tier).toBe('FREE');
expect(body).toHaveProperty('name');
expect(body).toHaveProperty('maxListings');
});
test('returns plan details for AGENT_PRO tier', async ({ request }) => {
const res = await request.get('subscriptions/plans/AGENT_PRO');
expect(res.status()).toBe(200);
const body = await res.json();
expect(body.tier).toBe('AGENT_PRO');
});
test('returns 404 for non-existent tier', async ({ request }) => {
const res = await request.get('subscriptions/plans/NONEXISTENT');
expect(res.ok()).toBeFalsy();
expect([404, 400]).toContain(res.status());
});
});
test.describe('POST /subscriptions — Create subscription', () => {
test('creates a FREE subscription', async ({ request }) => {
const res = await request.post('subscriptions', {
data: { planTier: 'FREE', billingCycle: 'monthly' },
headers: { Authorization: `Bearer ${accessToken}` },
});
// May succeed or conflict if user already has subscription
expect([201, 409]).toContain(res.status());
if (res.status() === 201) {
const body = await res.json();
expect(body).toHaveProperty('subscriptionId');
expect(body).toHaveProperty('planTier');
}
});
test('rejects subscription with invalid plan tier', async ({ request }) => {
const res = await request.post('subscriptions', {
data: { planTier: 'INVALID_TIER', billingCycle: 'monthly' },
headers: { Authorization: `Bearer ${accessToken}` },
});
expect(res.ok()).toBeFalsy();
expect(res.status()).toBe(400);
});
test('rejects subscription with invalid billing cycle', async ({ request }) => {
const res = await request.post('subscriptions', {
data: { planTier: 'FREE', billingCycle: 'weekly' },
headers: { Authorization: `Bearer ${accessToken}` },
});
expect(res.ok()).toBeFalsy();
expect(res.status()).toBe(400);
});
test('rejects unauthenticated subscription creation', async ({ request }) => {
const res = await request.post('subscriptions', {
data: { planTier: 'FREE', billingCycle: 'monthly' },
});
expect(res.status()).toBe(401);
});
});
test.describe('GET /subscriptions/quota/:metric — Check quota', () => {
test('returns quota for listings metric', async ({ request }) => {
// Ensure user has a subscription first
await request.post('subscriptions', {
data: { planTier: 'FREE', billingCycle: 'monthly' },
headers: { Authorization: `Bearer ${accessToken}` },
});
const res = await request.get('subscriptions/quota/listings', {
headers: { Authorization: `Bearer ${accessToken}` },
});
// 200 if subscription exists, 404 if no subscription
if (res.status() === 200) {
const body = await res.json();
expect(body).toHaveProperty('limit');
expect(body).toHaveProperty('used');
expect(body).toHaveProperty('remaining');
}
});
test('rejects unauthenticated quota check', async ({ request }) => {
const res = await request.get('subscriptions/quota/listings');
expect(res.status()).toBe(401);
});
});
test.describe('POST /subscriptions/usage — Meter usage', () => {
test('meters usage for authenticated user', async ({ request }) => {
const res = await request.post('subscriptions/usage', {
data: { metric: 'listings', count: 1 },
headers: { Authorization: `Bearer ${accessToken}` },
});
// 200/201 if subscription exists, 404 if not
expect([200, 201, 404]).toContain(res.status());
});
test('rejects usage with invalid count', async ({ request }) => {
const res = await request.post('subscriptions/usage', {
data: { metric: 'listings', count: -1 },
headers: { Authorization: `Bearer ${accessToken}` },
});
expect(res.ok()).toBeFalsy();
expect(res.status()).toBe(400);
});
});
test.describe('GET /subscriptions/billing — Billing history', () => {
test('returns billing history for authenticated user', async ({ request }) => {
const res = await request.get('subscriptions/billing', {
headers: { Authorization: `Bearer ${accessToken}` },
});
expect(res.status()).toBe(200);
const body = await res.json();
// Response contains subscription, payments, and total
expect(body).toHaveProperty('payments');
expect(Array.isArray(body.payments)).toBeTruthy();
});
test('supports pagination', async ({ request }) => {
const res = await request.get('subscriptions/billing', {
params: { limit: 5, offset: 0 },
headers: { Authorization: `Bearer ${accessToken}` },
});
expect(res.status()).toBe(200);
});
test('rejects unauthenticated billing request', async ({ request }) => {
const res = await request.get('subscriptions/billing');
expect(res.status()).toBe(401);
});
});
test.describe('PUT /subscriptions/upgrade — Upgrade subscription', () => {
test('rejects unauthenticated upgrade', async ({ request }) => {
const res = await request.put('subscriptions/upgrade', {
data: { newPlanTier: 'AGENT_PRO' },
});
expect(res.status()).toBe(401);
});
});
test.describe('DELETE /subscriptions — Cancel subscription', () => {
test('rejects unauthenticated cancellation', async ({ request }) => {
const res = await request.delete('subscriptions');
expect(res.status()).toBe(401);
});
});
});