Skip to content

Commit

Permalink
web-wallet: wallet doesn't wait for the Wasm to load at startup
Browse files Browse the repository at this point in the history
Resolves #3238
  • Loading branch information
ascartabelli committed Dec 20, 2024
1 parent 4c8fca7 commit 5f83cc7
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 36 deletions.
2 changes: 2 additions & 0 deletions web-wallet/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed

- Fix wrong error shown in the login screen [#3226] [#3097]
- Fix wallet not waiting for the Wasm to load at startup [#3238]

## [0.10.1] - 2024-12-18

Expand Down Expand Up @@ -470,6 +471,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[#3203]: https://github.com/dusk-network/rusk/issues/3203
[#3212]: https://github.com/dusk-network/rusk/issues/3212
[#3226]: https://github.com/dusk-network/rusk/issues/3226
[#3238]: https://github.com/dusk-network/rusk/issues/3238
[#3245]: https://github.com/dusk-network/rusk/issues/3245

<!-- VERSIONS -->
Expand Down
13 changes: 11 additions & 2 deletions web-wallet/src/lib/components/Banner/Banner.svelte
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
<svelte:options immutable={true} />

<script>
import { Icon } from "$lib/dusk/components";
import {
mdiAlertCircleOutline,
mdiAlertDecagramOutline,
mdiAlertOutline,
} from "@mdi/js";
import { makeClassName } from "$lib/dusk/string";
import { Icon } from "$lib/dusk/components";
import "./Banner.css";
/** @type {string | undefined} */
export let className = undefined;
/** @type {string} */
export let title;
Expand All @@ -24,9 +31,11 @@
return mdiAlertCircleOutline;
}
}
$: classes = makeClassName(["banner", `banner--${variant}`, className]);
</script>

<div class="banner banner--{variant}">
<div {...$$restProps} class={classes}>
<Icon
path={getBannerIconPath()}
size="large"
Expand Down
10 changes: 8 additions & 2 deletions web-wallet/src/lib/stores/__tests__/walletStore.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -229,9 +229,15 @@ describe("Wallet store", async () => {
);

expect(clearTimeoutSpy).toHaveBeenCalledTimes(1);
expect(setTimeoutSpy).toHaveBeenCalledTimes(1);

/**
* The first call is caused by the timeout in the network
* connect, so we check the last call, that is the one
* made in the wallet store.
*/
expect(setTimeoutSpy).toHaveBeenCalledTimes(2);
expect(clearTimeoutSpy.mock.invocationCallOrder[0]).toBeLessThan(
setTimeoutSpy.mock.invocationCallOrder[0]
setTimeoutSpy.mock.invocationCallOrder[1]
);

await vi.advanceTimersByTimeAsync(1);
Expand Down
12 changes: 11 additions & 1 deletion web-wallet/src/lib/stores/networkStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
AddressSyncer,
Network,
} from "$lib/vendor/w3sper.js/src/mod";
import { rejectAfter } from "$lib/dusk/promise";
import { makeNodeUrl } from "$lib/url";

function getNetworkUrl() {
Expand Down Expand Up @@ -50,7 +51,16 @@ const checkBlock = (height, hash) =>
.then(getKey("checkBlock"));

/** @type {NetworkStoreServices["connect"]} */
const connect = async () => (network.connected ? network : network.connect());
const connect = async () =>
network.connected
? network
: Promise.race([
network.connect(),
rejectAfter(
10000,
new Error("Timed out while connecting to the network")
),
]);

/** @type {NetworkStoreServices["disconnect"]} */
const disconnect = () => network.disconnect();
Expand Down
61 changes: 58 additions & 3 deletions web-wallet/src/routes/(welcome)/+layout.svelte
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
<script>
import { AppImage } from "$lib/components";
import { settingsStore } from "$lib/stores";
import { ErrorDetails, Throbber } from "$lib/dusk/components";
import { AppAnchor, AppImage, Banner } from "$lib/components";
import { networkStore, settingsStore } from "$lib/stores";
const { darkMode } = $settingsStore;
let retryKey = 0;
/** @param {Event} event */
function handleRetry(event) {
event.preventDefault();
retryKey ^= 1;
}
</script>

<header>
Expand All @@ -13,5 +23,50 @@
height="31"
/>
</header>
{#key retryKey}
{#await networkStore.connect().then(() => networkStore.init())}
<div class="welcome-layout__loading">
<Throbber />
<strong>CONNECTING TO THE NETWORK</strong>
</div>
{:then}
<slot />
{:catch error}
<Banner
className="welcome-layout__error"
title="Error while trying to connect to the network"
variant="error"
>
<p>
The Web Wallet is unable to connect to the network.<br />
This may be a temporary issue.<br />
Please try again in a few minutes by clicking <AppAnchor
href="/setup"
on:click={handleRetry}>retry</AppAnchor
>.
</p>
<ErrorDetails {error} summary="Error details" />
</Banner>
{/await}
{/key}

<style lang="postcss">
:global {
.welcome-layout__error,
.welcome-layout__loading {
margin-top: 10dvh;
}
.welcome-layout__error > .banner__content {
gap: var(--medium-gap);
}
<slot />
.welcome-layout__loading {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
gap: var(--medium-gap);
}
}
</style>
12 changes: 1 addition & 11 deletions web-wallet/src/routes/+layout.svelte
Original file line number Diff line number Diff line change
@@ -1,22 +1,12 @@
<script>
import { onDestroy, onMount } from "svelte";
import { networkStore, settingsStore } from "$lib/stores";
import { settingsStore } from "$lib/stores";
import { Toast, Tooltip } from "$lib/dusk/components";
import "../style/main.css";
settingsStore.subscribe(({ darkMode }) => {
document.documentElement.classList.toggle("dark", darkMode);
});
onDestroy(async () => {
await networkStore.disconnect();
});
onMount(async () => {
await networkStore.connect();
await networkStore.init();
});
</script>

<main class="app">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`Main layout > should render the main layout and disconnect from the network when dismounting 1`] = `
exports[`Main layout > should render the main layout 1`] = `
<div>
<main
class="app svelte-3y7xzm"
Expand Down
20 changes: 4 additions & 16 deletions web-wallet/src/routes/__tests__/layout.spec.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,25 @@
import { afterAll, afterEach, describe, expect, it, vi } from "vitest";
import { afterEach, describe, expect, it } from "vitest";
import { cleanup, render } from "@testing-library/svelte";
import { get } from "svelte/store";

import { networkStore, settingsStore } from "$lib/stores";
import { settingsStore } from "$lib/stores";

import MainLayout from "../+layout.svelte";

describe("Main layout", async () => {
const isDarkMode = () => get(settingsStore).darkMode;
const hasDarkClass = () =>
document.documentElement.classList.contains("dark");
const networkDisconnectSpy = vi
.spyOn(networkStore, "disconnect")
.mockResolvedValue(undefined);

afterEach(() => {
cleanup();
settingsStore.reset();
networkDisconnectSpy.mockClear();
});

afterAll(() => {
networkDisconnectSpy.mockRestore();
});

it("should render the main layout and disconnect from the network when dismounting", () => {
const { container, unmount } = render(MainLayout);
it("should render the main layout", () => {
const { container } = render(MainLayout);

expect(container).toMatchSnapshot();

unmount();

expect(networkDisconnectSpy).toHaveBeenCalledTimes(1);
});

it('should add and remove the "dark" class name to the `html` element when the `darkMode` value changes in thesettings store', () => {
Expand Down

0 comments on commit 5f83cc7

Please sign in to comment.