Files
project-inter-server/test/repositories/NotificationRepositorySharedTests.test.ts

199 lines
6.1 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, jest } from "@jest/globals";
import { InMemoryNotificationRepository } from "../../src/repositories/InMemoryNotificationRepository";
import { NotificationEvent, NotificationRepository } from "../../src/repositories/NotificationRepository";
import { RedisNotificationRepository } from "../../src/repositories/RedisNotificationRepository";
interface RepositoryHolder {
name: string;
factory(): Promise<NotificationRepository>,
teardown(): Promise<void>,
}
class InMemoryRepositoryHolder implements RepositoryHolder {
name = 'InMemoryNotificationRepository';
factory = async () => {
return new InMemoryNotificationRepository();
}
teardown = async () => {}
}
class RedisNotificationRepositoryHolder implements RepositoryHolder {
repo: RedisNotificationRepository | undefined;
name = 'RedisNotificationRepository';
factory = async () => {
this.repo = new RedisNotificationRepository();
await this.repo.connect();
return this.repo;
}
teardown = async () => {
if (this.repo) {
await this.repo.clearAllData();
await this.repo.disconnect();
}
}
}
const repositoryImplementations = [
new InMemoryRepositoryHolder(),
new RedisNotificationRepositoryHolder(),
]
describe.each(repositoryImplementations)('$name', (holder) => {
let repo: NotificationRepository;
beforeEach(async () => {
repo = await holder.factory();
});
afterEach(async () => {
await holder.teardown();
})
const notification = {
deviceId: "device1",
shuttleId: "shuttle1",
stopId: "stop1",
secondsThreshold: 180
};
describe("getAllNotificationsForShuttleAndStopId", () => {
it("gets notifications correctly", async () => {
await repo.addOrUpdateNotification(notification);
const result = await repo.getAllNotificationsForShuttleAndStopId("shuttle1", "stop1");
expect(result).toHaveLength(1);
expect(result[0]).toEqual(notification);
});
it("returns empty array if no notifications", async () => {
const result = await repo.getAllNotificationsForShuttleAndStopId("shuttle1", "stop1");
expect(result).toEqual([]);
});
});
describe("getSecondsThresholdForNotificationIfExists", () => {
it("gets the seconds threshold if exists", async () => {
await repo.addOrUpdateNotification(notification);
const result = await repo.getSecondsThresholdForNotificationIfExists({
deviceId: "device1",
shuttleId: "shuttle1",
stopId: "stop1"
});
expect(result).toBe(180);
});
it("returns null if there is no seconds threshold", async () => {
const result = await repo.getSecondsThresholdForNotificationIfExists({
deviceId: "device1",
shuttleId: "shuttle1",
stopId: "stop1"
});
expect(result).toBeNull();
});
});
describe("addOrUpdateNotification", () => {
// Add/get flow is covered in getAllNotificationsForShuttleAndStopId
it("updates the seconds threshold if the notification exists already", async () => {
await repo.addOrUpdateNotification(notification);
await repo.addOrUpdateNotification({...notification, secondsThreshold: 300});
const result = await repo.getSecondsThresholdForNotificationIfExists({
deviceId: "device1",
shuttleId: "shuttle1",
stopId: "stop1"
});
expect(result).toBe(300);
});
});
describe("deleteNotificationIfExists", () => {
it("deletes the notification", async () => {
await repo.addOrUpdateNotification(notification);
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",
shuttleId: "shuttle1",
stopId: "stop1"
})).resolves.not.toThrow();
});
});
describe("subscribeToNotificationChanges", () => {
it("calls subscribers when something is added", async () => {
const mockCallback = jest.fn();
repo.subscribeToNotificationChanges(mockCallback);
await repo.addOrUpdateNotification(notification);
const expectedEvent: NotificationEvent = {
event: 'addOrUpdate',
notification,
}
expect(mockCallback).toHaveBeenCalledTimes(1);
expect(mockCallback).toHaveBeenCalledWith(expectedEvent);
});
it("calls subscribers when something is updated", async () => {
const mockCallback = jest.fn();
repo.subscribeToNotificationChanges(mockCallback);
await repo.addOrUpdateNotification(notification);
const updatedNotification = {
...notification,
secondsThreshold: notification.secondsThreshold + 60,
};
await repo.addOrUpdateNotification(updatedNotification);
const expectedEvent: NotificationEvent = {
event: 'addOrUpdate',
notification,
}
expect(mockCallback).toHaveBeenCalledTimes(2);
expect(mockCallback).toHaveBeenCalledWith(expectedEvent);
});
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,
};
expect(mockCallback).toHaveBeenCalledWith(expectedEvent);
});
});
describe("isNotificationScheduled", () => {
it("returns true if the notification is in the repo", async () => {
await repo.addOrUpdateNotification(notification);
const result = await repo.isNotificationScheduled(notification);
expect(result).toBe(true);
});
it("returns false if the notification isn't in the repo", async () => {
const result = await repo.isNotificationScheduled(notification);
expect(result).toBe(false);
})
});
});