Skip to content
This repository has been archived by the owner on Mar 23, 2023. It is now read-only.

refactor: add the openExternal() electron to the Link component #2666

Merged
merged 5 commits into from Aug 14, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/app/components/Link/Link.stories.tsx
Expand Up @@ -5,11 +5,11 @@ import { Link } from "./Link";
export default { title: "App / Components / Link" };

export const Default = () => <Link to="/wallets">Wallets</Link>;

export const External = () => (
<Link to={{ pathname: "https://ark.io" }} isExternal>
<Link to="https://ark.io" isExternal>
ARK.io
</Link>
);
export const WithTooltip = () => (
<Link to={{ pathname: "https://ark.io" }} isExternal tooltip="ASuusXSW9kfWnicScSgUTjttP6T9GQ3kqT" />
);

export const WithTooltip = () => <Link to="https://ark.io" tooltip="ASuusXSW9kfWnicScSgUTjttP6T9GQ3kqT" isExternal />;
41 changes: 32 additions & 9 deletions src/app/components/Link/Link.test.tsx
@@ -1,44 +1,67 @@
import electron from "electron";
import React from "react";
import { act, fireEvent, renderWithRouter } from "testing-library";

import { Link } from "./Link";

jest.mock("electron", () => ({
shell: {
openExternal: jest.fn(),
},
}));

