From 51d66d88865ce8e4ccf70b4e4375c1c8ada9e239 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Thu, 27 Mar 2025 11:18:43 -0700 Subject: [PATCH] add tests and implementation for notification deletes --- .../InMemoryNotificationRepository.ts | 24 ++++++++++++- ...nMemoryNotificationRepositoryTests.test.ts | 35 +++++++++++++++---- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/src/repositories/InMemoryNotificationRepository.ts b/src/repositories/InMemoryNotificationRepository.ts index 78a4834..e543e8c 100644 --- a/src/repositories/InMemoryNotificationRepository.ts +++ b/src/repositories/InMemoryNotificationRepository.ts @@ -19,7 +19,7 @@ export class InMemoryNotificationRepository implements NotificationRepository { */ private deviceIdsToDeliverTo: { [key: string]: DeviceIdSecondsThresholdAssociation } = {} - private subscribers: Listener[] = []; + private listeners: Listener[] = []; async getAllNotificationsForShuttleAndStopId(shuttleId: string, stopId: string) { const tuple = new TupleKey(shuttleId, stopId); @@ -81,12 +81,34 @@ export class InMemoryNotificationRepository implements NotificationRepository { return; } + const secondsThreshold = this.deviceIdsToDeliverTo[tupleKey.toString()][deviceId]; delete this.deviceIdsToDeliverTo[tupleKey.toString()][deviceId]; + this.listeners.forEach((listener) => { + const event: NotificationEvent = { + event: 'delete', + notification: { + deviceId, + shuttleId, + stopId, + secondsThreshold + } + } + + listener(event); + }) } public subscribeToNotificationChanges(listener: Listener): void { + const index = this.listeners.findIndex((existingListener) => existingListener == listener); + if (index < 0) { + this.listeners.push(listener); + } } public unsubscribeFromNotificationChanges(listener: Listener): void { + const index = this.listeners.findIndex((existingListener) => existingListener == listener); + if (index >= 0) { + this.listeners.splice(index, 1); + } } } diff --git a/test/repositories/InMemoryNotificationRepositoryTests.test.ts b/test/repositories/InMemoryNotificationRepositoryTests.test.ts index 20ce245..1feb9c3 100644 --- a/test/repositories/InMemoryNotificationRepositoryTests.test.ts +++ b/test/repositories/InMemoryNotificationRepositoryTests.test.ts @@ -1,5 +1,6 @@ -import { beforeEach, describe, expect, it } from "@jest/globals"; +import { beforeEach, describe, expect, it, jest } from "@jest/globals"; import { InMemoryNotificationRepository } from "../../src/repositories/InMemoryNotificationRepository"; +import { NotificationEvent } from "../../src/repositories/NotificationRepository"; describe("InMemoryNotificationRepository", () => { let repo: InMemoryNotificationRepository; @@ -71,16 +72,13 @@ describe("InMemoryNotificationRepository", () => { describe("deleteNotificationIfExists", () => { it("deletes the notification", async () => { await repo.addOrUpdateNotification(notification); - await repo.deleteNotificationIfExists({ - deviceId: "device1", - shuttleId: "shuttle1", - stopId: "stop1" - }); + await repo.deleteNotificationIfExists(notification); const result = await repo.getAllNotificationsForShuttleAndStopId("shuttle1", "stop1"); expect(result).toHaveLength(0); }); + it("does nothing if there's no notification", async () => { await expect(repo.deleteNotificationIfExists({ deviceId: "device1", @@ -89,4 +87,29 @@ describe("InMemoryNotificationRepository", () => { })).resolves.not.toThrow(); }); }); + + describe("subscribeToNotificationChanges", () => { + it("calls subscribers when something is added", async () => { + + }); + + it("calls subscribers when something is deleted", async () => { + await repo.addOrUpdateNotification(notification); + + const mockCallback = jest.fn(); + repo.subscribeToNotificationChanges(mockCallback); + + await repo.deleteNotificationIfExists(notification); + + expect(mockCallback).toHaveBeenCalledTimes(1); + + const expectedEvent: NotificationEvent = { + event: 'delete', + notification: { + ...notification, + }, + }; + expect(mockCallback).toHaveBeenCalledWith(expectedEvent); + }); + }) });