Skip to content

Commit

Permalink
web-wallet: Add possibility to serve the web wallet from a sub folder
Browse files Browse the repository at this point in the history
Resolves #1362
  • Loading branch information
ascartabelli committed Feb 9, 2024
1 parent 871fb3c commit fb8fe48
Show file tree
Hide file tree
Showing 47 changed files with 537 additions and 77 deletions.
2 changes: 2 additions & 0 deletions web-wallet/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add `fiatPrice` optional property to Balance component [#1331](https://github.com/dusk-network/rusk/pull/1331)
- Add ability to revert words when entering the mnemonic phrase [#1333](https://github.com/dusk-network/rusk/pull/1333)
- Add missing error handling when querying the quote API [#1344](https://github.com/dusk-network/rusk/pull/1334)
- Add `VITE_BASE_PATH` env variable [#1362](https://github.com/dusk-network/rusk/tree/feature-1362)
- Add possibility to serve the web wallet from a sub folder [#1362](https://github.com/dusk-network/rusk/tree/feature-1362)

### Changed

Expand Down
4 changes: 3 additions & 1 deletion web-wallet/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ The application defines these variables by reading a local `.env` file containin
N.B. the current `0.1.2` version of the library has no option to pick the network and uses the `LOCAL_NODE` only. The current testnet address is set in that variable in the example below:

```
# can be empty string, must start with a slash otherwise, must not end with a slash
VITE_BASE_PATH=""
VITE_CONTRACT_STAKE_DISABLED=false
VITE_CONTRACT_TRANSFER_DISABLED=false
VITE_CURRENT_NODE=${VITE_LOCAL_NODE}
Expand Down Expand Up @@ -67,4 +69,4 @@ To run a local node different steps are needed, so please read the [related sect

## Running a local Rusk node

To run a local node, follow the instructions outlined in the [Rusk's readme](https://github.com/dusk-network/rusk).
To run a local node, follow the instructions outlined in the [Rusk's readme](https://github.com/dusk-network/rusk).
17 changes: 17 additions & 0 deletions web-wallet/src/lib/components/AppAnchor/AppAnchor.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<svelte:options immutable={true}/>

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

<Anchor
{...$$restProps}
href={addBasePath(href)}
on:click
>
<slot/>
</Anchor>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<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
/>
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

<script>
import {
AnchorButton,
ErrorDetails,
Icon,
Throbber
} from "$lib/dusk/components";
import { mdiCheckDecagramOutline, mdiCloseThick } from "@mdi/js";
import { makeClassName } from "$lib/dusk/string";
import { AppAnchorButton } from "$lib/components";
/** @type {string|undefined} */
export let className = undefined;
Expand Down Expand Up @@ -49,7 +49,7 @@
/>
<span>{successMessage}</span>
<slot name="success-content" {result}/>
<AnchorButton
<AppAnchorButton
href="/dashboard"
on:click={handleGoHomeClick}
variant="tertiary"
Expand All @@ -65,7 +65,7 @@
summary={errorMessage}
/>
<slot name="error-content"/>
<AnchorButton
<AppAnchorButton
href="/dashboard"
on:click={handleGoHomeClick}
variant="tertiary"
Expand Down
4 changes: 2 additions & 2 deletions web-wallet/src/lib/components/Send/Send.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import { luxToDusk } from "$lib/dusk/currency";
import { logo } from "$lib/dusk/icons";
import {
AnchorButton,
Badge,
Button,
Icon,
Expand All @@ -18,6 +17,7 @@
WizardStep
} from "$lib/dusk/components";
import {
AppAnchorButton,
ContractStatusesList,
GasFee,
GasSettings,
Expand Down Expand Up @@ -224,7 +224,7 @@
>
<svelte:fragment slot="success-content" let:result={hash}>
{#if hash}
<AnchorButton
<AppAnchorButton
href={`https://explorer.dusk.network/transactions/transaction?id=${hash}`}
on:click={resetOperation}
text="VIEW ON BLOCK EXPLORER"
Expand Down
4 changes: 2 additions & 2 deletions web-wallet/src/lib/components/Stake/Stake.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import { luxToDusk } from "$lib/dusk/currency";
import { logo } from "$lib/dusk/icons";
import {
AnchorButton,
Badge,
Button,
Icon,
Expand All @@ -18,6 +17,7 @@
WizardStep
} from "$lib/dusk/components";
import {
AppAnchorButton,
ContractStatusesList,
GasFee,
GasSettings,
Expand Down Expand Up @@ -212,7 +212,7 @@
>
<svelte:fragment slot="success-content" let:result={hash}>
{#if hash}
<AnchorButton
<AppAnchorButton
href={`https://explorer.dusk.network/transactions/transaction?id=${hash}`}
on:click={resetOperation}
text="VIEW ON BLOCK EXPLORER"
Expand Down
13 changes: 7 additions & 6 deletions web-wallet/src/lib/components/Transactions/Transactions.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
import { fade } from "svelte/transition";
import { logo } from "$lib/dusk/icons";
import {
Anchor,
AnchorButton,
Badge,
ErrorDetails,
Icon,
Expand All @@ -16,6 +14,9 @@
import { calculateAdaptiveCharCount, middleEllipsis } from "$lib/dusk/string";
import { sortByHeightDesc } from "$lib/transactions";
import AppAnchor from "../AppAnchor/AppAnchor.svelte";
import AppAnchorButton from "../AppAnchorButton/AppAnchorButton.svelte";
/** @type {String} */
export let language;
Expand Down Expand Up @@ -65,7 +66,7 @@
<dt class="transactions-list__term">Hash</dt>
<dd class="transactions-list__datum transactions-list__datum--hash">
<samp>
<Anchor
<AppAnchor
href="https://explorer.dusk.network/transactions/transaction?id={transaction.id}"
rel="noopener noreferrer"
target="_blank"
Expand All @@ -74,7 +75,7 @@
transaction.id,
calculateAdaptiveCharCount(screenWidth, 320, 640, 5, 20)
)}
</Anchor>
</AppAnchor>
</samp>
</dd>
{#if transaction.tx_type}
Expand Down Expand Up @@ -127,14 +128,14 @@

<footer class="transactions__footer">
{#if limit}
<AnchorButton
<AppAnchorButton
className="transactions__footer-button"
href="/dashboard/transactions"
text="View all transactions"
variant="tertiary"
/>
{:else}
<AnchorButton
<AppAnchorButton
className="transactions__footer-button"
href="/dashboard"
text="Back"
Expand Down
83 changes: 83 additions & 0 deletions web-wallet/src/lib/components/__tests__/AppAnchor.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import {
afterEach,
describe,
expect,
it,
vi
} from "vitest";
import {
cleanup,
fireEvent,
render
} from "@testing-library/svelte";
import { base } from "$app/paths";

import { renderWithSimpleContent } from "$lib/dusk/test-helpers";

import { AppAnchor } from "..";

describe("AppAnchor", () => {
const baseProps = {
className: "foo bar",
href: "/setup",
id: "some-id"
};
const baseOptions = {
props: baseProps,
target: document.body
};

afterEach(cleanup);

it("should render an `Anchor` with the base path prepended to the `href` attribute, if the `href` represents an absolute URL", () => {
const renderA = renderWithSimpleContent(AppAnchor, baseOptions);
const anchorA = renderA.getByRole("link");

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

cleanup();

const renderB = renderWithSimpleContent(
AppAnchor,
{ ...baseOptions, props: { ...baseProps, href: "/" } }
);
const anchorB = renderB.getByRole("link");

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

it("should leave the `Anchor` as it is if the `href` points to a relative path", () => {
const { getByRole } = renderWithSimpleContent(
AppAnchor,
{ ...baseOptions, props: { ...baseProps, href: "foo/bar" } }
);

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

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

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

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

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

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

expect(handler).toHaveBeenCalledTimes(1);
});
});
67 changes: 67 additions & 0 deletions web-wallet/src/lib/components/__tests__/AppAnchorButton.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
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);
});
});
7 changes: 4 additions & 3 deletions web-wallet/src/lib/components/__tests__/Transactions.spec.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { cleanup, render } from "@testing-library/svelte";
import { afterEach, describe, expect, it, vi } from "vitest";
import { get } from "svelte/store";
import { settingsStore } from "$lib/stores";
import { base } from "$app/paths";

import { settingsStore } from "$lib/stores";
import { transactions } from "$lib/mock-data";
import { sortByHeightDesc } from "$lib/transactions";
import { createFeeFormatter, createTransferFormatter } from "$lib/dusk/currency";
Expand Down Expand Up @@ -145,7 +146,7 @@ describe("Transactions", () => {
const viewAllTransactionAnchor = getByRole("link", { name: "View all transactions" });

expect(viewAllTransactionAnchor).toBeInTheDocument();
expect(viewAllTransactionAnchor).toHaveAttribute("href", "/dashboard/transactions");
expect(viewAllTransactionAnchor).toHaveAttribute("href", `${base}/dashboard/transactions`);
});

it("displays the \"Back\" CTA if no limit is supplied", async () => {
Expand All @@ -158,7 +159,7 @@ describe("Transactions", () => {
const viewAllTransactionAnchor = getByRole("link", { name: "Back" });

expect(viewAllTransactionAnchor).toBeInTheDocument();
expect(viewAllTransactionAnchor).toHaveAttribute("href", "/dashboard");
expect(viewAllTransactionAnchor).toHaveAttribute("href", `${base}/dashboard`);
});

it("handles error state when items are rejected", async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`AppAnchor > should render an \`Anchor\` with the base path prepended to the \`href\` attribute, if the \`href\` represents an absolute URL 1`] = `
<a
class="dusk-anchor foo bar"
href="/some-base-path/setup"
id="some-id"
>
<span>
some text
</span>
</a>
`;
Loading

0 comments on commit fb8fe48

Please sign in to comment.