Last active
December 22, 2021 17:10
-
-
Save pmcelhaney/accf7727294a8315c504e1985d44c0ce to your computer and use it in GitHub Desktop.
Reactive controller with unit test
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import type { ReactiveControllerHost } from "lit"; | |
| import { ClockController } from "../../src/controllers/clock-controller"; | |
| class Host implements ReactiveControllerHost { | |
| updateComplete: Promise<boolean>; | |
| clock: ClockController; | |
| emittedTimes: string[] = []; | |
| addController(controller: ClockController): void { | |
| this.clock = controller; | |
| this.requestUpdate(); | |
| } | |
| removeController(): void { | |
| return undefined; | |
| } | |
| requestUpdate(): void { | |
| this.emittedTimes.push( | |
| this.clock.time.toString({ smallestUnit: "minute" }) | |
| ); | |
| } | |
| } | |
| function emittedTimesAfterTicks(hours: number, minutes: number, ticks: number) { | |
| jest.useFakeTimers(); | |
| const spy = jest | |
| .spyOn(Date, "now") | |
| .mockReturnValue(new Date(2021, 1, 1, hours, minutes).valueOf()); | |
| try { | |
| const host = new Host(); | |
| const clock = new ClockController(host); | |
| clock.hostConnected(); | |
| for (let secondsPassed = 1; secondsPassed <= ticks; secondsPassed += 1) { | |
| spy.mockReturnValue( | |
| new Date(2021, 1, 1, hours, minutes, secondsPassed).valueOf() | |
| ); | |
| jest.advanceTimersByTime(1000); | |
| } | |
| return host.emittedTimes; | |
| } finally { | |
| jest.useRealTimers(); | |
| spy.mockRestore(); | |
| } | |
| } | |
| describe("clock Controller", () => { | |
| it("starts with the current time", () => { | |
| expect(emittedTimesAfterTicks(12, 15, 0)).toStrictEqual(["12:15"]); | |
| }); | |
| it("does not update the time if the minute has not changed", () => { | |
| expect(emittedTimesAfterTicks(12, 15, 59)).toStrictEqual(["12:15"]); | |
| }); | |
| it("updates the time if the minute has changed", () => { | |
| expect(emittedTimesAfterTicks(12, 15, 60)).toStrictEqual([ | |
| "12:15", | |
| "12:16", | |
| ]); | |
| }); | |
| it("updates more than once", () => { | |
| expect(emittedTimesAfterTicks(12, 15, 180)).toStrictEqual([ | |
| "12:15", | |
| "12:16", | |
| "12:17", | |
| "12:18", | |
| ]); | |
| }); | |
| it("stops updating the host when disconnected", () => { | |
| jest.useFakeTimers(); | |
| const spy = jest | |
| .spyOn(Date, "now") | |
| .mockReturnValue(new Date(2021, 1, 1, 12, 15).valueOf()); | |
| try { | |
| const host = new Host(); | |
| const clock = new ClockController(host); | |
| clock.hostConnected(); | |
| spy.mockReturnValue(new Date(2021, 1, 1, 12, 15).valueOf()); | |
| clock.hostDisconnected(); | |
| spy.mockReturnValue(new Date(2021, 1, 1, 12, 16).valueOf()); | |
| jest.advanceTimersByTime(60 * 1000); | |
| expect(clock.time.toString({ smallestUnit: "minute" })).toBe("12:15"); | |
| } finally { | |
| jest.useRealTimers(); | |
| spy.mockRestore(); | |
| } | |
| }); | |
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import type { ReactiveController, ReactiveControllerHost } from "lit"; | |
| import { Temporal } from "@js-temporal/polyfill"; | |
| const CLOCK_TICK_INTERVAL_IN_MS = 1000; | |
| export interface Clock { | |
| time: Temporal.PlainTime; | |
| } | |
| export class ClockController implements Clock, ReactiveController { | |
| time: Temporal.PlainTime = Temporal.Now.plainTimeISO(); | |
| host: ReactiveControllerHost; | |
| #interval: ReturnType<typeof setInterval>; | |
| constructor(host: ReactiveControllerHost) { | |
| host.addController(this); | |
| this.host = host; | |
| } | |
| hostConnected() { | |
| this.#interval = setInterval(() => { | |
| const oldTime = this.time; | |
| this.time = Temporal.Now.plainTimeISO(); | |
| if ( | |
| this.time.toString({ smallestUnit: "minute" }) !== | |
| oldTime.toString({ smallestUnit: "minute" }) | |
| ) { | |
| this.host.requestUpdate(); | |
| } | |
| }, CLOCK_TICK_INTERVAL_IN_MS); | |
| } | |
| hostDisconnected() { | |
| clearInterval(this.#interval); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment