Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade amplify to v6 #791

Merged
merged 18 commits into from
Oct 29, 2024
Merged
2 changes: 1 addition & 1 deletion services/ui-src/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"@emotion/styled": "^11.13.0",
"@hookform/resolvers": "^2.9.11",
"@vitejs/plugin-react": "^4.3.0",
"aws-amplify": "^5.3.19",
"aws-amplify": "^6.6.4",
"date-fns": "^2.26.0",
"date-fns-tz": "^1.3.8",
"dompurify": "^2.5.3",
Expand Down
51 changes: 24 additions & 27 deletions services/ui-src/src/components/logins/LoginCognito.test.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,46 @@
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
// utils
import { RouterWrappedComponent } from "utils/testing/setupJest";
import { Auth } from "aws-amplify";
//components
import { LoginCognito } from "components";
import { testA11y } from "utils/testing/commonTests";
// utils
import { RouterWrappedComponent } from "utils/testing/setupJest";

const mockSignIn = jest.fn();
jest.mock("aws-amplify/auth", () => ({
signIn: (credentials: any) => mockSignIn(credentials),
}));

const mockUseNavigate = jest.fn();

jest.mock("react-router-dom", () => ({
useNavigate: () => mockUseNavigate,
}));

const loginCognitoComponent = (
<RouterWrappedComponent>
<LoginCognito />
</RouterWrappedComponent>
);

jest.mock("aws-amplify", () => ({
Auth: {
signIn: jest.fn(),
},
}));

