Files
blackcanyontickets/reactrebuild0825/tests/territory-access.spec.ts
dzinesco d5c3953888 fix(typescript): resolve build errors and improve type safety
- Fix billing components ConnectError type compatibility with exactOptionalPropertyTypes
- Update Select component usage to match proper API (options vs children)
- Remove unused imports and fix optional property assignments in system components
- Resolve duplicate Order/Ticket type definitions and add null safety checks
- Handle optional branding properties correctly in organization features
- Add window property type declarations for test environment
- Fix Playwright API usage (page.setOffline → page.context().setOffline)
- Clean up unused imports, variables, and parameters across codebase
- Add comprehensive global type declarations for test window extensions

Resolves major TypeScript compilation issues and improves type safety throughout the application.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-22 13:31:19 -06:00

265 lines
11 KiB
TypeScript

import { test, expect } from '@playwright/test';
test.describe('Territory Access Control', () => {
test.beforeEach(async ({ page }) => {
// Navigate to login page
await page.goto('/login');
});
test('Territory Manager sees only assigned territories in events', async ({ page }) => {
// Login as territory manager
await page.fill('[data-testid="login-email"]', 'territory@example.com');
await page.fill('[data-testid="login-password"]', 'password123');
await page.click('[data-testid="login-submit"]');
// Wait for redirect to dashboard
await page.waitForURL('/dashboard');
// Navigate to events page
await page.click('[data-testid="nav-events"]');
await page.waitForURL('/events');
// Territory manager should only see events from their assigned territories (WNW and SE)
// Event 1 is in WNW (territory_001) - should be visible
await expect(page.locator('[data-testid="event-card-evt-1"]')).toBeVisible();
// Event 2 is in SE (territory_002) - should be visible
await expect(page.locator('[data-testid="event-card-evt-2"]')).toBeVisible();
// Event 3 is in NE (territory_003) - should NOT be visible
await expect(page.locator('[data-testid="event-card-evt-3"]')).not.toBeVisible();
// Check that territory filter shows only assigned territories
const territoryFilter = page.locator('[data-testid="territory-filter"]');
await expect(territoryFilter).toBeVisible();
// Should show WNW and SE badges (territory manager's assigned territories)
await expect(page.locator('[data-testid="territory-badge-WNW"]')).toBeVisible();
await expect(page.locator('[data-testid="territory-badge-SE"]')).toBeVisible();
// Should not show NE badge
await expect(page.locator('[data-testid="territory-badge-NE"]')).not.toBeVisible();
// Territory filter should be read-only for territory managers
const addTerritoryButton = page.locator('[data-testid="add-territory-button"]');
await expect(addTerritoryButton).not.toBeVisible();
});
test('OrgAdmin sees all territories and can manage them', async ({ page }) => {
// Login as admin (which is mapped to orgAdmin in new system)
await page.fill('[data-testid="login-email"]', 'admin@example.com');
await page.fill('[data-testid="login-password"]', 'password123');
await page.click('[data-testid="login-submit"]');
await page.waitForURL('/dashboard');
// Navigate to events page
await page.click('[data-testid="nav-events"]');
await page.waitForURL('/events');
// Admin should see all events in their organization
await expect(page.locator('[data-testid="event-card-evt-1"]')).toBeVisible();
await expect(page.locator('[data-testid="event-card-evt-2"]')).toBeVisible();
await expect(page.locator('[data-testid="event-card-evt-3"]')).toBeVisible();
// Territory filter should be editable for admins
const territoryFilter = page.locator('[data-testid="territory-filter"]');
await expect(territoryFilter).toBeVisible();
// Should be able to add/remove territories
const addTerritorySelect = page.locator('[data-testid="add-territory-select"]');
await expect(addTerritorySelect).toBeVisible();
});
test('Territory Manager cannot write to events outside their territory', async ({ page }) => {
// This would test Firestore security rules in a real environment
// For now, we'll test UI-level restrictions
await page.fill('[data-testid="login-email"]', 'territory@example.com');
await page.fill('[data-testid="login-password"]', 'password123');
await page.click('[data-testid="login-submit"]');
await page.waitForURL('/dashboard');
// Navigate to create event page
await page.click('[data-testid="nav-events"]');
await page.click('[data-testid="create-event-button"]');
// In event creation form, territory dropdown should only show assigned territories
const territorySelect = page.locator('[data-testid="event-territory-select"]');
await expect(territorySelect).toBeVisible();
// Should only have options for WNW and SE (territory manager's assigned territories)
await territorySelect.click();
await expect(page.locator('option:has-text("WNW - West Northwest")')).toBeVisible();
await expect(page.locator('option:has-text("SE - Southeast")')).toBeVisible();
await expect(page.locator('option:has-text("NE - Northeast")')).not.toBeVisible();
});
test('Territory assignment UI is only visible to admins', async ({ page }) => {
// Test as territory manager first - should not see admin UI
await page.fill('[data-testid="login-email"]', 'territory@example.com');
await page.fill('[data-testid="login-password"]', 'password123');
await page.click('[data-testid="login-submit"]');
await page.waitForURL('/dashboard');
// Navigate to admin page (if it exists in nav)
const adminNavLink = page.locator('[data-testid="nav-admin"]');
if (await adminNavLink.isVisible()) {
await adminNavLink.click();
// Should show access denied message
await expect(page.locator('[data-testid="access-denied-message"]')).toBeVisible();
}
// Now test as admin
await page.click('[data-testid="logout-button"]');
await page.waitForURL('/login');
await page.fill('[data-testid="login-email"]', 'admin@example.com');
await page.fill('[data-testid="login-password"]', 'password123');
await page.click('[data-testid="login-submit"]');
await page.waitForURL('/dashboard');
// Admin should see territory management interface
if (await page.locator('[data-testid="nav-admin"]').isVisible()) {
await page.click('[data-testid="nav-admin"]');
// Should see user territory manager component
await expect(page.locator('[data-testid="user-territory-manager"]')).toBeVisible();
// Should be able to select users and assign territories
await expect(page.locator('[data-testid="user-select"]')).toBeVisible();
await expect(page.locator('[data-testid="role-select"]')).toBeVisible();
await expect(page.locator('[data-testid="territory-checkboxes"]')).toBeVisible();
}
});
test('Event creation requires territory selection', async ({ page }) => {
await page.fill('[data-testid="login-email"]', 'admin@example.com');
await page.fill('[data-testid="login-password"]', 'password123');
await page.click('[data-testid="login-submit"]');
await page.waitForURL('/dashboard');
// Navigate to create event
await page.click('[data-testid="nav-events"]');
await page.click('[data-testid="create-event-button"]');
// Fill in event details but leave territory empty
await page.fill('[data-testid="event-title"]', 'Test Event');
await page.fill('[data-testid="event-description"]', 'Test Description');
await page.fill('[data-testid="event-venue"]', 'Test Venue');
await page.fill('[data-testid="event-date"]', '2024-12-25T18:00');
// Try to proceed without selecting territory
await page.click('[data-testid="next-step-button"]');
// Should show validation error
await expect(page.locator('[data-testid="territory-required-error"]')).toBeVisible();
await expect(page.locator('text=Please select a territory for this event')).toBeVisible();
// Select a territory
await page.selectOption('[data-testid="event-territory-select"]', 'territory_001');
// Now should be able to proceed
await page.click('[data-testid="next-step-button"]');
// Should move to next step (ticket configuration)
await expect(page.locator('[data-testid="ticket-configuration-step"]')).toBeVisible();
});
test('Territory filter persists in URL and localStorage', async ({ page }) => {
await page.fill('[data-testid="login-email"]', 'admin@example.com');
await page.fill('[data-testid="login-password"]', 'password123');
await page.click('[data-testid="login-submit"]');
await page.waitForURL('/dashboard');
// Navigate to events page
await page.click('[data-testid="nav-events"]');
await page.waitForURL('/events');
// Select specific territories in filter
await page.click('[data-testid="add-territory-select"]');
await page.selectOption('[data-testid="add-territory-select"]', 'territory_001');
await page.click('[data-testid="add-territory-select"]');
await page.selectOption('[data-testid="add-territory-select"]', 'territory_002');
// URL should include territories parameter
await expect(page).toHaveURL(/territories=territory_001,territory_002/);
// Refresh page
await page.reload();
// Territory filter should be restored
await expect(page.locator('[data-testid="territory-badge-WNW"]')).toBeVisible();
await expect(page.locator('[data-testid="territory-badge-SE"]')).toBeVisible();
// Navigate away and back
await page.click('[data-testid="nav-dashboard"]');
await page.click('[data-testid="nav-events"]');
// Territory filter should still be there (from localStorage)
await expect(page.locator('[data-testid="territory-badge-WNW"]')).toBeVisible();
await expect(page.locator('[data-testid="territory-badge-SE"]')).toBeVisible();
});
test('Claims are properly set in Firebase auth tokens', async ({ page }) => {
// This test verifies that custom claims are working correctly
// In a real implementation, this would test the actual Firebase auth
await page.fill('[data-testid="login-email"]', 'territory@example.com');
await page.fill('[data-testid="login-password"]', 'password123');
await page.click('[data-testid="login-submit"]');
await page.waitForURL('/dashboard');
// Check that user info displays correct role and territories
await page.click('[data-testid="user-menu"]');
await expect(page.locator('[data-testid="user-role"]')).toContainText('Territory Manager');
await expect(page.locator('[data-testid="user-territories"]')).toContainText('WNW, SE');
// Check in dev tools console that claims are present
const claims = await page.evaluate(async () =>
// In real app, this would get claims from Firebase auth
// For mock, we'll simulate checking localStorage or context
({
role: 'territoryManager',
territoryIds: ['territory_001', 'territory_002'],
orgId: 'org_001'
})
);
expect(claims.role).toBe('territoryManager');
expect(claims.territoryIds).toEqual(['territory_001', 'territory_002']);
expect(claims.orgId).toBe('org_001');
});
});
// Helper test for validating Firestore security rules (would run in Firebase emulator)
test.describe('Firestore Security Rules (Emulator)', () => {
test.skip('Territory Manager cannot read events outside their territory', async () => {
// This test would require Firebase emulator setup
// Skip for now but document the test pattern
// 1. Initialize Firebase emulator with test data
// 2. Authenticate as territory manager with specific claims
// 3. Attempt to read events from other territories
// 4. Verify access is denied
// 5. Verify write operations are also denied
});
test.skip('OrgAdmin can read all events in their organization', async () => {
// Similar pattern for testing orgAdmin permissions
});
test.skip('Cross-organization access is denied', async () => {
// Test that users cannot access data from other organizations
});
});