diff --git a/app/server/tests/controllers/appsController.test.ts b/app/server/tests/controllers/appsController.test.ts index ac1fe9ccf..7ee0b1734 100644 --- a/app/server/tests/controllers/appsController.test.ts +++ b/app/server/tests/controllers/appsController.test.ts @@ -3,13 +3,18 @@ import { WodinWebError } from "../../src/errors/wodinWebError"; // Need to mock getSessionStore before importing the controller let sessionIdFromFriendlyId: string | null; -const mockSessionStore = { - getSessionIdFromFriendlyId: jest.fn().mockImplementation(() => { return sessionIdFromFriendlyId; }) -}; -const mockGetSessionStore = jest.fn().mockReturnValue(mockSessionStore); -jest.mock("../../src/db/sessionStore", () => { return { getSessionStore: mockGetSessionStore }; }); +const { mockSessionStore, mockGetSessionStore } = vi.hoisted(() => { + const mockSessionStore = { + getSessionIdFromFriendlyId: vi.fn().mockImplementation(() => { return sessionIdFromFriendlyId; }) + }; + const mockGetSessionStore = vi.fn().mockReturnValue(mockSessionStore); + return { + mockSessionStore, + mockGetSessionStore + } +}) +vi.mock("../../src/db/sessionStore", () => { return { getSessionStore: mockGetSessionStore }; }); -/* eslint-disable import/first */ import { AppsController } from "../../src/controllers/appsController"; describe("appsController", () => { @@ -20,7 +25,7 @@ describe("appsController", () => { wodinConfig = {} ) => { const mockConfigReader = { - readConfigFile: jest.fn().mockReturnValue(appConfig) + readConfigFile: vi.fn().mockReturnValue(appConfig) }; return { app: { @@ -45,8 +50,8 @@ describe("appsController", () => { } as any; }; - const mockRender = jest.fn(); - const mockStatus = jest.fn().mockReturnValue({ render: mockRender }); + const mockRender = vi.fn(); + const mockStatus = vi.fn().mockReturnValue({ render: mockRender }); const mockResponse = { render: mockRender, status: mockStatus @@ -59,13 +64,13 @@ describe("appsController", () => { }); afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); it("renders view with app config", () => { const appConfig = { title: "testTitle", appType: "testType" }; const request = getMockRequest(appConfig, "1234", undefined); - AppsController.getApp(request, mockResponse, jest.fn()); + AppsController.getApp(request, mockResponse, vi.fn()); expect(mockRender).toBeCalledTimes(1); expect(mockRender.mock.calls[0][0]).toBe("app"); @@ -90,7 +95,7 @@ describe("appsController", () => { it("sets loadSessionId to be empty when not in query string", () => { const request = getMockRequest({ title: "testTitle", appType: "testType" }, undefined, undefined); - AppsController.getApp(request, mockResponse, jest.fn()); + AppsController.getApp(request, mockResponse, vi.fn()); expect(mockRender.mock.calls[0][1]).toStrictEqual({ appName: "test", @@ -112,7 +117,7 @@ describe("appsController", () => { it("gets session id from share parameter when provided", async () => { const request = getMockRequest({ title: "testTitle", appType: "testType" }, undefined, "tiny-mouse"); - await AppsController.getApp(request, mockResponse, jest.fn()); + await AppsController.getApp(request, mockResponse, vi.fn()); expect(mockGetSessionStore).toHaveBeenCalledTimes(1); expect(mockGetSessionStore.mock.calls[0][0]).toBe(request); @@ -140,7 +145,7 @@ describe("appsController", () => { it("sets shareNotFound value when share parameter does not exist in db", async () => { sessionIdFromFriendlyId = null; const request = getMockRequest({ title: "testTitle", appType: "testType" }, undefined, "tiny-mouse"); - await AppsController.getApp(request, mockResponse, jest.fn()); + await AppsController.getApp(request, mockResponse, vi.fn()); expect(mockGetSessionStore).toHaveBeenCalledTimes(1); expect(mockRender).toHaveBeenCalledTimes(1); @@ -171,7 +176,7 @@ describe("appsController", () => { "app-not-found", { appName: "test" } ); - const next = jest.fn(); + const next = vi.fn(); await AppsController.getApp(request, mockResponse, next); expect(next).toHaveBeenCalledTimes(1); expect(next.mock.calls[0][0]).toStrictEqual(expectedErr); @@ -181,7 +186,7 @@ describe("appsController", () => { it("removes trailing slash from baseUrl", async () => { const wodinConfig = { baseUrl: "http://localhost:3000/instance/" }; const request = getMockRequest({ title: "testTitle", appType: "testType" }, "1234", undefined, wodinConfig); - await AppsController.getApp(request, mockResponse, jest.fn()); + await AppsController.getApp(request, mockResponse, vi.fn()); expect(mockRender.mock.calls[0][1].baseUrl).toBe("http://localhost:3000/instance"); }); }); diff --git a/app/server/tests/controllers/configController.test.ts b/app/server/tests/controllers/configController.test.ts index 3f6ea610b..09d50e9ff 100644 --- a/app/server/tests/controllers/configController.test.ts +++ b/app/server/tests/controllers/configController.test.ts @@ -34,18 +34,18 @@ describe("configController", () => { const defaultCode = ["default", "code"]; const appHelp = ["## HELP"]; - const spyJsonResponseSuccess = jest.spyOn(jsonResponse, "jsonResponseSuccess"); + const spyJsonResponseSuccess = vi.spyOn(jsonResponse, "jsonResponseSuccess"); beforeEach(() => { - jest.resetAllMocks(); + vi.resetAllMocks(); }); it("getConfig reads config file, default code file and app help file", () => { - const mockReadConfigFile = jest.fn().mockReturnValue(basicConfig); + const mockReadConfigFile = vi.fn().mockReturnValue(basicConfig); const mockConfigReader = { readConfigFile: mockReadConfigFile } as any; - const mockReadDefaultCode = jest.fn().mockReturnValue(defaultCode); + const mockReadDefaultCode = vi.fn().mockReturnValue(defaultCode); const mockDefaultCodeReader = { readFile: mockReadDefaultCode } as any; - const mockReadAppHelp = jest.fn().mockReturnValue(appHelp) as any; + const mockReadAppHelp = vi.fn().mockReturnValue(appHelp) as any; const mockAppHelpReader = { readFile: mockReadAppHelp } as any; const req = getRequest(mockConfigReader, mockDefaultCodeReader, mockAppHelpReader); @@ -76,9 +76,9 @@ describe("configController", () => { }); it("getConfig does not add help prop to config if no app help found", () => { - const mockConfigReader = { readConfigFile: jest.fn().mockReturnValue(basicConfig) } as any; - const mockDefaultCodeReader = { readFile: jest.fn().mockReturnValue([]) } as any; - const mockReadAppHelp = jest.fn().mockReturnValue([]) as any; + const mockConfigReader = { readConfigFile: vi.fn().mockReturnValue(basicConfig) } as any; + const mockDefaultCodeReader = { readFile: vi.fn().mockReturnValue([]) } as any; + const mockReadAppHelp = vi.fn().mockReturnValue([]) as any; const mockAppHelpReader = { readFile: mockReadAppHelp } as any; const req = getRequest(mockConfigReader, mockDefaultCodeReader, mockAppHelpReader); @@ -96,15 +96,15 @@ describe("configController", () => { it("getConfig includes help tabName from config file along with markdown", () => { const mockConfigReader = { - readConfigFile: jest.fn().mockReturnValue({ + readConfigFile: vi.fn().mockReturnValue({ ...basicConfig, help: { tabName: "Help" } }) } as any; - const mockDefaultCodeReader = { readFile: jest.fn().mockReturnValue([]) } as any; - const mockReadAppHelp = jest.fn().mockReturnValue(appHelp) as any; + const mockDefaultCodeReader = { readFile: vi.fn().mockReturnValue([]) } as any; + const mockReadAppHelp = vi.fn().mockReturnValue(appHelp) as any; const mockAppHelpReader = { readFile: mockReadAppHelp } as any; const req = getRequest(mockConfigReader, mockDefaultCodeReader, mockAppHelpReader); @@ -125,8 +125,8 @@ describe("configController", () => { }); it("getConfig throws expected error when app config file is not found", () => { - const mockConfigReader = { readConfigFile: jest.fn().mockReturnValue(null) } as any; - const req = getRequest(mockConfigReader, jest.fn() as any, jest.fn() as any); + const mockConfigReader = { readConfigFile: vi.fn().mockReturnValue(null) } as any; + const req = getRequest(mockConfigReader, vi.fn() as any, vi.fn() as any); const expectedError = new WodinError("App with name TestApp is not configured.", 404, ErrorType.NOT_FOUND); expect(() => { ConfigController.getConfig(req, res); }).toThrow(expectedError); diff --git a/app/server/tests/controllers/indexController.test.ts b/app/server/tests/controllers/indexController.test.ts index 2e950d280..7cd388957 100644 --- a/app/server/tests/controllers/indexController.test.ts +++ b/app/server/tests/controllers/indexController.test.ts @@ -10,7 +10,7 @@ describe("indexController", () => { } } as any; const mockResponse = { - sendFile: jest.fn() + sendFile: vi.fn() } as any; IndexController.getIndex(mockRequest, mockResponse); expect(mockResponse.sendFile).toBeCalledTimes(1); diff --git a/app/server/tests/controllers/odinController.test.ts b/app/server/tests/controllers/odinController.test.ts index d7f7f3440..69ddd4d8c 100644 --- a/app/server/tests/controllers/odinController.test.ts +++ b/app/server/tests/controllers/odinController.test.ts @@ -1,16 +1,15 @@ import * as apiService from "../../src/apiService"; import { OdinController } from "../../src/controllers/odinController"; -import clearAllMocks = jest.clearAllMocks; -const mockAPIGet = jest.fn(); -const mockAPIPost = jest.fn(); +const mockAPIGet = vi.fn(); +const mockAPIPost = vi.fn(); const mockAPIService = { get: mockAPIGet, post: mockAPIPost } as any; -const mockNext = jest.fn(); +const mockNext = vi.fn(); -const apiSpy = jest.spyOn(apiService, "api").mockReturnValue(mockAPIService); +const apiSpy = vi.spyOn(apiService, "api").mockReturnValue(mockAPIService); describe("odinController", () => { const mockRequest = { @@ -19,7 +18,7 @@ describe("odinController", () => { const mockResponse = {} as any; beforeEach(() => { - clearAllMocks(); + vi.clearAllMocks(); }); it("getRunnerOde gets from api service", async () => { diff --git a/app/server/tests/controllers/sessionsController.test.ts b/app/server/tests/controllers/sessionsController.test.ts index abb34a069..491a1cee1 100644 --- a/app/server/tests/controllers/sessionsController.test.ts +++ b/app/server/tests/controllers/sessionsController.test.ts @@ -1,16 +1,20 @@ -const mockSessionStore = { - saveSession: jest.fn(), - getSessionsMetadata: jest.fn(), - saveSessionLabel: jest.fn(), - getSession: jest.fn(), - generateFriendlyId: jest.fn() -}; - -// Need to mock getSessionStore before importing the controller -const mockGetSessionStore = jest.fn().mockReturnValue(mockSessionStore); -jest.mock("../../src/db/sessionStore", () => { return { getSessionStore: mockGetSessionStore }; }); - -/* eslint-disable import/first */ +const { mockSessionStore, mockGetSessionStore } = vi.hoisted(() => { + const mockSessionStore = { + saveSession: vi.fn(), + getSessionsMetadata: vi.fn(), + saveSessionLabel: vi.fn(), + getSession: vi.fn(), + generateFriendlyId: vi.fn() + }; + // Need to mock getSessionStore before importing the controller + const mockGetSessionStore = vi.fn().mockReturnValue(mockSessionStore); + return { + mockSessionStore, + mockGetSessionStore + } +}) +vi.mock("../../src/db/sessionStore", () => { return { getSessionStore: mockGetSessionStore }; }); + import { serialiseSession, SessionsController } from "../../src/controllers/sessionsController"; describe("SessionsController", () => { @@ -24,18 +28,18 @@ describe("SessionsController", () => { } as any; const res = { - end: jest.fn(), - header: jest.fn() + end: vi.fn(), + header: vi.fn() } as any; beforeEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); const testError = { message: "test error" }; it("can save session", async () => { - await SessionsController.postSession(req, res, jest.fn()); + await SessionsController.postSession(req, res, vi.fn()); expect(mockGetSessionStore).toHaveBeenCalledTimes(1); expect(mockGetSessionStore.mock.calls[0][0]).toBe(req); expect(mockSessionStore.saveSession).toHaveBeenCalledTimes(1); @@ -46,7 +50,7 @@ describe("SessionsController", () => { it("postSession handles error", async () => { mockSessionStore.saveSession.mockImplementation(() => { throw testError; }); - const next = jest.fn(); + const next = vi.fn(); await SessionsController.postSession(req, res, next); expect(next).toHaveBeenCalledWith(testError); }); @@ -59,7 +63,7 @@ describe("SessionsController", () => { removeDuplicates: "true" } }; - await SessionsController.getSessionsMetadata(metadataReq, res, jest.fn()); + await SessionsController.getSessionsMetadata(metadataReq, res, vi.fn()); expect(mockGetSessionStore).toHaveBeenCalledTimes(1); expect(mockGetSessionStore.mock.calls[0][0]).toBe(metadataReq); expect(mockSessionStore.getSessionsMetadata).toHaveBeenCalledTimes(1); @@ -78,7 +82,7 @@ describe("SessionsController", () => { removeDuplicates: "false" } }; - await SessionsController.getSessionsMetadata(metadataReq, res, jest.fn()); + await SessionsController.getSessionsMetadata(metadataReq, res, vi.fn()); expect(mockGetSessionStore).toHaveBeenCalledTimes(1); expect(mockGetSessionStore.mock.calls[0][0]).toBe(metadataReq); expect(mockSessionStore.getSessionsMetadata).toHaveBeenCalledTimes(1); @@ -88,7 +92,7 @@ describe("SessionsController", () => { it("getSessionMetadata handles error", async () => { mockSessionStore.getSessionsMetadata.mockImplementation(() => { throw testError; }); - const next = jest.fn(); + const next = vi.fn(); const metadataReq = { ...req, query: { @@ -100,7 +104,7 @@ describe("SessionsController", () => { }); it("can get empty session metadata with missing ids parameter", async () => { - await SessionsController.getSessionsMetadata(req, res, jest.fn()); + await SessionsController.getSessionsMetadata(req, res, vi.fn()); expect(mockGetSessionStore).not.toHaveBeenCalled(); expect(res.header).toHaveBeenCalledWith("Content-Type", "application/json"); expect(res.end).toHaveBeenCalledTimes(1); @@ -123,7 +127,7 @@ describe("SessionsController", () => { body: "some label" } as any; - SessionsController.postSessionLabel(labelReq, res, jest.fn()); + SessionsController.postSessionLabel(labelReq, res, vi.fn()); expect(mockGetSessionStore).toHaveBeenCalledTimes(1); expect(mockGetSessionStore.mock.calls[0][0]).toBe(labelReq); expect(mockSessionStore.saveSessionLabel).toHaveBeenCalledTimes(1); @@ -133,7 +137,7 @@ describe("SessionsController", () => { it("postSessionLabel handles error", async () => { mockSessionStore.saveSessionLabel.mockImplementation(() => { throw testError; }); - const next = jest.fn(); + const next = vi.fn(); await SessionsController.postSessionLabel(req, res, next); expect(next).toHaveBeenCalledWith(testError); }); @@ -153,7 +157,7 @@ describe("SessionsController", () => { id: "1234" } } as any; - SessionsController.getSession(sessionReq, res, jest.fn()); + SessionsController.getSession(sessionReq, res, vi.fn()); expect(mockGetSessionStore).toHaveBeenCalledTimes(1); expect(mockGetSessionStore.mock.calls[0][0]).toBe(sessionReq); expect(mockSessionStore.getSession).toHaveBeenCalledTimes(1); @@ -162,7 +166,7 @@ describe("SessionsController", () => { it("getSession handles error", async () => { mockSessionStore.getSession.mockImplementation(() => { throw testError; }); - const next = jest.fn(); + const next = vi.fn(); await SessionsController.getSession(req, res, next); expect(next).toHaveBeenCalledWith(testError); }); @@ -182,7 +186,7 @@ describe("SessionsController", () => { id: "1234" } } as any; - SessionsController.generateFriendlyId(sessionReq, res, jest.fn()); + SessionsController.generateFriendlyId(sessionReq, res, vi.fn()); expect(mockGetSessionStore).toHaveBeenCalledTimes(1); expect(mockGetSessionStore.mock.calls[0][0]).toBe(sessionReq); expect(mockSessionStore.generateFriendlyId).toHaveBeenCalledTimes(1); @@ -191,7 +195,7 @@ describe("SessionsController", () => { it("generateFriendlyId handles error", async () => { mockSessionStore.generateFriendlyId.mockImplementation(() => { throw testError; }); - const next = jest.fn(); + const next = vi.fn(); await SessionsController.generateFriendlyId(req, res, next); expect(next).toHaveBeenCalledWith(testError); }); @@ -199,13 +203,13 @@ describe("SessionsController", () => { describe("Sessions serialise correctly", () => { const res = { - status: jest.fn(), - end: jest.fn(), - header: jest.fn() + status: vi.fn(), + end: vi.fn(), + header: vi.fn() } as any; beforeEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); it("serialises json string", () => { diff --git a/app/server/tests/db/sessionStore.test.ts b/app/server/tests/db/sessionStore.test.ts index d43a67833..fcddea5b0 100644 --- a/app/server/tests/db/sessionStore.test.ts +++ b/app/server/tests/db/sessionStore.test.ts @@ -1,29 +1,29 @@ -import * as md5 from "md5"; +import md5 from "md5"; import { friendlyAdjectiveAnimal, cleanFriendlyId, SessionStore, getSessionStore } from "../../src/db/sessionStore"; // Mock Date.now to return hardcoded date -Date.now = jest.spyOn(Date, "now").mockImplementation(() => new Date(2022, 0, 24, 17).getTime()) as any; +Date.now = vi.spyOn(Date, "now").mockImplementation(() => new Date(2022, 0, 24, 17).getTime()) as any; describe("SessionStore", () => { beforeEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); const mockPipeline = { - exec: jest.fn() + exec: vi.fn() } as any; - mockPipeline.hset = jest.fn().mockReturnValue(mockPipeline); + mockPipeline.hset = vi.fn().mockReturnValue(mockPipeline); const mockRedis = { - pipeline: jest.fn().mockReturnValue(mockPipeline), - hget: jest.fn().mockReturnValue(mockPipeline), - hmget: jest.fn().mockImplementation(async (key: string, ...fields: string[]) => { + pipeline: vi.fn().mockReturnValue(mockPipeline), + hget: vi.fn().mockReturnValue(mockPipeline), + hmget: vi.fn().mockImplementation(async (key: string, ...fields: string[]) => { return fields.map((field: string) => `${field} value for ${key}`); }), - hset: jest.fn().mockReturnValue(mockPipeline), - hsetnx: jest.fn().mockReturnValue(mockPipeline) + hset: vi.fn().mockReturnValue(mockPipeline), + hsetnx: vi.fn().mockReturnValue(mockPipeline) } as any; it("can save session", async () => { @@ -66,7 +66,7 @@ describe("SessionStore", () => { it("filters out session metadata for session ids with no values in db", async () => { const mockNullResultRedis = { - hmget: jest.fn().mockImplementation(async (key: string, ...fields: string[]) => { + hmget: vi.fn().mockImplementation(async (_key: string, ...fields: string[]) => { return fields.map(() => null); }) } as any; @@ -99,13 +99,13 @@ describe("SessionStore", () => { it("can create friendly id with no collisions", async () => { const mockRedis2 = { - hget: jest.fn(), - hset: jest.fn(), - hsetnx: jest.fn().mockReturnValue(1) + hget: vi.fn(), + hset: vi.fn(), + hsetnx: vi.fn().mockReturnValue(1) } as any; const id = "1234"; - const mockFriendly = jest.fn().mockReturnValue("happy-rabbit"); + const mockFriendly = vi.fn().mockReturnValue("happy-rabbit"); const sut = new SessionStore(mockRedis2, "Test Course", "testApp", mockFriendly); const friendly = await sut.generateFriendlyId(id); expect(friendly).toBe("happy-rabbit"); @@ -113,13 +113,13 @@ describe("SessionStore", () => { it("can create friendly id with collisions", async () => { const mockRedis2 = { - hget: jest.fn(), - hset: jest.fn(), - hsetnx: jest.fn().mockReturnValueOnce(0).mockReturnValueOnce(0).mockReturnValue(1) + hget: vi.fn(), + hset: vi.fn(), + hsetnx: vi.fn().mockReturnValueOnce(0).mockReturnValueOnce(0).mockReturnValue(1) } as any; const id = "1234"; - const mockFriendly = jest.fn().mockReturnValueOnce("a").mockReturnValueOnce("b").mockReturnValueOnce("c"); + const mockFriendly = vi.fn().mockReturnValueOnce("a").mockReturnValueOnce("b").mockReturnValueOnce("c"); const sut = new SessionStore(mockRedis2, "Test Course", "testApp", mockFriendly); const friendly = await sut.generateFriendlyId(id); expect(friendly).toBe("c"); @@ -134,13 +134,13 @@ describe("SessionStore", () => { it("can fall back on machine id when there are many collisions", async () => { const mockRedis2 = { - hget: jest.fn(), - hset: jest.fn(), - hsetnx: jest.fn().mockReturnValue(0) + hget: vi.fn(), + hset: vi.fn(), + hsetnx: vi.fn().mockReturnValue(0) } as any; const id = "1234"; - const mockFriendly = jest.fn(); + const mockFriendly = vi.fn(); const sut = new SessionStore(mockRedis2, "Test Course", "testApp", mockFriendly); const friendly = await sut.generateFriendlyId(id); expect(friendly).toBe("1234"); @@ -154,13 +154,13 @@ describe("SessionStore", () => { it("can return existing friendly id if already set", async () => { const mockRedis2 = { - hget: jest.fn().mockReturnValue("happy-rabbit"), - hset: jest.fn(), - hsetnx: jest.fn().mockReturnValue(1) + hget: vi.fn().mockReturnValue("happy-rabbit"), + hset: vi.fn(), + hsetnx: vi.fn().mockReturnValue(1) } as any; const id = "1234"; - const mockFriendly = jest.fn(); + const mockFriendly = vi.fn(); const sut = new SessionStore(mockRedis2, "Test Course", "testApp", mockFriendly); const friendly = await sut.generateFriendlyId(id); expect(friendly).toBe("happy-rabbit"); @@ -207,14 +207,14 @@ describe("SessionStore handles duplicate sessions", () => { savedHGetValues: Record = {} ) => { return { - hmget: jest.fn().mockImplementation(async (sessionKey: string) => { + hmget: vi.fn().mockImplementation(async (sessionKey: string) => { const key = sessionKey.split(":").slice(-1)[0]; return savedHmGetValues[key]; }), - hget: jest.fn().mockImplementation(async (sessionKey: string, sessionId: string) => { + hget: vi.fn().mockImplementation(async (_sessionKey: string, sessionId: string) => { return savedHGetValues[sessionId]; }), - hset: jest.fn() + hset: vi.fn() } as any; }; diff --git a/app/server/tests/errors/asyncControllerHandler.test.ts b/app/server/tests/errors/asyncControllerHandler.test.ts index 66cbb3c8b..fd385b917 100644 --- a/app/server/tests/errors/asyncControllerHandler.test.ts +++ b/app/server/tests/errors/asyncControllerHandler.test.ts @@ -2,8 +2,8 @@ import asyncControllerHandler from "../../src/errors/asyncControllerHandler"; describe("asyncControllerHandler", () => { it("calls method", async () => { - const method = jest.fn(); - const next = jest.fn(); + const method = vi.fn(); + const next = vi.fn(); await asyncControllerHandler(next, method); expect(method).toHaveBeenCalledTimes(1); expect(next).not.toHaveBeenCalled(); @@ -11,8 +11,8 @@ describe("asyncControllerHandler", () => { it("handles error by calling next", async () => { const error = { message: "test error" }; - const method = jest.fn().mockImplementation(() => { throw error; }); - const next = jest.fn(); + const method = vi.fn().mockImplementation(() => { throw error; }); + const next = vi.fn(); await asyncControllerHandler(next, method); expect(next).toHaveBeenCalledWith(error); }); diff --git a/app/server/views/app.mustache b/app/server/views/app.mustache index cfa7e137a..daa593ca3 100644 --- a/app/server/views/app.mustache +++ b/app/server/views/app.mustache @@ -27,5 +27,5 @@ {{/hotReload}} - +