Files
project-inter-server/test/notifications/schedulers/ETANotificationSchedulerTests.test.ts

146 lines
5.9 KiB
TypeScript

import { beforeEach, describe, expect, it, jest } from "@jest/globals";
import { ETANotificationScheduler } from "../../../src/notifications/schedulers/ETANotificationScheduler";
import { UnoptimizedInMemoryShuttleRepository } from "../../../src/repositories/UnoptimizedInMemoryShuttleRepository";
import { IEta, IShuttle, IStop } from "../../../src/entities/entities";
import { addMockShuttleToRepository, addMockStopToRepository } from "../../testHelpers/repositorySetupHelpers";
import { AppleNotificationSender } from "../../../src/notifications/senders/AppleNotificationSender";
import { InMemoryNotificationRepository } from "../../../src/repositories/InMemoryNotificationRepository";
import { NotificationRepository } from "../../../src/repositories/NotificationRepository";
jest.mock("http2");
jest.mock("../../../src/notifications/senders/AppleNotificationSender");
const MockAppleNotificationSender = AppleNotificationSender as jest.MockedClass<typeof AppleNotificationSender>;
function mockNotificationSenderMethods(shouldSimulateNotificationSend: boolean) {
MockAppleNotificationSender.prototype.sendNotificationImmediately = jest.fn(async () => shouldSimulateNotificationSend);
}
/**
* Wait for a specified number of milliseconds.
* @param ms
*/
async function waitForMilliseconds(ms: number): Promise<void> {
await new Promise((resolve) => setTimeout(resolve, ms));
}
describe("ETANotificationScheduler", () => {
let shuttleRepository: UnoptimizedInMemoryShuttleRepository
let notificationService: ETANotificationScheduler;
let notificationRepository: NotificationRepository;
beforeEach(() => {
shuttleRepository = new UnoptimizedInMemoryShuttleRepository();
notificationRepository = new InMemoryNotificationRepository();
mockNotificationSenderMethods(true);
const appleNotificationSender = new MockAppleNotificationSender(false);
notificationService = new ETANotificationScheduler(
shuttleRepository,
notificationRepository,
appleNotificationSender
);
notificationService.startListeningForUpdates();
});
function generateNotificationDataAndEta(shuttle: IShuttle, stop: IStop) {
const eta: IEta = {
shuttleId: shuttle.id,
stopId: stop.id,
secondsRemaining: 120,
};
const notificationData1 = {
deviceId: "1",
shuttleId: eta.shuttleId,
stopId: eta.stopId,
secondsThreshold: 240,
}
const notificationData2 = {
...notificationData1,
deviceId: "2",
secondsThreshold: 180,
}
return { eta, notificationData1, notificationData2 };
}
describe("etaSubscriberCallback", () => {
it("sends and clears correct notification after ETA changed", async () => {
// Arrange
const shuttle = await addMockShuttleToRepository(shuttleRepository, "1");
const stop = await addMockStopToRepository(shuttleRepository, "1");
const { eta, notificationData1, notificationData2 } = generateNotificationDataAndEta(shuttle, stop);
// Act
await notificationRepository.addOrUpdateNotification(notificationData1);
await notificationRepository.addOrUpdateNotification(notificationData2);
await shuttleRepository.addOrUpdateEta(eta);
// Assert
// Wait for the callback to actually be called
await waitForMilliseconds(1000);
const isFirstNotificationScheduled = await notificationRepository.isNotificationScheduled(notificationData1);
const isSecondNotificationScheduled = await notificationRepository.isNotificationScheduled(notificationData2);
// No longer scheduled after being sent
expect(isFirstNotificationScheduled).toBe(false);
expect(isSecondNotificationScheduled).toBe(false);
});
it("doesn't send notification if seconds threshold not exceeded", async () => {
// Arrange
const shuttle = await addMockShuttleToRepository(shuttleRepository, "1");
const stop = await addMockStopToRepository(shuttleRepository, "1");
const { eta, notificationData1 } = generateNotificationDataAndEta(shuttle, stop);
notificationData1.secondsThreshold = eta.secondsRemaining - 10;
// Act
await notificationRepository.addOrUpdateNotification(notificationData1);
await shuttleRepository.addOrUpdateEta(eta);
// Assert
await waitForMilliseconds(500);
const isNotificationScheduled = await notificationRepository.isNotificationScheduled(notificationData1);
expect(isNotificationScheduled).toBe(true);
});
it("leaves notification in array if delivery unsuccessful", async () => {
// Arrange
const shuttle = await addMockShuttleToRepository(shuttleRepository, "1");
const stop = await addMockStopToRepository(shuttleRepository, "1");
const { eta, notificationData1 } = generateNotificationDataAndEta(shuttle, stop)
// replace the old notification scheduler with a new one
// detach the old callback method from the shuttle repo
notificationService.stopListeningForUpdates();
// replace the notification repository with a fresh one too
const notificationRepository = new InMemoryNotificationRepository();
mockNotificationSenderMethods(false);
const updatedNotificationSender = new MockAppleNotificationSender(false);
notificationService = new ETANotificationScheduler(
shuttleRepository,
notificationRepository,
updatedNotificationSender
);
notificationService.startListeningForUpdates();
// Act
await notificationRepository.addOrUpdateNotification(notificationData1);
await shuttleRepository.addOrUpdateEta(eta);
// Assert
// The notification should stay scheduled to be retried once
// the ETA updates again
await waitForMilliseconds(500);
const isNotificationScheduled = await notificationRepository.isNotificationScheduled(notificationData1);
expect(isNotificationScheduled).toBe(true);
});
});
});