From 39e779dc1d6df99bc31978ccfaaaabf9ec57167b Mon Sep 17 00:00:00 2001 From: John Wu <76966357+jwu-fisker@users.noreply.github.com> Date: Thu, 4 Mar 2021 14:30:56 -0800 Subject: [PATCH] Use compute auth service and fix static code analyzer warnings (#15) * Clean up formatting * Use new compute_auth service Implment SSO Implement token refresh Clean up unit tests * Fix unit tests * Fix auth test Fix warnings * Update default settings for compute_auth --- .vscode/settings.json | 3 + src/components/404/index.jsx | 4 +- src/components/App/App.test.js | 21 +- .../App/__snapshots__/App.test.js.snap | 524 +----------------- src/components/App/index.jsx | 6 +- src/components/Contexts/FileUploadContext.jsx | 48 +- .../Contexts/FileUploadContext.test.jsx | 105 ++-- src/components/Contexts/UserContext.jsx | 190 ++++--- src/components/Contexts/UserContext.test.jsx | 296 ++++++---- .../Contexts/__mocks__/FileUploadContext.jsx | 6 +- .../Contexts/__mocks__/UserContext.jsx | 23 +- src/components/ErrorBoundary.jsx | 23 +- src/components/FileUploadForm/index.jsx | 71 ++- src/components/MessageBar.jsx | 23 +- src/components/ModalProgressBar/index.jsx | 27 +- src/components/Routes/AuthRoute.jsx | 11 +- src/components/Routes/ProtectedRoute.jsx | 22 +- src/components/Routes/SiteRoutes.jsx | 43 +- src/components/SSOForm/SSOForm.test.js | 19 + .../__snapshots__/SSOForm.test.js.snap | 40 ++ src/components/SSOForm/index.jsx | 45 ++ src/components/SignInForm/SignInForm.test.jsx | 15 - .../__snapshots__/SignInForm.test.jsx.snap | 145 ----- src/components/SignInForm/index.jsx | 78 --- src/components/SignUpForm/SignUpForm.test.jsx | 17 - .../__snapshots__/SignUpForm.test.jsx.snap | 189 ------- src/components/SignUpForm/index.jsx | 90 --- src/components/{Styles.jsx => useStyles.jsx} | 12 +- src/index.css | 7 +- src/services/__mocks__/auth.js | 13 +- src/services/__mocks__/uploadFile.js | 2 +- src/services/auth.js | 22 +- src/services/auth.test.js | 23 + src/setupTests.js | 2 +- 34 files changed, 703 insertions(+), 1462 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 src/components/SSOForm/SSOForm.test.js create mode 100644 src/components/SSOForm/__snapshots__/SSOForm.test.js.snap create mode 100644 src/components/SSOForm/index.jsx delete mode 100644 src/components/SignInForm/SignInForm.test.jsx delete mode 100644 src/components/SignInForm/__snapshots__/SignInForm.test.jsx.snap delete mode 100644 src/components/SignInForm/index.jsx delete mode 100644 src/components/SignUpForm/SignUpForm.test.jsx delete mode 100644 src/components/SignUpForm/__snapshots__/SignUpForm.test.jsx.snap delete mode 100644 src/components/SignUpForm/index.jsx rename src/components/{Styles.jsx => useStyles.jsx} (60%) create mode 100644 src/services/auth.test.js diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..cac0e10 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "editor.formatOnSave": true +} \ No newline at end of file diff --git a/src/components/404/index.jsx b/src/components/404/index.jsx index 9d266a0..2493367 100644 --- a/src/components/404/index.jsx +++ b/src/components/404/index.jsx @@ -1,6 +1,6 @@ import { Typography } from "@material-ui/core"; import React from "react"; -import useStyles from '../Styles'; +import useStyles from "../useStyles"; const PageNotFound = () => { const classes = useStyles(); @@ -12,6 +12,6 @@ const PageNotFound = () => { ); -} +}; export default PageNotFound; diff --git a/src/components/App/App.test.js b/src/components/App/App.test.js index 628b509..150a38a 100644 --- a/src/components/App/App.test.js +++ b/src/components/App/App.test.js @@ -1,11 +1,11 @@ jest.mock("../Contexts/UserContext"); jest.mock("../Contexts/FileUploadContext"); -import { render, screen, cleanup, waitForElementToBeRemoved, waitFor } from "@testing-library/react" +import { render, screen, cleanup, waitForElementToBeRemoved } from "@testing-library/react"; import { setToken } from "../Contexts/UserContext"; import App from "."; -const TEST_TOKEN = { idToken: { jwtToken: "TEST" }}; +const TEST_TOKEN = { idToken: { jwtToken: "TEST" } }; const LOADING_STATUS = "Loading..."; const renderRoute = async (route) => { @@ -26,19 +26,13 @@ describe("App", () => { it("Route / unauthenticated", async () => { const container = await renderRoute("/"); - expect(container.querySelector("h1").innerHTML).toEqual("Sign in"); - expect(container).toMatchSnapshot(); - }); - - it("Route /signup unauthenticated", async () => { - const container = await renderRoute("/signup"); - expect(container.querySelector("h1").innerHTML).toEqual("Sign up"); + expect(container.querySelector("h1").innerHTML).toEqual("Fisker OTA Portal"); expect(container).toMatchSnapshot(); }); it("Route /home unauthenticated", async () => { const container = await renderRoute("/home"); - expect(container.querySelector("h1").innerHTML).toEqual("Sign in"); + expect(container.querySelector("h1").innerHTML).toEqual("Fisker OTA Portal"); expect(container).toMatchSnapshot(); }); @@ -49,13 +43,6 @@ describe("App", () => { expect(container).toMatchSnapshot(); }); - it("Route /signup authenticated", async () => { - setToken(TEST_TOKEN); - const container = await renderRoute("/signup"); - expect(container.querySelector("h1").innerHTML).toEqual("Upload file"); - expect(container).toMatchSnapshot(); - }); - it("Route /home authenticated", async () => { setToken(TEST_TOKEN); const container = await renderRoute("/home"); diff --git a/src/components/App/__snapshots__/App.test.js.snap b/src/components/App/__snapshots__/App.test.js.snap index 68cc874..21b2926 100644 --- a/src/components/App/__snapshots__/App.test.js.snap +++ b/src/components/App/__snapshots__/App.test.js.snap @@ -9,7 +9,7 @@ exports[`App Route / authenticated 1`] = ` class="MuiContainer-root MuiContainer-maxWidthXs" >

- Sign in + Fisker OTA Portal

-
- -
- - -
-
-
- -
- - -
-
- -
- -
+
@@ -241,7 +136,7 @@ exports[`App Route /home authenticated 1`] = ` class="MuiContainer-root MuiContainer-maxWidthXs" >

- Sign in + Fisker OTA Portal

-
- -
- - -
-
-
- -
- - -
-
- - +
@@ -470,7 +260,7 @@ exports[`App Route /page-not-found authenticated 1`] = ` data-testid="mocked-userprovider" >

`; - -exports[`App Route /signup authenticated 1`] = ` -
-
-
-
-

- Upload file -

-
-
-
- -
-

- Drag and drop a file here or click -

- -
-
-
-
-
-
- -
-
-
-
-
-
-`; - -exports[`App Route /signup unauthenticated 1`] = ` -
-
-
-
-

- Sign up -

-
-
- -
- - -
-
-
- -
- - -
-
-
- -
- - -
-
- - -
-
-
-
-
-`; diff --git a/src/components/App/index.jsx b/src/components/App/index.jsx index e914bae..156e5d8 100644 --- a/src/components/App/index.jsx +++ b/src/components/App/index.jsx @@ -1,6 +1,6 @@ -import React from 'react'; -import { UserProvider } from '../Contexts/UserContext'; -import SiteRoutes from '../Routes/SiteRoutes'; +import React from "react"; +import { UserProvider } from "../Contexts/UserContext"; +import SiteRoutes from "../Routes/SiteRoutes"; function App() { return ( diff --git a/src/components/Contexts/FileUploadContext.jsx b/src/components/Contexts/FileUploadContext.jsx index 82563b4..0c462a0 100644 --- a/src/components/Contexts/FileUploadContext.jsx +++ b/src/components/Contexts/FileUploadContext.jsx @@ -26,26 +26,36 @@ export const FileUploadProvider = ({ children }) => { const upload = async (files, accessToken) => { try { - if (!files || files.length === 0) throw new Error("File required"); - if (!accessToken || accessToken.length === 0) throw new Error("Access token required") + if (!files || files.length === 0) { + throw new Error("File required"); + } + if (!accessToken || accessToken.length === 0) { + throw new Error("Access token required"); + } const file = files[0].file; const filename = file.name; - + setUploading(true); setLinkURL(null); setProgress(0); setStatus(`Uploading ${filename}`); setCancelUpload(getCancelToken()); - - const { data } = await uploadFile(file, accessToken, setProgress, cancelUpload); - if (data.message) throw new Error(`${data.error}. ${data.message}`); - const url = ((data && data.link) ? data.link : "No URL available"); + + const { data } = await uploadFile( + file, + accessToken, + setProgress, + cancelUpload + ); + if (data.message) { + throw new Error(`${data.error}. ${data.message}`); + } + const url = data && data.link ? data.link : "No URL available"; setLinkURL(url); setStatus(`Uploaded ${filename}`); setCancelUpload(null); setProgress(100); - } - catch (e) { + } catch (e) { setStatus(`Error occured: ${e.message}`); setProgress(-1); } @@ -59,15 +69,17 @@ export const FileUploadProvider = ({ children }) => { }; return ( - + {children} ); diff --git a/src/components/Contexts/FileUploadContext.test.jsx b/src/components/Contexts/FileUploadContext.test.jsx index 2ee3468..52e88e6 100644 --- a/src/components/Contexts/FileUploadContext.test.jsx +++ b/src/components/Contexts/FileUploadContext.test.jsx @@ -1,15 +1,37 @@ jest.mock("../../services/uploadFile"); -import { setUploadFileDelay } from "../../services/uploadFile" -import { FileUploadProvider, useFileUploadContext } from "../Contexts/FileUploadContext"; -import {render, cleanup, screen, fireEvent, waitFor} from "@testing-library/react" +import { setUploadFileDelay } from "../../services/uploadFile"; +import { + FileUploadProvider, + useFileUploadContext, +} from "../Contexts/FileUploadContext"; +import { + render, + cleanup, + screen, + fireEvent, + waitFor, +} from "@testing-library/react"; + +const checkState = (uploading, progress, status, linkURL) => { + expect(screen.getByTestId("uploading").innerHTML).toEqual(uploading); + expect(screen.getByTestId("progress").innerHTML).toEqual(progress); + expect(screen.getByTestId("status").innerHTML).toEqual(status); + expect(screen.getByTestId("linkURL").innerHTML).toEqual(linkURL); +}; describe("FileUploadContext", () => { - beforeEach(() => { const TestComp = () => { - const { progress, uploading, status, linkURL, upload, cancel } = useFileUploadContext(); - const TEST_FILE = [{ file: { name: "test.jpg", size: 0 }}]; + const { + progress, + uploading, + status, + linkURL, + upload, + cancel, + } = useFileUploadContext(); + const TEST_FILE = [{ file: { name: "test.jpg", size: 0 } }]; const TEST_ACCESSTOKEN = "ACCESSTOKEN"; return ( <> @@ -17,14 +39,24 @@ describe("FileUploadContext", () => {
{progress.toString()}
{status}
{linkURL}
- - + return ( + + +
+ + Upload file + + + + + + + -
-
- ); - } \ No newline at end of file + +

+ + ); +} diff --git a/src/components/MessageBar.jsx b/src/components/MessageBar.jsx index 665b29f..f57d280 100644 --- a/src/components/MessageBar.jsx +++ b/src/components/MessageBar.jsx @@ -1,15 +1,18 @@ -import React from 'react'; +import React from "react"; import { Snackbar } from "@material-ui/core"; -import { useUserContext } from './Contexts/UserContext'; +import { useUserContext } from "./Contexts/UserContext"; export const MessageBar = () => { const { error, setError } = useUserContext(); - const open = (error !== null); + const open = error !== null; - return ( setError(null)}/>) -} + return ( + setError(null)} + /> + ); +}; diff --git a/src/components/ModalProgressBar/index.jsx b/src/components/ModalProgressBar/index.jsx index d266198..73c2528 100644 --- a/src/components/ModalProgressBar/index.jsx +++ b/src/components/ModalProgressBar/index.jsx @@ -1,8 +1,8 @@ import React from "react"; -import Modal from '@material-ui/core/Modal'; +import Modal from "@material-ui/core/Modal"; import { Button, LinearProgress } from "@material-ui/core"; -import { useFileUploadContext } from "../Contexts/FileUploadContext"; +import { useFileUploadContext } from "../Contexts/FileUploadContext"; const getModalStyle = () => { const top = 30; @@ -23,7 +23,13 @@ const getModalStyle = () => { }; const ModalProgressBar = () => { - const { uploading, progress, status, linkURL, cancel } = useFileUploadContext(); + const { + uploading, + progress, + status, + linkURL, + cancel, + } = useFileUploadContext(); const modalStyle = getModalStyle(); const onClickCancel = cancel; @@ -32,15 +38,20 @@ const ModalProgressBar = () => {
{status &&

{status}

} - {linkURL &&

View

} + {linkURL && ( +

+ + View + +

+ )}
-
+ ); - -} +}; export default ModalProgressBar; diff --git a/src/components/Routes/AuthRoute.jsx b/src/components/Routes/AuthRoute.jsx index 7775630..ed530cb 100644 --- a/src/components/Routes/AuthRoute.jsx +++ b/src/components/Routes/AuthRoute.jsx @@ -1,5 +1,5 @@ -import React from 'react'; -import { Redirect, Route } from 'react-router-dom'; +import React from "react"; +import { Redirect, Route } from "react-router-dom"; export const TYPES = { PUBLIC: 0, @@ -9,10 +9,9 @@ export const TYPES = { export const AuthRoute = ({ token, type, ...others }) => { if (!token && type === TYPES.PROTECTED) { - return ; - } - else if (token && type === TYPES.GUEST) { + return ; + } else if (token && type === TYPES.GUEST) { return ; } return ; -} \ No newline at end of file +}; diff --git a/src/components/Routes/ProtectedRoute.jsx b/src/components/Routes/ProtectedRoute.jsx index e2cded1..d8ca0e5 100644 --- a/src/components/Routes/ProtectedRoute.jsx +++ b/src/components/Routes/ProtectedRoute.jsx @@ -1,13 +1,13 @@ -import React from 'react'; -import { Redirect, Route } from 'react-router-dom'; -import { useUserContext } from '../Contexts/UserContext'; +import React from "react"; +import { Redirect, Route } from "react-router-dom"; +import { useUserContext } from "../Contexts/UserContext"; export const ProtectedRoute = ({ render, ...others }) => { - const context = useUserContext(); - const { token, setError } = context; - if (!token) { - setError('Please sign in to access'); - return ; - } - return ; -} \ No newline at end of file + const context = useUserContext(); + const { token, setError } = context; + if (!token) { + setError("Please sign in to access"); + return ; + } + return ; +}; diff --git a/src/components/Routes/SiteRoutes.jsx b/src/components/Routes/SiteRoutes.jsx index 728f33e..79a0f4c 100644 --- a/src/components/Routes/SiteRoutes.jsx +++ b/src/components/Routes/SiteRoutes.jsx @@ -1,34 +1,39 @@ -import React, { Suspense } from 'react'; -import { - BrowserRouter, - Switch, -} from 'react-router-dom'; +import React, { Suspense } from "react"; +import { BrowserRouter, Switch } from "react-router-dom"; -import { AuthRoute, TYPES } from '../Routes/AuthRoute' -import { MessageBar } from '../MessageBar'; -import { useUserContext } from '../Contexts/UserContext'; +import { AuthRoute, TYPES } from "../Routes/AuthRoute"; +import { MessageBar } from "../MessageBar"; +import { useUserContext } from "../Contexts/UserContext"; -const SignInForm = React.lazy(() => import('../SignInForm')); -const SignUpForm = React.lazy(() => import('../SignUpForm')); -const FileUploadForm = React.lazy(() => import('../FileUploadForm')); -const PageNotFound = React.lazy(() => import('../404')); +const SSOForm = React.lazy(() => import("../SSOForm")); +const FileUploadForm = React.lazy(() => import("../FileUploadForm")); +const PageNotFound = React.lazy(() => import("../404")); const SiteRoutes = () => { const { token } = useUserContext(); return ( - + - } type={TYPES.GUEST} token={token} /> - } type={TYPES.GUEST} token={token} /> - } type={TYPES.PROTECTED} token={token} /> + } + type={TYPES.GUEST} + token={token} + /> + } + type={TYPES.PROTECTED} + token={token} + /> - + ); }; - -export default SiteRoutes; \ No newline at end of file +export default SiteRoutes; diff --git a/src/components/SSOForm/SSOForm.test.js b/src/components/SSOForm/SSOForm.test.js new file mode 100644 index 0000000..cbc05ed --- /dev/null +++ b/src/components/SSOForm/SSOForm.test.js @@ -0,0 +1,19 @@ +jest.mock("../Contexts/UserContext"); + +import React from "react"; +import { BrowserRouter } from "react-router-dom"; +import { render, cleanup } from "@testing-library/react"; +import SSOForm from "./index"; + +describe("Sign In Form", () => { + it("Should render", () => { + const { container } = render( + + + + ); + expect(container).toMatchSnapshot(); + + cleanup(); + }); +}); diff --git a/src/components/SSOForm/__snapshots__/SSOForm.test.js.snap b/src/components/SSOForm/__snapshots__/SSOForm.test.js.snap new file mode 100644 index 0000000..0979c84 --- /dev/null +++ b/src/components/SSOForm/__snapshots__/SSOForm.test.js.snap @@ -0,0 +1,40 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Sign In Form Should render 1`] = ` +
+
+
+

+ Fisker OTA Portal +

+
+ + + Sign In + + + +
+
+
+
+`; diff --git a/src/components/SSOForm/index.jsx b/src/components/SSOForm/index.jsx new file mode 100644 index 0000000..e4009c8 --- /dev/null +++ b/src/components/SSOForm/index.jsx @@ -0,0 +1,45 @@ +import React, { useEffect } from "react"; +import { Button, Container, CssBaseline, Typography } from "@material-ui/core"; +import { useUserContext } from "../Contexts/UserContext"; +import useStyles from "../useStyles"; + +const getCode = (search) => { + if (!search) return null; + const s = new URLSearchParams(search); + return s.get("code"); +}; + +export default function SignInForm() { + const classes = useStyles(); + const { getAuthorizeURL, signIn } = useUserContext(); + + useEffect(() => { + const code = getCode(document.location.search); + if (!code) return; + signIn(code); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return ( + + +
+ + Fisker OTA Portal + +
+ +
+
+
+ ); +} diff --git a/src/components/SignInForm/SignInForm.test.jsx b/src/components/SignInForm/SignInForm.test.jsx deleted file mode 100644 index 45c15d3..0000000 --- a/src/components/SignInForm/SignInForm.test.jsx +++ /dev/null @@ -1,15 +0,0 @@ -jest.mock("../Contexts/UserContext"); - -import React from "react"; -import { BrowserRouter } from 'react-router-dom'; -import { render, cleanup } from "@testing-library/react" -import SignInForm from './index'; - -describe("Sign In Form", () => { - - it("Should render", () => { - const { container } = render(); - expect(container).toMatchSnapshot(); - cleanup(); - }) -}) \ No newline at end of file diff --git a/src/components/SignInForm/__snapshots__/SignInForm.test.jsx.snap b/src/components/SignInForm/__snapshots__/SignInForm.test.jsx.snap deleted file mode 100644 index e99b269..0000000 --- a/src/components/SignInForm/__snapshots__/SignInForm.test.jsx.snap +++ /dev/null @@ -1,145 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Sign In Form Should render 1`] = ` -
-
-
-

- Sign in -

-
-
- -
- - -
-
-
- -
- - -
-
- - -
-
-
-
-`; diff --git a/src/components/SignInForm/index.jsx b/src/components/SignInForm/index.jsx deleted file mode 100644 index ec5fd54..0000000 --- a/src/components/SignInForm/index.jsx +++ /dev/null @@ -1,78 +0,0 @@ -import React, { useRef } from 'react'; -import { Link as RouterLink } from 'react-router-dom'; -import { Button, Container, CssBaseline, Grid, Link, TextField, Typography } from '@material-ui/core'; -import { useUserContext } from '../Contexts/UserContext'; -import useStyles from '../Styles'; - -export default function SignInForm() { - const classes = useStyles(); - const emailEl = useRef(null); - const passwordEl = useRef(null); - const { fetching, signIn, setError } = useUserContext(); - const onSubmit = async (event) => { - try { - event.preventDefault(); - const username = emailEl.current.value; - const password = passwordEl.current.value; - await signIn(username, password); - } - catch (e) { - setError(e.message); - } - }; - - return ( - - -
- - Sign in - -
- - - - - - - {"Don't have an account? Sign Up"} - - - - -
-
- ); - } \ No newline at end of file diff --git a/src/components/SignUpForm/SignUpForm.test.jsx b/src/components/SignUpForm/SignUpForm.test.jsx deleted file mode 100644 index 859f2d7..0000000 --- a/src/components/SignUpForm/SignUpForm.test.jsx +++ /dev/null @@ -1,17 +0,0 @@ -jest.mock("../Contexts/UserContext"); - -import { BrowserRouter } from 'react-router-dom'; -import { render, cleanup, screen, fireEvent, waitFor } from "@testing-library/react"; -import SignUpForm from './index'; - -describe.only("Sign Up Form", () => { - - afterEach(() => { - cleanup(); - }); - - it("Should render", () => { - const { container } = render(); - expect(container).toMatchSnapshot(); - }); -}) \ No newline at end of file diff --git a/src/components/SignUpForm/__snapshots__/SignUpForm.test.jsx.snap b/src/components/SignUpForm/__snapshots__/SignUpForm.test.jsx.snap deleted file mode 100644 index 1e1b0d8..0000000 --- a/src/components/SignUpForm/__snapshots__/SignUpForm.test.jsx.snap +++ /dev/null @@ -1,189 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Sign Up Form Should render 1`] = ` -
-
-
-

- Sign up -

-
-
- -
- - -
-
-
- -
- - -
-
-
- -
- - -
-
- - -
-
-
-
-`; diff --git a/src/components/SignUpForm/index.jsx b/src/components/SignUpForm/index.jsx deleted file mode 100644 index 145c097..0000000 --- a/src/components/SignUpForm/index.jsx +++ /dev/null @@ -1,90 +0,0 @@ -import React, { useRef } from 'react'; -import { Link as RouterLink } from 'react-router-dom'; -import { Button, Container, CssBaseline, Grid, Link, TextField, Typography } from '@material-ui/core'; -import useStyles from '../Styles'; -import { useUserContext } from '../Contexts/UserContext'; - -export default function SignInForm() { - const { signUpAndIn, fetching, setError } = useUserContext(); - const classes = useStyles(); - const emailEl = useRef(null); - const passwordEl = useRef(null); - const confirmEl = useRef(null); - const onSubmit = async (event) => { - try { - event.preventDefault(); - const email = emailEl.current.value; - const password = passwordEl.current.value; - const confirm = confirmEl.current.value; - await signUpAndIn(email, password, confirm); - } - catch (e) { - setError(e.message); - } - }; - - return ( - - -
- - Sign up - -
- - - - - - - - {"Already have an account? Sign In"} - - - - -
-
- ); - } \ No newline at end of file diff --git a/src/components/Styles.jsx b/src/components/useStyles.jsx similarity index 60% rename from src/components/Styles.jsx rename to src/components/useStyles.jsx index d2beb00..1493f7b 100644 --- a/src/components/Styles.jsx +++ b/src/components/useStyles.jsx @@ -1,18 +1,18 @@ -import { makeStyles } from '@material-ui/core/styles'; +import { makeStyles } from "@material-ui/core/styles"; const useStyles = makeStyles((theme) => ({ paper: { marginTop: theme.spacing(8), - display: 'flex', - flexDirection: 'column', - alignItems: 'center', + display: "flex", + flexDirection: "column", + alignItems: "center", }, avatar: { margin: theme.spacing(1), backgroundColor: theme.palette.primary.main, }, form: { - width: '100%', // Fix IE 11 issue. + width: "100%", // Fix IE 11 issue. marginTop: theme.spacing(1), }, submit: { @@ -20,4 +20,4 @@ const useStyles = makeStyles((theme) => ({ }, })); -export default useStyles; \ No newline at end of file +export default useStyles; diff --git a/src/index.css b/src/index.css index ec2585e..8285d2a 100644 --- a/src/index.css +++ b/src/index.css @@ -1,13 +1,10 @@ body { margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; } diff --git a/src/services/__mocks__/auth.js b/src/services/__mocks__/auth.js index dd50c68..8375478 100644 --- a/src/services/__mocks__/auth.js +++ b/src/services/__mocks__/auth.js @@ -1,16 +1,21 @@ +const AUTH_URL = process.env.REACT_APP_AUTH_SERVICE_URL || "https://gw-dev.fiskerdps.com/compute_auth"; +const CALLBACK_URL = process.env.REACT_APP_AUTH_CALLBACK_URL || ""; + let signInResponse = {}; -let signUpResponse = {}; let verifyResponse = {}; +let refreshResponse = {}; const logResponse = (response) => { return response; }; export default { + ssoAuthorize: () => `${AUTH_URL}/authorize?redirect=${CALLBACK_URL}`, + ssoLogout: () => `${AUTH_URL}/logout?redirect=${CALLBACK_URL}`, signIn: async (username, password) => logResponse(signInResponse), - signUp: async (username, password) => logResponse(signUpResponse), - verify: async (accessToken) => logResponse(verifyResponse), + verify: async (idToken) => logResponse(verifyResponse), + refresh: async (refreshToken) => logResponse(refreshResponse), setSignInResponse: (value) => { signInResponse = value; }, - setSignUpResponse: (value) => { signUpResponse = value; }, setVerifyResponse: (value) => { verifyResponse = value; }, + setRefreshResponse: (value) => { refreshResponse = value; }, } \ No newline at end of file diff --git a/src/services/__mocks__/uploadFile.js b/src/services/__mocks__/uploadFile.js index 57d934d..4443a17 100644 --- a/src/services/__mocks__/uploadFile.js +++ b/src/services/__mocks__/uploadFile.js @@ -11,7 +11,7 @@ export const getCancelToken = () => { return issuedCancelToken; } -export const uploadFile = async (file, token, onProgress, cancelToken, hash) => { +export const uploadFile = async (file, token, onProgress, cancelToken) => { if (!uploadFileDelay) return uploadFileResponse; onProgress(50); await delay(10000); diff --git a/src/services/auth.js b/src/services/auth.js index 27a340f..454f3dc 100644 --- a/src/services/auth.js +++ b/src/services/auth.js @@ -1,34 +1,34 @@ -const AUTH_URL = process.env.REACT_APP_AUTH_SERVICE_URL || "https://dev-auth.fiskerdps.com"; +const AUTH_URL = process.env.REACT_APP_AUTH_SERVICE_URL || "https://gw-dev.fiskerdps.com/compute_auth"; +const CALLBACK_URL = process.env.REACT_APP_AUTH_CALLBACK_URL || "https://dev-ota-admin.fiskerdps.com"; const auth = { - signIn: (username, password) => fetch(`${AUTH_URL}/auth/login`, { + ssoAuthorize: () => `${AUTH_URL}/authorize?redirect=${CALLBACK_URL}`, + ssoLogout: () => `${AUTH_URL}/logout?redirect=${CALLBACK_URL}`, + signIn: (code) => fetch(`${AUTH_URL}/token`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ - username, - password, + code, + redirect: CALLBACK_URL, }) }).then((response) => response.json()), - signUp: (username, password) => fetch(`${AUTH_URL}/auth/register`, { + verify: (idToken) => fetch(`${AUTH_URL}/verify`, { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - username, - password, - }) + body: JSON.stringify({ token: idToken }) }).then((response) => response.json()), - verify: (accessToken) => fetch(`${AUTH_URL}/auth/verify`, { + refresh: (refreshToken) => fetch(`${AUTH_URL}/refresh`, { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ token: accessToken }) + body: JSON.stringify({ refresh_token: refreshToken }) }).then((response) => response.json()), }; diff --git a/src/services/auth.test.js b/src/services/auth.test.js new file mode 100644 index 0000000..bda2c35 --- /dev/null +++ b/src/services/auth.test.js @@ -0,0 +1,23 @@ +import auth from "./auth"; + +const testAuthURL = (url, endpoint) => { + const u = new URL(url); + const path = u.pathname.split("/"); + + expect(u.protocol).toMatch(/^http/); + expect(u.host).toBeTruthy(); + expect(path[path.length - 1]).toEqual(endpoint); + expect(u.searchParams.get("redirect")).toBeTruthy(); +}; + +describe("Auth service", () => { + describe("Auth URLs", () => { + it("Authorize URL", () => { + testAuthURL(auth.ssoAuthorize(), "authorize"); + }); + + it("Logout URL", () => { + testAuthURL(auth.ssoLogout(), "logout"); + }); + }); +}); \ No newline at end of file diff --git a/src/setupTests.js b/src/setupTests.js index 8f2609b..1dd407a 100644 --- a/src/setupTests.js +++ b/src/setupTests.js @@ -2,4 +2,4 @@ // allows you to do things like: // expect(element).toHaveTextContent(/react/i) // learn more: https://github.com/testing-library/jest-dom -import '@testing-library/jest-dom'; +import "@testing-library/jest-dom";