Skip to content

Commit

Permalink
Update react from 17 to 18 (#2791)
Browse files Browse the repository at this point in the history
Also:
* In `src/index.tsx` replace `import { render } from "react-dom";` with `import { createRoot } from "react-dom/client"` (per https://react.dev/blog/2022/03/08/react-18-upgrade-guide#updates-to-client-rendering-apis)
* Update `@material-table/core` from 6.2 to 6.3 (not compatible with react 17)
* Remove dependency `@mui/styles` (not compatible with react 18); replace with either `import { styled } from "@mui/system";` or direct `sx=`
* Remove extra space from between audio components
* Update `@microsoft/signalr` from 6 to 8
* Add dev dependency:`@babel/plugin-proposal-private-property-in-object` to deal with legacy warning
* Migrate `@testing-library/react-hooks` usage to the corresponding parts in `@testing-library/react`
* Remove unnecessary/problematic `await act(...` instances from `@testing-library/react tests`
* Use `as any` to handle `TextFieldWithFont` type issues
* Replace deprecated `tobeCalled` with `toHaveBeenCalled` and `tobeCalledTimes` with `toHaveBeenCalledTimes`
* Remove extra space from between audio components
  • Loading branch information
imnasnainaec authored Nov 17, 2023
1 parent 642eae3 commit fcb36da
Show file tree
Hide file tree
Showing 49 changed files with 5,180 additions and 5,584 deletions.
656 changes: 272 additions & 384 deletions docs/user_guide/assets/licenses/frontend_licenses.txt

Large diffs are not rendered by default.

9,570 changes: 4,682 additions & 4,888 deletions package-lock.json

Large diffs are not rendered by default.

25 changes: 12 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,11 @@
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@loadable/component": "^5.15.3",
"@material-table/core": "^6.2.11",
"@material-table/core": "^6.3.0",
"@matt-block/react-recaptcha-v2": "^2.0.1",
"@microsoft/signalr": "^6.0.7",
"@microsoft/signalr": "^8.0.0",
"@mui/icons-material": "^5.14.11",
"@mui/material": "^5.14.16",
"@mui/styles": "^5.14.16",
"@redux-devtools/extension": "^3.2.5",
"@reduxjs/toolkit": "^1.9.5",
"@segment/analytics-next": "^1.55.0",
Expand All @@ -66,10 +65,10 @@
"notistack": "^3.0.1",
"nspell": "^2.1.5",
"punycode": "^2.3.0",
"react": "^17.0.2",
"react": "^18.2.0",
"react-beautiful-dnd": "^13.1.1",
"react-chartjs-2": "^5.2.0",
"react-dom": "^17.0.2",
"react-dom": "^18.2.0",
"react-i18next": "^13.3.1",
"react-modal": "^3.16.1",
"react-redux": "^8.1.3",
Expand All @@ -84,24 +83,24 @@
"validator": "^13.11.0"
},
"devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@testing-library/jest-dom": "^6.1.4",
"@testing-library/react": "^12.1.5",
"@testing-library/react-hooks": "^8.0.0",
"@testing-library/react": "^14.1.0",
"@testing-library/user-event": "^14.5.1",
"@types/crypto-js": "^4.1.3",
"@types/css-mediaquery": "^0.1.2",
"@types/jest": "^29.5.5",
"@types/loadable__component": "^5.13.5",
"@types/node": "^20.5.1",
"@types/nspell": "^2.1.5",
"@types/react": "^17.0.34",
"@types/react": "^18.2.37",
"@types/react-beautiful-dnd": "^13.1.4",
"@types/react-dom": "^17.0.11",
"@types/react-dom": "^18.2.15",
"@types/react-modal": "^3.16.0",
"@types/react-test-renderer": "^17.0.0",
"@types/react-test-renderer": "^18.0.6",
"@types/recordrtc": "^5.6.12",
"@types/redux-mock-store": "^1.0.4",
"@types/segment-analytics": "^0.0.34",
"@types/segment-analytics": "^0.0.37",
"@types/uuid": "^9.0.4",
"@types/validator": "^13.11.1",
"@typescript-eslint/eslint-plugin": "^6.7.2",
Expand All @@ -120,10 +119,10 @@
"npm-run-all": "^4.1.5",
"prettier": "^3.0.3",
"react-scripts": "^5.0.1",
"react-test-renderer": "^17.0.1",
"react-test-renderer": "^18.2.0",
"redux-mock-store": "^1.5.4",
"source-map-explorer": "^2.5.3",
"typescript": "4.9.5"
"typescript": "^4.9.5"
},
"jest": {
"coverageReporters": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,13 @@ export default function GlossWithSuggestions(
}}
renderInput={(params) => (
<TextFieldWithFont
{...params}
{...(params as any)}
analysis
fullWidth
inputRef={props.glossInput}
label={props.isNew ? props.analysisLang.name : ""}
lang={props.analysisLang.bcp47}
variant={props.isNew ? "outlined" : "standard"}
variant={(props.isNew ? "outlined" : "standard") as any}
/>
)}
renderOption={(liProps, option, { selected }) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ export default function VernWithSuggestions(
onClose={props.onClose}
renderInput={(params) => (
<TextFieldWithFont
{...params}
{...(params as any)}
fullWidth
inputRef={props.vernInput}
label={props.isNew ? props.vernacularLang.name : ""}
variant={props.isNew ? "outlined" : "standard"}
variant={(props.isNew ? "outlined" : "standard") as any}
vernacular
/>
)}
Expand Down
24 changes: 11 additions & 13 deletions src/components/DataEntry/DataEntryTable/NewEntry/StyledMenuItem.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
import { MenuItem } from "@mui/material";
import { withStyles } from "@mui/styles";
import { styled } from "@mui/system";

// Copied from customized menus at https://material-ui.com/components/menus/
const StyledMenuItem = withStyles((theme) => ({
root: {
border: "1px solid gray",
borderRadius: "8px",
marginTop: "8px",
"&:focus": {
backgroundColor: theme.palette.primary.main,
"& .MuiListItemIcon-root, & .MuiListItemText-primary": {
color: theme.palette.common.white,
},
// https://mui.com/system/styled/#using-the-theme
const StyledMenuItem = styled(MenuItem)(({ theme }) => ({
border: "1px solid gray",
borderRadius: "8px",
marginTop: "8px",
"&:focus": {
backgroundColor: theme.palette.primary.main,
"& .MuiListItemIcon-root, & .MuiListItemText-primary": {
color: theme.palette.common.white,
},
},
}))(MenuItem);
}));

export default StyledMenuItem;
4 changes: 2 additions & 2 deletions src/components/DataEntry/DataEntryTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -408,8 +408,8 @@ export default function DataEntryTable(
selectedDup: id
? prev.suggestedDups.find((w) => w.id === id)
: id === ""
? newWord(prev.newVern)
: undefined,
? newWord(prev.newVern)
: undefined,
}));
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ describe("ExistingEntry", () => {
}

await updateVernAndBlur(mockVern);
expect(mockUpdateVern).toBeCalledTimes(0);
expect(mockUpdateVern).toHaveBeenCalledTimes(0);
await updateVernAndBlur(mockText);
expect(mockUpdateVern).toBeCalledWith(0, mockText);
});
Expand All @@ -123,7 +123,7 @@ describe("ExistingEntry", () => {
}

await updateGlossAndBlur(mockGloss);
expect(mockUpdateGloss).toBeCalledTimes(0);
expect(mockUpdateGloss).toHaveBeenCalledTimes(0);
await updateGlossAndBlur(mockText);
expect(mockUpdateGloss).toBeCalledWith(0, mockText);
});
Expand Down
32 changes: 16 additions & 16 deletions src/components/DataEntry/DataEntryTable/tests/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,29 +134,29 @@ describe("DataEntryTable", () => {
beforeEach(async () => await renderTable());

it("gets frontier word", () => {
expect(mockGetFrontierWords).toBeCalledTimes(1);
expect(mockGetFrontierWords).toHaveBeenCalledTimes(1);
});
});