describe("<LoginCognito />", () => {
describe("Renders", () => {
beforeEach(() => {
render(loginCognitoComponent);
});

test("LoginCognito email field is visible", () => {
expect(screen.getByText("Email")).toBeVisible();
});

test("LoginCognito password field is visible", () => {
expect(screen.getByText("Password")).toBeVisible();
});

test("LoginCognito login button is visible", () => {
expect(screen.getByRole("button")).toBeVisible();
});

test("LoginCognito calls Auth.signIn", async () => {
const loginButton = screen.getByText("Log In with Cognito", {
selector: "button",
test("LoginCognito login calls amplify auth login", async () => {
const emailInput = screen.getByLabelText("Email");
const passwordInput = screen.getByLabelText("Password");
const submitButton = screen.getByRole("button");
await userEvent.type(emailInput, "email@address.com");
await userEvent.type(passwordInput, "p@$$w0rd"); //pragma: allowlist secret
await userEvent.click(submitButton);
expect(mockSignIn).toHaveBeenCalledWith({
username: "email@address.com",
password: "p@$$w0rd", //pragma: allowlist secret
});
await userEvent.click(loginButton);

expect(Auth.signIn).toHaveBeenCalled();
expect(mockUseNavigate).toHaveBeenCalledWith("/");
});
});

Expand Down
4 changes: 2 additions & 2 deletions services/ui-src/src/components/logins/LoginCognito.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import { Auth } from "aws-amplify";
import { signIn } from "aws-amplify/auth";
// components
import { Box, Button, Heading, Input, Stack, Text } from "@chakra-ui/react";
import { ErrorAlert } from "components";
Expand Down Expand Up @@ -32,7 +32,7 @@ export const LoginCognito = () => {
const handleLogin = async (event: any) => {
event.preventDefault();
try {
await Auth.signIn(fields.email, fields.password);
await signIn({ username: fields.email, password: fields.password });
navigate(`/`);
} catch (error: any) {
let errorMessage: ErrorVerbiage = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export const ReportProvider = ({ children }: Props) => {
return result;
} catch {
setError(reportErrors.GET_REPORT_FAILED);
return;
JonHolman marked this conversation as resolved.
Show resolved Hide resolved
}
};

Expand Down
54 changes: 40 additions & 14 deletions services/ui-src/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,53 @@ import { ChakraProvider } from "@chakra-ui/react";
import theme from "styles/theme";
import "./styles/index.scss";

let apiRestConfig: any = {
mfp: {
endpoint: config.apiGateway.URL,
region: config.apiGateway.REGION,
},
};

if (config.DEV_API_URL) {
apiRestConfig = {
...apiRestConfig,
mfpDev: {
endpoint: config.DEV_API_URL,
region: "us-east-1",
},
};
}

Amplify.configure({
Storage: {
region: config.s3.REGION,
bucket: config.s3.BUCKET,
identityPoolId: config.cognito.IDENTITY_POOL_ID,
S3: {
region: config.s3.REGION,
bucket: config.s3.BUCKET,
},
},
Auth: {
mandatorySignIn: true,
region: config.cognito.REGION,
userPoolId: config.cognito.USER_POOL_ID,
identityPoolId: config.cognito.IDENTITY_POOL_ID,
userPoolWebClientId: config.cognito.APP_CLIENT_ID,
oauth: {
domain: config.cognito.APP_CLIENT_DOMAIN,
redirectSignIn: config.cognito.REDIRECT_SIGNIN,
redirectSignOut: config.cognito.REDIRECT_SIGNOUT,
scope: ["email", "openid", "profile"],
responseType: "code",
Cognito: {
userPoolId: config.cognito.USER_POOL_ID,
identityPoolId: config.cognito.IDENTITY_POOL_ID,
userPoolClientId: config.cognito.APP_CLIENT_ID,
loginWith: {
oauth: {
domain: config.cognito.APP_CLIENT_DOMAIN,
redirectSignIn: config.cognito.REDIRECT_SIGNIN,
redirectSignOut: config.cognito.REDIRECT_SIGNOUT,
scopes: ["email", "openid", "profile"],
responseType: "code",
},
},
},
},
API: {
REST: {
...apiRestConfig,
},
},
});

// LaunchDarkly configuration
const ldClientId = config.REACT_APP_LD_SDK_CLIENT;
(async () => {
Expand Down
25 changes: 1 addition & 24 deletions services/ui-src/src/utils/api/providers/ApiProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { ReactNode, useEffect, useMemo, createContext } from "react";
import { API } from "aws-amplify";
import config from "config";
import { ReactNode, useMemo, createContext } from "react";

export const ApiContext = createContext(null);

Expand All @@ -9,27 +7,6 @@ interface Props {
}

export const ApiProvider = ({ children }: Props) => {
useEffect(() => {
const endpoints = [
{
name: "mfp",
endpoint: config.apiGateway.URL,
region: config.apiGateway.REGION,
},
];
if (config.DEV_API_URL) {
// Add dev endpoint for pdf printing access locally
endpoints.push({
name: "mfpDev",
endpoint: config.DEV_API_URL,
region: "us-east-1",
});
}
API.configure({
endpoints: endpoints,
});
}, []);

const values = useMemo(() => ({}), []);
// @ts-ignore
return <ApiContext.Provider value={values}>{children}</ApiContext.Provider>;
Expand Down
42 changes: 23 additions & 19 deletions services/ui-src/src/utils/api/requestMethods/banner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,34 @@ import { getBanner, writeBanner, deleteBanner } from "./banner";
// utils
import { bannerId } from "../../../constants";
import { mockBannerData } from "utils/testing/setupJest";
import { initAuthManager } from "utils/auth/authLifecycle";

describe("utils/banner", () => {
beforeEach(async () => {
jest.useFakeTimers();
initAuthManager();
jest.runAllTimers();
});
const mockAmplifyApi = require("aws-amplify/api");

jest.mock("utils/auth/authLifecycle", () => ({
updateTimeout: jest.fn(),
initAuthManager: jest.fn(),
refreshCredentials: jest.fn(),
}));

describe("getBanner()", () => {
test("executes", () => {
expect(getBanner(bannerId)).toBeTruthy();
});
describe("Test banner methods", () => {
beforeEach(() => {
jest.clearAllMocks();
});
test("getBanner", async () => {
const apiSpy = jest.spyOn(mockAmplifyApi, "get");
expect(await getBanner(bannerId)).toBeTruthy();
expect(apiSpy).toHaveBeenCalledTimes(1);
});

describe("writeBanner()", () => {
test("executes", () => {
expect(writeBanner(mockBannerData)).toBeTruthy();
});
test("postBanner", async () => {
const apiSpy = jest.spyOn(mockAmplifyApi, "post");
await writeBanner(mockBannerData);
expect(apiSpy).toHaveBeenCalledTimes(1);
});

describe("deleteBanner()", () => {
test("executes", () => {
expect(deleteBanner(bannerId)).toBeTruthy();
});
test("delBanner", async () => {
const apiSpy = jest.spyOn(mockAmplifyApi, "del");
await deleteBanner(bannerId);
expect(apiSpy).toHaveBeenCalledTimes(1);
});
});
35 changes: 25 additions & 10 deletions services/ui-src/src/utils/api/requestMethods/banner.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,55 @@
import { API } from "aws-amplify";
import { get, post, del } from "aws-amplify/api";
import { getRequestHeaders } from "./getRequestHeaders";
import { AdminBannerData } from "types/banners";
import { updateTimeout } from "utils";

const apiName = "mfp";

async function getBanner(bannerKey: string) {
const requestHeaders = await getRequestHeaders();
const request = {
const options = {
headers: { ...requestHeaders },
};
const path = `/banners/${bannerKey}`;

updateTimeout();
const response = await API.get("mfp", `/banners/${bannerKey}`, request);
return response;
const { body } = await get({
apiName,
path,
options,
}).response;
return (await body.json()) as unknown as AdminBannerData;
}

async function writeBanner(bannerData: AdminBannerData) {
const requestHeaders = await getRequestHeaders();
const request = {
const options = {
headers: { ...requestHeaders },
body: bannerData,
};
const path = `/banners/${bannerData.key}`;

updateTimeout();
const response = await API.post("mfp", `/banners/${bannerData.key}`, request);
return response;
await post({
apiName,
path,
options,
}).response;
}

async function deleteBanner(bannerKey: string) {
const requestHeaders = await getRequestHeaders();
const request = {
const options = {
headers: { ...requestHeaders },
};
const path = `/banners/${bannerKey}`;

updateTimeout();
const response = await API.del("mfp", `/banners/${bannerKey}`, request);
return response;
await del({
apiName,
path,
options,
}).response;
}

export { getBanner, writeBanner, deleteBanner };
Original file line number Diff line number Diff line change
@@ -1,19 +1,32 @@
import { getRequestHeaders } from "./getRequestHeaders";

const mockAmplify = require("aws-amplify/auth");

describe("utils/getRequestHeaders", () => {
describe("getRequestHeaders()", () => {
test("Logs error to console if Auth throws error", async () => {
jest.spyOn(console, "log").mockImplementation(jest.fn());
const spy = jest.spyOn(console, "log");
test("Logs error to console if Auth throws error", async () => {
jest.spyOn(console, "log").mockImplementation(jest.fn());
const spy = jest.spyOn(console, "log");

mockAmplify.fetchAuthSession = jest.fn().mockImplementation(() => {
throw new Error();
});

const mockAmplify = require("aws-amplify");
mockAmplify.Auth.currentSession = jest.fn().mockImplementation(() => {
throw new Error();
});
await getRequestHeaders();

await getRequestHeaders();
await expect(spy).toHaveBeenCalled();
});

await expect(spy).toHaveBeenCalled();
test("Returns token if current idToken exists", async () => {
mockAmplify.fetchAuthSession = jest.fn().mockResolvedValue({
tokens: {
idToken: {
toString: () => "stringToken",
},
},
});

const result = await getRequestHeaders();

expect(result).toStrictEqual({ "x-api-key": "stringToken" });
});
});
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { Auth } from "aws-amplify";
import { fetchAuthSession } from "aws-amplify/auth";

export const getRequestHeaders = async (): Promise<any> => {
try {
const session = await Auth.currentSession();
const token = await session.getIdToken().getJwtToken();
const { idToken } = (await fetchAuthSession()).tokens ?? {};
const headers = {
"x-api-key": token,
"x-api-key": idToken?.toString(),
};
return headers;
} catch (error) {
Expand Down
Loading