diff --git a/e2e/pages/home.spec.ts b/e2e/pages/home.spec.ts index 13b9fa1..8ec39dd 100644 --- a/e2e/pages/home.spec.ts +++ b/e2e/pages/home.spec.ts @@ -2,44 +2,82 @@ import { test, expect } from '@playwright/test'; import { login, verifyCreateUser, todate } from './util'; test.beforeEach(async ({ page }) => { - await login(page); + await login(page); }); test('can log out', async ({ page }) => { - await page.getByText("Logout").click(); - await expect(page.getByLabel("Username")).toBeVisible(); + await page.getByText("Logout").click(); + await expect(page.getByLabel("Username")).toBeVisible(); }); test('has no contacts', async ({ page }) => { - await expect(page.getByRole("navigation").getByRole("link")).toHaveCount(0); + await expect(page.getByRole("navigation").getByRole("link")).toHaveCount(0); }); test('can add contacts', async ({ page }) => { - await verifyCreateUser(page, { names: ['John Contact'] }); - await verifyCreateUser(page, { names: ['Jack Contact'] }); - await expect(page.getByRole("navigation").getByRole("link")).toHaveCount(2); + await verifyCreateUser(page, { names: ['John Contact'] }); + await verifyCreateUser(page, { names: ['Jack Contact'] }); + await expect(page.getByRole("navigation").getByRole("link")).toHaveCount(2); }); test('shows "never" for unfreshened contacts', async ({ page }) => { - await verifyCreateUser(page, { names: ['John Contact'] }); - await page.getByRole('link', { name: 'Mascarpone' }).click(); + await verifyCreateUser(page, { names: ['John Contact'] }); + await page.getByRole('link', { name: 'Mascarpone' }).click(); - await expect(page.locator('#freshness')).toContainText('John Contactnever'); + await expect(page.locator('#freshness')).toContainText('John Contactnever'); }); test('shows the date for fresh contacts', async ({ page }) => { - 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()}`); + 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()}`); }); test('sidebar is sorted alphabetically', async ({ page }) => { - await verifyCreateUser(page, { names: ['Zulu'] }); - await verifyCreateUser(page, { names: ['Alfa'] }); - await verifyCreateUser(page, { names: ['Golf'] }); + await verifyCreateUser(page, { names: ['Zulu'] }); + await verifyCreateUser(page, { names: ['Alfa'] }); + await verifyCreateUser(page, { names: ['Golf'] }); - await expect(page.getByRole('navigation')).toHaveText(/Alfa\s*Golf\s*Zulu/); + 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); }); diff --git a/src/models/birthday.rs b/src/models/birthday.rs index f7c0256..2db0296 100644 --- a/src/models/birthday.rs +++ b/src/models/birthday.rs @@ -20,11 +20,10 @@ pub enum Birthday { impl Display for Birthday { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - let str = match self { - Birthday::Date(date) => date.to_string(), - Birthday::Text(t) => t.value.clone(), - }; - write!(f, "{}", str) + match self { + Birthday::Date(date) => write!(f, "{}", date), + Birthday::Text(t) => write!(f, "{}", t.value), + } } } @@ -56,13 +55,6 @@ impl Birthday { } } } - - pub fn serialize(&self) -> String { - match &self { - Birthday::Text(text) => text.value.clone(), - Birthday::Date(date) => date.serialize(), - } - } } impl FromStr for Birthday { diff --git a/src/models/year_optional_date.rs b/src/models/year_optional_date.rs index fa1fc1f..d0052b8 100644 --- a/src/models/year_optional_date.rs +++ b/src/models/year_optional_date.rs @@ -43,15 +43,6 @@ impl YearOptionalDate { None } } - - pub fn serialize(&self) -> String { - format!( - "{}{:0>2}{:0>2}", - self.year.map_or("--".to_string(), |y| format!("{:0>4}", y)), - self.month, - self.day - ) - } } impl Display for YearOptionalDate { @@ -110,6 +101,6 @@ where &self, buf: &mut ::ArgumentBuffer<'r>, ) -> Result> { - >::encode(self.serialize(), buf) + >::encode(self.to_string(), buf) } } diff --git a/src/web/home.rs b/src/web/home.rs index 231ee6a..81ba00e 100644 --- a/src/web/home.rs +++ b/src/web/home.rs @@ -57,7 +57,7 @@ fn birthdays_section( div id="birthdays" { h2 { "Birthdays" } #birthday-sections { - .datelist { + .datelist #upcoming { h3 { "upcoming" } @for contact in &upcoming_birthdays[0..std::cmp::min(3, upcoming_birthdays.len())] { a href=(format!("/contact/{}", contact.contact_id)) { @@ -68,7 +68,7 @@ fn birthdays_section( } } } - .datelist { + .datelist #recent { h3 { "recent" } @for contact in &prev_birthdays[0..std::cmp::min(3, prev_birthdays.len())] { a href=(format!("/contact/{}", contact.contact_id)) {