describe("exit button", () => {
beforeEach(async () => await renderTable());

it("hides questions", async () => {
expect(mockHideQuestions).not.toBeCalled();
expect(mockHideQuestions).not.toHaveBeenCalled();
testHandle = testRenderer.root.findByProps({ id: exitButtonId });
await act(async () => await testHandle.props.onClick());
expect(mockHideQuestions).toBeCalled();
expect(mockHideQuestions).toHaveBeenCalled();
});

it("creates word when new entry has vernacular", async () => {
expect(mockCreateWord).not.toBeCalled();
expect(mockCreateWord).not.toHaveBeenCalled();
testHandle = testRenderer.root.findByType(NewEntry);
expect(testHandle).not.toBeNull;
// Set newVern but not newGloss.
await act(async () => testHandle.props.setNewVern("hasVern"));
testHandle = testRenderer.root.findByProps({ id: exitButtonId });
await act(async () => await testHandle.props.onClick());
expect(mockCreateWord).toBeCalledTimes(1);
expect(mockCreateWord).toHaveBeenCalledTimes(1);
});

it("doesn't create word when new entry has no vernacular", async () => {
Expand All @@ -166,14 +166,14 @@ describe("DataEntryTable", () => {
await act(async () => testHandle.props.setNewGloss("hasGloss"));
testHandle = testRenderer.root.findByProps({ id: exitButtonId });
await act(async () => await testHandle.props.onClick());
expect(mockCreateWord).not.toBeCalled();
expect(mockCreateWord).not.toHaveBeenCalled();
});

it("opens the domain tree", async () => {
expect(mockOpenTree).not.toBeCalled();
expect(mockOpenTree).not.toHaveBeenCalled();
testHandle = testRenderer.root.findByProps({ id: exitButtonId });
await act(async () => await testHandle.props.onClick());
expect(mockOpenTree).toBeCalledTimes(1);
expect(mockOpenTree).toHaveBeenCalledTimes(1);
});
});

Expand Down Expand Up @@ -301,7 +301,7 @@ describe("DataEntryTable", () => {
await testHandle.props.setNewGloss(firstGlossText(word.senses[0]));
await testHandle.props.updateWordWithNewGloss(word.id);
});
expect(mockUpdateWord).not.toBeCalled();
expect(mockUpdateWord).not.toHaveBeenCalled();
});

