personal-lifecycle-tracker / e2e / groups.spec.ts
groups.spec.ts
Raw
import { test, expect } from '@playwright/test';
import { resetDatabase } from './helpers';

test.describe('Groups & Shared Access Flow (@spec.md Decision 4, 13, 14, 18, 30)', () => {
  test.beforeEach(async () => {
    await resetDatabase();
  });

  test('should display existing groups and allow creating a new group', async ({ page }) => {
    await page.goto('/');
    await expect(page.locator('text=Lifecycle Tracker').first()).toBeVisible();

    // Navigate to Groups tab
    await page.getByRole('button', { name: 'Groups' }).click();

    await expect(page.getByRole('heading', { name: 'Groups & Shared Access' })).toBeVisible();

    // Verify existing seed groups
    await expect(page.getByRole('heading', { name: 'Oakridge Family & Home' })).toBeVisible();
    await expect(page.getByRole('heading', { name: 'Shared Vehicle Maintenance' })).toBeVisible();

    // Create a new group
    const newGroupName = 'Lakehouse Vacation Property';
    const input = page.locator('input[placeholder="e.g. Oakridge Family & Home"]');
    await input.fill(newGroupName);
    await page.getByRole('button', { name: 'Create Group' }).click();

    // Verify newly created group card appears
    await expect(page.getByText(newGroupName)).toBeVisible();
  });

  test('should invite a new member by email to a group', async ({ page }) => {
    await page.goto('/');
    await expect(page.locator('text=Lifecycle Tracker').first()).toBeVisible();

    await page.getByRole('button', { name: 'Groups' }).click();

    const groupCard = page.locator('.bg-white').filter({ hasText: 'Oakridge Family & Home' });
    await expect(groupCard).toBeVisible();

    // Invite a new member
    const inviteEmail = 'partner@example.com';
    const emailInput = groupCard.locator('input[type="email"]');
    await emailInput.fill(inviteEmail);
    await groupCard.getByRole('button', { name: 'Invite' }).click();

    // Member should now appear in the members list
    await expect(groupCard.getByText(inviteEmail)).toBeVisible();
  });

  test('should remove a member from a group', async ({ page }) => {
    await page.goto('/');
    await expect(page.locator('text=Lifecycle Tracker').first()).toBeVisible();

    await page.getByRole('button', { name: 'Groups' }).click();

    const groupCard = page.locator('.bg-white').filter({ hasText: 'Oakridge Family & Home' });
    await expect(groupCard).toBeVisible();

    // Alex is owner of Oakridge Family & Home; Sarah is a member
    const removeBtn = groupCard.getByRole('button', { name: 'Remove sarah@example.com' });
    if (await removeBtn.isVisible()) {
      await removeBtn.click();
      await expect(groupCard.getByText('sarah@example.com')).toHaveCount(0);
    }
  });

  test('should delete group and all associated items permanently (Decision 30)', async ({ page }) => {
    await page.goto('/');
    await expect(page.locator('text=Lifecycle Tracker').first()).toBeVisible();

    await page.getByRole('button', { name: 'Groups' }).click();

    const groupCard = page.locator('.bg-white').filter({ hasText: 'Oakridge Family & Home' });
    await expect(groupCard).toBeVisible();

    // Set dialog handler
    page.once('dialog', async (dialog) => {
      await dialog.accept();
    });

    // Click delete group
    await groupCard.getByRole('button', { name: 'Delete group' }).click();

    // Group should disappear
    await expect(page.locator('.bg-white').filter({ hasText: 'Oakridge Family & Home' })).toHaveCount(0);
  });
});