describe("Link", () => {
it("should render", () => {
const { getByTestId, asFragment } = renderWithRouter(<Link to="/test">Test</Link>);
const { asFragment, getByTestId } = renderWithRouter(<Link to="/test">Test</Link>);
expect(getByTestId("Link")).toHaveTextContent("Test");
expect(asFragment()).toMatchSnapshot();
});

it("should render external", () => {
const { getByTestId, asFragment } = renderWithRouter(
<Link to={{ pathname: "https://ark.io" }} isExternal>
const { getByTestId } = renderWithRouter(
<Link to="https://ark.io" isExternal>
ARK.io
</Link>,
);
expect(getByTestId("Link")).toHaveAttribute("rel", "noopener noreferrer");
expect(getByTestId("Link")).toHaveAttribute("target", "_blank");
expect(getByTestId("Link__external")).toBeTruthy();
expect(asFragment()).toMatchSnapshot();
});

it("should render external without children", () => {
const { getByTestId, asFragment } = renderWithRouter(<Link to={{ pathname: "https://ark.io" }} isExternal />);
const { asFragment, getByTestId } = renderWithRouter(<Link to="https://ark.io" isExternal />);
expect(getByTestId("Link__external")).toBeTruthy();
expect(asFragment()).toMatchSnapshot();
});

it("should open an external link", () => {
const externalLink = "https://ark.io";
const openExternalMock = jest.spyOn(electron.shell, "openExternal").mockImplementation();
const { asFragment, getByTestId } = renderWithRouter(<Link to={externalLink} isExternal />);
const link = getByTestId("Link");

act(() => {
fireEvent.click(link);
});
expect(openExternalMock).toHaveBeenCalledWith(externalLink);
expect(asFragment()).toMatchSnapshot();
});

it("should render with tooltip", () => {
const { getByTestId, baseElement } = renderWithRouter(
const { asFragment, baseElement, getByTestId } = renderWithRouter(
<Link to="/test" tooltip="Custom Tooltip">
Test
</Link>,
);
const link = getByTestId("Link");

act(() => {
fireEvent.mouseEnter(getByTestId("Link"));
fireEvent.mouseEnter(link);
});

expect(baseElement).toHaveTextContent("Custom Tooltip");

act(() => {
fireEvent.click(link);
});
expect(asFragment()).toMatchSnapshot();
});
});
21 changes: 18 additions & 3 deletions src/app/components/Link/Link.tsx
Expand Up @@ -2,6 +2,7 @@ import Tippy from "@tippyjs/react";
import React from "react";
import { Link as RouterLink, LinkProps } from "react-router-dom";
import { styled } from "twin.macro";
import { openExternal } from "utils/electron-utils";

import { Icon } from "../Icon";

Expand All @@ -22,17 +23,21 @@ const AnchorStyled = styled.a<{ isExternal: boolean }>`

type AnchorProps = {
isExternal?: boolean;
navigate?: () => void;
} & React.AnchorHTMLAttributes<any>;

const Anchor = React.forwardRef<HTMLAnchorElement, Props>(
({ isExternal, children, target, rel, ...props }: AnchorProps, ref) => (
({ isExternal, children, rel, ...props }: AnchorProps, ref) => (
<AnchorStyled
data-testid="Link"
isExternal={isExternal!}
className="inline-flex items-center font-semibold cursor-pointer transition-colors duration-200 text-theme-primary hover:text-theme-primary-dark hover:underline active:text-theme-primary-500"
target={isExternal ? "_blank" : target}
rel={isExternal ? "noopener noreferrer" : rel}
ref={ref}
onClick={(event) => {
event.preventDefault();
return props.navigate?.();
}}
{...props}
>
{children}
Expand All @@ -57,7 +62,17 @@ type Props = {

export const Link = ({ tooltip, ...props }: Props) => (
<Tippy content={tooltip} disabled={!tooltip}>
<RouterLink component={Anchor} {...props} />
{props.isExternal ? (
<Anchor
onClick={(event) => {
event.preventDefault();
return openExternal(props.to);
}}
{...props}
/>
) : (
<RouterLink component={Anchor} {...props} />
)}
</Tippy>
);

Expand Down
47 changes: 28 additions & 19 deletions src/app/components/Link/__snapshots__/Link.test.tsx.snap
@@ -1,29 +1,15 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Link should render 1`] = `
<DocumentFragment>
<a
class="sc-AxirZ bvOtTg inline-flex items-center font-semibold cursor-pointer transition-colors duration-200 text-theme-primary hover:text-theme-primary-dark hover:underline active:text-theme-primary-500"
data-testid="Link"
href="/test"
>
Test
</a>
</DocumentFragment>
`;

exports[`Link should render external 1`] = `
exports[`Link should open an external link 1`] = `
<DocumentFragment>
<a
class="sc-AxirZ fYobRB inline-flex items-center font-semibold cursor-pointer transition-colors duration-200 text-theme-primary hover:text-theme-primary-dark hover:underline active:text-theme-primary-500"
data-testid="Link"
href="https://ark.io"
rel="noopener noreferrer"
target="_blank"
to="https://ark.io"
>
ARK.io
<div
class="sc-AxjAm cpczEI flex-shrink-0 ml-2 text-sm"
class="sc-AxjAm cpczEI flex-shrink-0 "
data-testid="Link__external"
height="1em"
width="1em"
Expand All @@ -36,14 +22,25 @@ exports[`Link should render external 1`] = `
</DocumentFragment>
`;

exports[`Link should render 1`] = `
<DocumentFragment>
<a
class="sc-AxirZ bvOtTg inline-flex items-center font-semibold cursor-pointer transition-colors duration-200 text-theme-primary hover:text-theme-primary-dark hover:underline active:text-theme-primary-500"
data-testid="Link"
href="/test"
>
Test
</a>
</DocumentFragment>
`;

exports[`Link should render external without children 1`] = `
<DocumentFragment>
<a
class="sc-AxirZ fYobRB inline-flex items-center font-semibold cursor-pointer transition-colors duration-200 text-theme-primary hover:text-theme-primary-dark hover:underline active:text-theme-primary-500"
data-testid="Link"
href="https://ark.io"
rel="noopener noreferrer"
target="_blank"
to="https://ark.io"
>
<div
class="sc-AxjAm cpczEI flex-shrink-0 "
Expand All @@ -58,3 +55,15 @@ exports[`Link should render external without children 1`] = `
</a>
</DocumentFragment>
`;

exports[`Link should render with tooltip 1`] = `
<DocumentFragment>
<a
class="sc-AxirZ bvOtTg inline-flex items-center font-semibold cursor-pointer transition-colors duration-200 text-theme-primary hover:text-theme-primary-dark hover:underline active:text-theme-primary-500"
data-testid="Link"
href="/test"
>
Test
</a>
</DocumentFragment>
`;
Expand Up @@ -205,9 +205,8 @@ exports[`Transactions should render with with transactions 1`] = `
<a
class="sc-AxheI bALhgA inline-flex items-center font-semibold cursor-pointer transition-colors duration-200 text-theme-primary hover:text-theme-primary-dark hover:underline active:text-theme-primary-500"
data-testid="TransactionRow__ID"
href=""
rel="noopener noreferrer"
target="_blank"
to="https://explorer.ark.io/"
>
<div
class="sc-AxirZ iQaTP flex-shrink-0 "
Expand Down Expand Up @@ -358,9 +357,8 @@ exports[`Transactions should render with with transactions 1`] = `
<a
class="sc-AxheI bALhgA inline-flex items-center font-semibold cursor-pointer transition-colors duration-200 text-theme-primary hover:text-theme-primary-dark hover:underline active:text-theme-primary-500"
data-testid="TransactionRow__ID"
href=""
rel="noopener noreferrer"
target="_blank"
to="https://explorer.ark.io/"
>
<div
class="sc-AxirZ iQaTP flex-shrink-0 "
Expand Down Expand Up @@ -511,9 +509,8 @@ exports[`Transactions should render with with transactions 1`] = `
<a
class="sc-AxheI bALhgA inline-flex items-center font-semibold cursor-pointer transition-colors duration-200 text-theme-primary hover:text-theme-primary-dark hover:underline active:text-theme-primary-500"
data-testid="TransactionRow__ID"
href=""
rel="noopener noreferrer"
target="_blank"
to="https://explorer.ark.io/"
>
<div
class="sc-AxirZ iQaTP flex-shrink-0 "
Expand Down Expand Up @@ -660,9 +657,8 @@ exports[`Transactions should render with with transactions 1`] = `
<a
class="sc-AxheI bALhgA inline-flex items-center font-semibold cursor-pointer transition-colors duration-200 text-theme-primary hover:text-theme-primary-dark hover:underline active:text-theme-primary-500"
data-testid="TransactionRow__ID"
href=""
rel="noopener noreferrer"
target="_blank"
to="https://explorer.ark.io/"
>
<div
class="sc-AxirZ iQaTP flex-shrink-0 "
Expand Down