mirror of
https://github.com/brendan-ch/project-inter-server.git
synced 2026-04-17 07:50:31 +00:00
Merge pull request #21 from brendan-ch/feat/notifications-state
feat/notifications-state
This commit is contained in:
@@ -63,6 +63,8 @@ type Shuttle {
|
|||||||
type Query {
|
type Query {
|
||||||
systems: [System!]!
|
systems: [System!]!
|
||||||
system(id: ID): System
|
system(id: ID): System
|
||||||
|
|
||||||
|
isNotificationScheduled(input: NotificationInput!): Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
# Mutations
|
# Mutations
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ export const QueryResolvers: Resolvers<ServerContext> = {
|
|||||||
name: system.name,
|
name: system.name,
|
||||||
id: system.id,
|
id: system.id,
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
isNotificationScheduled: async (_parent, args, contextValue, _info) => {
|
||||||
|
const notificationData = args.input;
|
||||||
|
return contextValue.notificationService.isNotificationScheduled(notificationData);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -250,4 +250,28 @@ export class NotificationService {
|
|||||||
}
|
}
|
||||||
return this.deviceIdsToDeliverTo[tuple.toString()].has(deviceId);
|
return this.deviceIdsToDeliverTo[tuple.toString()].has(deviceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return all scheduled notification for the given device ID.
|
||||||
|
* @param deviceId
|
||||||
|
*/
|
||||||
|
public async getAllScheduledNotificationsForDevice(deviceId: string): Promise<ScheduledNotificationData[]> {
|
||||||
|
const scheduledNotifications: ScheduledNotificationData[] = [];
|
||||||
|
|
||||||
|
for (const key of Object.keys(this.deviceIdsToDeliverTo)) {
|
||||||
|
if (this.deviceIdsToDeliverTo[key].has(deviceId)) {
|
||||||
|
const tupleKey = TupleKey.fromExistingStringKey(key);
|
||||||
|
const shuttleId = tupleKey.tuple[0]
|
||||||
|
const stopId = tupleKey.tuple[1];
|
||||||
|
|
||||||
|
scheduledNotifications.push({
|
||||||
|
shuttleId,
|
||||||
|
stopId,
|
||||||
|
deviceId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return scheduledNotifications;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,4 +16,9 @@ export class TupleKey<T extends any[]> {
|
|||||||
valueOf(): string {
|
valueOf(): string {
|
||||||
return this.strKey;
|
return this.strKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static fromExistingStringKey(strKey: string) {
|
||||||
|
const tuple = strKey.split(separator);
|
||||||
|
return new TupleKey(...tuple);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { describe, expect, it } from "@jest/globals";
|
|||||||
import { generateMockSystems } from "../testHelpers/mockDataGenerators";
|
import { generateMockSystems } from "../testHelpers/mockDataGenerators";
|
||||||
import { setupTestServerContext, setupTestServerHolder } from "../testHelpers/apolloTestServerHelpers";
|
import { setupTestServerContext, setupTestServerHolder } from "../testHelpers/apolloTestServerHelpers";
|
||||||
import assert = require("node:assert");
|
import assert = require("node:assert");
|
||||||
|
import { ScheduledNotificationData } from "../../src/services/NotificationService";
|
||||||
|
import { addMockShuttleToRepository, addMockStopToRepository } from "../testHelpers/repositorySetupHelpers";
|
||||||
|
|
||||||
// See Apollo documentation for integration test guide
|
// See Apollo documentation for integration test guide
|
||||||
// https://www.apollographql.com/docs/apollo-server/testing/testing
|
// https://www.apollographql.com/docs/apollo-server/testing/testing
|
||||||
@@ -93,4 +95,63 @@ describe("QueryResolvers", () => {
|
|||||||
expect(response.body.singleResult.data?.system).toBeNull();
|
expect(response.body.singleResult.data?.system).toBeNull();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("isNotificationScheduled", () => {
|
||||||
|
const query = `
|
||||||
|
query IsNotificationScheduled($input: NotificationInput!) {
|
||||||
|
isNotificationScheduled(input: $input)
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
it("returns true if the notification is scheduled", async () => {
|
||||||
|
// Arrange
|
||||||
|
const shuttle = await addMockShuttleToRepository(context.repository, "1");
|
||||||
|
const stop = await addMockStopToRepository(context.repository, "1")
|
||||||
|
|
||||||
|
const notification: ScheduledNotificationData = {
|
||||||
|
shuttleId: shuttle.id,
|
||||||
|
stopId: stop.id,
|
||||||
|
deviceId: "1",
|
||||||
|
};
|
||||||
|
await context.notificationService.scheduleNotification(notification);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const response = await holder.testServer.executeOperation({
|
||||||
|
query,
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
...notification,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
contextValue: context,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
assert(response.body.kind === "single");
|
||||||
|
expect(response.body.singleResult.errors).toBeUndefined();
|
||||||
|
expect(response.body.singleResult.data?.isNotificationScheduled).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns false if the notification isn't scheduled", async () => {
|
||||||
|
// Act
|
||||||
|
const response = await holder.testServer.executeOperation({
|
||||||
|
query,
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
shuttleId: "1",
|
||||||
|
stopId: "1",
|
||||||
|
deviceId: "1",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
contextValue: context,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
assert(response.body.kind === "single");
|
||||||
|
expect(response.body.singleResult.errors).toBeUndefined();
|
||||||
|
expect(response.body.singleResult.data?.isNotificationScheduled).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -230,4 +230,38 @@ describe("NotificationService", () => {
|
|||||||
expect(http2.connect as jest.Mock).toHaveBeenCalledTimes(0);
|
expect(http2.connect as jest.Mock).toHaveBeenCalledTimes(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("getAllScheduledNotificationsForDevice", () => {
|
||||||
|
it("returns scheduled notifications for the device ID", async () => {
|
||||||
|
// Arrange
|
||||||
|
const shuttle1 = await addMockShuttleToRepository(repository, "1");
|
||||||
|
const stop = await addMockStopToRepository(repository, "1");
|
||||||
|
const { eta, notificationData1 } = generateNotificationDataAndEta(shuttle1, stop);
|
||||||
|
await notificationService.scheduleNotification(notificationData1);
|
||||||
|
|
||||||
|
const shuttle2 = {
|
||||||
|
...shuttle1,
|
||||||
|
id: "2",
|
||||||
|
}
|
||||||
|
await repository.addOrUpdateShuttle(shuttle2);
|
||||||
|
|
||||||
|
const notificationData2 = {
|
||||||
|
...notificationData1,
|
||||||
|
shuttleId: shuttle2.id,
|
||||||
|
}
|
||||||
|
await notificationService.scheduleNotification(notificationData2);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const notifications = await notificationService.getAllScheduledNotificationsForDevice(notificationData1.deviceId);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(notifications.length).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns an empty array if there are no notifications", async () => {
|
||||||
|
// Act
|
||||||
|
const notifications = await notificationService.getAllScheduledNotificationsForDevice("1");
|
||||||
|
expect(notifications.length).toBe(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -28,4 +28,18 @@ describe("TupleKey", () => {
|
|||||||
expect(sampleObject[tupleKey1.toString()]).toEqual("value1");
|
expect(sampleObject[tupleKey1.toString()]).toEqual("value1");
|
||||||
expect(sampleObject[(new TupleKey("1", "2")).toString()]).toEqual("value1");
|
expect(sampleObject[(new TupleKey("1", "2")).toString()]).toEqual("value1");
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
describe("fromExistingStringKey", () => {
|
||||||
|
it("creates a new TupleKey from an existing string key", () => {
|
||||||
|
const strKey = "hello|there";
|
||||||
|
const tupleKey = TupleKey.fromExistingStringKey(strKey);
|
||||||
|
expect(tupleKey.toString()).toEqual(strKey);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("creates an empty tuple if there is no string", () => {
|
||||||
|
const strKey = "";
|
||||||
|
const tupleKey = TupleKey.fromExistingStringKey(strKey);
|
||||||
|
expect(tupleKey.toString()).toEqual(strKey);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user