Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/dfinity/nns-dapp into NNS1-…
Browse files Browse the repository at this point in the history
…3349-add-neuron-visibility-toggle
  • Loading branch information
coskucinkilic committed Oct 1, 2024
2 parents 6c0d59d + 0521511 commit 33759e8
Show file tree
Hide file tree
Showing 21 changed files with 227 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Candid for canister `sns_governance` obtained by `scripts/update_ic_commit` from: <https://raw.githubusercontent.com/dfinity/ic/release-2024-09-19_01-31-base/rs/sns/governance/canister/governance.did>
//! Candid for canister `sns_governance` obtained by `scripts/update_ic_commit` from: <https://raw.githubusercontent.com/dfinity/ic/release-2024-09-26_01-31-no-canister-snapshots/rs/sns/governance/canister/governance.did>
type Account = record {
owner : opt principal;
subaccount : opt Subaccount;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Candid for canister `sns_ledger` obtained by `scripts/update_ic_commit` from: <https://raw.githubusercontent.com/dfinity/ic/release-2024-09-19_01-31-base/rs/rosetta-api/icrc1/ledger/ledger.did>
//! Candid for canister `sns_ledger` obtained by `scripts/update_ic_commit` from: <https://raw.githubusercontent.com/dfinity/ic/release-2024-09-26_01-31-no-canister-snapshots/rs/rosetta-api/icrc1/ledger/ledger.did>
type BlockIndex = nat;
type Subaccount = blob;
// Number of nanoseconds since the UNIX epoch in UTC timezone.
Expand Down
2 changes: 1 addition & 1 deletion declarations/used_by_sns_aggregator/sns_root/sns_root.did
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Candid for canister `sns_root` obtained by `scripts/update_ic_commit` from: <https://raw.githubusercontent.com/dfinity/ic/release-2024-09-19_01-31-base/rs/sns/root/canister/root.did>
//! Candid for canister `sns_root` obtained by `scripts/update_ic_commit` from: <https://raw.githubusercontent.com/dfinity/ic/release-2024-09-26_01-31-no-canister-snapshots/rs/sns/root/canister/root.did>
type CanisterCallError = record {
code : opt int32;
description : text;
Expand Down
2 changes: 1 addition & 1 deletion declarations/used_by_sns_aggregator/sns_swap/sns_swap.did
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Candid for canister `sns_swap` obtained by `scripts/update_ic_commit` from: <https://raw.githubusercontent.com/dfinity/ic/release-2024-09-19_01-31-base/rs/sns/swap/canister/swap.did>
//! Candid for canister `sns_swap` obtained by `scripts/update_ic_commit` from: <https://raw.githubusercontent.com/dfinity/ic/release-2024-09-26_01-31-no-canister-snapshots/rs/sns/swap/canister/swap.did>
type BuyerState = record {
icp : opt TransferableAmount;
has_created_neuron_recipes : opt bool;
Expand Down
2 changes: 1 addition & 1 deletion declarations/used_by_sns_aggregator/sns_wasm/sns_wasm.did
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Candid for canister `sns_wasm` obtained by `scripts/update_ic_commit` from: <https://raw.githubusercontent.com/dfinity/ic/release-2024-09-19_01-31-base/rs/nns/sns-wasm/canister/sns-wasm.did>
//! Candid for canister `sns_wasm` obtained by `scripts/update_ic_commit` from: <https://raw.githubusercontent.com/dfinity/ic/release-2024-09-26_01-31-no-canister-snapshots/rs/nns/sns-wasm/canister/sns-wasm.did>
type AddWasmRequest = record {
hash : blob;
wasm : opt SnsWasm;
Expand Down
2 changes: 1 addition & 1 deletion dfx.json
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@
"CARGO_SORT_VERSION": "1.0.9",
"SNSDEMO_RELEASE": "release-2024-09-25",
"IC_COMMIT_FOR_PROPOSALS": "release-2024-09-26_01-31-no-canister-snapshots",
"IC_COMMIT_FOR_SNS_AGGREGATOR": "release-2024-09-19_01-31-base"
"IC_COMMIT_FOR_SNS_AGGREGATOR": "release-2024-09-26_01-31-no-canister-snapshots"
},
"packtool": ""
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
}
proposalInfo = proposal;
},
silentUpdateErrorMessages: true,
});
}
};
Expand Down
1 change: 0 additions & 1 deletion frontend/src/lib/pages/NnsProposalDetail.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@
}));
},
handleError: onError,
silentUpdateErrorMessages: true,
});
};
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/lib/services/icrc-accounts.services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ export const loadAccounts = async ({
}

// hide unproven data
icrcAccountsStore.reset();
icrcAccountsStore.resetUniverse(ledgerCanisterId);
icrcTransactionsStore.resetUniverse(ledgerCanisterId);

if (
Expand Down
17 changes: 8 additions & 9 deletions frontend/src/lib/services/public/proposals.services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,28 +236,28 @@ export const loadProposal = async ({
handleError,
callback,
silentErrorMessages,
silentUpdateErrorMessages,
strategy,
}: {
proposalId: ProposalId;
setProposal: (proposal: ProposalInfo) => void;
handleError?: (certified: boolean) => void;
callback?: (certified: boolean) => void;
silentErrorMessages?: boolean;
silentUpdateErrorMessages?: boolean;
strategy?: QueryAndUpdateStrategy;
}): Promise<void> => {
const identity = getCurrentIdentity();

const catchError: QueryAndUpdateOnError<Error | unknown> = (
erroneusResponse
) => {
console.error(erroneusResponse);

const skipUpdateErrorHandling =
silentUpdateErrorMessages === true &&
(erroneusResponse.certified === true ||
(erroneusResponse.certified === false && isForceCallStrategy()));

if (silentErrorMessages !== true && !skipUpdateErrorHandling) {
if (silentErrorMessages !== true && (
erroneusResponse.certified || (
strategy === "query" ||
identity.getPrincipal().isAnonymous()
)
)) {
const details = errorToString(erroneusResponse?.error);
toastsShow({
labelKey: "error.proposal_not_found",
Expand All @@ -271,7 +271,6 @@ export const loadProposal = async ({
handleError?.(erroneusResponse.certified);
};

const identity = getCurrentIdentity();
try {
return await getProposal({
proposalId,
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/lib/stores/icrc-accounts.store.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Account } from "$lib/types/account";
import { removeKeys } from "$lib/utils/utils";
import type { Principal } from "@dfinity/principal";
import type { Readable } from "svelte/store";
import { writable } from "svelte/store";
Expand All @@ -21,6 +22,7 @@ export interface IcrcAccountsStore extends Readable<IcrcAccountStoreData> {
accounts: IcrcAccounts;
ledgerCanisterId: Principal;
}) => void;
resetUniverse: (ledgerCanisterId: Principal) => void;
reset: () => void;
}

Expand Down Expand Up @@ -72,6 +74,15 @@ const initIcrcAccountsStore = (): IcrcAccountsStore => {
}));
},

resetUniverse: (ledgerCanisterId: Principal) => {
update((currentState: IcrcAccountStoreData) =>
removeKeys({
obj: currentState,
keysToRemove: [ledgerCanisterId.toText()],
})
);
},

reset: () => set(initialAccounts),
};
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import * as proposalsApi from "$lib/api/proposals.api";
import ProjectProposal from "$lib/components/project-detail/ProjectProposal.svelte";
import { resetIdentity, setNoIdentity } from "$tests/mocks/auth.store.mock";
import { mockProposalInfo } from "$tests/mocks/proposal.mock";
import { createSummary } from "$tests/mocks/sns-projects.mock";
import { blockAllCallsTo } from "$tests/utils/module.test-utils";
import { runResolvedPromises } from "$tests/utils/timers.test-utils";
import { toastsStore } from "@dfinity/gix-components";
import { render } from "@testing-library/svelte";
import { get } from "svelte/store";

vi.mock("$lib/api/proposals.api");

Expand All @@ -13,6 +16,9 @@ describe("ProjectProposal", () => {
blockAllCallsTo(blockedApiPaths);

beforeEach(() => {
vi.restoreAllMocks();
toastsStore.reset();
setNoIdentity();
vi.spyOn(proposalsApi, "queryProposal").mockResolvedValue(mockProposalInfo);
});

Expand All @@ -28,6 +34,63 @@ describe("ProjectProposal", () => {
await runResolvedPromises();

expect(queryByTestId("proposal-card")).toBeInTheDocument();
expect(get(toastsStore)).toEqual([]);
});

it("should show a toast if proposal fails to load while signed out", async () => {
setNoIdentity();
const errorMessage = "Failed to load proposal";
vi.spyOn(console, "error").mockReturnValue(undefined);
vi.spyOn(proposalsApi, "queryProposal").mockRejectedValue(
new Error(errorMessage)
);

expect(get(toastsStore)).toEqual([]);

const { queryByTestId } = render(ProjectProposal, {
props: {
summary: createSummary({
nnsProposalId: mockProposalInfo.id,
}),
},
});
await runResolvedPromises();

expect(queryByTestId("proposal-card")).toBeNull();
expect(get(toastsStore)).toMatchObject([
{
level: "error",
text: `An error occurred while loading the proposal. id: "${mockProposalInfo.id}". ${errorMessage}`,
},
]);
});

it("should show a toast if proposal fails to load while signed in", async () => {
resetIdentity();
const errorMessage = "Failed to load proposal";
vi.spyOn(console, "error").mockReturnValue(undefined);
vi.spyOn(proposalsApi, "queryProposal").mockRejectedValue(
new Error(errorMessage)
);

expect(get(toastsStore)).toEqual([]);

const { queryByTestId } = render(ProjectProposal, {
props: {
summary: createSummary({
nnsProposalId: mockProposalInfo.id,
}),
},
});
await runResolvedPromises();

expect(queryByTestId("proposal-card")).toBeNull();
expect(get(toastsStore)).toMatchObject([
{
level: "error",
text: `An error occurred while loading the proposal. id: "${mockProposalInfo.id}". ${errorMessage}`,
},
]);
});

it("should not show a proposal card if no nns proposal id", async () => {
Expand Down
40 changes: 40 additions & 0 deletions frontend/src/tests/lib/pages/NnsProposalDetail.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import { mockProposalInfo } from "$tests/mocks/proposal.mock";
import { NnsProposalPo } from "$tests/page-objects/NnsProposal.page-object";
import { JestPageObjectElement } from "$tests/page-objects/jest.page-object";
import { runResolvedPromises } from "$tests/utils/timers.test-utils";
import { toastsStore } from "@dfinity/gix-components";
import { render } from "@testing-library/svelte";
import { get } from "svelte/store";

vi.mock("$lib/api/governance.api");

Expand All @@ -21,6 +23,7 @@ describe("NnsProposalDetail", () => {
resetIdentity();
vi.restoreAllMocks();
resetNeuronsApiService();
toastsStore.reset();
vi.spyOn(governanceApi, "queryNeurons").mockResolvedValue([]);

actionableProposalsSegmentStore.set("all");
Expand Down Expand Up @@ -52,6 +55,25 @@ describe("NnsProposalDetail", () => {
expect(await po.getProposalProposerActionsEntryPo().isPresent()).toBe(
true
);
expect(get(toastsStore)).toEqual([]);
});

it("should show one toast if queryProposal fails", async () => {
vi.spyOn(console, "error").mockReturnValue(undefined);
const errorMessage = "proposal not found";
vi.spyOn(proposalsApi, "queryProposal").mockRejectedValue(
new Error(errorMessage)
);

renderComponent();
await runResolvedPromises();

expect(get(toastsStore)).toMatchObject([
{
level: "error",
text: `An error occurred while loading the proposal. id: "${mockProposalInfo.id}". ${errorMessage}`,
},
]);
});

it("should query neurons", async () => {
Expand Down Expand Up @@ -90,6 +112,24 @@ describe("NnsProposalDetail", () => {
);
});

it("should show one toast if queryProposal fails", async () => {
vi.spyOn(console, "error").mockReturnValue(undefined);
const errorMessage = "proposal not found";
vi.spyOn(proposalsApi, "queryProposal").mockRejectedValue(
new Error(errorMessage)
);

renderComponent();
await runResolvedPromises();

expect(get(toastsStore)).toMatchObject([
{
level: "error",
text: `An error occurred while loading the proposal. id: "${mockProposalInfo.id}". ${errorMessage}`,
},
]);
});

it("should NOT query neurons", async () => {
renderComponent();
await runResolvedPromises();
Expand Down
40 changes: 40 additions & 0 deletions frontend/src/tests/lib/services/icrc-accounts.services.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,46 @@ describe("icrc-accounts-services", () => {
).toBeUndefined();
});

it("should remove only failed account from the store", async () => {
vi.spyOn(ledgerApi, "queryIcrcBalance")
.mockResolvedValueOnce(mockCkBTCMainAccount.balanceUlps)
.mockRejectedValueOnce(new Error());
icrcAccountsStore.set({
accounts: {
accounts: [mockCkBTCMainAccount],
certified: true,
},
ledgerCanisterId: ledgerCanisterId,
});
icrcAccountsStore.set({
accounts: {
accounts: [mockCkBTCMainAccount],
certified: false,
},
ledgerCanisterId: ledgerCanisterId2,
});

expect(get(icrcAccountsStore)).toEqual({
[ledgerCanisterId.toText()]: {
accounts: [mockCkBTCMainAccount],
certified: true,
},
[ledgerCanisterId2.toText()]: {
accounts: [mockCkBTCMainAccount],
certified: false,
},
});

await loadAccounts({ ledgerCanisterId });

expect(get(icrcAccountsStore)).toEqual({
[ledgerCanisterId2.toText()]: {
accounts: [mockCkBTCMainAccount],
certified: false,
},
});
});

it("displays a toast on error", async () => {
vi.spyOn(ledgerApi, "queryIcrcBalance").mockRejectedValue(
new Error("test")
Expand Down
15 changes: 10 additions & 5 deletions frontend/src/tests/lib/services/public/proposals.services.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,15 +195,16 @@ describe("proposals-services", () => {
});

describe("error message in details", () => {
let spyQueryProposal;

beforeEach(() => {
vi.spyOn(api, "queryProposal").mockImplementation(() => {
// TODO: Return a promise to be more realistic.
throw new Error("test-message");
});
spyQueryProposal = vi.spyOn(api, "queryProposal").mockRejectedValue(
new Error("test-message")
);
vi.spyOn(console, "error").mockReturnValue();
});

it("should show error message in details", async () => {
it("should show one error message in details", async () => {
expect(get(toastsStore)).toEqual([]);

await loadProposal({
Expand All @@ -214,6 +215,10 @@ describe("proposals-services", () => {
level: "error",
text: "An error occurred while loading the proposal. id: \"0\". test-message",
}]);

// `queryProposal` gave an error twice (query + update) but it should
// result only in a single toast message.
expect(spyQueryProposal).toBeCalledTimes(2);
});
});

Expand Down
Loading

0 comments on commit 33759e8

Please sign in to comment.