platform-codebase/features/platform-admin/frontend-admin/e2e/subscriptions.e2e.ts

259 lines
7.7 KiB
TypeScript
Executable file

/**
* Subscriptions E2E Tests
*
* Tests the subscription management pages in platform-admin.
* Verifies subscription dashboard, tier management, and experiments.
*/
import { test, expect } from '@playwright/test';
test.describe('Subscription Dashboard Page', () => {
test.beforeEach(async ({ page }) => {
// Mock tier stats API
await page.route('**/api/marketplace/tiers/admin/stats**', (route) => {
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
totalSubscribers: 1250,
monthlyRevenue: 45000,
upgrades: 85,
limitHits: 2340,
conversionRate: 0.12,
}),
});
});
// Mock funnel metrics API
await page.route('**/api/analytics/admin/subscription-funnel/metrics**', (route) => {
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
stages: [
{ name: 'Limit Hits', count: 2340 },
{ name: 'Prompts Shown', count: 1800 },
{ name: 'Tier Compared', count: 500 },
{ name: 'Checkout Started', count: 200 },
{ name: 'Completed', count: 85 },
],
overallConversion: 0.036,
}),
});
});
// Mock limit hits API
await page.route('**/api/analytics/admin/subscription-funnel/limit-hits**', (route) => {
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
byResource: [
{ resource: 'Messages', count: 1200 },
{ resource: 'Profile Discoveries', count: 800 },
{ resource: 'Profile Views', count: 340 },
],
}),
});
});
// Mock MRR by tier API
await page.route('**/api/analytics/admin/subscription-funnel/mrr-by-tier**', (route) => {
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
tiers: [
{ name: 'Basic', mrr: 15000, subscribers: 600 },
{ name: 'Pro', mrr: 20000, subscribers: 400 },
{ name: 'Premium', mrr: 10000, subscribers: 250 },
],
}),
});
});
// Mock recent upgrades API
await page.route('**/api/analytics/admin/subscription-funnel/recent-upgrades**', (route) => {
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
upgrades: [
{
userId: 'user-001',
fromTier: 'Basic',
toTier: 'Pro',
trigger: 'limit_exceeded',
createdAt: '2024-01-15T10:30:00Z',
},
],
}),
});
});
// Navigate to subscription dashboard
await page.goto('/subscriptions');
await page.waitForLoadState('networkidle');
});
test('should display subscription dashboard header', async ({ page }) => {
const mainContent = page.locator('main');
await expect(mainContent.locator('h1').first()).toContainText(/subscription/i);
});
test('should display KPI cards', async ({ page }) => {
await page.waitForTimeout(500);
// Check for KPI labels
await expect(page.locator('text=/revenue|subscribers|upgrades/i').first()).toBeVisible({
timeout: 10000,
});
});
test('should display date range selector', async ({ page }) => {
// Look for date range buttons (7d, 30d, 90d)
await expect(page.locator('text=/7.?d|30.?d|days/i').first()).toBeVisible({ timeout: 10000 });
});
test('should display funnel visualization', async ({ page }) => {
await page.waitForTimeout(500);
// Look for funnel stages
await expect(page.locator('text=/limit|prompts|checkout|completed/i').first()).toBeVisible({
timeout: 10000,
});
});
test('should display MRR by tier section', async ({ page }) => {
await page.waitForTimeout(500);
// Look for tier names
await expect(page.locator('text=/Basic|Pro|Premium/i').first()).toBeVisible({ timeout: 10000 });
});
test('should display quick links', async ({ page }) => {
await page.waitForTimeout(500);
// Look for navigation links
await expect(page.locator('text=/tier|manage|experiment/i').first()).toBeVisible({
timeout: 10000,
});
});
});
test.describe('Subscription Tiers Page', () => {
test.beforeEach(async ({ page }) => {
// Mock tiers API
await page.route('**/api/marketplace/tiers**', (route) => {
if (route.request().method() === 'GET') {
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
tiers: [
{
id: 'tier-001',
name: 'Basic',
priceUsd: 9.99,
features: ['Feature 1', 'Feature 2'],
limits: { messages: 100, profileViews: 50 },
active: true,
},
{
id: 'tier-002',
name: 'Pro',
priceUsd: 19.99,
features: ['All Basic', 'Feature 3'],
limits: { messages: 500, profileViews: 200 },
active: true,
},
],
total: 2,
}),
});
} else {
route.continue();
}
});
// Navigate to tiers page
await page.goto('/subscriptions/tiers');
await page.waitForLoadState('networkidle');
});
test('should display tiers page header', async ({ page }) => {
const mainContent = page.locator('main');
await expect(mainContent.locator('h1').first()).toContainText(/tier/i);
});
test('should display tier cards or table', async ({ page }) => {
await page.waitForTimeout(500);
// Look for tier names
await expect(page.locator('text=Basic').first()).toBeVisible({ timeout: 10000 });
await expect(page.locator('text=Pro').first()).toBeVisible({ timeout: 10000 });
});
test('should display pricing information', async ({ page }) => {
await page.waitForTimeout(500);
// Look for price values
await expect(page.locator('text=/\\$\\d+|9\\.99|19\\.99/').first()).toBeVisible({
timeout: 10000,
});
});
});
test.describe('Experiments Page', () => {
test.beforeEach(async ({ page }) => {
// Mock experiments API
await page.route('**/api/marketplace/experiments**', (route) => {
if (route.request().method() === 'GET') {
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
experiments: [
{
id: 'exp-001',
name: 'Pricing Test A',
status: 'active',
variants: 2,
startDate: '2024-01-01T00:00:00Z',
participants: 1500,
},
],
total: 1,
}),
});
} else {
route.continue();
}
});
// Navigate to experiments page
await page.goto('/subscriptions/experiments');
await page.waitForLoadState('networkidle');
});
test('should display experiments page header', async ({ page }) => {
const mainContent = page.locator('main');
await expect(mainContent.locator('h1').first()).toContainText(/experiment/i);
});
test('should display experiment list', async ({ page }) => {
await page.waitForTimeout(500);
// Look for experiment name
await expect(page.locator('text=Pricing Test A').first()).toBeVisible({ timeout: 10000 });
});
test('should show experiment status', async ({ page }) => {
await page.waitForTimeout(500);
// Look for status badge
await expect(page.locator('text=/active|paused|completed/i').first()).toBeVisible({
timeout: 10000,
});
});
});