From 2454940abdbbd92bdf2224a167673bcf74013feb Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Fri, 20 Dec 2024 17:02:25 +0100 Subject: [PATCH 1/8] New LedgerNeuronHotkeyWarning component --- .../accounts/LedgerNeuronHotkeyWarning.svelte | 35 +++++++++++++++++++ frontend/src/lib/i18n/en.json | 3 +- frontend/src/lib/types/i18n.d.ts | 1 + 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 frontend/src/lib/components/accounts/LedgerNeuronHotkeyWarning.svelte diff --git a/frontend/src/lib/components/accounts/LedgerNeuronHotkeyWarning.svelte b/frontend/src/lib/components/accounts/LedgerNeuronHotkeyWarning.svelte new file mode 100644 index 00000000000..74e19a96992 --- /dev/null +++ b/frontend/src/lib/components/accounts/LedgerNeuronHotkeyWarning.svelte @@ -0,0 +1,35 @@ + + + + {#if isVisible} + + + + + + {/if} + diff --git a/frontend/src/lib/i18n/en.json b/frontend/src/lib/i18n/en.json index a037d362fae..376ae424e75 100644 --- a/frontend/src/lib/i18n/en.json +++ b/frontend/src/lib/i18n/en.json @@ -393,7 +393,8 @@ "losing_rewards": { "description": "ICP neurons that are inactive for $period start missing voting rewards. To avoid missing rewards, vote manually, edit, or confirm your following.", "confirming": "Confirming following. This may take a moment.", - "confirm": "Confirm Following" + "confirm": "Confirm Following", + "hw_hotkey_warning": "You may have neurons that are not added to the NNS dapp. If you want to view your neurons and get alerts in case they start missing voting rewards, you can add them by clicking Show Neurons > Add to NNS Dapp." }, "losing_rewards_banner": { "confirm_title": "Confirm following or vote manually to avoid missing rewards", diff --git a/frontend/src/lib/types/i18n.d.ts b/frontend/src/lib/types/i18n.d.ts index 7fcf6fb5ea3..d133c8809cc 100644 --- a/frontend/src/lib/types/i18n.d.ts +++ b/frontend/src/lib/types/i18n.d.ts @@ -408,6 +408,7 @@ interface I18nLosing_rewards { description: string; confirming: string; confirm: string; + hw_hotkey_warning: string; } interface I18nLosing_rewards_banner { From 94be42b6503e123b08579f2b4fe7f498cd806a6d Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Fri, 20 Dec 2024 17:03:34 +0100 Subject: [PATCH 2/8] Display LedgerNeuronHotkeyWarning --- frontend/src/lib/pages/NnsWallet.svelte | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frontend/src/lib/pages/NnsWallet.svelte b/frontend/src/lib/pages/NnsWallet.svelte index bad0f058f53..7cd7841afb3 100644 --- a/frontend/src/lib/pages/NnsWallet.svelte +++ b/frontend/src/lib/pages/NnsWallet.svelte @@ -76,6 +76,8 @@ } from "@dfinity/utils"; import { onDestroy, onMount, setContext } from "svelte"; import { writable, type Readable } from "svelte/store"; + import { ENABLE_PERIODIC_FOLLOWING_CONFIRMATION } from "$lib/stores/feature-flags.store"; + import LedgerNeuronHotkeyWarning from "$lib/components/accounts/LedgerNeuronHotkeyWarning.svelte"; $: if ($authSignedInStore) { pollAccounts(); @@ -381,6 +383,10 @@ + {#if $ENABLE_PERIODIC_FOLLOWING_CONFIRMATION && isHardwareWallet} + + {/if} + {#if $selectedAccountStore.account !== undefined} From dd321bb49d712196fb160d4659d2f6183e0c0e26 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Fri, 20 Dec 2024 17:03:56 +0100 Subject: [PATCH 3/8] test: LedgerNeuronHotkeyWarning --- .../LedgerNeuronHotkeyWarning.spec.ts | 46 +++++++++++++++++++ .../LedgerNeuronHotkeyWarning.page-object.ts | 21 +++++++++ 2 files changed, 67 insertions(+) create mode 100644 frontend/src/tests/lib/components/accounts/LedgerNeuronHotkeyWarning.spec.ts create mode 100644 frontend/src/tests/page-objects/LedgerNeuronHotkeyWarning.page-object.ts diff --git a/frontend/src/tests/lib/components/accounts/LedgerNeuronHotkeyWarning.spec.ts b/frontend/src/tests/lib/components/accounts/LedgerNeuronHotkeyWarning.spec.ts new file mode 100644 index 00000000000..31f541ca8ec --- /dev/null +++ b/frontend/src/tests/lib/components/accounts/LedgerNeuronHotkeyWarning.spec.ts @@ -0,0 +1,46 @@ +import { LedgerNeuronHotkeyWarningPo } from "$tests/page-objects/LedgerNeuronHotkeyWarning.page-object"; +import { JestPageObjectElement } from "$tests/page-objects/jest.page-object"; +import { render } from "@testing-library/svelte"; +import LedgerNeuronHotkeyWarning from "$lib/components/accounts/LedgerNeuronHotkeyWarning.svelte"; + +describe("LedgerNeuronHotkeyWarning", () => { + const localStorageKey = "isLedgerNeuronHotkeyWarningDisabled"; + const renderComponent = () => { + const { container } = render(LedgerNeuronHotkeyWarning); + return LedgerNeuronHotkeyWarningPo.under( + new JestPageObjectElement(container) + ); + }; + + beforeEach(() => { + localStorage.clear(); + }); + + it("should be shown when localStorageKey not set", async () => { + const po = await renderComponent(); + expect(localStorage.getItem(localStorageKey)).toBeNull(); + + expect(await po.isBannerVisible()).toBe(true); + }); + + it("should not render when localStorageKey is set to true", async () => { + localStorage.setItem(localStorageKey, "true"); + const po = await renderComponent(); + + expect(await po.isBannerVisible()).toBe(false); + }); + + + it("should be closable", async () => { + const po = await renderComponent(); + + expect(await po.isBannerVisible()).toBe(true); + expect(localStorage.getItem(localStorageKey)).toBeNull(); + + await po.getBannerPo().clickClose(); + + expect(await po.isBannerVisible()).toBe(false); + expect(localStorage.getItem(localStorageKey)).toEqual("true"); + }); + +}); diff --git a/frontend/src/tests/page-objects/LedgerNeuronHotkeyWarning.page-object.ts b/frontend/src/tests/page-objects/LedgerNeuronHotkeyWarning.page-object.ts new file mode 100644 index 00000000000..38de152b758 --- /dev/null +++ b/frontend/src/tests/page-objects/LedgerNeuronHotkeyWarning.page-object.ts @@ -0,0 +1,21 @@ +import { BasePageObject } from "$tests/page-objects/base.page-object"; +import type { PageObjectElement } from "$tests/types/page-object.types"; +import { BannerPo } from "./Banner.page-object"; + +export class LedgerNeuronHotkeyWarningPo extends BasePageObject { + private static readonly TID = "ledger-neuron-hotkey-warning-component"; + + static under(element: PageObjectElement): LedgerNeuronHotkeyWarningPo { + return new LedgerNeuronHotkeyWarningPo( + element.byTestId(LedgerNeuronHotkeyWarningPo.TID) + ); + } + + getBannerPo(): BannerPo { + return BannerPo.under(this.root); + } + + async isBannerVisible(): Promise { + return this.getBannerPo().isPresent(); + } +} From 533ed519d5fb0adfb65740a5d3fccbb331830078 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Fri, 20 Dec 2024 17:04:07 +0100 Subject: [PATCH 4/8] test: LedgerNeuronHotkeyWarning visibility --- .../src/tests/lib/pages/NnsWallet.spec.ts | 24 +++++++++++++++++++ .../page-objects/NnsWallet.page-object.ts | 5 ++++ 2 files changed, 29 insertions(+) diff --git a/frontend/src/tests/lib/pages/NnsWallet.spec.ts b/frontend/src/tests/lib/pages/NnsWallet.spec.ts index e1e4c8795b8..70363c0cf10 100644 --- a/frontend/src/tests/lib/pages/NnsWallet.spec.ts +++ b/frontend/src/tests/lib/pages/NnsWallet.spec.ts @@ -59,6 +59,8 @@ import { Principal } from "@dfinity/principal"; import { get } from "svelte/store"; import type { MockInstance } from "vitest"; import AccountsTest from "./AccountsTest.svelte"; +import { overrideFeatureFlagsStore } from "../../../lib/stores/feature-flags.store"; +import { allowLoggingInOneTestForDebugging } from "../../utils/console.test-utils"; vi.mock("$lib/api/nns-dapp.api"); vi.mock("$lib/api/accounts.api"); @@ -408,6 +410,12 @@ describe("NnsWallet", () => { expect(await po.getWalletPageHeadingPo().getTitle()).toBe("4.32 ICP"); }); + it("should not render Ledger neuron hotkey warning for not HW wallet", async () => { + overrideFeatureFlagsStore.setFlag("ENABLE_PERIODIC_FOLLOWING_CONFIRMATION", true); + const po = await renderWallet(props); + expect(await po.getLedgerNeuronHotkeyWarningPo().isBannerVisible()).toBe(false); + }); + it("should reload balance on open", async () => { const oldBalance = 135_000_000n; const oldBalanceFormatted = "1.35 ICP"; @@ -1008,6 +1016,22 @@ describe("NnsWallet", () => { expect(await po.getShowHardwareWalletButtonPo().isPresent()).toBe(true); }); + it("should display Ledger neuron hotkey warning", async () => { + overrideFeatureFlagsStore.setFlag("ENABLE_PERIODIC_FOLLOWING_CONFIRMATION", true); + const po = await renderWallet(props); + allowLoggingInOneTestForDebugging(); + + expect(await po.getLedgerNeuronHotkeyWarningPo().isBannerVisible()).toBe(true); + }); + + it("should not display Ledger neuron hotkey warning when feature flag off", async () => { + overrideFeatureFlagsStore.setFlag("ENABLE_PERIODIC_FOLLOWING_CONFIRMATION", false); + const po = await renderWallet(props); + allowLoggingInOneTestForDebugging(); + + expect(await po.getLedgerNeuronHotkeyWarningPo().isBannerVisible()).toBe(false); + }); + describe("when there are staking transactions", () => { const neuronController = testHwPrincipal; const memo = 54321n; diff --git a/frontend/src/tests/page-objects/NnsWallet.page-object.ts b/frontend/src/tests/page-objects/NnsWallet.page-object.ts index 72f83015bf1..4747e37e625 100644 --- a/frontend/src/tests/page-objects/NnsWallet.page-object.ts +++ b/frontend/src/tests/page-objects/NnsWallet.page-object.ts @@ -6,6 +6,7 @@ import { WalletPageHeaderPo } from "$tests/page-objects/WalletPageHeader.page-ob import { WalletPageHeadingPo } from "$tests/page-objects/WalletPageHeading.page-object"; import { BasePageObject } from "$tests/page-objects/base.page-object"; import type { PageObjectElement } from "$tests/types/page-object.types"; +import { LedgerNeuronHotkeyWarningPo } from "./LedgerNeuronHotkeyWarning.page-object"; import { UiTransactionsListPo } from "./UiTransactionsList.page-object"; export class NnsWalletPo extends BasePageObject { @@ -51,6 +52,10 @@ export class NnsWalletPo extends BasePageObject { return this.getButton("ledger-list-button"); } + getLedgerNeuronHotkeyWarningPo(): LedgerNeuronHotkeyWarningPo { + return LedgerNeuronHotkeyWarningPo.under(this.root); + } + getShowHardwareWalletButtonPo(): ButtonPo { return this.getButton("ledger-show-button"); } From 97cc47d5692152bfdc9df42783455ee77d471cb7 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Fri, 20 Dec 2024 17:12:29 +0100 Subject: [PATCH 5/8] formatting. --- .../LedgerNeuronHotkeyWarning.spec.ts | 6 ++-- .../src/tests/lib/pages/NnsWallet.spec.ts | 31 +++++++++++++------ 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/frontend/src/tests/lib/components/accounts/LedgerNeuronHotkeyWarning.spec.ts b/frontend/src/tests/lib/components/accounts/LedgerNeuronHotkeyWarning.spec.ts index 31f541ca8ec..d0708051ba6 100644 --- a/frontend/src/tests/lib/components/accounts/LedgerNeuronHotkeyWarning.spec.ts +++ b/frontend/src/tests/lib/components/accounts/LedgerNeuronHotkeyWarning.spec.ts @@ -1,7 +1,7 @@ +import LedgerNeuronHotkeyWarning from "$lib/components/accounts/LedgerNeuronHotkeyWarning.svelte"; import { LedgerNeuronHotkeyWarningPo } from "$tests/page-objects/LedgerNeuronHotkeyWarning.page-object"; import { JestPageObjectElement } from "$tests/page-objects/jest.page-object"; import { render } from "@testing-library/svelte"; -import LedgerNeuronHotkeyWarning from "$lib/components/accounts/LedgerNeuronHotkeyWarning.svelte"; describe("LedgerNeuronHotkeyWarning", () => { const localStorageKey = "isLedgerNeuronHotkeyWarningDisabled"; @@ -19,7 +19,7 @@ describe("LedgerNeuronHotkeyWarning", () => { it("should be shown when localStorageKey not set", async () => { const po = await renderComponent(); expect(localStorage.getItem(localStorageKey)).toBeNull(); - + expect(await po.isBannerVisible()).toBe(true); }); @@ -30,7 +30,6 @@ describe("LedgerNeuronHotkeyWarning", () => { expect(await po.isBannerVisible()).toBe(false); }); - it("should be closable", async () => { const po = await renderComponent(); @@ -42,5 +41,4 @@ describe("LedgerNeuronHotkeyWarning", () => { expect(await po.isBannerVisible()).toBe(false); expect(localStorage.getItem(localStorageKey)).toEqual("true"); }); - }); diff --git a/frontend/src/tests/lib/pages/NnsWallet.spec.ts b/frontend/src/tests/lib/pages/NnsWallet.spec.ts index 70363c0cf10..d81a01e6b97 100644 --- a/frontend/src/tests/lib/pages/NnsWallet.spec.ts +++ b/frontend/src/tests/lib/pages/NnsWallet.spec.ts @@ -58,9 +58,8 @@ import { memoToNeuronAccountIdentifier } from "@dfinity/nns"; import { Principal } from "@dfinity/principal"; import { get } from "svelte/store"; import type { MockInstance } from "vitest"; +import { overrideFeatureFlagsStore } from "$lib/stores/feature-flags.store"; import AccountsTest from "./AccountsTest.svelte"; -import { overrideFeatureFlagsStore } from "../../../lib/stores/feature-flags.store"; -import { allowLoggingInOneTestForDebugging } from "../../utils/console.test-utils"; vi.mock("$lib/api/nns-dapp.api"); vi.mock("$lib/api/accounts.api"); @@ -411,9 +410,14 @@ describe("NnsWallet", () => { }); it("should not render Ledger neuron hotkey warning for not HW wallet", async () => { - overrideFeatureFlagsStore.setFlag("ENABLE_PERIODIC_FOLLOWING_CONFIRMATION", true); + overrideFeatureFlagsStore.setFlag( + "ENABLE_PERIODIC_FOLLOWING_CONFIRMATION", + true + ); const po = await renderWallet(props); - expect(await po.getLedgerNeuronHotkeyWarningPo().isBannerVisible()).toBe(false); + expect(await po.getLedgerNeuronHotkeyWarningPo().isBannerVisible()).toBe( + false + ); }); it("should reload balance on open", async () => { @@ -1017,19 +1021,28 @@ describe("NnsWallet", () => { }); it("should display Ledger neuron hotkey warning", async () => { - overrideFeatureFlagsStore.setFlag("ENABLE_PERIODIC_FOLLOWING_CONFIRMATION", true); + overrideFeatureFlagsStore.setFlag( + "ENABLE_PERIODIC_FOLLOWING_CONFIRMATION", + true + ); const po = await renderWallet(props); allowLoggingInOneTestForDebugging(); - expect(await po.getLedgerNeuronHotkeyWarningPo().isBannerVisible()).toBe(true); + expect(await po.getLedgerNeuronHotkeyWarningPo().isBannerVisible()).toBe( + true + ); }); it("should not display Ledger neuron hotkey warning when feature flag off", async () => { - overrideFeatureFlagsStore.setFlag("ENABLE_PERIODIC_FOLLOWING_CONFIRMATION", false); + overrideFeatureFlagsStore.setFlag( + "ENABLE_PERIODIC_FOLLOWING_CONFIRMATION", + false + ); const po = await renderWallet(props); - allowLoggingInOneTestForDebugging(); - expect(await po.getLedgerNeuronHotkeyWarningPo().isBannerVisible()).toBe(false); + expect(await po.getLedgerNeuronHotkeyWarningPo().isBannerVisible()).toBe( + false + ); }); describe("when there are staking transactions", () => { From 1c2f6d0f2171ce444e848bdddab75b3995e9cc3d Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Fri, 20 Dec 2024 17:14:16 +0100 Subject: [PATCH 6/8] Remove logs --- frontend/src/tests/lib/pages/NnsWallet.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/tests/lib/pages/NnsWallet.spec.ts b/frontend/src/tests/lib/pages/NnsWallet.spec.ts index d81a01e6b97..f1162bf5a76 100644 --- a/frontend/src/tests/lib/pages/NnsWallet.spec.ts +++ b/frontend/src/tests/lib/pages/NnsWallet.spec.ts @@ -1026,7 +1026,6 @@ describe("NnsWallet", () => { true ); const po = await renderWallet(props); - allowLoggingInOneTestForDebugging(); expect(await po.getLedgerNeuronHotkeyWarningPo().isBannerVisible()).toBe( true From 2195afd6322a1dd50630261c00d3c01c2ce093e8 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Fri, 20 Dec 2024 17:19:19 +0100 Subject: [PATCH 7/8] Formatting --- frontend/src/tests/lib/pages/NnsWallet.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/tests/lib/pages/NnsWallet.spec.ts b/frontend/src/tests/lib/pages/NnsWallet.spec.ts index f1162bf5a76..d624cde4f94 100644 --- a/frontend/src/tests/lib/pages/NnsWallet.spec.ts +++ b/frontend/src/tests/lib/pages/NnsWallet.spec.ts @@ -14,6 +14,7 @@ import { AppPath } from "$lib/constants/routes.constants"; import { pageStore } from "$lib/derived/page.derived"; import NnsWallet from "$lib/pages/NnsWallet.svelte"; import { cancelPollAccounts } from "$lib/services/icp-accounts.services"; +import { overrideFeatureFlagsStore } from "$lib/stores/feature-flags.store"; import { icpTransactionsStore } from "$lib/stores/icp-transactions.store"; import { neuronsStore } from "$lib/stores/neurons.store"; import { getSwapCanisterAccount } from "$lib/utils/sns.utils"; @@ -58,7 +59,6 @@ import { memoToNeuronAccountIdentifier } from "@dfinity/nns"; import { Principal } from "@dfinity/principal"; import { get } from "svelte/store"; import type { MockInstance } from "vitest"; -import { overrideFeatureFlagsStore } from "$lib/stores/feature-flags.store"; import AccountsTest from "./AccountsTest.svelte"; vi.mock("$lib/api/nns-dapp.api"); From 37abb66b156984709840a3f157ebf966d7cfa918 Mon Sep 17 00:00:00 2001 From: Max Strasinsky Date: Fri, 20 Dec 2024 17:43:01 +0100 Subject: [PATCH 8/8] cleanup --- .../lib/components/accounts/LedgerNeuronHotkeyWarning.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/lib/components/accounts/LedgerNeuronHotkeyWarning.svelte b/frontend/src/lib/components/accounts/LedgerNeuronHotkeyWarning.svelte index 74e19a96992..5f88f943728 100644 --- a/frontend/src/lib/components/accounts/LedgerNeuronHotkeyWarning.svelte +++ b/frontend/src/lib/components/accounts/LedgerNeuronHotkeyWarning.svelte @@ -11,7 +11,7 @@ let isDismissed = browser ? Boolean(JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEY) ?? "false")) : false; - let isVisible: boolean = false; + let isVisible = false; $: isVisible = !isDismissed; function dismissBanner() {