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

#304 Add confirmation for deleting connection #305

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 52 additions & 1 deletion apps/web/e2e/pages/connections.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,63 @@ test("should be able to add a connection", async ({ page }) => {
await createConnection(page, "0x60a7048c3136293071605a4eaffef49923e981cc");
});

test("should be able to remove a connection", async ({ page }) => {
test("should display a confirmation modal for removing a connection", async ({
page,
}) => {
await createConnection(page, "0x60a7048c3136293071605a4eaffef49923e981cc");

const deleteButton = page.getByTestId("remove-connection");
await deleteButton.click();

await expect(page.getByText("Delete connection?")).toBeVisible();
await expect(
page.getByText(
"This will delete the data for this connection. Are you sure you want to proceed?",
),
).toBeVisible();
});

test("should close the confirmation modal when canceling the connection deletion", async ({
page,
}) => {
await createConnection(page, "0x60a7048c3136293071605a4eaffef49923e981cc");

const deleteButton = page.getByTestId("remove-connection");
await deleteButton.click();

await expect(page.getByText("Delete connection?")).toBeVisible();
await expect(
page.getByText(
"This will delete the data for this connection. Are you sure you want to proceed?",
),
).toBeVisible();

const cancelButton = page.getByText("Cancel");
await cancelButton.click();

await expect(page.getByText("Delete connection?")).not.toBeVisible();
await expect(page.getByText("No connections found.")).not.toBeVisible();
});

test("should remove the connection when the delete action was confirmed", async ({
page,
}) => {
await createConnection(page, "0x60a7048c3136293071605a4eaffef49923e981cc");

const deleteButton = page.getByTestId("remove-connection");
await deleteButton.click();

await expect(page.getByText("Delete connection?")).toBeVisible();
await expect(
page.getByText(
"This will delete the data for this connection. Are you sure you want to proceed?",
),
).toBeVisible();

const cancelButton = page.getByText("Confirm");
await cancelButton.click();

await expect(page.getByText("Delete connection?")).not.toBeVisible();
await expect(page.getByText("No connections found.")).toBeVisible();
});

Expand Down
98 changes: 66 additions & 32 deletions apps/web/src/components/connection/connectionInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ import {
Button,
Card,
Flex,
Group,
List,
Modal,
Text,
VisuallyHidden,
useMantineTheme,
} from "@mantine/core";
import { useDisclosure } from "@mantine/hooks";
import { FC } from "react";
import { TbNetwork, TbTrash } from "react-icons/tb";
import { useConnectionConfig } from "../../providers/connectionConfig/hooks";
Expand All @@ -20,43 +23,74 @@ interface ConnectionInfoProps {
const ConnectionInfo: FC<ConnectionInfoProps> = ({ connection }) => {
const { removeConnection } = useConnectionConfig();
const theme = useMantineTheme();
const [opened, { open, close }] = useDisclosure(false);

return (
<Card
withBorder
py="lg"
radius="sm"
shadow="sm"
data-testid="connection-card"
>
<Card.Section inheritPadding withBorder>
<Flex justify="space-between">
<Address value={connection.address} shorten icon />
<>
<Modal
opened={opened}
onClose={close}
title="Delete connection?"
centered
>
<Text>
This will delete the data for this connection. Are you sure
you want to proceed?
</Text>

<Group mt="xl" justify="flex-end">
<Button variant="default" onClick={close}>
Cancel
</Button>
<Button
aria-label={`remove-${connection.address}`}
role="button"
justify="flex-end"
size="compact-sm"
variant="transparent"
color="red"
data-testid="remove-connection"
onClick={() => removeConnection(connection.address)}
onClick={() => {
removeConnection(connection.address);
close();
}}
>
<TbTrash size={theme.other.iconSize} />
<VisuallyHidden>
Remove connection for address {connection.address}
</VisuallyHidden>
Confirm
</Button>
</Flex>
</Card.Section>
</Group>
</Modal>

<Card
withBorder
py="lg"
radius="sm"
shadow="sm"
data-testid="connection-card"
>
<Card.Section inheritPadding withBorder>
<Flex justify="space-between">
<Address value={connection.address} shorten icon />
<Button
aria-label={`remove-${connection.address}`}
role="button"
justify="flex-end"
size="compact-sm"
variant="transparent"
color="red"
data-testid="remove-connection"
onClick={open}
>
<TbTrash size={theme.other.iconSize} />
<VisuallyHidden>
Remove connection for address{" "}
{connection.address}
</VisuallyHidden>
</Button>
</Flex>
</Card.Section>

<List pt="sm" center>
<List.Item icon={<TbNetwork size={theme.other.iconSize} />}>
<Text style={{ lineBreak: "anywhere" }}>
{connection.url}
</Text>
</List.Item>
</List>
</Card>
<List pt="sm" center>
<List.Item icon={<TbNetwork size={theme.other.iconSize} />}>
<Text style={{ lineBreak: "anywhere" }}>
{connection.url}
</Text>
</List.Item>
</List>
</Card>
</>
);
};

Expand Down
77 changes: 75 additions & 2 deletions apps/web/test/components/connection/connectionInfo.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { cleanup, fireEvent, render, screen } from "@testing-library/react";
import {
cleanup,
fireEvent,
render,
screen,
waitFor,
} from "@testing-library/react";
import { describe, it } from "vitest";
import ConnectionInfo from "../../../src/components/connection/connectionInfo";
import { useConnectionConfig } from "../../../src/providers/connectionConfig/hooks";
Expand Down Expand Up @@ -41,7 +47,7 @@ describe("Connection info component", () => {
).toBeInTheDocument();
});

it("should call the remove action when clicking on the trash icon", async () => {
it("should open the confirmation modal when clicking on the trash icon", async () => {
render(<ConnectionInfo connection={connections[0]} />, {
wrapper: StyleProvider,
});
Expand All @@ -52,6 +58,73 @@ describe("Connection info component", () => {

fireEvent.click(button);

await waitFor(() => screen.getByText("Delete connection?"));
expect(
screen.getByText(
"This will delete the data for this connection. Are you sure you want to proceed?",
),
).toBeInTheDocument();
});

it("should close the confirmation modal when clicking on cancel button", async () => {
const [connection] = connections;
render(<ConnectionInfo connection={connection} />, {
wrapper: StyleProvider,
});

const button = screen.getByRole("button", {
name: `remove-${connection.address}`,
});

fireEvent.click(button);

await waitFor(() => screen.getByText("Delete connection?"));
expect(
screen.getByText(
"This will delete the data for this connection. Are you sure you want to proceed?",
),
).toBeInTheDocument();

const cancelButton = screen.getByText("Cancel");
fireEvent.click(cancelButton);

await waitFor(() =>
expect(() => screen.getByText("Delete connection?")).toThrow(
"Unable to find an element with the text: Delete connection?",
),
);

expect(screen.getByText(connection.url)).toBeInTheDocument();
});

it("should call the remove action when confirming the connection deletion", async () => {
const [connection] = connections;
render(<ConnectionInfo connection={connection} />, {
wrapper: StyleProvider,
});

const button = screen.getByRole("button", {
name: `remove-${connection.address}`,
});

fireEvent.click(button);

await waitFor(() => screen.getByText("Delete connection?"));
expect(
screen.getByText(
"This will delete the data for this connection. Are you sure you want to proceed?",
),
).toBeInTheDocument();

const confirmButton = screen.getByText("Confirm");
fireEvent.click(confirmButton);

await waitFor(() =>
expect(() => screen.getByText("Delete connection?")).toThrow(
"Unable to find an element with the text: Delete connection?",
),
);

expect(useConnMock().removeConnection).toHaveBeenCalledOnce();
expect(useConnMock().removeConnection).toHaveBeenCalledWith(
"0x70ac08179605AF2D9e75782b8DEcDD3c22aA4D0C",
Expand Down
16 changes: 0 additions & 16 deletions apps/web/test/components/connection/connectionView.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,20 +81,4 @@ describe("Connection view component", () => {
);
expect(screen.getByText(connections[1].url)).toBeInTheDocument();
});

it("should call the remove connection correctly when clicking the trash can", () => {
const { removeConnection, listConnections } =
useConnectionConfigReturnStub;
listConnections.mockReturnValue(connections);

render(<View />);

fireEvent.click(
screen.getByText(
`Remove connection for address ${connections[0].address}`,
),
);

expect(removeConnection).toHaveBeenCalledWith(connections[0].address);
});
});
Loading