Skip to content

Commit

Permalink
Update UI dependencies (#1180)
Browse files Browse the repository at this point in the history
* Update package.json dependencies

* Fix legacy react code

* Fix ESLint errors and warnings
  • Loading branch information
DybekK authored Jan 9, 2024
1 parent 25ce3c5 commit 80332ff
Show file tree
Hide file tree
Showing 39 changed files with 5,693 additions and 6,552 deletions.
55 changes: 29 additions & 26 deletions ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,37 @@
"node": ">=16"
},
"dependencies": {
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^12.0.0",
"@testing-library/user-event": "^14.3.0",
"@types/jest": "^26.0.0",
"@types/node": "^16.0.0",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@testing-library/jest-dom": "^6.2.0",
"@testing-library/react": "^14.1.2",
"@testing-library/user-event": "^14.5.2",
"@types/jest": "^29.2.6",
"@types/node": "^20.10.7",
"@types/react": "^18.2.47",
"@types/react-dom": "^18.2.18",
"@types/react-icons": "^3.0.0",
"@types/react-router-bootstrap": "^0.24.5",
"@types/react-router-bootstrap": "^0.26.6",
"@types/react-router-dom": "^5.3.3",
"@types/yup": "^0.29.14",
"axios": "^0.27.2",
"bootstrap": "^5.2.0",
"eslint-config-prettier": "^8.5.0",
"formik": "^2.2.9",
"immer": "^9.0.15",
"prettier": "^2.7.1",
"react": "^17.0.0",
"react-bootstrap": "^2.4.0",
"react-dom": "^17.0.0",
"react-icons": "^4.4.0",
"@types/yup": "^0.32.0",
"axios": "^1.6.5",
"bootstrap": "^5.3.2",
"eslint-config-prettier": "^9.1.0",
"formik": "^2.4.5",
"immer": "^10.0.3",
"prettier": "^3.1.1",
"react": "^18.2.0",
"react-bootstrap": "^2.9.2",
"react-dom": "^18.2.0",
"react-icons": "^4.12.0",
"react-router-bootstrap": "^0.26.2",
"react-router-dom": "^6.3.0",
"react-scripts": "^4.0.0",
"react-use-promise-matcher": "^1.4.2",
"typescript": "^4.7.4",
"yup": "^0.32.11"
"react-router-dom": "^6.21.1",
"react-scripts": "^5.0.1",
"react-use-promise-matcher": "^1.5.0",
"typescript": "5.1.6",
"yup": "^1.3.3"
},
"scripts": {
"start": "react-scripts --openssl-legacy-provider start",
"build": "react-scripts --openssl-legacy-provider build",
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"test:coverage": "react-scripts test --coverage --watchAll=false",
"test:ci": "CI=true react-scripts test --maxWorkers 2",
Expand All @@ -56,6 +56,9 @@
"src/**/*.{ts,tsx}",
"!src/index.tsx",
"!src/serviceWorker.ts"
],
"transformIgnorePatterns": [
"node_modules/(?!(axios)/)"
]
},
"browserslist": {
Expand Down
6 changes: 3 additions & 3 deletions ui/src/App.test.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { render } from "@testing-library/react";
import { render, screen } from "@testing-library/react";
import { App } from "./App";

test("should render", () => {
const { getByText } = render(<App />);
const header = getByText("Welcome to Bootzooka!");
render(<App />);
const header = screen.getByText("Welcome to Bootzooka!");
expect(header).toBeInTheDocument();
});
8 changes: 7 additions & 1 deletion ui/src/components/TwoColumnHero/TwoColumnHero.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import React from "react";

import Container from "react-bootstrap/Container";
import Col from "react-bootstrap/Col";
import Row from "react-bootstrap/Row";
import Fade from "react-bootstrap/Fade";
import Image from "react-bootstrap/Image";
import logo from "assets/sml-logo-vertical-white-all-trans.png";

export const TwoColumnHero: React.FC = ({ children }) => {
interface TwoColumnHeroProps {
children: React.ReactNode;
}

export const TwoColumnHero: React.FC<TwoColumnHeroProps> = ({ children }) => {
return (
<Container className="h-100">
<Row className="h-100">
Expand Down
85 changes: 43 additions & 42 deletions ui/src/contexts/UserContext/UserContext.test.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,34 @@
import React from "react";
import { render, fireEvent } from "@testing-library/react";
import { render, screen } from "@testing-library/react";
import { UserContextProvider, UserContext, UserAction } from "./UserContext";
import { userEvent } from "@testing-library/user-event";

const TestComponent: React.FC<{ action?: UserAction; label?: string }> = ({ action, label }) => {
const { state, dispatch } = React.useContext(UserContext);
return (
<>
<div>{JSON.stringify(state)}</div>
{action && <a onClick={() => dispatch(action)}>{label}</a>}
{action && <button onClick={() => dispatch(action)}>{label}</button>}
</>
);
};

test("handles set api key action", () => {
const { getByText } = render(
test("handles set api key action", async () => {
render(
<UserContextProvider>
<TestComponent action={{ type: "SET_API_KEY", apiKey: "test-api-key" }} label="set api key" />
</UserContextProvider>
</UserContextProvider>,
);

expect(getByText('{"apiKey":null,"user":null,"loggedIn":null}')).toBeInTheDocument();
expect(screen.getByText('{"apiKey":null,"user":null,"loggedIn":null}')).toBeInTheDocument();

fireEvent.click(getByText("set api key"));
await userEvent.click(screen.getByText("set api key"));

expect(getByText('{"apiKey":"test-api-key","user":null,"loggedIn":null}')).toBeInTheDocument();
expect(screen.getByText('{"apiKey":"test-api-key","user":null,"loggedIn":null}')).toBeInTheDocument();
});

test("handles login action", () => {
const { getByText } = render(
test("handles login action", async () => {
render(
<UserContextProvider>
<TestComponent
action={{
Expand All @@ -36,22 +37,22 @@ test("handles login action", () => {
}}
label="log in"
/>
</UserContextProvider>
</UserContextProvider>,
);

expect(getByText('{"apiKey":null,"user":null,"loggedIn":null}')).toBeInTheDocument();
expect(screen.getByText('{"apiKey":null,"user":null,"loggedIn":null}')).toBeInTheDocument();

fireEvent.click(getByText("log in"));
await userEvent.click(screen.getByText("log in"));

expect(
getByText(
'{"apiKey":null,"user":{"login":"user-login","email":"[email protected]","createdOn":"2020-10-09T09:57:17.995288Z"},"loggedIn":true}'
)
screen.getByText(
'{"apiKey":null,"user":{"login":"user-login","email":"[email protected]","createdOn":"2020-10-09T09:57:17.995288Z"},"loggedIn":true}',
),
).toBeInTheDocument();
});

test("handles log in and update details action", () => {
const { getAllByText, getByText } = render(
test("handles log in and update details action", async () => {
render(
<UserContextProvider>
<TestComponent
action={{
Expand All @@ -67,34 +68,34 @@ test("handles log in and update details action", () => {
}}
label="update user data"
/>
</UserContextProvider>
</UserContextProvider>,
);

expect(getAllByText('{"apiKey":null,"user":null,"loggedIn":null}')[0]).toBeInTheDocument();
expect(screen.getAllByText('{"apiKey":null,"user":null,"loggedIn":null}')[0]).toBeInTheDocument();

fireEvent.click(getByText("update user data"));
await userEvent.click(screen.getByText("update user data"));

expect(getAllByText('{"apiKey":null,"user":null,"loggedIn":null}')[0]).toBeInTheDocument();
expect(screen.getAllByText('{"apiKey":null,"user":null,"loggedIn":null}')[0]).toBeInTheDocument();

fireEvent.click(getByText("log in"));
await userEvent.click(screen.getByText("log in"));

expect(
getAllByText(
'{"apiKey":null,"user":{"login":"user-login","email":"[email protected]","createdOn":"2020-10-09T09:57:17.995288Z"},"loggedIn":true}'
)[0]
screen.getAllByText(
'{"apiKey":null,"user":{"login":"user-login","email":"[email protected]","createdOn":"2020-10-09T09:57:17.995288Z"},"loggedIn":true}',
)[0],
).toBeInTheDocument();

fireEvent.click(getByText("update user data"));
await userEvent.click(screen.getByText("update user data"));

expect(
getAllByText(
'{"apiKey":null,"user":{"login":"updated-user-login","email":"[email protected]","createdOn":"2020-10-09T09:57:17.995288Z"},"loggedIn":true}'
)[0]
screen.getAllByText(
'{"apiKey":null,"user":{"login":"updated-user-login","email":"[email protected]","createdOn":"2020-10-09T09:57:17.995288Z"},"loggedIn":true}',
)[0],
).toBeInTheDocument();
});

test("handles log in and log out action", () => {
const { getAllByText, getByText } = render(
test("handles log in and log out action", async () => {
render(
<UserContextProvider>
<TestComponent
action={{
Expand All @@ -109,24 +110,24 @@ test("handles log in and log out action", () => {
}}
label="log out"
/>
</UserContextProvider>
</UserContextProvider>,
);

expect(getAllByText('{"apiKey":null,"user":null,"loggedIn":null}')[0]).toBeInTheDocument();
expect(screen.getAllByText('{"apiKey":null,"user":null,"loggedIn":null}')[0]).toBeInTheDocument();

fireEvent.click(getByText("log out"));
await userEvent.click(screen.getByText("log out"));

expect(getAllByText('{"apiKey":null,"user":null,"loggedIn":false}')[0]).toBeInTheDocument();
expect(screen.getAllByText('{"apiKey":null,"user":null,"loggedIn":false}')[0]).toBeInTheDocument();

fireEvent.click(getByText("log in"));
await userEvent.click(screen.getByText("log in"));

expect(
getAllByText(
'{"apiKey":null,"user":{"login":"user-login","email":"[email protected]","createdOn":"2020-10-09T09:57:17.995288Z"},"loggedIn":true}'
)[0]
screen.getAllByText(
'{"apiKey":null,"user":{"login":"user-login","email":"[email protected]","createdOn":"2020-10-09T09:57:17.995288Z"},"loggedIn":true}',
)[0],
).toBeInTheDocument();

fireEvent.click(getByText("log out"));
await userEvent.click(screen.getByText("log out"));

expect(getAllByText('{"apiKey":null,"user":null,"loggedIn":false}')[0]).toBeInTheDocument();
expect(screen.getAllByText('{"apiKey":null,"user":null,"loggedIn":false}')[0]).toBeInTheDocument();
});
18 changes: 11 additions & 7 deletions ui/src/contexts/UserContext/UserContext.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import immer from "immer";
import React, { ReactNode } from "react";
import { produce } from "immer";

export interface UserDetails {
createdOn: string;
Expand Down Expand Up @@ -28,24 +28,24 @@ export type UserAction =
const userReducer = (state: UserState, action: UserAction): UserState => {
switch (action.type) {
case "SET_API_KEY":
return immer(state, (draftState) => {
return produce(state, (draftState) => {
draftState.apiKey = action.apiKey;
});

case "UPDATE_USER_DATA":
return immer(state, (draftState) => {
return produce(state, (draftState) => {
if (!draftState.user) return;
draftState.user = { ...draftState.user, ...action.user };
});

case "LOG_IN":
return immer(state, (draftState) => {
return produce(state, (draftState) => {
draftState.user = action.user;
draftState.loggedIn = true;
});

case "LOG_OUT":
return immer(state, (draftState) => {
return produce(state, (draftState) => {
draftState.apiKey = null;
draftState.user = null;
draftState.loggedIn = false;
Expand All @@ -64,7 +64,11 @@ export const UserContext = React.createContext<{
dispatch: () => {},
});

export const UserContextProvider: React.FC = ({ children }) => {
interface UserContextProviderProps {
children: ReactNode;
}

export const UserContextProvider: React.FC<UserContextProviderProps> = ({ children }) => {
const [state, dispatch] = React.useReducer(userReducer, initialUserState);

return <UserContext.Provider value={{ state, dispatch }}>{children}</UserContext.Provider>;
Expand Down
5 changes: 3 additions & 2 deletions ui/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import ReactDOM from "react-dom";
import { createRoot } from "react-dom/client";
import { App } from "./App";
import * as serviceWorker from "./serviceWorker";
import "bootstrap/dist/css/bootstrap.min.css";
import "./index.css";

ReactDOM.render(<App />, document.getElementById("root"));
const root = createRoot(document.getElementById("root")!);
root.render(<App />);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
Expand Down
12 changes: 6 additions & 6 deletions ui/src/main/Footer/Footer.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { render } from "@testing-library/react";
import { render, screen } from "@testing-library/react";
import { Footer } from "./Footer";
import { versionService } from "services";

Expand All @@ -11,15 +11,15 @@ beforeEach(() => {
test("renders version data", async () => {
(versionService.getVersion as jest.Mock).mockResolvedValueOnce({ buildDate: "testDate", buildSha: "testSha" });

const { getByText, findByText, findAllByRole } = render(<Footer />);
render(<Footer />);

const info = getByText(/Bootzooka - application scaffolding by /);
const info = screen.getByText(/Bootzooka - application scaffolding by /);

await findAllByRole("loader");
await screen.findAllByRole("loader");

const buildSha = await findByText(/testSha/i);
const buildSha = await screen.findByText(/testSha/i);

expect(versionService.getVersion).toBeCalledWith();
expect(versionService.getVersion).toHaveBeenCalledWith();
expect(info).toBeInTheDocument();
expect(buildSha).toBeInTheDocument();
});
10 changes: 5 additions & 5 deletions ui/src/main/ForkMe/ForkMe.test.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { render } from "@testing-library/react";
import { render, screen } from "@testing-library/react";
import { ForkMe } from "./ForkMe";

test("renders image", () => {
const { getByAltText } = render(<ForkMe />);
const header = getByAltText(/fork me on github/i);
render(<ForkMe />);
const header = screen.getByAltText(/fork me on github/i);
expect(header).toBeInTheDocument();
});

test("renders children", () => {
const { getByText } = render(<ForkMe>test children content</ForkMe>);
const header = getByText(/test children content/i);
render(<ForkMe>test children content</ForkMe>);
const header = screen.getByText(/test children content/i);
expect(header).toBeInTheDocument();
});
6 changes: 5 additions & 1 deletion ui/src/main/ForkMe/ForkMe.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import Row from "react-bootstrap/Row";
import Image from "react-bootstrap/Image";
import forkMeOrange from "assets/forkme_orange.png";

export const ForkMe: React.FC = ({ children }) => (
interface ForkMeProps {
children?: React.ReactNode;
}

export const ForkMe: React.FC<ForkMeProps> = ({ children }) => (
<Container className="bg-light" style={{ height: "calc(100% - 56px)" }} fluid>
<Row className="position-relative h-100">
{children}
Expand Down
Loading

0 comments on commit 80332ff

Please sign in to comment.