Initial commit: Port Nimara CRM (Layers 0-4)
Full CRM rebuild with Next.js 15, TypeScript, Tailwind, Drizzle ORM, PostgreSQL, Redis, BullMQ, MinIO, and Socket.io. Includes 461 source files covering clients, berths, interests/pipeline, documents/EOI, expenses/invoices, email, notifications, dashboard, admin, and client portal. CI/CD via Gitea Actions with Docker builds. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
191
tests/e2e/smoke/global-setup.ts
Normal file
191
tests/e2e/smoke/global-setup.ts
Normal file
@@ -0,0 +1,191 @@
|
||||
/**
|
||||
* Global Setup — Seed the database with test users via Better Auth API
|
||||
* and insert supporting data (berths, system_settings) via direct SQL.
|
||||
*
|
||||
* This runs BEFORE any test spec via Playwright's `dependencies` config.
|
||||
*/
|
||||
import { test as setup } from '@playwright/test';
|
||||
|
||||
const BASE = 'http://localhost:3000';
|
||||
|
||||
// ── Test user credentials ───────────────────────────────────────────────────
|
||||
export const USERS = {
|
||||
super_admin: {
|
||||
email: 'admin@portnimara.test',
|
||||
password: 'SuperAdmin12345!',
|
||||
name: 'Test Admin',
|
||||
},
|
||||
sales_agent: {
|
||||
email: 'agent@portnimara.test',
|
||||
password: 'SalesAgent12345!',
|
||||
name: 'Test Agent',
|
||||
},
|
||||
viewer: {
|
||||
email: 'viewer@portnimara.test',
|
||||
password: 'ViewerUser12345!',
|
||||
name: 'Test Viewer',
|
||||
},
|
||||
};
|
||||
|
||||
// ── Helpers ─────────────────────────────────────────────────────────────────
|
||||
|
||||
/** Sign up a user via Better Auth REST API */
|
||||
async function signUpUser(email: string, password: string, name: string) {
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Origin': BASE,
|
||||
'Referer': `${BASE}/`,
|
||||
};
|
||||
|
||||
const res = await fetch(`${BASE}/api/auth/sign-up/email`, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: JSON.stringify({ email, password, name }),
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
return data.user?.id ?? data.id;
|
||||
}
|
||||
|
||||
// User may already exist — try sign-in instead
|
||||
const loginRes = await fetch(`${BASE}/api/auth/sign-in/email`, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: JSON.stringify({ email, password }),
|
||||
});
|
||||
|
||||
if (loginRes.ok) {
|
||||
const loginData = await loginRes.json();
|
||||
return loginData.user?.id ?? loginData.id;
|
||||
}
|
||||
|
||||
const errorBody = await loginRes.text().catch(() => 'no body');
|
||||
throw new Error(`Failed to create or sign in user ${email}: ${loginRes.status} ${errorBody}`);
|
||||
}
|
||||
|
||||
/** Run raw SQL via docker psql using stdin piping */
|
||||
async function runSQL(sql: string) {
|
||||
const { execSync } = await import('child_process');
|
||||
execSync(
|
||||
`docker compose -f docker-compose.yml -f docker-compose.dev.yml exec -T postgres psql -U crm -d port_nimara_crm`,
|
||||
{ cwd: process.cwd(), input: sql, stdio: ['pipe', 'pipe', 'pipe'] },
|
||||
);
|
||||
}
|
||||
|
||||
// ── Setup ───────────────────────────────────────────────────────────────────
|
||||
|
||||
setup('seed test database', async () => {
|
||||
setup.setTimeout(120_000);
|
||||
|
||||
console.log('🔧 Creating test users via Better Auth...');
|
||||
|
||||
// 1. Create users via Better Auth sign-up endpoint
|
||||
const adminId = await signUpUser(
|
||||
USERS.super_admin.email,
|
||||
USERS.super_admin.password,
|
||||
USERS.super_admin.name,
|
||||
);
|
||||
console.log(` ✓ super_admin created: ${adminId}`);
|
||||
|
||||
const agentId = await signUpUser(
|
||||
USERS.sales_agent.email,
|
||||
USERS.sales_agent.password,
|
||||
USERS.sales_agent.name,
|
||||
);
|
||||
console.log(` ✓ sales_agent created: ${agentId}`);
|
||||
|
||||
const viewerId = await signUpUser(
|
||||
USERS.viewer.email,
|
||||
USERS.viewer.password,
|
||||
USERS.viewer.name,
|
||||
);
|
||||
console.log(` ✓ viewer created: ${viewerId}`);
|
||||
|
||||
// 2. Get portId and roleIds from seed data
|
||||
console.log('🔧 Linking users to port and roles...');
|
||||
|
||||
// Create user_profiles + user_port_roles for each test user
|
||||
// The super_admin profile already exists from db:seed with a placeholder userId.
|
||||
// We need to update it and create profiles for agent + viewer.
|
||||
|
||||
await runSQL(`
|
||||
-- Update super_admin profile to match the real auth user ID
|
||||
UPDATE user_profiles SET user_id = '${adminId}' WHERE user_id = 'super-admin-matt-portnimara';
|
||||
|
||||
-- If that didn't match (profile might not exist), insert it
|
||||
INSERT INTO user_profiles (id, user_id, display_name, is_super_admin, is_active, preferences)
|
||||
VALUES (gen_random_uuid()::text, '${adminId}', 'Test Admin', true, true, '{}')
|
||||
ON CONFLICT (user_id) DO UPDATE SET is_super_admin = true, is_active = true;
|
||||
|
||||
-- Create sales_agent profile
|
||||
INSERT INTO user_profiles (id, user_id, display_name, is_super_admin, is_active, preferences)
|
||||
VALUES (gen_random_uuid()::text, '${agentId}', 'Test Agent', false, true, '{}')
|
||||
ON CONFLICT (user_id) DO NOTHING;
|
||||
|
||||
-- Create viewer profile
|
||||
INSERT INTO user_profiles (id, user_id, display_name, is_super_admin, is_active, preferences)
|
||||
VALUES (gen_random_uuid()::text, '${viewerId}', 'Test Viewer', false, true, '{}')
|
||||
ON CONFLICT (user_id) DO NOTHING;
|
||||
`);
|
||||
|
||||
await runSQL(`
|
||||
-- Assign super_admin role to admin user
|
||||
INSERT INTO user_port_roles (id, user_id, port_id, role_id)
|
||||
SELECT gen_random_uuid()::text, '${adminId}', p.id, r.id
|
||||
FROM ports p, roles r
|
||||
WHERE p.slug = 'port-nimara' AND r.name = 'super_admin'
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- Assign sales_agent role to agent user
|
||||
INSERT INTO user_port_roles (id, user_id, port_id, role_id)
|
||||
SELECT gen_random_uuid()::text, '${agentId}', p.id, r.id
|
||||
FROM ports p, roles r
|
||||
WHERE p.slug = 'port-nimara' AND r.name = 'sales_agent'
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- Assign viewer role to viewer user
|
||||
INSERT INTO user_port_roles (id, user_id, port_id, role_id)
|
||||
SELECT gen_random_uuid()::text, '${viewerId}', p.id, r.id
|
||||
FROM ports p, roles r
|
||||
WHERE p.slug = 'port-nimara' AND r.name = 'viewer'
|
||||
ON CONFLICT DO NOTHING;
|
||||
`);
|
||||
|
||||
console.log(' ✓ Users linked to port-nimara with correct roles');
|
||||
|
||||
// 3. Seed berths for testing
|
||||
console.log('🔧 Seeding berths...');
|
||||
await runSQL(`
|
||||
INSERT INTO berths (id, port_id, mooring_number, area, status, length_ft, width_ft, price, tenure_type)
|
||||
SELECT gen_random_uuid()::text, p.id, 'A-001', 'Marina A', 'available', '60', '20', '150000', 'permanent'
|
||||
FROM ports p WHERE p.slug = 'port-nimara'
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
INSERT INTO berths (id, port_id, mooring_number, area, status, length_ft, width_ft, price, tenure_type)
|
||||
SELECT gen_random_uuid()::text, p.id, 'A-002', 'Marina A', 'available', '80', '25', '250000', 'permanent'
|
||||
FROM ports p WHERE p.slug = 'port-nimara'
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
INSERT INTO berths (id, port_id, mooring_number, area, status, length_ft, width_ft, price, tenure_type)
|
||||
SELECT gen_random_uuid()::text, p.id, 'B-001', 'Marina B', 'under_offer', '45', '15', '95000', 'fixed_term'
|
||||
FROM ports p WHERE p.slug = 'port-nimara'
|
||||
ON CONFLICT DO NOTHING;
|
||||
`);
|
||||
console.log(' ✓ 3 berths seeded');
|
||||
|
||||
// 4. Seed system settings
|
||||
console.log('🔧 Seeding system settings...');
|
||||
await runSQL(`
|
||||
INSERT INTO system_settings (key, value, port_id)
|
||||
SELECT 'invoice_prefix', '"INV"'::jsonb, p.id FROM ports p WHERE p.slug = 'port-nimara'
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
INSERT INTO system_settings (key, value, port_id)
|
||||
SELECT 'default_payment_terms', '"net30"'::jsonb, p.id FROM ports p WHERE p.slug = 'port-nimara'
|
||||
ON CONFLICT DO NOTHING;
|
||||
`);
|
||||
console.log(' ✓ System settings seeded');
|
||||
|
||||
console.log('✅ Global setup complete!');
|
||||
});
|
||||
Reference in New Issue
Block a user