@@ -4,9 +4,9 @@ jest.mock("../Contexts/VehicleContext");
|
|||||||
|
|
||||||
import { render, screen, cleanup, waitForElementToBeRemoved } from "@testing-library/react";
|
import { render, screen, cleanup, waitForElementToBeRemoved } from "@testing-library/react";
|
||||||
import { setToken } from "../Contexts/UserContext";
|
import { setToken } from "../Contexts/UserContext";
|
||||||
|
import { TEST_AUTH_OBJECT } from "../../utils/testing"
|
||||||
import App from ".";
|
import App from ".";
|
||||||
|
|
||||||
const TEST_TOKEN = { idToken: { jwtToken: "TEST" } };
|
|
||||||
const LOADING_STATUS = "Loading...";
|
const LOADING_STATUS = "Loading...";
|
||||||
|
|
||||||
const renderRoute = async (route) => {
|
const renderRoute = async (route) => {
|
||||||
@@ -37,6 +37,12 @@ describe("App", () => {
|
|||||||
expect(container).toMatchSnapshot();
|
expect(container).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Route /package-upload unauthenticated", async () => {
|
||||||
|
const container = await renderRoute("/package-upload");
|
||||||
|
expect(container.querySelector("span.MuiButton-label").innerHTML).toEqual("Sign In");
|
||||||
|
expect(container).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
it("Route /vehicle-add unauthenticated", async () => {
|
it("Route /vehicle-add unauthenticated", async () => {
|
||||||
const container = await renderRoute("/vehicle-add");
|
const container = await renderRoute("/vehicle-add");
|
||||||
expect(container.querySelector("span.MuiButton-label").innerHTML).toEqual("Sign In");
|
expect(container.querySelector("span.MuiButton-label").innerHTML).toEqual("Sign In");
|
||||||
@@ -44,21 +50,28 @@ describe("App", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("Route / authenticated", async () => {
|
it("Route / authenticated", async () => {
|
||||||
setToken(TEST_TOKEN);
|
setToken(TEST_AUTH_OBJECT);
|
||||||
const container = await renderRoute("/");
|
const container = await renderRoute("/");
|
||||||
expect(container.querySelector("h1").innerHTML).toEqual("Upload Update Package");
|
expect(container.querySelector("h1").innerHTML).toEqual("Welcome John!");
|
||||||
expect(container).toMatchSnapshot();
|
expect(container).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Route /home authenticated", async () => {
|
it("Route /home authenticated", async () => {
|
||||||
setToken(TEST_TOKEN);
|
setToken(TEST_AUTH_OBJECT);
|
||||||
const container = await renderRoute("/home");
|
const container = await renderRoute("/home");
|
||||||
|
expect(container.querySelector("h1").innerHTML).toEqual("Welcome John!");
|
||||||
|
expect(container).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Route /package-upload authenticated", async () => {
|
||||||
|
setToken(TEST_AUTH_OBJECT);
|
||||||
|
const container = await renderRoute("/package-upload");
|
||||||
expect(container.querySelector("h1").innerHTML).toEqual("Upload Update Package");
|
expect(container.querySelector("h1").innerHTML).toEqual("Upload Update Package");
|
||||||
expect(container).toMatchSnapshot();
|
expect(container).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Route /vehicle-add authenticated", async () => {
|
it("Route /vehicle-add authenticated", async () => {
|
||||||
setToken(TEST_TOKEN);
|
setToken(TEST_AUTH_OBJECT);
|
||||||
const container = await renderRoute("/vehicle-add");
|
const container = await renderRoute("/vehicle-add");
|
||||||
expect(container.querySelector("h1").innerHTML).toEqual("Add Vehicle");
|
expect(container.querySelector("h1").innerHTML).toEqual("Add Vehicle");
|
||||||
expect(container).toMatchSnapshot();
|
expect(container).toMatchSnapshot();
|
||||||
@@ -71,7 +84,7 @@ describe("App", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("Route /page-not-found authenticated", async () => {
|
it("Route /page-not-found authenticated", async () => {
|
||||||
setToken(TEST_TOKEN);
|
setToken(TEST_AUTH_OBJECT);
|
||||||
const container = await renderRoute("/page-not-found");
|
const container = await renderRoute("/page-not-found");
|
||||||
expect(container.querySelector("h1").innerHTML).toEqual("Page Not Found");
|
expect(container.querySelector("h1").innerHTML).toEqual("Page Not Found");
|
||||||
expect(container).toMatchSnapshot();
|
expect(container).toMatchSnapshot();
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,15 @@
|
|||||||
import React, { useContext, useEffect, useState } from "react";
|
import React, { useContext, useEffect, useState } from "react";
|
||||||
import auth from "../../services/auth";
|
import auth from "../../services/auth";
|
||||||
import getTimerWorker from "../../services/timer";
|
import getTimerWorker from "../../services/timer";
|
||||||
|
import { parsePayload } from "../../utils/jwt";
|
||||||
|
import { getGroups } from "../../utils/roles";
|
||||||
|
|
||||||
const UserContext = React.createContext();
|
const UserContext = React.createContext();
|
||||||
|
|
||||||
export const UserProvider = ({ children }) => {
|
export const UserProvider = ({ children }) => {
|
||||||
const [fetching, setFetching] = useState(false);
|
const [fetching, setFetching] = useState(false);
|
||||||
const [token, setToken] = useState(null);
|
const [token, setToken] = useState(null);
|
||||||
|
const [groups, setGroups] = useState(null);
|
||||||
const [error, setError] = useState(null);
|
const [error, setError] = useState(null);
|
||||||
let timer;
|
let timer;
|
||||||
|
|
||||||
@@ -15,13 +18,7 @@ export const UserProvider = ({ children }) => {
|
|||||||
if (!localStorage) return;
|
if (!localStorage) return;
|
||||||
const t = JSON.parse(localStorage.getItem("token"));
|
const t = JSON.parse(localStorage.getItem("token"));
|
||||||
if (!t) return;
|
if (!t) return;
|
||||||
if (
|
if (!t.idToken || !t.idToken.jwtToken) throw new Error("Invalid token");
|
||||||
!t.idToken ||
|
|
||||||
!t.idToken.jwtToken ||
|
|
||||||
!t.idToken.payload ||
|
|
||||||
!t.idToken.payload.exp
|
|
||||||
)
|
|
||||||
throw new Error("Invalid token");
|
|
||||||
setToken(t);
|
setToken(t);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
document.location = signOut();
|
document.location = signOut();
|
||||||
@@ -45,7 +42,12 @@ export const UserProvider = ({ children }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const startSessionTimer = () => {
|
const startSessionTimer = () => {
|
||||||
const duration = 1000 * token.idToken.payload.exp - new Date().getTime();
|
if (!token || !token.idToken || !token.idToken.jwtToken) {
|
||||||
|
throw new Error("No id token");
|
||||||
|
}
|
||||||
|
const payload = parsePayload(token.idToken.jwtToken);
|
||||||
|
if (!payload || !payload.exp) throw new Error("Bad id token payload");
|
||||||
|
const duration = 1000 * payload.exp - new Date().getTime();
|
||||||
if (!timer) {
|
if (!timer) {
|
||||||
timer = getTimerWorker();
|
timer = getTimerWorker();
|
||||||
timer.onMessage(async (e) => {
|
timer.onMessage(async (e) => {
|
||||||
@@ -71,6 +73,7 @@ export const UserProvider = ({ children }) => {
|
|||||||
if (!t || t.error) throw new Error("Unable to refresh token");
|
if (!t || t.error) throw new Error("Unable to refresh token");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setGroups(getGroups(idToken));
|
||||||
startSessionTimer();
|
startSessionTimer();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setError(`Verify error. ${e.message}`);
|
setError(`Verify error. ${e.message}`);
|
||||||
@@ -103,6 +106,7 @@ export const UserProvider = ({ children }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const signOut = () => {
|
const signOut = () => {
|
||||||
|
setGroups(null);
|
||||||
setToken(null);
|
setToken(null);
|
||||||
if (localStorage) {
|
if (localStorage) {
|
||||||
localStorage.removeItem("token");
|
localStorage.removeItem("token");
|
||||||
@@ -149,6 +153,7 @@ export const UserProvider = ({ children }) => {
|
|||||||
value={{
|
value={{
|
||||||
fetching,
|
fetching,
|
||||||
token,
|
token,
|
||||||
|
groups,
|
||||||
error,
|
error,
|
||||||
setError,
|
setError,
|
||||||
signIn,
|
signIn,
|
||||||
|
|||||||
@@ -11,15 +11,7 @@ import {
|
|||||||
import { UserProvider, useUserContext } from "../Contexts/UserContext";
|
import { UserProvider, useUserContext } from "../Contexts/UserContext";
|
||||||
import auth from "../../services/auth";
|
import auth from "../../services/auth";
|
||||||
import getTimerWorker from "../../services/timer";
|
import getTimerWorker from "../../services/timer";
|
||||||
|
import { TEST_AUTH_OBJECT, TEST_EXPECTED_GROUPS } from "../../utils/testing";
|
||||||
const TEST_TOKEN = {
|
|
||||||
idToken: {
|
|
||||||
jwtToken: "TEST",
|
|
||||||
payload: {
|
|
||||||
exp: new Date().getTime() / 1000,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const INVALID_TOKEN_RESPONSE = {
|
const INVALID_TOKEN_RESPONSE = {
|
||||||
error: "Bad Request Error",
|
error: "Bad Request Error",
|
||||||
@@ -36,10 +28,11 @@ const setupSignInEnv = (refreshResponse, valid) => {
|
|||||||
auth.setVerifyResponse({ valid });
|
auth.setVerifyResponse({ valid });
|
||||||
};
|
};
|
||||||
|
|
||||||
const checkBaseResults = (error, fetching, token) => {
|
const checkBaseResults = (error, fetching, token, groups) => {
|
||||||
expect(screen.getByTestId("error").innerHTML).toEqual(error);
|
expect(screen.getByTestId("error").innerHTML).toEqual(error);
|
||||||
expect(screen.getByTestId("fetching").innerHTML).toEqual(fetching);
|
expect(screen.getByTestId("fetching").innerHTML).toEqual(fetching);
|
||||||
expect(screen.getByTestId("token").innerHTML).toEqual(token);
|
expect(screen.getByTestId("token").innerHTML).toEqual(token);
|
||||||
|
expect(screen.getByTestId("groups").innerHTML).toEqual(groups);
|
||||||
};
|
};
|
||||||
|
|
||||||
const checkTokenResults = (timer, token) => {
|
const checkTokenResults = (timer, token) => {
|
||||||
@@ -57,13 +50,14 @@ describe("UseContext", () => {
|
|||||||
describe("Signin", () => {
|
describe("Signin", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const TestComp = () => {
|
const TestComp = () => {
|
||||||
const { signIn, error, token, fetching } = useUserContext();
|
const { signIn, error, token, groups, fetching } = useUserContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div data-testid="error">{error}</div>
|
<div data-testid="error">{error}</div>
|
||||||
<div data-testid="fetching">{fetching.toString()}</div>
|
<div data-testid="fetching">{fetching.toString()}</div>
|
||||||
<div data-testid="token">{JSON.stringify(token)}</div>
|
<div data-testid="token">{JSON.stringify(token)}</div>
|
||||||
|
<div data-testid="groups">{groups}</div>
|
||||||
<button data-testid="signInNoCode" onClick={() => signIn("")} />
|
<button data-testid="signInNoCode" onClick={() => signIn("")} />
|
||||||
<button
|
<button
|
||||||
data-testid="signInInvalidCode"
|
data-testid="signInInvalidCode"
|
||||||
@@ -85,13 +79,13 @@ describe("UseContext", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("Initial state", () => {
|
it("Initial state", () => {
|
||||||
checkBaseResults("", "false", "null");
|
checkBaseResults("", "false", "null", "");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("No auth code", () => {
|
it("No auth code", () => {
|
||||||
fireEvent.click(screen.getByTestId("signInNoCode"));
|
fireEvent.click(screen.getByTestId("signInNoCode"));
|
||||||
|
|
||||||
checkBaseResults("", "false", "null");
|
checkBaseResults("", "false", "null", "");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Invalid auth code", async () => {
|
it("Invalid auth code", async () => {
|
||||||
@@ -103,14 +97,19 @@ describe("UseContext", () => {
|
|||||||
expect(screen.getByTestId("fetching").innerHTML).toEqual("true")
|
expect(screen.getByTestId("fetching").innerHTML).toEqual("true")
|
||||||
);
|
);
|
||||||
|
|
||||||
checkBaseResults("Sign in error. Bad Request Message", "false", "null");
|
checkBaseResults(
|
||||||
|
"Sign in error. Bad Request Message",
|
||||||
|
"false",
|
||||||
|
"null",
|
||||||
|
""
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Sign in form", async () => {
|
it("Sign in form", async () => {
|
||||||
const TOKEN_STRING = JSON.stringify(TEST_TOKEN);
|
const TOKEN_STRING = JSON.stringify(TEST_AUTH_OBJECT);
|
||||||
const timer = getTimerWorker();
|
const timer = getTimerWorker();
|
||||||
|
|
||||||
setupSignInEnv(TEST_TOKEN, true);
|
setupSignInEnv(TEST_AUTH_OBJECT, true);
|
||||||
|
|
||||||
fireEvent.click(screen.getByTestId("signIn"));
|
fireEvent.click(screen.getByTestId("signIn"));
|
||||||
|
|
||||||
@@ -118,7 +117,7 @@ describe("UseContext", () => {
|
|||||||
expect(screen.getByTestId("fetching").innerHTML).toEqual("true")
|
expect(screen.getByTestId("fetching").innerHTML).toEqual("true")
|
||||||
);
|
);
|
||||||
|
|
||||||
checkBaseResults("", "false", TOKEN_STRING);
|
checkBaseResults("", "false", TOKEN_STRING, TEST_EXPECTED_GROUPS);
|
||||||
checkTokenResults(timer, TOKEN_STRING);
|
checkTokenResults(timer, TOKEN_STRING);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -126,12 +125,20 @@ describe("UseContext", () => {
|
|||||||
describe("Signout", () => {
|
describe("Signout", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const TestComp = () => {
|
const TestComp = () => {
|
||||||
const { signIn, signOut, error, token, fetching } = useUserContext();
|
const {
|
||||||
|
signIn,
|
||||||
|
signOut,
|
||||||
|
error,
|
||||||
|
token,
|
||||||
|
groups,
|
||||||
|
fetching,
|
||||||
|
} = useUserContext();
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div data-testid="error">{error}</div>
|
<div data-testid="error">{error}</div>
|
||||||
<div data-testid="fetching">{fetching.toString()}</div>
|
<div data-testid="fetching">{fetching.toString()}</div>
|
||||||
<div data-testid="token">{JSON.stringify(token)}</div>
|
<div data-testid="token">{JSON.stringify(token)}</div>
|
||||||
|
<div data-testid="groups">{groups}</div>
|
||||||
<button data-testid="signIn" onClick={() => signIn("TEST_CODE")} />
|
<button data-testid="signIn" onClick={() => signIn("TEST_CODE")} />
|
||||||
<button data-testid="signOut" onClick={() => signOut()} />
|
<button data-testid="signOut" onClick={() => signOut()} />
|
||||||
</>
|
</>
|
||||||
@@ -142,7 +149,7 @@ describe("UseContext", () => {
|
|||||||
<TestComp />
|
<TestComp />
|
||||||
</UserProvider>
|
</UserProvider>
|
||||||
);
|
);
|
||||||
auth.setSignInResponse(TEST_TOKEN);
|
auth.setSignInResponse(TEST_AUTH_OBJECT);
|
||||||
fireEvent.click(screen.getByTestId("signIn"));
|
fireEvent.click(screen.getByTestId("signIn"));
|
||||||
await waitFor(() =>
|
await waitFor(() =>
|
||||||
expect(screen.getByTestId("fetching").innerHTML).toEqual("true")
|
expect(screen.getByTestId("fetching").innerHTML).toEqual("true")
|
||||||
@@ -154,10 +161,9 @@ describe("UseContext", () => {
|
|||||||
cleanup();
|
cleanup();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Token cleared", () => {
|
it("Token cleared", async () => {
|
||||||
fireEvent.click(screen.getByTestId("signOut"));
|
fireEvent.click(screen.getByTestId("signOut"));
|
||||||
|
checkBaseResults("", "false", "null", "");
|
||||||
checkBaseResults("", "false", "null");
|
|
||||||
if (!localStorage) return;
|
if (!localStorage) return;
|
||||||
expect(localStorage.getItem("token")).toBeNull();
|
expect(localStorage.getItem("token")).toBeNull();
|
||||||
});
|
});
|
||||||
@@ -166,13 +172,14 @@ describe("UseContext", () => {
|
|||||||
describe("Refresh", () => {
|
describe("Refresh", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const TestComp = () => {
|
const TestComp = () => {
|
||||||
const { refresh, error, token, fetching } = useUserContext();
|
const { refresh, error, token, groups, fetching } = useUserContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div data-testid="error">{error}</div>
|
<div data-testid="error">{error}</div>
|
||||||
<div data-testid="fetching">{fetching.toString()}</div>
|
<div data-testid="fetching">{fetching.toString()}</div>
|
||||||
<div data-testid="token">{JSON.stringify(token)}</div>
|
<div data-testid="token">{JSON.stringify(token)}</div>
|
||||||
|
<div data-testid="groups">{groups}</div>
|
||||||
<button data-testid="refreshNoToken" onClick={() => refresh("")} />
|
<button data-testid="refreshNoToken" onClick={() => refresh("")} />
|
||||||
<button
|
<button
|
||||||
data-testid="refreshInvalidToken"
|
data-testid="refreshInvalidToken"
|
||||||
@@ -197,12 +204,12 @@ describe("UseContext", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("Initial state", () => {
|
it("Initial state", () => {
|
||||||
checkBaseResults("", "false", "null");
|
checkBaseResults("", "false", "null", "");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("No refresh token", () => {
|
it("No refresh token", () => {
|
||||||
fireEvent.click(screen.getByTestId("refreshNoToken"));
|
fireEvent.click(screen.getByTestId("refreshNoToken"));
|
||||||
checkBaseResults("Refresh error. Token required", "false", "null");
|
checkBaseResults("Refresh error. Token required", "false", "null", "");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Invalid refresh token", async () => {
|
it("Invalid refresh token", async () => {
|
||||||
@@ -213,21 +220,26 @@ describe("UseContext", () => {
|
|||||||
expect(screen.getByTestId("fetching").innerHTML).toEqual("true")
|
expect(screen.getByTestId("fetching").innerHTML).toEqual("true")
|
||||||
);
|
);
|
||||||
|
|
||||||
checkBaseResults("Refresh error. Bad Request Message", "false", "null");
|
checkBaseResults(
|
||||||
|
"Refresh error. Bad Request Message",
|
||||||
|
"false",
|
||||||
|
"null",
|
||||||
|
""
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Valid refresh token", async () => {
|
it("Valid refresh token", async () => {
|
||||||
const TOKEN_STRING = JSON.stringify(TEST_TOKEN);
|
const TOKEN_STRING = JSON.stringify(TEST_AUTH_OBJECT);
|
||||||
const timer = getTimerWorker();
|
const timer = getTimerWorker();
|
||||||
|
|
||||||
setupRefreshEnv(TEST_TOKEN, true);
|
setupRefreshEnv(TEST_AUTH_OBJECT, true);
|
||||||
|
|
||||||
fireEvent.click(screen.getByTestId("refreshValidToken"));
|
fireEvent.click(screen.getByTestId("refreshValidToken"));
|
||||||
await waitFor(() =>
|
await waitFor(() =>
|
||||||
expect(screen.getByTestId("fetching").innerHTML).toEqual("true")
|
expect(screen.getByTestId("fetching").innerHTML).toEqual("true")
|
||||||
);
|
);
|
||||||
|
|
||||||
checkBaseResults("", "false", TOKEN_STRING);
|
checkBaseResults("", "false", TOKEN_STRING, TEST_EXPECTED_GROUPS);
|
||||||
checkTokenResults(timer, TOKEN_STRING);
|
checkTokenResults(timer, TOKEN_STRING);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
|
import { getGroups } from "../../../utils/roles";
|
||||||
|
|
||||||
let token = null;
|
let token = null;
|
||||||
|
let groups = null;
|
||||||
let fetching = false;
|
let fetching = false;
|
||||||
let error = null;
|
let error = null;
|
||||||
let signInResp = {};
|
let signInResp = {};
|
||||||
let authorizeURL = "https://cognito.com/authorize?redirect=https://example.com/callback";
|
let authorizeURL =
|
||||||
let logoutURL = "https://cognito.com/logout?redirect=https://example.com/callback";
|
"https://cognito.com/authorize?redirect=https://example.com/callback";
|
||||||
|
let logoutURL =
|
||||||
|
"https://cognito.com/logout?redirect=https://example.com/callback";
|
||||||
|
|
||||||
export const UserProvider = ({ children }) => {
|
export const UserProvider = ({ children }) => {
|
||||||
return <div data-testid="mocked-userprovider">{children}</div>;
|
return <div data-testid="mocked-userprovider">{children}</div>;
|
||||||
@@ -15,6 +20,7 @@ export const useUserContext = () => ({
|
|||||||
token,
|
token,
|
||||||
fetching,
|
fetching,
|
||||||
error,
|
error,
|
||||||
|
groups,
|
||||||
signIn: jest.fn(() => signInResp),
|
signIn: jest.fn(() => signInResp),
|
||||||
signOut: jest.fn(),
|
signOut: jest.fn(),
|
||||||
getAuthorizeURL: jest.fn(() => authorizeURL),
|
getAuthorizeURL: jest.fn(() => authorizeURL),
|
||||||
@@ -26,6 +32,11 @@ export const useUserContext = () => ({
|
|||||||
|
|
||||||
export const setToken = (val) => {
|
export const setToken = (val) => {
|
||||||
token = val;
|
token = val;
|
||||||
|
if (!val || !val.idToken || !val.idToken.jwtToken) {
|
||||||
|
groups = null;
|
||||||
|
} else {
|
||||||
|
groups = getGroups(val.idToken.jwtToken);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const setFetching = (val) => {
|
export const setFetching = (val) => {
|
||||||
|
|||||||
@@ -7,10 +7,11 @@ import { render, cleanup, waitFor } from "@testing-library/react";
|
|||||||
import FileUploadForm from "./index";
|
import FileUploadForm from "./index";
|
||||||
import { setToken } from "../Contexts/UserContext";
|
import { setToken } from "../Contexts/UserContext";
|
||||||
import { StatusProvider } from "../Contexts/StatusContext";
|
import { StatusProvider } from "../Contexts/StatusContext";
|
||||||
|
import { TEST_AUTH_OBJECT } from "../../utils/testing"
|
||||||
|
|
||||||
describe("File Upload Form", () => {
|
describe("File Upload Form", () => {
|
||||||
it("Should render", async () => {
|
it("Should render", async () => {
|
||||||
setToken({ idToken: { jwtToken: "TEST" } });
|
setToken(TEST_AUTH_OBJECT);
|
||||||
const { container } = render(<StatusProvider><BrowserRouter><FileUploadForm /></BrowserRouter></StatusProvider>);
|
const { container } = render(<StatusProvider><BrowserRouter><FileUploadForm /></BrowserRouter></StatusProvider>);
|
||||||
await waitFor(() => {});
|
await waitFor(() => {});
|
||||||
expect(container).toMatchSnapshot();
|
expect(container).toMatchSnapshot();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useRef, useState } from "react";
|
import React, { useRef, useState } from "react";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Chip,
|
Chip,
|
||||||
@@ -86,19 +86,17 @@ const MainForm = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
const handleCarOpen = async () => {
|
||||||
const {
|
const {
|
||||||
idToken: { jwtToken: authToken },
|
idToken: { jwtToken: authToken },
|
||||||
} = token;
|
} = token;
|
||||||
(async () => {
|
|
||||||
try {
|
try {
|
||||||
await getVehicles(null, authToken);
|
await getVehicles(null, authToken);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setMessage(e.message);
|
setMessage(e.message);
|
||||||
}
|
}
|
||||||
})();
|
};
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.paper}>
|
<div className={classes.paper}>
|
||||||
@@ -173,6 +171,7 @@ const MainForm = () => {
|
|||||||
name="vehicles"
|
name="vehicles"
|
||||||
multiple
|
multiple
|
||||||
className={classes.menuProps}
|
className={classes.menuProps}
|
||||||
|
onOpen={handleCarOpen}
|
||||||
onChange={handleVehiclesChange}
|
onChange={handleVehiclesChange}
|
||||||
value={selectedVehicles}
|
value={selectedVehicles}
|
||||||
input={<Input id="select-multiple-chip" />}
|
input={<Input id="select-multiple-chip" />}
|
||||||
|
|||||||
35
src/components/Home/index.jsx
Normal file
35
src/components/Home/index.jsx
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { Typography } from "@material-ui/core";
|
||||||
|
import useStyles from "../useStyles";
|
||||||
|
|
||||||
|
import { useUserContext } from "../Contexts/UserContext";
|
||||||
|
import { parsePayload } from "../../utils/jwt";
|
||||||
|
|
||||||
|
const DEFAULT_GREETING = "Welcome";
|
||||||
|
|
||||||
|
const getGreeting = (token) => {
|
||||||
|
if (!token || !token.idToken || !token.idToken.jwtToken)
|
||||||
|
return DEFAULT_GREETING;
|
||||||
|
|
||||||
|
const payload = parsePayload(token.idToken.jwtToken);
|
||||||
|
|
||||||
|
if (!payload || !payload.given_name) return DEFAULT_GREETING;
|
||||||
|
|
||||||
|
return `Welcome ${payload.given_name}!`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Home = () => {
|
||||||
|
const classes = useStyles();
|
||||||
|
const { token } = useUserContext();
|
||||||
|
const greeting = getGreeting(token);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes.paper}>
|
||||||
|
<Typography component="h1" variant="h5">
|
||||||
|
{greeting}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Home;
|
||||||
@@ -20,7 +20,7 @@ export default function MenuDrawer({ children }) {
|
|||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { signOut, token } = useUserContext();
|
const { signOut, token } = useUserContext();
|
||||||
const [open, setOpen] = React.useState(false);
|
const [open, setOpen] = React.useState(true);
|
||||||
|
|
||||||
const handleDrawerOpen = () => {
|
const handleDrawerOpen = () => {
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
|
|||||||
@@ -1,16 +1,40 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { List } from "@material-ui/core";
|
import { List } from "@material-ui/core";
|
||||||
import ListItemLink from "../ListItemLink";
|
import ListItemLink from "../ListItemLink";
|
||||||
|
import { useUserContext } from "../Contexts/UserContext";
|
||||||
|
import { Roles, hasRole } from "../../utils/roles";
|
||||||
|
|
||||||
|
const menuData = [
|
||||||
|
{
|
||||||
|
label: "Home",
|
||||||
|
to: "/home",
|
||||||
|
roles: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Upload Update Package",
|
||||||
|
to: "/package-upload",
|
||||||
|
roles: [Roles.CREATE],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Add Vehicles",
|
||||||
|
to: "/vehicle-add",
|
||||||
|
roles: [Roles.CREATE],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export default function SideMenu() {
|
export default function SideMenu() {
|
||||||
const menuData = [
|
const { groups } = useUserContext();
|
||||||
{ label: "Upload Update Package", to: "/home" },
|
const menu = menuData.reduce((result, item) => {
|
||||||
{ label: "Add Vehicles", to: "/vehicle-add" },
|
if (hasRole(item.roles, groups)) {
|
||||||
];
|
result.push(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<List>
|
<List>
|
||||||
{menuData.map((item, index) => (
|
{menu.map((item, index) => (
|
||||||
<ListItemLink key={index} primary={item.label} to={item.to} />
|
<ListItemLink key={index} primary={item.label} to={item.to} />
|
||||||
))}
|
))}
|
||||||
</List>
|
</List>
|
||||||
|
|||||||
33
src/components/Layouts/SideMenu.test.jsx
Normal file
33
src/components/Layouts/SideMenu.test.jsx
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
jest.mock("../Contexts/UserContext");
|
||||||
|
|
||||||
|
import { render, waitFor } from "@testing-library/react";
|
||||||
|
import { BrowserRouter } from "react-router-dom";
|
||||||
|
import { UserProvider, setToken } from "../Contexts/UserContext";
|
||||||
|
import { TEST_AUTH_OBJECT } from "../../utils/testing";
|
||||||
|
import SideMenu from "./SideMenu";
|
||||||
|
|
||||||
|
const renderMenu = async () => {
|
||||||
|
const { container } = render(
|
||||||
|
<UserProvider>
|
||||||
|
<BrowserRouter>
|
||||||
|
<SideMenu />
|
||||||
|
</BrowserRouter>
|
||||||
|
</UserProvider>
|
||||||
|
);
|
||||||
|
await waitFor(() => {});
|
||||||
|
return container;
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("SideMenu", () => {
|
||||||
|
it("Unauthenticated", async () => {
|
||||||
|
setToken(null);
|
||||||
|
const container = await renderMenu(null);
|
||||||
|
expect(container).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Authenticated", async () => {
|
||||||
|
setToken(TEST_AUTH_OBJECT);
|
||||||
|
const container = await renderMenu(TEST_AUTH_OBJECT);
|
||||||
|
expect(container).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
115
src/components/Layouts/__snapshots__/SideMenu.test.jsx.snap
Normal file
115
src/components/Layouts/__snapshots__/SideMenu.test.jsx.snap
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`SideMenu Authenticated 1`] = `
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
data-testid="mocked-userprovider"
|
||||||
|
>
|
||||||
|
<ul
|
||||||
|
class="MuiList-root MuiList-padding"
|
||||||
|
>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
aria-disabled="false"
|
||||||
|
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
|
||||||
|
href="/home"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiListItemText-root"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
|
>
|
||||||
|
Home
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
class="MuiTouchRipple-root"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
aria-disabled="false"
|
||||||
|
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
|
||||||
|
href="/package-upload"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiListItemText-root"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
|
>
|
||||||
|
Upload Update Package
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
class="MuiTouchRipple-root"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
aria-disabled="false"
|
||||||
|
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
|
||||||
|
href="/vehicle-add"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiListItemText-root"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
|
>
|
||||||
|
Add Vehicles
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
class="MuiTouchRipple-root"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`SideMenu Unauthenticated 1`] = `
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
data-testid="mocked-userprovider"
|
||||||
|
>
|
||||||
|
<ul
|
||||||
|
class="MuiList-root MuiList-padding"
|
||||||
|
>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
aria-disabled="false"
|
||||||
|
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
|
||||||
|
href="/home"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiListItemText-root"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||||
|
>
|
||||||
|
Home
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
class="MuiTouchRipple-root"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Redirect, Route } from "react-router-dom";
|
import { Redirect, Route } from "react-router-dom";
|
||||||
|
import { hasRole } from "../../utils/roles";
|
||||||
|
|
||||||
export const TYPES = {
|
export const TYPES = {
|
||||||
PUBLIC: 0,
|
PUBLIC: 0,
|
||||||
@@ -7,11 +8,19 @@ export const TYPES = {
|
|||||||
PROTECTED: 2,
|
PROTECTED: 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AuthRoute = ({ token, type, ...others }) => {
|
export const AuthRoute = ({ token, type, roles, groups, ...others }) => {
|
||||||
if (!token && type === TYPES.PROTECTED) {
|
if (type === TYPES.PROTECTED && !token) {
|
||||||
return <Redirect to="/" />;
|
return <Redirect to="/" />;
|
||||||
} else if (token && type === TYPES.GUEST) {
|
} else if (type === TYPES.GUEST && token) {
|
||||||
|
return <Redirect to="/home" />;
|
||||||
|
} else if (
|
||||||
|
type === TYPES.PROTECTED &&
|
||||||
|
token &&
|
||||||
|
roles &&
|
||||||
|
!hasRole(roles, groups)
|
||||||
|
) {
|
||||||
return <Redirect to="/home" />;
|
return <Redirect to="/home" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <Route render {...others} />;
|
return <Route render {...others} />;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,14 +4,16 @@ import { Switch } from "react-router-dom";
|
|||||||
import { AuthRoute, TYPES } from "../Routes/AuthRoute";
|
import { AuthRoute, TYPES } from "../Routes/AuthRoute";
|
||||||
import { MessageBar } from "../MessageBar";
|
import { MessageBar } from "../MessageBar";
|
||||||
import { useUserContext } from "../Contexts/UserContext";
|
import { useUserContext } from "../Contexts/UserContext";
|
||||||
|
import { Roles } from "../../utils/roles";
|
||||||
|
|
||||||
const SSOForm = React.lazy(() => import("../SSOForm"));
|
const SSOForm = React.lazy(() => import("../SSOForm"));
|
||||||
|
const Home = React.lazy(() => import("../Home"));
|
||||||
const FileUploadForm = React.lazy(() => import("../FileUploadForm"));
|
const FileUploadForm = React.lazy(() => import("../FileUploadForm"));
|
||||||
const VehicleAddForm = React.lazy(() => import("../VehicleAddForm"));
|
const VehicleAddForm = React.lazy(() => import("../VehicleAddForm"));
|
||||||
const PageNotFound = React.lazy(() => import("../404"));
|
const PageNotFound = React.lazy(() => import("../404"));
|
||||||
|
|
||||||
const SiteRoutes = () => {
|
const SiteRoutes = () => {
|
||||||
const { token } = useUserContext();
|
const { token, groups } = useUserContext();
|
||||||
return (
|
return (
|
||||||
<Suspense fallback={"Loading..."}>
|
<Suspense fallback={"Loading..."}>
|
||||||
<MessageBar />
|
<MessageBar />
|
||||||
@@ -25,15 +27,25 @@ const SiteRoutes = () => {
|
|||||||
/>
|
/>
|
||||||
<AuthRoute
|
<AuthRoute
|
||||||
path="/home"
|
path="/home"
|
||||||
|
render={() => <Home />}
|
||||||
|
type={TYPES.PROTECTED}
|
||||||
|
token={token}
|
||||||
|
/>
|
||||||
|
<AuthRoute
|
||||||
|
path="/package-upload"
|
||||||
render={() => <FileUploadForm />}
|
render={() => <FileUploadForm />}
|
||||||
type={TYPES.PROTECTED}
|
type={TYPES.PROTECTED}
|
||||||
token={token}
|
token={token}
|
||||||
|
groups={groups}
|
||||||
|
roles={[Roles.CREATE]}
|
||||||
/>
|
/>
|
||||||
<AuthRoute
|
<AuthRoute
|
||||||
path="/vehicle-add"
|
path="/vehicle-add"
|
||||||
render={() => <VehicleAddForm />}
|
render={() => <VehicleAddForm />}
|
||||||
type={TYPES.PROTECTED}
|
type={TYPES.PROTECTED}
|
||||||
token={token}
|
token={token}
|
||||||
|
groups={groups}
|
||||||
|
roles={[Roles.CREATE]}
|
||||||
/>
|
/>
|
||||||
<PageNotFound />
|
<PageNotFound />
|
||||||
</Switch>
|
</Switch>
|
||||||
|
|||||||
14
src/utils/jwt.js
Normal file
14
src/utils/jwt.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
export const parsePayload = (token) => {
|
||||||
|
if (!token) return null;
|
||||||
|
const parts = token.split(".");
|
||||||
|
if (parts.length < 2) return null;
|
||||||
|
return JSON.parse(decode(parts[1]));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const decode = (payload) => {
|
||||||
|
const l = (payload.length % 4);
|
||||||
|
if (l > 0) {
|
||||||
|
payload += "=".repeat(4 - l);
|
||||||
|
}
|
||||||
|
return atob(payload);
|
||||||
|
};
|
||||||
15
src/utils/jwt.test.js
Normal file
15
src/utils/jwt.test.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { parsePayload } from "./jwt";
|
||||||
|
import { TEST_TOKEN } from "./testing";
|
||||||
|
|
||||||
|
describe("JWT Helper", () => {
|
||||||
|
it("Should decode", () => {
|
||||||
|
const start = Date.now()
|
||||||
|
const v = parsePayload(TEST_TOKEN);
|
||||||
|
const diff = Date.now() - start;
|
||||||
|
|
||||||
|
expect(diff < 2).toBeTruthy();
|
||||||
|
expect(typeof v).toEqual("object");
|
||||||
|
expect(v.exp).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
35
src/utils/roles.js
Normal file
35
src/utils/roles.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { parsePayload } from "./jwt";
|
||||||
|
|
||||||
|
export const Roles = {
|
||||||
|
CREATE: "efcc3025-e2d8-4212-8227-805c7be39d2c",
|
||||||
|
READ: "a729bbd4-2038-4649-9127-16782bb1e701",
|
||||||
|
}
|
||||||
|
|
||||||
|
export const hasRoleToken = (roles, token) => {
|
||||||
|
if (!roles || roles.length === 0) return true;
|
||||||
|
|
||||||
|
const groups = getGroups(token);
|
||||||
|
|
||||||
|
if (!groups) return false;
|
||||||
|
|
||||||
|
return hasRole(roles, groups);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getGroups = (token) => {
|
||||||
|
const payload = parsePayload(token);
|
||||||
|
|
||||||
|
if (!payload || !payload["custom:groups"]) return null;
|
||||||
|
|
||||||
|
return payload["custom:groups"];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const hasRole = (roles, groups) => {
|
||||||
|
if (!roles || roles.length === 0) return true;
|
||||||
|
if (!groups) return false;
|
||||||
|
|
||||||
|
for (let role of roles) {
|
||||||
|
if (groups.indexOf(role) > -1) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
10
src/utils/roles.test.js
Normal file
10
src/utils/roles.test.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
import { hasRoleToken, Roles } from "./roles";
|
||||||
|
import { TEST_TOKEN } from "./testing";
|
||||||
|
|
||||||
|
describe("Roles Helper", () => {
|
||||||
|
it("Check roles", () => {
|
||||||
|
expect(hasRoleToken([Roles.CREATE], TEST_TOKEN)).toEqual(true);
|
||||||
|
expect(hasRoleToken([Roles.READ], TEST_TOKEN)).toEqual(false);
|
||||||
|
})
|
||||||
|
});
|
||||||
8
src/utils/testing.js
Normal file
8
src/utils/testing.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export const TEST_TOKEN = "eyJraWQiOiJlUTNuZFJLaUVcL084VUZ5RHFsYjN0S1RzWG00SzVPMlc4NXd3VWkzT2tNZz0iLCJhbGciOiJSUzI1NiJ9.eyJhdF9oYXNoIjoiOUlyV2RLaUxJU0FZUnFha1F2b2xmZyIsInN1YiI6IjJiMDk1NTY2LTllNDYtNGQ4ZS1iMTA5LTI0MTM1ZGYyMmVlNiIsImNvZ25pdG86Z3JvdXBzIjpbInVzLXdlc3QtMl9BV3dqTFh5bTJfQXp1cmVBRCJdLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImlzcyI6Imh0dHBzOlwvXC9jb2duaXRvLWlkcC51cy13ZXN0LTIuYW1hem9uYXdzLmNvbVwvdXMtd2VzdC0yX0FXd2pMWHltMiIsImNvZ25pdG86dXNlcm5hbWUiOiJhenVyZWFkX2p3dUBmaXNrZXJpbmMuY29tIiwiZ2l2ZW5fbmFtZSI6IkpvaG4iLCJjdXN0b206Z3JvdXBzIjoiWzhkODI3OGE1LTljMGUtNGM3Zi05MThhLTgxMWZkMWQyMzZlNCwgNmMzY2Y5OGQtMGFkYS00OGM2LWFlOTQtYjE3MWNmYTI3NWZjLCA1NmVmNGJlYy1kNzM5LTRkZGYtYTAwMy1lY2M4MTMwODViOGQsIGVmY2MzMDI1LWUyZDgtNDIxMi04MjI3LTgwNWM3YmUzOWQyYywgNTUxNWE5OGYtNDY2OC00MTIxLThlOGQtZmVlMjgyNTY5OWNmLCA4Njk1NmEyZi04ZDQ2LTQ3ZmYtOWIyOS1mOTkwNzlhZTNjMWQsIGM0ZDQzNjFjLTg4ODItNDdiNC04NjQxLWZkM2FiNjhhZTcyMiwgN2JjZGNkYjItMzI3OS00NGJmLWE5OTgtNzcxYmFiNGIzM2UxXSIsImF1ZCI6IjdjazJ0Zm9xYXZjNzJjNDVoaDd0Z2U0MmtkIiwiY3VzdG9tOnNlc3Npb24tZHVyYXRpb24iOiI5MDAiLCJpZGVudGl0aWVzIjpbeyJ1c2VySWQiOiJqd3VAZmlza2VyaW5jLmNvbSIsInByb3ZpZGVyTmFtZSI6IkF6dXJlQUQiLCJwcm92aWRlclR5cGUiOiJTQU1MIiwiaXNzdWVyIjoiaHR0cHM6XC9cL3N0cy53aW5kb3dzLm5ldFwvNWFhNGI2NDAtYzlmYy00YTliLWIzYTMtZDRhN2QwMDhmYjVlXC8iLCJwcmltYXJ5IjoidHJ1ZSIsImRhdGVDcmVhdGVkIjoiMTYxNDM2NDk3NDU4NSJ9XSwidG9rZW5fdXNlIjoiaWQiLCJhdXRoX3RpbWUiOjE2MTU4MjEzMDksImV4cCI6MTYxNTkyNzM0OSwiaWF0IjoxNjE1OTIzNzUwLCJmYW1pbHlfbmFtZSI6Ild1IiwiZW1haWwiOiJqd3VAZmlza2VyaW5jLmNvbSJ9.R3k-YGK0MrUdW030Xj2WxM7mdsm1tlobeDq3YRMIKMtdkJsf5qjwM_wqVPbErH-8OrFLW7YIPuMo2Rh5PCGvg4I6kL-tWfDOY4o5b5r_VdiifXov0be_ukdt5pZblhgg0dYSLmFaFZsxNjEng8-obl_FnWp6VtG1lnRGwORY3pFe88W7OM3zLMC0g-otfAEQ2KSOaV9bfUoRAaZaGlHe8ooIQx8Qoer9qYsnymK0Sk7jSZKwhtFsziSarhreHmBkCLaWBHDjc9PQDtBvO8wg1KMKmM-6oewA0xTKPtsuHxnvtVANYaR7Nqp9cbF940YRf2IK5FB7KWFtcR7Y6igLXw";
|
||||||
|
export const TEST_AUTH_OBJECT = {
|
||||||
|
idToken: {
|
||||||
|
jwtToken: TEST_TOKEN,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
export const TEST_EXPECTED_GROUPS =
|
||||||
|
"[8d8278a5-9c0e-4c7f-918a-811fd1d236e4, 6c3cf98d-0ada-48c6-ae94-b171cfa275fc, 56ef4bec-d739-4ddf-a003-ecc813085b8d, efcc3025-e2d8-4212-8227-805c7be39d2c, 5515a98f-4668-4121-8e8d-fee2825699cf, 86956a2f-8d46-47ff-9b29-f99079ae3c1d, c4d4361c-8882-47b4-8641-fd3ab68ae722, 7bcdcdb2-3279-44bf-a998-771bab4b33e1]";
|
||||||
Reference in New Issue
Block a user