diff --git a/package-lock.json b/package-lock.json index f9544cc..4d485f2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,6 @@ "version": "1.0.0", "dependencies": { "@apollo/server": "^4.11.2", - "@types/jsonwebtoken": "^9.0.8", "graphql": "^16.10.0", "jsonwebtoken": "^9.0.2" }, @@ -18,6 +17,7 @@ "@graphql-codegen/typescript": "4.1.2", "@graphql-codegen/typescript-resolvers": "4.4.1", "@jest/globals": "^29.7.0", + "@types/jsonwebtoken": "^9.0.8", "@types/node": "^22.10.2", "jest": "^29.7.0", "ts-jest": "^29.2.5", @@ -3571,6 +3571,7 @@ "version": "9.0.8", "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.8.tgz", "integrity": "sha512-7fx54m60nLFUVYlxAB1xpe9CBWX2vSrk50Y6ogRJ1v5xxtba7qXTg5BgYDN5dq+yuQQ9HaVlHJyAAt1/mxryFg==", + "dev": true, "dependencies": { "@types/ms": "*", "@types/node": "*" @@ -3589,7 +3590,8 @@ "node_modules/@types/ms": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==" + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true }, "node_modules/@types/node": { "version": "22.10.2", diff --git a/schema.graphqls b/schema.graphqls index 3d26683..6296660 100644 --- a/schema.graphqls +++ b/schema.graphqls @@ -1,8 +1,4 @@ -type Query { - systems: [System!]! - system(id: ID): System -} - +# Base types type System { id: ID! name: String! @@ -62,3 +58,33 @@ type Shuttle { etas: [ETA!] eta(forStopId: ID): ETA } + +# Queries +type Query { + systems: [System!]! + system(id: ID): System +} + +# Mutations +type Mutation { + scheduleNotification(input: NotificationInput!): NotificationResponse! + cancelNotification(input: NotificationInput!): NotificationResponse! +} + +input NotificationInput { + deviceId: ID! + shuttleId: ID! + stopId: ID! +} + +type NotificationResponse { + success: Boolean! + message: String! + data: Notification +} + +type Notification { + deviceId: ID! + shuttleId: ID! + stopId: ID! +} diff --git a/src/MergedResolvers.ts b/src/MergedResolvers.ts index bfa40eb..3c0caad 100644 --- a/src/MergedResolvers.ts +++ b/src/MergedResolvers.ts @@ -7,6 +7,7 @@ import { OrderedStopResolvers } from "./resolvers/OrderedStopResolvers"; import { StopResolvers } from "./resolvers/StopResolvers"; import { ShuttleResolvers } from "./resolvers/ShuttleResolvers"; import { RouteResolvers } from "./resolvers/RouteResolvers"; +import { MutationResolvers } from "./resolvers/MutationResolvers"; export const MergedResolvers: Resolvers = { ...QueryResolvers, @@ -16,4 +17,5 @@ export const MergedResolvers: Resolvers = { ...StopResolvers, ...OrderedStopResolvers, ...EtaResolvers, -}; \ No newline at end of file + ...MutationResolvers, +}; diff --git a/src/ServerContext.ts b/src/ServerContext.ts index c380583..6579453 100644 --- a/src/ServerContext.ts +++ b/src/ServerContext.ts @@ -1,5 +1,7 @@ -import { GetterRepository } from "./repositories/GetterRepository"; +import { NotificationService } from "./services/NotificationService"; +import { GetterSetterRepository } from "./repositories/GetterSetterRepository"; export interface ServerContext { - repository: GetterRepository; -} \ No newline at end of file + repository: GetterSetterRepository; + notificationService: NotificationService; +} diff --git a/src/index.ts b/src/index.ts index b90d962..9e93dcc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,6 +5,7 @@ import { MergedResolvers } from "./MergedResolvers"; import { ServerContext } from "./ServerContext"; import { UnoptimizedInMemoryRepository } from "./repositories/UnoptimizedInMemoryRepository"; import { TimedApiBasedRepositoryLoader } from "./loaders/TimedApiBasedRepositoryLoader"; +import { NotificationService } from "./services/NotificationService"; const typeDefs = readFileSync("./schema.graphqls", "utf8"); @@ -16,13 +17,13 @@ async function main() { }); const repository = new UnoptimizedInMemoryRepository(); - // await loadTestData(repository); - const repositoryDataUpdater = new TimedApiBasedRepositoryLoader( repository ); await repositoryDataUpdater.start(); + const notificationService = new NotificationService(repository); + const { url } = await startStandaloneServer(server, { listen: { port: process.env.PORT ? parseInt(process.env.PORT) : 4000, @@ -30,6 +31,7 @@ async function main() { context: async ({ req, res }) => { return { repository, + notificationService, } }, }); diff --git a/src/resolvers/MutationResolvers.ts b/src/resolvers/MutationResolvers.ts new file mode 100644 index 0000000..c1a4ce3 --- /dev/null +++ b/src/resolvers/MutationResolvers.ts @@ -0,0 +1,47 @@ +import { NotificationInput, NotificationResponse, Resolvers } from "../generated/graphql"; +import { ServerContext } from "../ServerContext"; + +export const MutationResolvers: Resolvers = { + Mutation: { + scheduleNotification: async (_parent, args, context, _info) => { + const shuttle = await context.repository.getShuttleById(args.input.shuttleId); + if (!shuttle) { + return { + message: "Shuttle ID doesn't exist", + success: false, + } + } + const stop = await context.repository.getStopById(args.input.stopId); + if (!stop) { + return { + message: "Stop ID doesn't exist", + success: false, + } + } + + await context.notificationService.scheduleNotification(args.input); + + const response: NotificationResponse = { + message: "Notification scheduled", + success: true, + data: args.input, + } + return response; + }, + cancelNotification: async (_parent, args, context, _info) => { + if (context.notificationService.isNotificationScheduled(args.input)) { + await context.notificationService.cancelNotificationIfExists(args.input); + return { + success: true, + message: "Notification cancelled", + data: args.input, + } + } + + return { + success: false, + message: "Notification doesn't exist" + } + }, + }, +} diff --git a/test/resolvers/EtaResolverTests.test.ts b/test/resolvers/EtaResolverTests.test.ts index 73c9770..98c2e52 100644 --- a/test/resolvers/EtaResolverTests.test.ts +++ b/test/resolvers/EtaResolverTests.test.ts @@ -1,5 +1,5 @@ import { beforeEach, describe, expect, it } from "@jest/globals"; -import { setupTestServerContext } from "../testHelpers/apolloTestServerHelpers"; +import { setupTestServerContext, setupTestServerHolder } from "../testHelpers/apolloTestServerHelpers"; import { IEta, IShuttle, IStop, ISystem } from "../../src/entities/entities"; import { addMockEtaToRepository, addMockShuttleToRepository, @@ -9,6 +9,7 @@ import { import assert = require("node:assert"); describe("EtaResolvers", () => { + const holder = setupTestServerHolder(); const context = setupTestServerContext(); let mockSystem: ISystem; @@ -24,7 +25,7 @@ describe("EtaResolvers", () => { }); async function getResponseForEtaQuery(query: string) { - const response = await context.testServer.executeOperation({ + const response = await holder.testServer.executeOperation({ query, variables: { systemId: mockSystem.id, @@ -87,4 +88,4 @@ describe("EtaResolvers", () => { expect(eta.shuttle.id).toEqual(expectedEta.shuttleId); }); }); -}); \ No newline at end of file +}); diff --git a/test/resolvers/MutationResolverTests.test.ts b/test/resolvers/MutationResolverTests.test.ts new file mode 100644 index 0000000..d4f5318 --- /dev/null +++ b/test/resolvers/MutationResolverTests.test.ts @@ -0,0 +1,156 @@ +import { describe, expect, it } from "@jest/globals"; +import { setupTestServerContext, setupTestServerHolder } from "../testHelpers/apolloTestServerHelpers"; +import { + addMockShuttleToRepository, + addMockStopToRepository, + addMockSystemToRepository +} from "../testHelpers/repositorySetupHelpers"; +import assert = require("node:assert"); +import { NotificationInput } from "../../src/generated/graphql"; + +describe("MutationResolvers", () => { + const holder = setupTestServerHolder() + const context = setupTestServerContext(); + + async function getServerResponse(query: string, notificationInput: { deviceId: string; shuttleId: string; stopId: string }) { + return await holder.testServer.executeOperation({ + query, + variables: { + input: notificationInput, + } + }, { + contextValue: context + }); + } + + describe("scheduleNotification", () => { + const query = ` + mutation ScheduleNotification($input: NotificationInput!) { + scheduleNotification(input: $input) { + success + message + data { + deviceId + shuttleId + stopId + } + } + } + ` + + function assertFailedResponse(response: any, notificationInput: NotificationInput) { + assert(response.body.kind === "single"); + expect(response.body.singleResult.errors).toBeUndefined(); + const notificationResponse = response.body.singleResult.data?.scheduleNotification as any; + expect(notificationResponse.success).toBe(false); + + expect(context.notificationService.isNotificationScheduled(notificationInput)).toBe(false); + } + + + it("adds a notification to the notification service", async () => { + const system = await addMockSystemToRepository(context.repository); + const shuttle = await addMockShuttleToRepository(context.repository, system.id); + const stop = await addMockStopToRepository(context.repository, system.id); + + const notificationInput = { + deviceId: "1", + shuttleId: shuttle.id, + stopId: stop.id, + }; + const response = await getServerResponse(query, notificationInput); + + assert(response.body.kind === "single"); + expect(response.body.singleResult.errors).toBeUndefined(); + + const notificationResponse = response.body.singleResult.data?.scheduleNotification as any; + expect(notificationResponse?.success).toBe(true); + expect(notificationResponse?.data).toEqual(notificationInput); + + expect(context.notificationService.isNotificationScheduled(notificationInput)).toBe(true); + }); + + it("fails if the shuttle ID doesn't exist", async () => { + const system = await addMockSystemToRepository(context.repository); + const stop = await addMockStopToRepository(context.repository, system.id); + + const notificationInput = { + deviceId: "1", + shuttleId: "1", + stopId: stop.id, + } + const response = await getServerResponse(query, notificationInput); + assertFailedResponse(response, notificationInput); + }); + + it("fails if the stop ID doesn't exist", async () => { + const system = await addMockSystemToRepository(context.repository); + const shuttle = await addMockShuttleToRepository(context.repository, system.id); + + const notificationInput = { + deviceId: "1", + shuttleId: shuttle.id, + stopId: "1", + } + const response = await getServerResponse(query, notificationInput); + + assertFailedResponse(response, notificationInput); + }); + }); + + describe("cancelNotification", () => { + const query = ` + mutation CancelNotification($input: NotificationInput!) { + cancelNotification(input: $input) { + success + message + data { + deviceId + shuttleId + stopId + } + } + } + ` + + it("removes the notification from the notification service", async () => { + const system = await addMockSystemToRepository(context.repository); + const shuttle = await addMockShuttleToRepository(context.repository, system.id); + const stop = await addMockStopToRepository(context.repository, system.id); + + const notificationInput = { + deviceId: "1", + shuttleId: shuttle.id, + stopId: stop.id, + } + await context.notificationService.scheduleNotification(notificationInput); + + const response = await getServerResponse(query, notificationInput); + + assert(response.body.kind === "single"); + expect(response.body.singleResult.errors).toBeUndefined(); + + const notificationResponse = response.body.singleResult.data?.cancelNotification as any; + expect(notificationResponse.success).toBe(true); + expect(notificationResponse.data).toEqual(notificationInput); + + expect(context.notificationService.isNotificationScheduled(notificationInput)).toBe(false); + }); + + it("fails if the notification doesn't exist", async () => { + const notificationInput = { + deviceId: "1", + shuttleId: "1", + stopId: "1", + } + + const response = await getServerResponse(query, notificationInput); + + assert(response.body.kind === "single"); + expect(response.body.singleResult.errors).toBeUndefined(); + + const notificationResponse = response.body.singleResult.data?.cancelNotification as any; + expect(notificationResponse.success).toBe(false); + }); + }); +}); diff --git a/test/resolvers/OrderedStopResolverTests.test.ts b/test/resolvers/OrderedStopResolverTests.test.ts index 11c46e4..0d047ac 100644 --- a/test/resolvers/OrderedStopResolverTests.test.ts +++ b/test/resolvers/OrderedStopResolverTests.test.ts @@ -1,11 +1,12 @@ import { beforeEach, describe, expect, it } from "@jest/globals"; -import { setupTestServerContext } from "../testHelpers/apolloTestServerHelpers"; +import { setupTestServerContext, setupTestServerHolder } from "../testHelpers/apolloTestServerHelpers"; import { IRoute, IStop, ISystem } from "../../src/entities/entities"; import { generateMockOrderedStops, generateMockStops } from "../testHelpers/mockDataGenerators"; import { addMockRouteToRepository, addMockSystemToRepository } from "../testHelpers/repositorySetupHelpers"; import assert = require("node:assert"); describe("OrderedStopResolvers", () => { + const holder = setupTestServerHolder(); const context = setupTestServerContext(); let mockSystem: ISystem; @@ -59,7 +60,7 @@ describe("OrderedStopResolvers", () => { } `; - return await context.testServer.executeOperation({ + return await holder.testServer.executeOperation({ query, variables: { systemId: mockSystem.id, @@ -131,7 +132,7 @@ describe("OrderedStopResolvers", () => { } `; - return await context.testServer.executeOperation({ + return await holder.testServer.executeOperation({ query, variables: { systemId: mockSystem.id, @@ -206,7 +207,7 @@ describe("OrderedStopResolvers", () => { } `; - return await context.testServer.executeOperation({ + return await holder.testServer.executeOperation({ query, variables: { systemId: mockSystem.id, @@ -256,7 +257,7 @@ describe("OrderedStopResolvers", () => { } `; - return await context.testServer.executeOperation({ + return await holder.testServer.executeOperation({ query, variables: { systemId: mockSystem.id, diff --git a/test/resolvers/QueryResolverTests.test.ts b/test/resolvers/QueryResolverTests.test.ts index 73f8e83..af73aca 100644 --- a/test/resolvers/QueryResolverTests.test.ts +++ b/test/resolvers/QueryResolverTests.test.ts @@ -1,12 +1,13 @@ import { describe, expect, it } from "@jest/globals"; import { generateMockSystems } from "../testHelpers/mockDataGenerators"; -import { setupTestServerContext } from "../testHelpers/apolloTestServerHelpers"; +import { setupTestServerContext, setupTestServerHolder } from "../testHelpers/apolloTestServerHelpers"; import assert = require("node:assert"); // See Apollo documentation for integration test guide // https://www.apollographql.com/docs/apollo-server/testing/testing describe("QueryResolvers", () => { + const holder = setupTestServerHolder(); const context = setupTestServerContext(); async function addMockSystems() { @@ -30,7 +31,7 @@ describe("QueryResolvers", () => { } `; - const response = await context.testServer.executeOperation({ + const response = await holder.testServer.executeOperation({ query, }, { contextValue: { @@ -59,7 +60,7 @@ describe("QueryResolvers", () => { const systems = await addMockSystems(); const systemToGet = systems[1]; - const response = await context.testServer.executeOperation({ + const response = await holder.testServer.executeOperation({ query, variables: { id: systemToGet.id, @@ -76,7 +77,7 @@ describe("QueryResolvers", () => { }); it("returns null if there is no system", async () => { - const response = await context.testServer.executeOperation({ + const response = await holder.testServer.executeOperation({ query, variables: { id: "nonexistent-id", @@ -92,4 +93,4 @@ describe("QueryResolvers", () => { expect(response.body.singleResult.data?.system).toBeNull(); }); }); -}); \ No newline at end of file +}); diff --git a/test/resolvers/RouteResolverTests.test.ts b/test/resolvers/RouteResolverTests.test.ts index ba5b403..0279a6e 100644 --- a/test/resolvers/RouteResolverTests.test.ts +++ b/test/resolvers/RouteResolverTests.test.ts @@ -1,5 +1,5 @@ import { beforeEach, describe, expect, it } from "@jest/globals"; -import { setupTestServerContext } from "../testHelpers/apolloTestServerHelpers"; +import { setupTestServerContext, setupTestServerHolder } from "../testHelpers/apolloTestServerHelpers"; import { addMockRouteToRepository, addMockStopToRepository, @@ -10,6 +10,7 @@ import { IRoute, IStop, ISystem } from "../../src/entities/entities"; import assert = require("node:assert"); describe("RouteResolvers", () => { + const holder = setupTestServerHolder(); const context = setupTestServerContext(); let mockSystem: ISystem; @@ -40,7 +41,7 @@ describe("RouteResolvers", () => { } `; - return await context.testServer.executeOperation({ + return await holder.testServer.executeOperation({ query, variables: { systemId: mockSystem.id, @@ -95,7 +96,7 @@ describe("RouteResolvers", () => { } `; - return await context.testServer.executeOperation({ + return await holder.testServer.executeOperation({ query, variables: { systemId: mockSystem.id, @@ -145,4 +146,4 @@ describe("RouteResolvers", () => { expect(orderedStop).toBeNull(); }); }); -}); \ No newline at end of file +}); diff --git a/test/resolvers/ShuttleResolverTests.test.ts b/test/resolvers/ShuttleResolverTests.test.ts index 0811c3b..b2b3e81 100644 --- a/test/resolvers/ShuttleResolverTests.test.ts +++ b/test/resolvers/ShuttleResolverTests.test.ts @@ -1,12 +1,13 @@ import { beforeEach, describe, expect, it } from "@jest/globals"; import { generateMockEtas, generateMockRoutes } from "../testHelpers/mockDataGenerators"; import { IShuttle, ISystem } from "../../src/entities/entities"; -import { setupTestServerContext } from "../testHelpers/apolloTestServerHelpers"; +import { setupTestServerContext, setupTestServerHolder } from "../testHelpers/apolloTestServerHelpers"; import { addMockShuttleToRepository, addMockSystemToRepository } from "../testHelpers/repositorySetupHelpers"; import assert = require("node:assert"); describe("ShuttleResolvers", () => { + const holder = setupTestServerHolder(); const context = setupTestServerContext(); let mockSystem: ISystem; @@ -47,7 +48,7 @@ describe("ShuttleResolvers", () => { const mockEta = etas[1]; // Act - const response = await context.testServer.executeOperation({ + const response = await holder.testServer.executeOperation({ query, variables: { systemId: mockSystem.id, @@ -68,7 +69,7 @@ describe("ShuttleResolvers", () => { }); it("returns null if it doesn't exist", async () => { - const response = await context.testServer.executeOperation({ + const response = await holder.testServer.executeOperation({ query, variables: { systemId: mockSystem.id, @@ -106,7 +107,7 @@ describe("ShuttleResolvers", () => { it("returns associated ETAs if they exist for the shuttle", async () => { const etas = await addMockEtas(mockShuttle.id); - const response = await context.testServer.executeOperation({ + const response = await holder.testServer.executeOperation({ query, variables: { systemId: mockSystem.id, @@ -125,7 +126,7 @@ describe("ShuttleResolvers", () => { }); it("returns empty array if no ETAs exist", async () => { - const response = await context.testServer.executeOperation({ + const response = await holder.testServer.executeOperation({ query, variables: { systemId: mockSystem.id, @@ -164,7 +165,7 @@ describe("ShuttleResolvers", () => { ` async function getResponseForQuery() { - return await context.testServer.executeOperation({ + return await holder.testServer.executeOperation({ query, variables: { systemId: mockSystem.id, @@ -197,4 +198,4 @@ describe("ShuttleResolvers", () => { }); }); -}); \ No newline at end of file +}); diff --git a/test/resolvers/StopResolverTests.test.ts b/test/resolvers/StopResolverTests.test.ts index 2a044b1..fdda62b 100644 --- a/test/resolvers/StopResolverTests.test.ts +++ b/test/resolvers/StopResolverTests.test.ts @@ -1,11 +1,12 @@ import { beforeEach, describe, expect, it } from "@jest/globals"; -import { setupTestServerContext } from "../testHelpers/apolloTestServerHelpers"; +import { setupTestServerContext, setupTestServerHolder } from "../testHelpers/apolloTestServerHelpers"; import { generateMockEtas, generateMockOrderedStops } from "../testHelpers/mockDataGenerators"; import { IStop, ISystem } from "../../src/entities/entities"; import { addMockStopToRepository, addMockSystemToRepository } from "../testHelpers/repositorySetupHelpers"; import assert = require("node:assert"); describe("StopResolvers", () => { + const holder = setupTestServerHolder(); const context = setupTestServerContext(); let mockStop: IStop; @@ -17,7 +18,7 @@ describe("StopResolvers", () => { }) async function getResponseForQuery(query: string) { - return await context.testServer.executeOperation({ + return await holder.testServer.executeOperation({ query, variables: { systemId: mockSystem.id, @@ -105,4 +106,4 @@ describe("StopResolvers", () => { expect((response.body.singleResult.data as any).system.stop.etas).toHaveLength(0); }); }); -}); \ No newline at end of file +}); diff --git a/test/resolvers/SystemResolverTests.test.ts b/test/resolvers/SystemResolverTests.test.ts index 7020075..b7f3f5d 100644 --- a/test/resolvers/SystemResolverTests.test.ts +++ b/test/resolvers/SystemResolverTests.test.ts @@ -1,5 +1,5 @@ import { beforeEach, describe, expect, it } from "@jest/globals"; -import { setupTestServerContext } from "../testHelpers/apolloTestServerHelpers"; +import { setupTestServerContext, setupTestServerHolder } from "../testHelpers/apolloTestServerHelpers"; import { generateMockRoutes, generateMockShuttles, generateMockStops } from "../testHelpers/mockDataGenerators"; import { addMockRouteToRepository, @@ -11,6 +11,7 @@ import { ISystem } from "../../src/entities/entities"; import assert = require("node:assert"); describe("SystemResolvers", () => { + const holder = setupTestServerHolder(); const context = setupTestServerContext(); let mockSystem: ISystem; @@ -21,7 +22,7 @@ describe("SystemResolvers", () => { // TODO: Consolidate these into one single method taking an object async function getResponseFromQueryNeedingSystemId(query: string) { - return await context.testServer.executeOperation({ + return await holder.testServer.executeOperation({ query, variables: { systemId: mockSystem.id, @@ -102,7 +103,7 @@ describe("SystemResolvers", () => { } `; - return await context.testServer.executeOperation({ + return await holder.testServer.executeOperation({ query, variables: { systemId: mockSystem.id, @@ -169,7 +170,7 @@ describe("SystemResolvers", () => { } `; - return await context.testServer.executeOperation({ + return await holder.testServer.executeOperation({ query, variables: { systemId: mockSystem.id, @@ -237,7 +238,7 @@ describe("SystemResolvers", () => { } `; - return await context.testServer.executeOperation({ + return await holder.testServer.executeOperation({ query, variables: { systemId: mockSystem.id, @@ -318,4 +319,4 @@ describe("SystemResolvers", () => { expect(shuttles.length === expectedShuttles.length); }); }); -}); \ No newline at end of file +}); diff --git a/test/testHelpers/apolloTestServerHelpers.ts b/test/testHelpers/apolloTestServerHelpers.ts index 78b322f..a8af9d4 100644 --- a/test/testHelpers/apolloTestServerHelpers.ts +++ b/test/testHelpers/apolloTestServerHelpers.ts @@ -4,6 +4,7 @@ import { MergedResolvers } from "../../src/MergedResolvers"; import { UnoptimizedInMemoryRepository } from "../../src/repositories/UnoptimizedInMemoryRepository"; import { beforeEach } from "@jest/globals"; import { ServerContext } from "../../src/ServerContext"; +import { NotificationService } from "../../src/services/NotificationService"; function setUpTestServer() { @@ -16,15 +17,33 @@ function setUpTestServer() { }); } +/** + * Returns a `ServerContext` object which can be passed to requests + * for testing. + */ export function setupTestServerContext() { - // @ts-ignore - const context: { testServer: ApolloServer; repository: UnoptimizedInMemoryRepository } = {}; + const context: { [key: string] : any } = {}; beforeEach(() => { - context.testServer = setUpTestServer(); context.repository = new UnoptimizedInMemoryRepository(); + context.notificationService = new NotificationService(context.repository); }); - // Return a reference, not destructured values - return context; -} \ No newline at end of file + return context as ServerContext; +} + +/** + * Returns an object which holds a test server. + * This server is reset before every test. + * Tests should keep a reference to the holder object, + * and not destructure it. + */ +export function setupTestServerHolder() { + const holder: { [key: string]: any } = {}; + + beforeEach(() => { + holder.testServer = setUpTestServer(); + }); + + return holder as { testServer: ApolloServer }; +} diff --git a/test/testHelpers/repositorySetupHelpers.ts b/test/testHelpers/repositorySetupHelpers.ts index d9e48e3..4c95363 100644 --- a/test/testHelpers/repositorySetupHelpers.ts +++ b/test/testHelpers/repositorySetupHelpers.ts @@ -1,4 +1,3 @@ -import { UnoptimizedInMemoryRepository } from "../../src/repositories/UnoptimizedInMemoryRepository"; import { generateMockEtas, generateMockRoutes, @@ -6,8 +5,9 @@ import { generateMockStops, generateMockSystems } from "./mockDataGenerators"; +import { GetterSetterRepository } from "../../src/repositories/GetterSetterRepository"; -export async function addMockSystemToRepository(repository: UnoptimizedInMemoryRepository) { +export async function addMockSystemToRepository(repository: GetterSetterRepository) { const mockSystems = generateMockSystems(); const mockSystem = mockSystems[0]; mockSystem.id = "1"; @@ -16,7 +16,7 @@ export async function addMockSystemToRepository(repository: UnoptimizedInMemoryR return mockSystem; } -export async function addMockRouteToRepository(repository: UnoptimizedInMemoryRepository, systemId: string) { +export async function addMockRouteToRepository(repository: GetterSetterRepository, systemId: string) { const mockRoutes = generateMockRoutes(); const mockRoute = mockRoutes[0]; mockRoute.systemId = systemId; @@ -25,7 +25,7 @@ export async function addMockRouteToRepository(repository: UnoptimizedInMemoryRe return mockRoute; } -export async function addMockStopToRepository(repository: UnoptimizedInMemoryRepository, systemId: string) { +export async function addMockStopToRepository(repository: GetterSetterRepository, systemId: string) { const mockStops = generateMockStops(); const mockStop = mockStops[0]; mockStop.systemId = systemId; @@ -34,7 +34,7 @@ export async function addMockStopToRepository(repository: UnoptimizedInMemoryRep return mockStop; } -export async function addMockShuttleToRepository(repository: UnoptimizedInMemoryRepository, systemId: string) { +export async function addMockShuttleToRepository(repository: GetterSetterRepository, systemId: string) { const mockShuttles = generateMockShuttles(); const mockShuttle = mockShuttles[0]; mockShuttle.systemId = systemId; @@ -42,7 +42,7 @@ export async function addMockShuttleToRepository(repository: UnoptimizedInMemory return mockShuttle; } -export async function addMockEtaToRepository(repository: UnoptimizedInMemoryRepository, stopId: string, shuttleId: string) { +export async function addMockEtaToRepository(repository: GetterSetterRepository, stopId: string, shuttleId: string) { const etas = generateMockEtas(); const expectedEta = etas[0]; expectedEta.stopId = stopId;