it("updates word in backend if gloss exists with different semantic domain", async () => {
Expand All @@ -320,7 +320,7 @@ describe("DataEntryTable", () => {
await testHandle.props.setNewGloss(glossText);
await testHandle.props.updateWordWithNewGloss(word.id);
});
expect(mockUpdateWord).toBeCalledTimes(1);
expect(mockUpdateWord).toHaveBeenCalledTimes(1);

// Confirm the semantic domain was added.
const wordUpdated: Word = mockUpdateWord.mock.calls[0][0];
Expand All @@ -338,7 +338,7 @@ describe("DataEntryTable", () => {
await testHandle.props.setNewGloss("differentGloss");
await testHandle.props.updateWordWithNewGloss(mockMultiWord.id);
});
expect(mockUpdateWord).toBeCalledTimes(1);
expect(mockUpdateWord).toHaveBeenCalledTimes(1);
});
});

Expand All @@ -351,8 +351,8 @@ describe("DataEntryTable", () => {
await act(async () => {
await testHandle.props.addNewEntry();
});
expect(mockUpdateDuplicate).toBeCalledTimes(1);
expect(mockCreateWord).not.toBeCalled();
expect(mockUpdateDuplicate).toHaveBeenCalledTimes(1);
expect(mockCreateWord).not.toHaveBeenCalled();
});

it("adds updated duplicate senses to recent entries", async () => {
Expand Down Expand Up @@ -403,7 +403,7 @@ describe("DataEntryTable", () => {
});

// Verify that createWord() was called with a word with the correct values
expect(mockCreateWord).toBeCalledTimes(1);
expect(mockCreateWord).toHaveBeenCalledTimes(1);
const wordAdded: Word = mockCreateWord.mock.calls[0][0];
expect(wordAdded.vernacular).toEqual(vern);
expect(wordAdded.senses[0].glosses[0].def).toEqual(glossDef);
Expand Down Expand Up @@ -449,7 +449,7 @@ describe("DataEntryTable", () => {
const senses: Sense[] = recentEntry.props.entry.senses;
expect(senses).toHaveLength(1);
expect(senses[0].semanticDomains).toHaveLength(1);
expect(mockUpdateWord).toBeCalledTimes(0);
expect(mockUpdateWord).toHaveBeenCalledTimes(0);

// Update the vernacular
const newVern = "not the vern generated in addRecentEntry";
Expand All @@ -458,7 +458,7 @@ describe("DataEntryTable", () => {
});

// Confirm the backend update was correctly called
expect(mockUpdateWord).toBeCalledTimes(1);
expect(mockUpdateWord).toHaveBeenCalledTimes(1);
const calledWith: Word = mockUpdateWord.mock.calls[0][0];
expect(calledWith.id).toEqual(wordId);
expect(calledWith.vernacular).toEqual(newVern);
Expand Down
12 changes: 6 additions & 6 deletions src/components/GoalTimeline/tests/GoalRedux.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ describe("asyncGetUserEdits", () => {
await store.dispatch(asyncGetUserEdits());
});
expect(store.getState().goalsState.history).toHaveLength(1);
expect(convertEditToGoalSpy).toBeCalledTimes(1);
expect(convertEditToGoalSpy).toHaveBeenCalledTimes(1);
});

it("backend returns no user edits", async () => {
Expand All @@ -163,7 +163,7 @@ describe("asyncGetUserEdits", () => {
await store.dispatch(asyncGetUserEdits());
});
expect(store.getState().goalsState.history).toHaveLength(0);
expect(convertEditToGoalSpy).toBeCalledTimes(0);
expect(convertEditToGoalSpy).toHaveBeenCalledTimes(0);
});

it("creates new user edits", async () => {
Expand All @@ -176,7 +176,7 @@ describe("asyncGetUserEdits", () => {
await store.dispatch(asyncGetUserEdits());
});
expect(store.getState().goalsState.history).toHaveLength(0);
expect(mockCreateUserEdit).toBeCalledTimes(1);
expect(mockCreateUserEdit).toHaveBeenCalledTimes(1);
});
});

