From 85695666b474d321d2908c85702131c0e54cab30 Mon Sep 17 00:00:00 2001 From: Ben Mitchinson Date: Sun, 17 Mar 2024 23:15:05 -0500 Subject: [PATCH] Add tests that mock + advance time --- README.md | 3 +- tests/CommonTestOperations.ts | 12 +++++- tests/main-page.spec.ts | 70 ++++++++++++++++++++++++++--------- 3 files changed, 65 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index dcbdd96..be2bb0c 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,5 @@ auto-generated categorization table. ### Next Up -- Need tests that can advance the mock time to test reset / submit sets time to - current. +- Blog post about time mock - Need shadcn before adding more features diff --git a/tests/CommonTestOperations.ts b/tests/CommonTestOperations.ts index df15fad..899598d 100644 --- a/tests/CommonTestOperations.ts +++ b/tests/CommonTestOperations.ts @@ -1,14 +1,19 @@ import { expect, type Page } from "@playwright/test"; import { format, parse } from "date-fns"; +const formatOfDatetimeFieldValue = "yyyy-MM-dd'T'HH:mm"; + export const mockedClockDatetimeString = "2023-05-12T01:30"; export const mockedClockDate = parse( mockedClockDatetimeString, - "yyyy-MM-dd'T'HH:mm", + formatOfDatetimeFieldValue, new Date() ); +export const dateToDatetimeFieldValue = (date: Date) => + format(date, formatOfDatetimeFieldValue); + export const fillPurchaseFormWithValidData = async (page: Page) => { await page.getByLabel("Amount").fill("10.77"); await page.getByLabel("Description").fill("cool trip"); @@ -62,6 +67,11 @@ export const categoryOnForm = async (page: Page) => { } }; +export const advanceTimeOneMinute = async (page: Page) => + await page.evaluate(() => { + (window as any).advanceTimeOneMinute(); + }); + export const expectTheseAtPurchaseIndex = async ( page: Page, values: string[], diff --git a/tests/main-page.spec.ts b/tests/main-page.spec.ts index 132617e..b974ab9 100644 --- a/tests/main-page.spec.ts +++ b/tests/main-page.spec.ts @@ -14,8 +14,10 @@ import { expectTheseAtPurchaseIndex, mockedClockDate, mockedClockDatetimeString, + advanceTimeOneMinute, + dateToDatetimeFieldValue, } from "./CommonTestOperations"; -import { format } from "date-fns"; +import { add, format } from "date-fns"; // TODO: Use shadcn/ui @@ -25,17 +27,21 @@ test.beforeEach(async ({ page }) => { // Update the Date accordingly in your test pages await page.addInitScript(`{ - // Extend Date constructor to default to fakeNow + window.__minutesPassed = 0; + + window.advanceTimeOneMinute = () => { + console.log("TIME ADVANCING TO " + ++window.__minutesPassed + " MINUTE(S) PASSED."); + } + + Date.now = () => { + return ${fakeNow} + window.__minutesPassed * 60000; + } + Date = class extends Date { constructor(...args) { - (args.length === 0) ? super(${fakeNow}) : super(...args) + (args.length === 0) ? super(${fakeNow} + window.__minutesPassed * 60000) : super(...args) } } - - // Override Date.now() to start from fakeNow - const __DateNowOffset = ${fakeNow} - Date.now(); - const __DateNow = Date.now; - Date.now = () => __DateNow() + __DateNowOffset; }`); await clearFirebaseData().then(createFakePurchases); @@ -77,13 +83,25 @@ test.describe("Entry form", () => { // todo-postshadcn: add clear button to form - test("Defaults to the current datetime", async ({ page }) => {}); + test("Defaults to the current datetime", async ({ page }) => { + await advanceTimeOneMinute(page); + await advanceTimeOneMinute(page); + await page.getByText("Submit").click(); + + const expectedTime = add(mockedClockDate, { minutes: 2 }); + await expect(page.getByTestId("datetime-input")).toHaveValue( + new RegExp(dateToDatetimeFieldValue(expectedTime)) + ); + }); }); test.describe("Adding", () => { - test("Adding a purchase saves it to the database", async ({ page }) => { + test.beforeEach(async ({ page }) => { await clearFirebaseData().then(() => page.goto("/")); await fillPurchaseFormWithValidData(page); + }); + + test("Adding a purchase saves it to the database", async ({ page }) => { await page.getByText("Submit").click(); await expect(page.getByTestId("purchase-list-item-0")).toContainText( @@ -95,8 +113,18 @@ test.describe("Adding", () => { await expect(page.getByTestId("purchase-list-item-0")).toContainText("Gas"); }); - // TODO done but needs test - // test("Adding a purchase÷ resets date/time to current time"); + test("Adding a purchase resets date/time to current time", async ({ + page, + }) => { + await advanceTimeOneMinute(page); + await advanceTimeOneMinute(page); + await page.getByText("Submit").click(); + + const expectedTime = add(mockedClockDate, { minutes: 2 }); + await expect(page.getByTestId("datetime-input")).toHaveValue( + new RegExp(dateToDatetimeFieldValue(expectedTime)) + ); + }); // todo-postshadcn: validation for each field (right now you can just do category) }); @@ -217,11 +245,19 @@ test("Tests running in playwright use fake database", async ({ page }) => { }); }); -// test.describe("Reset", async ({ page }) => { -// todo: reset should populate to an updated time, not the time when the page was loaded -// done but needs test. -// need a way to advance time a minute -// }); +test.describe("Reset", () => { + test("Reseting updates time in date/time entry", async ({ page }) => { + await advanceTimeOneMinute(page); + await advanceTimeOneMinute(page); + + await page.getByText("Reset").click(); + + const expectedTime = add(mockedClockDate, { minutes: 2 }); + await expect(page.getByTestId("datetime-input")).toHaveValue( + new RegExp(dateToDatetimeFieldValue(expectedTime)) + ); + }); +}); // todo: enable some of these tests to run in offline mode // as well?