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

explorer: disable block height navigation #1783

Merged
merged 3 commits into from
May 24, 2024
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
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
Loading