Expand Down Expand Up @@ -305,7 +305,7 @@ describe("asyncUpdateGoal", () => {
});
// verify:
// - backend is called to addGoalToUserEdit
expect(mockAddGoalToUserEdit).toBeCalled();
expect(mockAddGoalToUserEdit).toHaveBeenCalled();
});

it("update MergeDups goal", async () => {
Expand All @@ -330,7 +330,7 @@ describe("asyncUpdateGoal", () => {
.changes as MergesCompleted;
expect(changes.merges).toEqual([mockCompletedMerge]);
// - backend is called to addGoalToUserEdit
expect(mockAddGoalToUserEdit).toBeCalled();
expect(mockAddGoalToUserEdit).toHaveBeenCalled();
});

it("update ReviewDeferredDups goal", async () => {
Expand All @@ -355,6 +355,6 @@ describe("asyncUpdateGoal", () => {
.changes as MergesCompleted;
expect(changes.merges).toEqual([mockCompletedMerge]);
// - backend is called to addGoalToUserEdit
expect(mockAddGoalToUserEdit).toBeCalled();
expect(mockAddGoalToUserEdit).toHaveBeenCalled();
});
});
2 changes: 1 addition & 1 deletion src/components/GoalTimeline/tests/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ describe("GoalTimeline", () => {
id: `new-goal-${allGoals[goalNumber].name}`,
});
await renderer.act(async () => goalButton.props.onClick());
expect(mockChooseGoal).toBeCalledTimes(1);
expect(mockChooseGoal).toHaveBeenCalledTimes(1);
expect(mockChooseGoal.mock.calls[0][0].goalType).toEqual(
defaultState.allGoalTypes[goalNumber]
);
Expand Down
4 changes: 2 additions & 2 deletions src/components/Login/Redux/tests/LoginActions.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ describe("LoginAction", () => {

// A failed signup does not trigger a login.
jest.runAllTimers();
expect(mockAuthenticateUser).not.toBeCalled();
expect(mockAuthenticateUser).not.toHaveBeenCalled();
});

it("correctly affects state on success", async () => {
Expand All @@ -87,7 +87,7 @@ describe("LoginAction", () => {
// A successful signup triggers a login using `setTimeout`.
mockAuthenticateUser.mockRejectedValueOnce({});
jest.runAllTimers();
expect(mockAuthenticateUser).toBeCalledTimes(1);
expect(mockAuthenticateUser).toHaveBeenCalledTimes(1);
});
});
});
14 changes: 5 additions & 9 deletions src/components/PasswordReset/tests/Request.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,9 @@ describe("ResetRequest", () => {
const button = screen.getByRole("button");
expect(button).toBeDisabled();

// Act
// Agent
const field = screen.getByTestId(PasswordRequestIds.FieldEmailOrUsername);
await act(async () => {
await agent.type(field, "a");
});
await agent.type(field, "a");

// After
expect(button).toBeEnabled();
Expand All @@ -64,12 +62,10 @@ describe("ResetRequest", () => {
expect(screen.queryAllByRole("button")).toHaveLength(1);
expect(screen.queryByTestId(PasswordRequestIds.ButtonLogin)).toBeNull();

// Act
// Agent
const field = screen.getByTestId(PasswordRequestIds.FieldEmailOrUsername);
await act(async () => {
await agent.type(field, "a");
await agent.click(screen.getByRole("button"));
});
await agent.type(field, "a");
await agent.click(screen.getByRole("button"));

// After
expect(screen.queryAllByRole("textbox")).toHaveLength(0);
Expand Down
Loading

0 comments on commit fcb36da

Please sign in to comment.