import { test, expect } from '@playwright/test';
const VITE_URL = 'http://localhost:3000';
test.describe('Multi-Tab Vite App', () => {
test('should display leader badge on first tab', async ({ page }) => {
await page.goto(VITE_URL);
await page.waitForSelector('#leaderBadge', { timeout: 10000 });
const badge = await page.locator('#leaderBadge').textContent();
expect(badge).toContain('LEADER');
const runBtn = await page.locator('#runTest');
await expect(runBtn).toBeEnabled();
});
test('should coordinate between two tabs', async ({ context }) => {
const tab1 = await context.newPage();
await tab1.goto(VITE_URL);
await tab1.waitForSelector('#leaderBadge');
let badge1 = await tab1.locator('#leaderBadge').textContent();
expect(badge1).toContain('LEADER');
const tab2 = await context.newPage();
await tab2.goto(VITE_URL);
await tab2.waitForSelector('#leaderBadge');
await tab2.waitForTimeout(1000);
const badge2 = await tab2.locator('#leaderBadge').textContent();
expect(badge2).toContain('FOLLOWER');
const runBtn2 = await tab2.locator('#runTest');
await expect(runBtn2).toBeDisabled();
await tab1.close();
await tab2.close();
});
test('should allow leader to write and sync to follower', async ({ context }) => {
const tab1 = await context.newPage();
await tab1.goto(VITE_URL);
await tab1.waitForSelector('#leaderBadge');
await tab1.waitForTimeout(500);
const tab2 = await context.newPage();
await tab2.goto(VITE_URL);
await tab2.waitForSelector('#leaderBadge');
await tab2.waitForTimeout(1000);
await tab1.click('#runTest');
await tab1.waitForTimeout(500);
const output1 = await tab1.locator('#output').textContent();
expect(output1).toContain('Inserted 3 items');
expect(output1).toContain('Widget');
await tab2.waitForTimeout(1000);
const log2 = await tab2.locator('#output').textContent();
expect(log2).toContain('Data changed');
await tab1.close();
await tab2.close();
});
test('should handle leader change when leader tab closes', async ({ context }) => {
const tab1 = await context.newPage();
await tab1.goto(VITE_URL);
await tab1.waitForSelector('#leaderBadge');
await tab1.waitForTimeout(500);
const tab2 = await context.newPage();
await tab2.goto(VITE_URL);
await tab2.waitForSelector('#leaderBadge');
await tab2.waitForTimeout(1000);
let badge2 = await tab2.locator('#leaderBadge').textContent();
expect(badge2).toContain('FOLLOWER');
await tab1.evaluate(() => window.db.close());
await tab1.waitForTimeout(200);
await tab1.close();
await tab2.waitForTimeout(8000);
badge2 = await tab2.locator('#leaderBadge').textContent();
expect(badge2).toContain('LEADER');
const runBtn = await tab2.locator('#runTest');
await expect(runBtn).toBeEnabled();
await tab2.close();
});
test('should prevent follower from writing', async ({ context }) => {
const tab1 = await context.newPage();
await tab1.goto(VITE_URL);
await tab1.waitForSelector('#leaderBadge');
await tab1.waitForTimeout(500);
const tab2 = await context.newPage();
await tab2.goto(VITE_URL);
await tab2.waitForSelector('#leaderBadge');
await tab2.waitForTimeout(1000);
const badge2 = await tab2.locator('#leaderBadge').textContent();
expect(badge2).toContain('FOLLOWER');
const runBtn2 = await tab2.locator('#runTest');
const isDisabled = await runBtn2.isDisabled();
expect(isDisabled).toBe(true);
await tab1.close();
await tab2.close();
});
test('should allow requesting leadership', async ({ context }) => {
const tab1 = await context.newPage();
await tab1.goto(VITE_URL);
await tab1.waitForSelector('#leaderBadge');
await tab1.waitForTimeout(500);
const tab2 = await context.newPage();
await tab2.goto(VITE_URL);
await tab2.waitForSelector('#leaderBadge');
await tab2.waitForTimeout(1000);
let badge2 = await tab2.locator('#leaderBadge').textContent();
expect(badge2).toContain('FOLLOWER');
await tab1.evaluate(() => window.db.close());
await tab1.waitForTimeout(200);
await tab1.close();
await tab2.waitForTimeout(6000);
await tab2.click('#requestLeader');
await tab2.waitForTimeout(2500);
badge2 = await tab2.locator('#leaderBadge').textContent();
expect(badge2).toContain('LEADER');
await tab2.close();
});
});