2025-11-27 13:45:21 -06:00
|
|
|
import { test, expect } from '@playwright/test';
|
|
|
|
|
import { login, verifyCreateUser, todate } from './util';
|
|
|
|
|
|
2026-02-14 13:35:59 -06:00
|
|
|
test.beforeEach(async ({ page }) => {
|
2026-04-05 12:05:13 -05:00
|
|
|
await login(page);
|
2026-02-14 13:35:59 -06:00
|
|
|
});
|
2025-11-27 13:45:21 -06:00
|
|
|
|
2026-02-14 13:35:59 -06:00
|
|
|
test('can log out', async ({ page }) => {
|
2026-04-05 12:05:13 -05:00
|
|
|
await page.getByText("Logout").click();
|
|
|
|
|
await expect(page.getByLabel("Username")).toBeVisible();
|
2025-11-27 13:45:21 -06:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('has no contacts', async ({ page }) => {
|
2026-04-05 12:05:13 -05:00
|
|
|
await expect(page.getByRole("navigation").getByRole("link")).toHaveCount(0);
|
2025-11-27 13:45:21 -06:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('can add contacts', async ({ page }) => {
|
2026-04-05 12:05:13 -05:00
|
|
|
await verifyCreateUser(page, { names: ['John Contact'] });
|
|
|
|
|
await verifyCreateUser(page, { names: ['Jack Contact'] });
|
|
|
|
|
await expect(page.getByRole("navigation").getByRole("link")).toHaveCount(2);
|
2025-11-27 13:45:21 -06:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('shows "never" for unfreshened contacts', async ({ page }) => {
|
2026-04-05 12:05:13 -05:00
|
|
|
await verifyCreateUser(page, { names: ['John Contact'] });
|
|
|
|
|
await page.getByRole('link', { name: 'Mascarpone' }).click();
|
2025-11-27 13:45:21 -06:00
|
|
|
|
2026-04-05 12:05:13 -05:00
|
|
|
await expect(page.locator('#freshness')).toContainText('John Contactnever');
|
2025-11-27 13:45:21 -06:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('shows the date for fresh contacts', async ({ page }) => {
|
2026-04-05 12:05:13 -05:00
|
|
|
await verifyCreateUser(page, { names: ['John Contact'] });
|
|
|
|
|
await page.getByRole('link', { name: /edit/i }).click();
|
|
|
|
|
await page.getByRole('button', { name: /fresh/i }).click();
|
|
|
|
|
await page.getByRole('button', { name: /save/i }).click();
|
|
|
|
|
await page.getByRole('link', { name: 'Mascarpone' }).click();
|
|
|
|
|
await expect(page.locator('#freshness')).toContainText(`John Contact${todate()}`);
|
2025-11-27 13:45:21 -06:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('sidebar is sorted alphabetically', async ({ page }) => {
|
2026-04-05 12:05:13 -05:00
|
|
|
await verifyCreateUser(page, { names: ['Zulu'] });
|
|
|
|
|
await verifyCreateUser(page, { names: ['Alfa'] });
|
|
|
|
|
await verifyCreateUser(page, { names: ['Golf'] });
|
2025-11-27 13:45:21 -06:00
|
|
|
|
2026-04-05 12:05:13 -05:00
|
|
|
await expect(page.getByRole('navigation')).toHaveText(/Alfa\s*Golf\s*Zulu/);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('upcoming and recent show at least one birthday a week away', async ({ page }) => {
|
|
|
|
|
const monthday = d => d.toISOString().split("T")[0].replace(/^\d{4}-/, '');
|
|
|
|
|
const today = monthday(new Date());
|
|
|
|
|
const yesterday = monthday((() => {
|
|
|
|
|
let date = new Date();
|
|
|
|
|
date.setDate(date.getDate() - 1);
|
|
|
|
|
return date;
|
|
|
|
|
})());
|
|
|
|
|
const tomorrow = monthday((() => {
|
|
|
|
|
let date = new Date();
|
|
|
|
|
date.setDate(date.getDate() + 1);
|
|
|
|
|
return date;
|
|
|
|
|
})());
|
|
|
|
|
const aMonthAgo = monthday((() => {
|
|
|
|
|
let date = new Date();
|
|
|
|
|
date.setDate(date.getDate() - 28);
|
|
|
|
|
return date;
|
|
|
|
|
})());
|
|
|
|
|
const inAMonth = monthday((() => {
|
|
|
|
|
let date = new Date();
|
|
|
|
|
date.setDate(date.getDate() + 28);
|
|
|
|
|
return date;
|
|
|
|
|
})());
|
|
|
|
|
await verifyCreateUser(page, { names: ['Alfa'], birthday: today });
|
|
|
|
|
await verifyCreateUser(page, { names: ['Beta'], birthday: yesterday });
|
|
|
|
|
await verifyCreateUser(page, { names: ['Echo'], birthday: today });
|
|
|
|
|
await verifyCreateUser(page, { names: ['Golf'], birthday: yesterday });
|
|
|
|
|
await verifyCreateUser(page, { names: ['Lima'], birthday: tomorrow });
|
|
|
|
|
await verifyCreateUser(page, { names: ['Mike'], birthday: yesterday });
|
|
|
|
|
await verifyCreateUser(page, { names: ['Xray'], birthday: inAMonth });
|
|
|
|
|
await verifyCreateUser(page, { names: ['Zulu'], birthday: aMonthAgo });
|
|
|
|
|
|
|
|
|
|
await page.goto('/');
|
|
|
|
|
|
|
|
|
|
await expect(page.locator('#upcoming').getByRole('link')).toHaveCount(4);
|
|
|
|
|
await expect(page.locator('#recent').getByRole('link')).toHaveCount(4);
|
2025-11-27 13:45:21 -06:00
|
|
|
});
|
2026-04-07 10:49:04 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
test('contact list scrolls (independently) to current contact in center of view', async ({ page }) => {
|
|
|
|
|
for (let count = 0; count < 30; count++) {
|
|
|
|
|
await verifyCreateUser(page, { names: [`Contact${count < 10 ? '0' + count : count}`] });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await page.goto('/contact/28');
|
|
|
|
|
await expect(page.getByRole('navigation').getByRole('link', { name: /Contact28/ })).toBeVisible();
|
|
|
|
|
expect(await page.locator('main').evaluate(e => e.scrollTop)).toEqual(0);
|
|
|
|
|
|
|
|
|
|
await page.goto('/contact/16');
|
|
|
|
|
await expect(page.locator('#nav-link-16')).toBeVisible();
|
|
|
|
|
const linkPos: number = await page.locator('#nav-link-16').evaluate(e => e.getBoundingClientRect().y);
|
|
|
|
|
|
|
|
|
|
// roughly centered is fine, not that fussy about headers and whatnot
|
|
|
|
|
expect(Math.abs(linkPos - (await page.evaluate('window.innerHeight/2') as number))).toBeLessThan(200);
|
|
|
|
|
});
|
2026-04-07 10:49:23 -05:00
|
|
|
|
|
|
|
|
test('clicking off contact list when expanded closes it', async ({ page }) => {
|
|
|
|
|
await page.setViewportSize({
|
|
|
|
|
width: 640,
|
|
|
|
|
height: 1000,
|
|
|
|
|
});
|
|
|
|
|
// TODO aria-label
|
|
|
|
|
await page.locator('#sidebar-show-hide').click();
|
|
|
|
|
await expect(page.getByRole('button', { name: /add contact/i })).toBeVisible();
|
|
|
|
|
await page.mouse.click(600, 500);
|
|
|
|
|
await expect(page.getByRole('button', { name: /add contact/i })).not.toBeVisible();
|
|
|
|
|
});
|
2026-04-07 10:49:46 -05:00
|
|
|
|
|
|
|
|
test('contact list is sorted ignoring case', async ({ page }) => {
|
|
|
|
|
await verifyCreateUser(page, { names: ['Alfa'] });
|
|
|
|
|
await verifyCreateUser(page, { names: ['bob'] });
|
|
|
|
|
await verifyCreateUser(page, { names: ['Charlie'] });
|
|
|
|
|
|
|
|
|
|
await expect(page.locator('#contacts-sidebar')).toContainText(/alfa\s*bob\s*charlie/i);
|
|
|
|
|
});
|