From a15ceb8c154475a3e2bd5bc525d36d5ceb9b5655 Mon Sep 17 00:00:00 2001 From: Max Frederiksen <maxfrederiksen@Maxs-MacBook-Air.local> Date: Mon, 13 Jan 2025 17:11:13 +0100 Subject: [PATCH] Add typing /mocks --- src/mocks/AppHarness.tsx | 6 +- src/mocks/UserImpersonator.tsx | 62 ++++++++++++----- src/mocks/handlers.ts | 7 +- src/mocks/mockAPI.ts | 123 ++++++++++++++++++--------------- 4 files changed, 119 insertions(+), 79 deletions(-) diff --git a/src/mocks/AppHarness.tsx b/src/mocks/AppHarness.tsx index 45a20db9..e44806ec 100644 --- a/src/mocks/AppHarness.tsx +++ b/src/mocks/AppHarness.tsx @@ -3,7 +3,7 @@ import { SnackbarProvider } from "notistack"; import { Container, CssBaseline, StyledEngineProvider } from "@mui/material"; import { ThemeProvider } from "@mui/material/styles"; import { MemoryRouter } from "react-router-dom"; -import { TestUserProvider, UserImpersonator } from "./UserImpersonator"; +import { TestAuthContextProvider, UserImpersonator } from "./UserImpersonator"; import { theme } from "../style/Theme"; import { UserProvider } from "../api/UserProvider"; import { NavigationMenu } from "../components/navigation/NavigationMenu"; @@ -46,14 +46,14 @@ export function AppHarness({ }: AppHarnessProps) { const SelectedUserProvider = useTestUser ? ({ children }: { children: ReactNode }) => ( - <TestUserProvider> + <TestAuthContextProvider> <UserImpersonator user={user} userRoles={userRoles} > {children} </UserImpersonator> - </TestUserProvider> + </TestAuthContextProvider> ) : UserProvider; diff --git a/src/mocks/UserImpersonator.tsx b/src/mocks/UserImpersonator.tsx index 71f85e41..277c11eb 100644 --- a/src/mocks/UserImpersonator.tsx +++ b/src/mocks/UserImpersonator.tsx @@ -1,19 +1,43 @@ -import { useCallback, useContext, useEffect, useMemo, useState } from "react"; +import { + ReactNode, + useCallback, + useContext, + useEffect, + useMemo, + useState +} from "react"; import { userContext } from "@ess-ics/ce-ui-common"; import { defaultUser, defaultUserRoles } from "../stories/utils/common-args"; - -const testAuthContext = userContext; +import { User } from "../types/common"; const defaultLogin = ""; const defaultLogout = ""; const defaultLoginError = ""; -const TestAuthContextProvider = ({ children }) => { +interface TestAuthContext { + user: User; + setUser: (user: User) => void; + userRoles: string[]; + setUserRoles: (roles: string[]) => void; + login: string; + setLogin: (login: string) => void; + loginError: string; + setLoginError: (error: string) => void; + logout: string; + setLogout: (logout: string) => void; + resetLoginError: () => void; +} + +export const TestAuthContextProvider = ({ + children +}: { + children: ReactNode; +}) => { const [user, setUser] = useState(defaultUser); const [userRoles, setUserRoles] = useState(defaultUserRoles); const [login, setLogin] = useState(defaultLogin); - const [loginError, setLoginError] = useState(defaultLoginError); const [logout, setLogout] = useState(defaultLogout); + const [loginError, setLoginError] = useState(defaultLoginError); const resetLoginError = useCallback(() => { setLoginError(defaultLoginError); @@ -48,23 +72,27 @@ const TestAuthContextProvider = ({ children }) => { ] ); - return ( - <testAuthContext.Provider value={value}> - {children} - </testAuthContext.Provider> - ); + return <userContext.Provider value={value}>{children}</userContext.Provider>; }; -export const TestUserProvider = ({ children }) => { - return <TestAuthContextProvider>{children}</TestAuthContextProvider>; -}; +interface UserImpersonatorProps { + user?: User; + userRoles?: string[]; + children: ReactNode; +} -export const UserImpersonator = ({ user, userRoles, children }) => { - const { setUser, setUserRoles } = useContext(testAuthContext); +export const UserImpersonator = ({ + user, + userRoles, + children +}: UserImpersonatorProps) => { + const { setUser, setUserRoles } = useContext<TestAuthContext>(userContext); useEffect(() => { - setUser(user); - setUserRoles(userRoles); + if (user && userRoles) { + setUser(user); + setUserRoles(userRoles); + } }, [setUser, setUserRoles, user, userRoles]); return <>{children}</>; diff --git a/src/mocks/handlers.ts b/src/mocks/handlers.ts index 2a2a7f52..e5e5ad54 100644 --- a/src/mocks/handlers.ts +++ b/src/mocks/handlers.ts @@ -1,8 +1,8 @@ import { http, HttpResponse } from "msw"; import { apiHandlers } from "./mockAPI"; -const glue = (requestHandler) => { - return (info) => { +const glue = (requestHandler: any) => { + return (info: any) => { const d = requestHandler(info); let cookie; // the only cookie the mockAPI will set is the authorization cookie @@ -35,7 +35,8 @@ const restMap = { }; // define our MSW handlers to mock our API endpoints -export const handlers = apiHandlers.map((h) => { +export const handlers = apiHandlers.map((h: any) => { + // @ts-ignore const method = restMap[h.method]; return method(h.matcher, glue(h.requestHandler)); }); diff --git a/src/mocks/mockAPI.ts b/src/mocks/mockAPI.ts index 7492643a..9a003197 100644 --- a/src/mocks/mockAPI.ts +++ b/src/mocks/mockAPI.ts @@ -24,7 +24,7 @@ import maintenanceData from "./fixtures/MaintenanceMode.json"; // String representation of the request url // (Swagger client's request is a fetch Request, // so the url is a String and not a URL object) -function searchParams({ request }) { +function searchParams({ request }: { request: any }) { if (typeof request.url === "string") { const url = new URL(request.url); return url.searchParams; @@ -33,13 +33,21 @@ function searchParams({ request }) { } } -function getParameters(req, pattern) { - let url = req.request ? req.request.url : req.url; +function getParameters(req: any, pattern: any) { + const url = req.request ? req.request.url : req.url; const match = matchPath({ path: "/api/v1" + pattern }, new URL(url).pathname); return match?.params; } -function withMockPagination({ req, data, key }) { +function withMockPagination({ + req, + data, + key +}: { + req: any; + data: any; + key: string; +}) { const params = searchParams(req); const page = Number(params.get("page")) || 0; const limit = Number(params.get("limit")) || 20; @@ -59,13 +67,13 @@ function withMockPagination({ req, data, key }) { return results; } -function spec(req) { +function spec() { return { body: specData }; } -function login(req) { +function login() { const token = "DEADBEEF"; return { body: { token }, @@ -75,7 +83,7 @@ function login(req) { }; } -function logout(req) { +function logout() { return { headers: { "Set-Cookie": "ccce-auth=; Max-Age=0" @@ -83,18 +91,18 @@ function logout(req) { }; } -function isLoggedIn(req) { - let { cookies } = req; +function isLoggedIn(req: any) { + const { cookies } = req; if (cookies) { return Boolean(cookies["ce-deploy-auth"]); } else { - let { headers } = req; + const { headers } = req; return (headers.cookie ?? "").includes("ce-deploy-auth="); } } -function auth(routeHandler) { - return function (req) { +function auth(routeHandler: any) { + return function (req: any) { if (isLoggedIn(req)) { return routeHandler(req); } else { @@ -103,51 +111,51 @@ function auth(routeHandler) { }; } -function getUserRoles(req) { +function getUserRoles() { const body = ["DeploymentToolAdmin", "DeploymentToolIntegrator"]; return { body }; } // Git -function infoFromUserName(req) { +function infoFromUserName() { const body = [userData]; return { body }; } -function listProjects(req) { +function listProjects() { return { gitProjectsData }; } -function gitProjectDetails(req) { +function gitProjectDetails(req: any) { const params = getParameters(req, "/git_helper/project_info/:project_id"); const jobs = jobsData.jobs; const job = jobs.find( - (job) => job.gitProjectId === Number(params.project_id) + (job) => job.gitProjectId === Number(params?.project_id) ); const body = job ? job.git_project_info : null; return { body }; } -function listTagsAndCommitIds(req) { +function listTagsAndCommitIds(req: any) { const params = getParameters(req, "/git_helper/:project_id/tags_and_commits"); const jobs = jobsData.jobs; const job = jobs.find( - (job) => job.gitProjectId === Number(params.project_id) + (job) => job.gitProjectId === Number(params?.project_id) ); const body = job ? job.tags_and_commits : []; return { body }; } -function gitReferenceType(req) { +function gitReferenceType(req: any) { const params = getParameters( req, "/git_helper/:project_id/reference_type/:git_reference" ); const jobs = jobsData.jobs; - const body = jobs.find((job) => job.gitReference === params.git_reference); + const body = jobs.find((job) => job.gitReference === params?.git_reference); return { body }; } -function renew(req) { +function renew() { const token = "FADEDEAD"; return { body: { token }, @@ -157,136 +165,134 @@ function renew(req) { }; } -function listIOCs(req) { +function listIOCs() { return { pagedResponseData }; } -function createIoc(req) { +function createIoc() { return { createIocData }; } -function getIOC(req) { +function getIOC(req: any) { const params = getParameters(req, "/iocs/:id"); const data = iocDetailsData; - const body = data.find((x) => x.id === Number(params.id)); + const body = data.find((x) => x.id === Number(params?.id)); console.debug("getIOC", data, params, body); const status = body ? 200 : 404; return { body, status }; } -function deleteIOC(req) { +function deleteIOC(req: any) { return req; } -function getIocDescription(req) { +function getIocDescription(req: AnalyserNode) { const params = getParameters(req, "/iocs/:id/description"); const data = iocDescriptionData; - const body = data.find((x) => x.id === Number(params.id)); + const body = data.find((x) => x.id === Number(params?.id)); console.debug("getIocDescription", data, params, body); const status = body ? 200 : 404; return { body, status }; } -function findAllRecords(req) { +function findAllRecords() { return { record_response: recordResponseData }; } -function fetchJobStatus(req) { +function fetchJobStatus(req: any) { const params = getParameters(req, "/jobs/:job_id/awx/status"); const data = awxDetailsData; - const body = data.find((x) => x.id === Number(params.job_id)); + const body = data.find((x) => x.jobId === Number(params?.job_id)); const status = body ? 200 : 404; return { body, status }; } -function fetchDeploymentJobLog(req) { +function fetchDeploymentJobLog(req: any) { const params = getParameters(req, "/jobs/:id/awx/log"); const jobDetailsData = awxDetailsData; - const body = jobDetailsData.find((x) => x.jobId === Number(params.id)); + const body = jobDetailsData.find((x) => x.jobId === Number(params?.id)); const status = body ? 200 : 404; return { body, status }; } -function listJobs(req) { +function listJobs(req: any) { const data = jobsData; const body = withMockPagination({ req, data, key: "jobs" }); return { body }; } -function fetchJob(req) { +function fetchJob(req: any) { const params = getParameters(req, "/jobs/:operation_id"); const data = jobsData; - const body = data.operations.find( - (x) => x?.id === Number(params?.operation_id) - ); + const body = data?.jobs?.find((x) => x?.id === Number(params?.operation_id)); const status = body ? 200 : 404; return { body, status }; } -function findNetBoxHostByFqdn(req) { +function findNetBoxHostByFqdn(req: any) { const params = getParameters(req, "/hosts/:fqdn/info_by_fqdn"); const hosts = hostsData; - const body = hosts.netBoxHosts.find((x) => x.fqdn === params.fqdn); + const body = hosts.netBoxHosts.find((x) => x.fqdn === params?.fqdn); const status = body ? 200 : 404; return { body, status }; } -function listHosts(req) { +function listHosts(req: any) { const data = hostsData; const body = withMockPagination({ req, data, key: "netBoxHosts" }); return { body }; } -function findHostStatus(req) { +function findHostStatus(req: any) { const params = getParameters(req, "/hosts/:host_id/status"); const data = hostStatusData; - const body = data.find((x) => x.hostId === params.host_id); + const body = data.find((x) => x.hostId === params?.host_id); const status = body ? 200 : 404; return { body, status }; } -function findHostAlerts(req) { +function findHostAlerts(req: any) { const params = getParameters(req, "/hosts/:host_id/alerts"); const data = hostAlertsData; - const body = data.find((x) => x.hostId === params.host_id); + const body = data.find((x) => x.hostId === params?.host_id); const status = body ? 200 : 404; return { body, status }; } -function fetchSysLogLines(req) { +function fetchSysLogLines() { return { hostSyslogsData }; } -function fetchProcServLogLines(req) { +function fetchProcServLogLines() { return { iocProcLogsData }; } -function fetchIocStatus(req) { +function fetchIocStatus(req: any) { const params = getParameters(req, "/iocs/:ioc_id/status"); const data = iocStatusData; console.debug("fetchIocStatus ", params); - const body = data.find((x) => `${x.iocId}` === params.ioc_id); + const body = data.find((x) => `${x.iocId}` === params?.ioc_id); const status = body ? 200 : 404; return { body, status }; } -function fetchIocAlerts(req) { +function fetchIocAlerts(req: any) { const params = getParameters(req, "/iocs/:ioc_id/alerts"); const data = iocAlertsData; - const body = data.find((x) => `${x.iocId}` === params.ioc_id); + const body = data.find((x) => `${x.iocId}` === params?.ioc_id); const status = body ? 200 : 404; return { body, status }; } -function fetchIOCByName(req) { +function fetchIOCByName() { const body = namingNamesData; return { body }; } -function getCurrentMode(req) { +function getCurrentMode() { const body = maintenanceData; return Math.random() < 0.5 ? { body } : null; } @@ -342,7 +348,12 @@ const mockAPI = { }; // Enough info to create handlers in cypress or MSW -const makeHandler = (method, matcher, requestHandler, wrapper) => ({ +const makeHandler = ( + method: any, + matcher: any, + requestHandler: any, + wrapper?: (routeHandler: any) => (req: any) => any +) => ({ method, matcher, requestHandler: wrapper ? wrapper(requestHandler) : requestHandler, @@ -350,7 +361,7 @@ const makeHandler = (method, matcher, requestHandler, wrapper) => ({ }); const queryPattern = "(\\?.*)?$"; -const qRegExp = (pattern) => RegExp(pattern + queryPattern); +const qRegExp = (pattern: any) => RegExp(pattern + queryPattern); // Handlers for our whole API export const apiHandlers = [ -- GitLab