Skip to content

Commit

Permalink
Merge pull request #1783 from dusk-network/feature-1781
Browse files Browse the repository at this point in the history
explorer: disable block height navigation
  • Loading branch information
deuch13 authored May 24, 2024
2 parents 109ddcc + 468fce9 commit bd1d42a
Show file tree
Hide file tree
Showing 12 changed files with 510 additions and 23 deletions.
66 changes: 66 additions & 0 deletions explorer/src/lib/components/__tests__/AppAnchorButton.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import { cleanup, fireEvent, render } from "@testing-library/svelte";
import { base } from "$app/paths";

import { AppAnchorButton } from "..";

describe("AppAnchorButton", () => {
const baseProps = {
className: "foo bar",
href: "/setup",
id: "some-id",
};

afterEach(cleanup);

it("should render an `AnchorButton` with the base path prepended to the `href` attribute, if the `href` represents an absolute URL", () => {
const { container, getByRole, rerender } = render(
AppAnchorButton,
baseProps
);
const anchorA = getByRole("link");

expect(container.firstChild).toMatchSnapshot();
expect(anchorA).toHaveAttribute("href", `${base}${baseProps.href}`);
expect(anchorA).toHaveClass("foo bar");
expect(anchorA).toHaveAttribute("id", baseProps.id);

rerender({ ...baseProps, href: "/" });

const anchorB = getByRole("link");

expect(anchorB).toHaveAttribute("href", `${base}/`);
expect(anchorB).toHaveClass("foo bar");
expect(anchorB).toHaveAttribute("id", baseProps.id);
});

it("should leave the `AnchorButton` as it is if the `href` points to a relative path", () => {
const { getByRole } = render(AppAnchorButton, {
...baseProps,
href: "foo/bar",
});

expect(getByRole("link")).toHaveAttribute("href", "foo/bar");
});

it("should leave the `AnchorButton` as it is if the `href` points to an external URL", () => {
const href = "http://example.com";
const { getByRole } = render(AppAnchorButton, { ...baseProps, href });

expect(getByRole("link")).toHaveAttribute("href", href);
});

it("should forward the `onclick` event to the `AnchorButton`", async () => {
const handler = vi.fn();
const { component, getByRole } = render(AppAnchorButton, {
...baseProps,
href: "#",
});

component.$on("click", handler);

await fireEvent.click(getByRole("link"));

expect(handler).toHaveBeenCalledTimes(1);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`AppAnchorButton > should render an \`AnchorButton\` with the base path prepended to the \`href\` attribute, if the \`href\` represents an absolute URL 1`] = `
<div>
<a
aria-disabled="false"
class="dusk-anchor dusk-anchor-button dusk-anchor-button--variant--primary dusk-anchor-button--size--normal foo bar"
href="/some-base-path/setup"
id="some-id"
>
</a>
<!--&lt;Anchor&gt;-->
<!--&lt;AnchorButton&gt;-->
<!--&lt;AppAnchorButton&gt;-->
</div>
`;
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,12 @@ exports[`Block Details > renders the Block Details component 1`] = `
class="details-list__definition"
>
<a
class="dusk-anchor block-details__list-anchor"
aria-disabled="false"
class="dusk-anchor dusk-anchor-button dusk-anchor-button--variant--primary dusk-anchor-button--size--normal dusk-icon-button block-details__list-anchor"
href="/some-base-path/blocks/block?id=07b74b35c2c7cf8f41426cd0870bafa1a2c7adee3fdd876643548096186fc4cb"
>
<svg
class="dusk-icon dusk-icon--size--normal"
class="dusk-icon dusk-icon--size--normal dusk-anchor-button__icon"
role="graphics-symbol"
viewBox="0 0 24 24"
>
Expand All @@ -99,18 +100,23 @@ exports[`Block Details > renders the Block Details component 1`] = `
</svg>
<!--&lt;Icon&gt;-->
</a>
<!--&lt;Anchor&gt;-->
<!--&lt;AppAnchor&gt;-->
<!--&lt;AnchorButton&gt;-->
<!--&lt;AppAnchorButton&gt;-->
495,868
<a
class="dusk-anchor block-details__list-anchor"
aria-disabled="false"
class="dusk-anchor dusk-anchor-button dusk-anchor-button--variant--primary dusk-anchor-button--size--normal dusk-icon-button block-details__list-anchor"
href="/some-base-path/blocks/block?id=6011556208a85e6001bd01ccbf936486b91318a7f6cbcf7ab810adf6fae34204"
>
<svg
class="dusk-icon dusk-icon--size--normal"
class="dusk-icon dusk-icon--size--normal dusk-anchor-button__icon"
role="graphics-symbol"
viewBox="0 0 24 24"
>
Expand All @@ -120,9 +126,13 @@ exports[`Block Details > renders the Block Details component 1`] = `
</svg>
<!--&lt;Icon&gt;-->
</a>
<!--&lt;Anchor&gt;-->
<!--&lt;AppAnchor&gt;-->
<!--&lt;AnchorButton&gt;-->
<!--&lt;AppAnchorButton&gt;-->
</dd>
<!--&lt;ListItem&gt;-->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<svelte:options immutable={true} />

<script>
import { AnchorButton } from "$lib/dusk/components";
import { addBasePath } from "$lib/navigation";
/** @type {string} */
export let href;
</script>

<AnchorButton {...$$restProps} href={addBasePath(href)} on:click />
20 changes: 10 additions & 10 deletions explorer/src/lib/components/block-details/BlockDetails.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

<script>
import { mdiArrowLeft, mdiArrowRight } from "@mdi/js";
import { AppAnchor, DataCard, ListItem } from "$lib/components";
import { Icon, ProgressBar } from "$lib/dusk/components";
import { AppAnchorButton, DataCard, ListItem } from "$lib/components";
import { ProgressBar } from "$lib/dusk/components";
import { luxToDusk } from "$lib/dusk/currency";
import { createValueFormatter } from "$lib/dusk/value";
import {
Expand Down Expand Up @@ -80,19 +80,19 @@
>
<svelte:fragment slot="term">height</svelte:fragment>
<svelte:fragment slot="definition">
<AppAnchor
<AppAnchorButton
className="block-details__list-anchor"
href="/blocks/block?id={data.header.prevblockhash}"
>
<Icon path={mdiArrowLeft} />
</AppAnchor>
icon={{ path: mdiArrowLeft }}
disabled={!data.header.prevblockhash}
/>
{formatter(data.header.height)}
<AppAnchor
<AppAnchorButton
className="block-details__list-anchor"
href="/blocks/block?id={data.header.nextblockhash}"
>
<Icon path={mdiArrowRight} />
</AppAnchor>
icon={{ path: mdiArrowRight }}
disabled={!data.header.nextblockhash}
/>
</svelte:fragment>
</ListItem>

Expand Down
3 changes: 2 additions & 1 deletion explorer/src/lib/components/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
export { default as DataAlert } from "./data-alert/DataAlert.svelte";
export { default as AppAnchor } from "./app-anchor/AppAnchor.svelte";
export { default as AppAnchorButton } from "./app-anchor-button/AppAnchorButton.svelte";
export { default as AppImage } from "./app-image/AppImage.svelte";
export { default as BlockDetails } from "./block-details/BlockDetails.svelte";
export { default as BlocksCard } from "./blocks-card/BlocksCard.svelte";
export { default as BlocksList } from "./blocks-list/BlocksList.svelte";
export { default as BlocksTable } from "./blocks-table/BlocksTable.svelte";
export { default as DataAlert } from "./data-alert/DataAlert.svelte";
export { default as DataCard } from "./data-card/DataCard.svelte";
export { default as DataGuard } from "./data-guard/DataGuard.svelte";
export { default as DetailList } from "./detail-list/DetailList.svelte";
Expand Down
87 changes: 87 additions & 0 deletions explorer/src/lib/dusk/components/__tests__/AnchorButton.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { afterEach, describe, expect, it } from "vitest";
import { cleanup, render } from "@testing-library/svelte";
import { mdiFolderOutline } from "@mdi/js";

import { AnchorButton } from "..";

describe("AnchorButton", () => {
const baseProps = {
href: "/some-url",
text: "some text",
};
const baseOptions = {
props: baseProps,
target: document.body,
};
const iconPositions = /** @type {const} */ (["after", "before", undefined]);

afterEach(cleanup);

it("should render the AnchorButton component", () => {
const { container } = render(AnchorButton, baseOptions);

expect(container.firstChild).toMatchSnapshot();
});

it("should add a disabled class if the related property is `true`", () => {
const props = {
...baseProps,
disabled: true,
};
const { container } = render(AnchorButton, { ...baseOptions, props });

expect(container.firstChild).toMatchSnapshot();
});

it("should pass additional class names and attributes to the rendered element", () => {
const props = {
...baseProps,
className: "foo bar",
id: "some-id",
};
const { container } = render(AnchorButton, { ...baseOptions, props });

expect(container.firstChild).toMatchSnapshot();
});

it("should render a AnchorButton without a text", () => {
const props = {
...baseProps,
text: "",
};
const { container } = render(AnchorButton, { ...baseOptions, props });

expect(container.firstChild).toMatchSnapshot();
});

it("should be able to render a AnchorButton with an icon and text", () => {
iconPositions.forEach((position) => {
const props = {
...baseProps,
icon: {
path: mdiFolderOutline,
position,
},
};
const { container } = render(AnchorButton, { ...baseOptions, props });

expect(container.firstChild).toMatchSnapshot();
});
});

it("should be able to render a AnchorButton with an icon only", () => {
iconPositions.forEach((position) => {
const props = {
...baseProps,
icon: {
path: mdiFolderOutline,
position,
},
text: "",
};
const { container } = render(AnchorButton, { ...baseOptions, props });

expect(container.firstChild).toMatchSnapshot();
});
});
});
Loading

0 comments on commit bd1d42a

Please sign in to comment.