Skip to content

Commit

Permalink
upgrade react types (#2051)
Browse files Browse the repository at this point in the history
* upgrade react types

* upgrade react-router-dom

* fix failing tests
  • Loading branch information
abbiesims authored Jan 10, 2025
1 parent 7aa853d commit cef1df5
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 416 deletions.
11 changes: 5 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"watch-js": "webpack --watch --mode development",
"watch-scss": "watch -p 'static/sass/**/*.scss' -c 'yarn run build-css'",
"build": "yarn run build-css && yarn run build-js",
"build-css": "sass static/sass/styles.scss:static/css/styles.css static/sass/styles-embedded.scss:static/css/styles-embedded.css --load-path=node_modules --style=compressed --quiet-deps --silence-deprecation=mixed-decls && postcss --map false --use autoprefixer --replace 'static/css/**/*.css' ",
"build-css": "sass static/sass/styles.scss:static/css/styles.css static/sass/styles-embedded.scss:static/css/styles-embedded.css --load-path=node_modules --style=compressed --quiet-deps --quiet --silence-deprecation=mixed-decls && postcss --map false --use autoprefixer --replace 'static/css/**/*.css' ",
"build-js": "webpack",
"format-python": "black --line-length 79 webapp",
"lint-python": "flake8 --extend-ignore=E203 webapp tests && black --check --line-length 79 webapp tests",
Expand All @@ -33,10 +33,10 @@
"@sentry/react": "7.120.2",
"@testing-library/dom": "10.4.0",
"@testing-library/jest-dom": "6.6.3",
"@testing-library/react": "14.3.1",
"@testing-library/react": "16.1.0",
"@testing-library/user-event": "14.5.2",
"@types/jest": "29.5.14",
"@types/react-dom": "18.3.5",
"@types/react-dom": "19.0.2",
"@types/react-router-dom": "5.3.3",
"autoprefixer": "10.4.20",
"babel-loader": "9.2.1",
Expand All @@ -54,7 +54,7 @@
"react-dropzone": "14.3.5",
"react-markdown": "9.0.3",
"react-query": "3.39.3",
"react-router-dom": "6.28.1",
"react-router-dom": "7.1.1",
"recoil": "0.7.7",
"remark-mermaidjs": "6.0.0",
"sass": "1.83.1",
Expand All @@ -69,7 +69,7 @@
"devDependencies": {
"@babel/eslint-parser": "7.25.9",
"@types/deep-equal": "1.0.4",
"@types/react": "18.3.18",
"@types/react": "19.0.4",
"@types/uuid": "9.0.8",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
Expand All @@ -84,7 +84,6 @@
"eslint-plugin-react": "7.37.3",
"jest": "29.7.0",
"jest-environment-jsdom": "29.7.0",
"msw": "2.7.0",
"sass-loader": "14.2.1",
"stylelint": "16.12.0",
"stylelint-config-standard-scss": "13.1.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { useParams } from "react-router-dom";
import { useQueryClient } from "react-query";
import { useRecoilState, useSetRecoilState, useRecoilValue } from "recoil";
import { Modal, Button } from "@canonical/react-components";
import { Button, Modal as CanonicalModal } from "@canonical/react-components";
import type { Props as ModalProps } from "@canonical/react-components/dist/components/Modal/Modal";

import {
activeInviteEmailState,
Expand All @@ -25,6 +26,10 @@ type Props = {
queryKey?: string;
};

const Modal = (props: ModalProps): JSX.Element => {
return CanonicalModal(props) as unknown as JSX.Element;
};

function InviteConfirmationModal({
action,
setShowModal,
Expand Down
126 changes: 45 additions & 81 deletions static/js/src/publisher-admin/pages/Listing/__tests__/Listing.test.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import React from "react";
import { MutableSnapshot, RecoilRoot } from "recoil";
import { render, screen, waitFor } from "@testing-library/react";
import { http, HttpResponse } from "msw";
import { setupServer } from "msw/node";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import "@testing-library/jest-dom";

Expand All @@ -25,19 +23,13 @@ const renderComponent = (mockPackageData: Package) => {
);
};

const server = setupServer(
http.patch(`/api/packages/${mockPackage.name}`, () => {
return HttpResponse.json({
data: mockPackage,
message: "",
success: true,
});
})
);
beforeEach(() => {
global.fetch = jest.fn();
});

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
afterEach(() => {
jest.resetAllMocks();
});

describe("Listing", () => {
test("shows notification if package not published", () => {
Expand Down Expand Up @@ -86,37 +78,6 @@ describe("Listing", () => {
expect(screen.getByLabelText("Title:")).toHaveValue(mockPackage.title);
});

test("shows success notification if data saved", () => {
const user = userEvent.setup();
renderComponent(mockPackage);
user.type(screen.getByLabelText("Title:"), "Package title");
user.click(screen.getByRole("button", { name: "Save" }));
waitFor(() => {
expect(screen.getByRole("alert")).toHaveTextContent(
`${mockPackage.name} has been updated successfully`
);
});
});

test("shows error notification if error saving", () => {
const user = userEvent.setup();
server.use(
http.patch(`/api/packages/${mockPackage.name}`, () => {
return new HttpResponse(null, {
status: 500,
});
})
);
renderComponent(mockPackage);
user.type(screen.getByLabelText("Title:"), "Package title");
user.click(screen.getByRole("button", { name: "Save" }));
waitFor(() => {
expect(
screen.getByText(`There was a problem updating ${mockPackage.name}`)
).toBeInTheDocument();
});
});

test("initialises form data correctly", () => {
renderComponent(mockPackage);
expect(screen.getByLabelText("Title:")).toHaveValue(mockPackage.title);
Expand All @@ -129,51 +90,54 @@ describe("Listing", () => {
);
});

test("disables 'Revert' button if no changes are made", () => {
test("updates form fields correctly when user types input", async () => {
const user = userEvent.setup();
renderComponent(mockPackage);
expect(screen.getByRole("button", { name: "Revert" })).toHaveAttribute(
"aria-disabled",
"true"
);

const titleInput = screen.getByLabelText("Title:");
const summaryInput = screen.getByLabelText("Summary:");
const websiteInput = screen.getByLabelText("Project homepage:");
const contactInput = screen.getByLabelText("Contact:");

await user.clear(titleInput);
await user.type(titleInput, "Updated Title");
expect(titleInput).toHaveValue("Updated Title");

await user.clear(summaryInput);
await user.type(summaryInput, "Updated Summary");
expect(summaryInput).toHaveValue("Updated Summary");

await user.clear(websiteInput);
await user.type(websiteInput, "https://new-website.com");
expect(websiteInput).toHaveValue("https://new-website.com");

await user.clear(contactInput);
await user.type(contactInput, "[email protected]");
expect(contactInput).toHaveValue("[email protected]");
});

test("disables 'Save' button if no changes are made", () => {
test("disables Save and Revert buttons by default", () => {
renderComponent(mockPackage);
expect(screen.getByRole("button", { name: "Save" })).toHaveAttribute(
"aria-disabled",
"true"
);

const saveButton = screen.getByRole("button", { name: "Save" });
const revertButton = screen.getByRole("button", { name: "Revert" });

expect(saveButton).toHaveAttribute("aria-disabled", "true");
expect(revertButton).toHaveAttribute("aria-disabled", "true");
});

test("updates form fields correctly when user types input", () => {
test("enables Save and Revert buttons after changes", async () => {
const user = userEvent.setup();
renderComponent(mockPackage);

user.type(screen.getByLabelText("Title:"), "Updated Title");
waitFor(() => {
expect(screen.getByLabelText("Title:")).toHaveValue("Updated Title");
});
const saveButton = screen.getByRole("button", { name: "Save" });
const revertButton = screen.getByRole("button", { name: "Revert" });

user.type(screen.getByLabelText("Summary:"), "Updated Summary");
waitFor(() => {
expect(screen.getByLabelText("Summary:")).toHaveValue("Updated Summary");
});
const titleInput = screen.getByLabelText("Title:");
await user.clear(titleInput);
await user.type(titleInput, "Updated Title");

user.type(
screen.getByLabelText("Project homepage:"),
"https://new-homepage.com"
);
waitFor(() => {
expect(screen.getByLabelText("Project homepage:")).toHaveValue(
"https://new-homepage.com"
);
});

user.type(screen.getByLabelText("Contact:"), "[email protected]");
waitFor(() => {
expect(screen.getByLabelText("Contact:")).toHaveValue(
"[email protected]"
);
});
expect(saveButton).not.toBeDisabled();
expect(revertButton).not.toBeDisabled();
});
});
8 changes: 7 additions & 1 deletion static/js/src/publisher-admin/pages/Releases/Releases.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import {
Spinner,
AppAside,
Notification,
EmptyState,
EmptyState as CanonicalEmptyState,
Button,
} from "@canonical/react-components";
import type { Props as EmptyStateProps } from "@canonical/react-components/dist/components/EmptyState/EmptyState";

import { usePackage } from "../../hooks";
import { TrackInfo } from "./TrackInfo";
import { TrackDropdown } from "./TrackDropdown";
Expand All @@ -22,6 +24,10 @@ enum SidePanelType {
AddTrack = "AddTrack",
}

const EmptyState = (props: EmptyStateProps): JSX.Element => {
return CanonicalEmptyState(props) as unknown as JSX.Element;
};

export default function Releases() {
const { packageName } = useParams();
const { data: releaseData } = useReleases(packageName);
Expand Down
16 changes: 8 additions & 8 deletions static/js/src/publisher-admin/utils/buildInviteTableRows.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { useSetRecoilState } from "recoil";
import { format } from "date-fns";
import { Button } from "@canonical/react-components";
import { Button, MainTable } from "@canonical/react-components";

import { activeInviteEmailState } from "../state/atoms";

import type { Invite } from "../types";

type MainTableProps = Parameters<typeof MainTable>[0];
type MainTableRow = NonNullable<MainTableProps["rows"]>[number];
type MainTableCell = NonNullable<MainTableRow["columns"]>[number];

function buildInviteTableRows(
invites: Array<Invite>,
status: "Pending" | "Expired" | "Revoked",
Expand All @@ -16,12 +20,8 @@ function buildInviteTableRows(
const setActiveInviteEmail = useSetRecoilState(activeInviteEmailState);

return invites.map((invite: Invite, index) => {
let columns: {
content: React.ReactNode;
rowSpan?: number;
className?: string;
}[] = [];
let statusColumn;
let columns: MainTableCell[] = [];
let statusColumn: MainTableCell | undefined;

if (invites.length > 0 && index === 0) {
statusColumn = {
Expand All @@ -38,7 +38,7 @@ function buildInviteTableRows(
};
}

const remainingColumns = [
const remainingColumns: MainTableCell[] = [
{
content: invite?.email,
className: "u-truncate",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ export const EmptyResultSection = ({
<h1 className="p-heading--2">
Search results for "{searchTerm}"
</h1>
<SearchInput searchRef={searchRef} />
<SearchInput
searchRef={searchRef as React.RefObject<HTMLInputElement>}
/>
</Col>
</Row>
<Row>
Expand Down
2 changes: 1 addition & 1 deletion static/js/src/store/components/PackageList/PackageList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const PackageList = ({

return (
<>
<Banner searchRef={searchRef} />
<Banner searchRef={searchRef as React.RefObject<HTMLInputElement>} />
<Strip>
<Row>
<Col size={3}>
Expand Down
Loading

0 comments on commit cef1df5

Please sign in to comment.