+
{$i18n.proposal_detail.loading_neurons}
{/if}
@@ -165,15 +57,52 @@
diff --git a/frontend/src/lib/components/proposal-detail/VotingCard/VotingNeuronSelect.svelte b/frontend/src/lib/components/proposal-detail/VotingCard/VotingNeuronSelect.svelte
deleted file mode 100644
index 30b43024764..00000000000
--- a/frontend/src/lib/components/proposal-detail/VotingCard/VotingNeuronSelect.svelte
+++ /dev/null
@@ -1,112 +0,0 @@
-
-
-
-
-
- {$i18n.proposal_detail__vote
- .neurons}{#if displayNeuronsInfo} ({selectedVotingNeurons}/{totalVotingNeurons})
- {/if}
-
-
-
-
- {#if displayNeuronsInfo}
-
- {$i18n.proposal_detail__vote.voting_power}
- {formatVotingPower(
- totalNeuronsVotingPower === undefined ? 0n : totalNeuronsVotingPower
- )}
-
- {/if}
-
-
-
-
-
-
-
-
diff --git a/frontend/src/lib/components/proposal-detail/VotingCard/VotingNeuronSelectContainer.svelte b/frontend/src/lib/components/proposal-detail/VotingCard/VotingNeuronSelectContainer.svelte
deleted file mode 100644
index 9a66e5b4389..00000000000
--- a/frontend/src/lib/components/proposal-detail/VotingCard/VotingNeuronSelectContainer.svelte
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-
-
-
-
-
diff --git a/frontend/src/lib/components/proposal-detail/VotingCard/VotingNeuronSelectList.svelte b/frontend/src/lib/components/proposal-detail/VotingCard/VotingNeuronSelectList.svelte
index 61fc023be54..8094831a150 100644
--- a/frontend/src/lib/components/proposal-detail/VotingCard/VotingNeuronSelectList.svelte
+++ b/frontend/src/lib/components/proposal-detail/VotingCard/VotingNeuronSelectList.svelte
@@ -1,11 +1,13 @@
{#if $votingNeuronSelectStore.neurons.length > 0}
-
+
{#each $votingNeuronSelectStore.neurons as neuron}
- -
- toggleSelection(neuron.neuronIdString)}
- text="block"
- {disabled}
- >
- {shortenWithMiddleEllipsis(
- neuron.neuronIdString,
- SNS_NEURON_ID_DISPLAY_LENGTH
- )}
- {formatVotingPower(neuron.votingPower)}
-
+
-
+
+
+ {shortenWithMiddleEllipsis(
+ neuron.neuronIdString,
+ SNS_NEURON_ID_DISPLAY_LENGTH
+ )}
+
+
+ toggleSelection(neuron.neuronIdString)}
+ {disabled}
+ >
+ {formatVotingPower(neuron.votingPower)}
+
+
+
{/each}
-
+
{/if}
-
-
diff --git a/frontend/src/lib/components/sns-proposals/SnsVotingCard.svelte b/frontend/src/lib/components/sns-proposals/SnsVotingCard.svelte
index fbde444d48f..edbcb775627 100644
--- a/frontend/src/lib/components/sns-proposals/SnsVotingCard.svelte
+++ b/frontend/src/lib/components/sns-proposals/SnsVotingCard.svelte
@@ -1,8 +1,4 @@
-
-
-
-
-
- {#if $sortedSnsUserNeuronsStore.length > 0}
- {#if neuronsReady}
- {#if visible}
-
- {/if}
-
-
-
-
-
-
- {:else}
-
- {$i18n.proposal_detail.loading_neurons}
-
- {/if}
- {/if}
- {$i18n.proposal_detail.sign_in}
-
-
-
-
-
-
+
diff --git a/frontend/src/lib/i18n/en.json b/frontend/src/lib/i18n/en.json
index d44bbaf91aa..e34fa0c095f 100644
--- a/frontend/src/lib/i18n/en.json
+++ b/frontend/src/lib/i18n/en.json
@@ -520,7 +520,7 @@
"proposer_prefix": "Proposer",
"proposer_description": "The ID of the neuron that submitted the proposal.",
"open_voting_prefix": "Voting open:",
- "my_votes": "My Votes",
+ "neurons_voted": "$count neurons voted",
"loading_neurons": "Loading your neurons...",
"unknown_nns_function": "Unknown nnsFunction",
"nns_function_name": "nnsFunctionName",
@@ -553,8 +553,9 @@
},
"proposal_detail__vote": {
"headline": "Cast Vote",
- "neurons": "Neurons",
- "voting_power": "Voting power",
+ "vote_with_neurons": "Vote with $votable_count/$all_count Neurons",
+ "voting_power_value": "Voting power: $value",
+ "voting_power": "Voting Power:",
"vote_progress": "Vote Progress",
"total": "Total",
"adopt": "Adopt",
@@ -565,7 +566,7 @@
"confirm_reject_text": "You are about to cast $votingPower votes against this proposal, are you sure you want to proceed?",
"vote_status": "Neuron $neuronId has voted $vote",
"cast_vote_neuronId": "Neuron ID $neuronId",
- "cast_vote_votingPower": "Voting power of $votingPower",
+ "cast_vote_votingPower": "Voting Power: $votingPower",
"vote_adopt_in_progress": "Adopting proposal $proposalType ($proposalId). $status",
"vote_reject_in_progress": "Rejecting proposal $proposalType ($proposalId). $status",
"vote_status_registering": "Neurons registered: $completed/$amount. Keep the dapp open until completed.",
@@ -585,8 +586,8 @@
"cast_votes_needs": "(Yes needs $immediate_majority)"
},
"proposal_detail__ineligible": {
- "headline": "Ineligible Neurons",
- "text": "The following neurons had a dissolve delay of less than $minDissolveDelay at the time the proposal was submitted, or were created after the proposal was submitted, and therefore are not eligible to vote on it:",
+ "headline": "$count Ineligible neurons",
+ "text": "The following neurons are not eligible to vote.",
"reason_since": "created after the proposal",
"reason_no_permission": "no voting permission",
"reason_short": "dissolve delay < $minDissolveDelay"
diff --git a/frontend/src/lib/types/i18n.d.ts b/frontend/src/lib/types/i18n.d.ts
index f31a1344508..0d5347d406b 100644
--- a/frontend/src/lib/types/i18n.d.ts
+++ b/frontend/src/lib/types/i18n.d.ts
@@ -540,7 +540,7 @@ interface I18nProposal_detail {
proposer_prefix: string;
proposer_description: string;
open_voting_prefix: string;
- my_votes: string;
+ neurons_voted: string;
loading_neurons: string;
unknown_nns_function: string;
nns_function_name: string;
@@ -574,7 +574,8 @@ interface I18nProposal_detail {
interface I18nProposal_detail__vote {
headline: string;
- neurons: string;
+ vote_with_neurons: string;
+ voting_power_value: string;
voting_power: string;
vote_progress: string;
total: string;
diff --git a/frontend/src/lib/utils/neuron.utils.ts b/frontend/src/lib/utils/neuron.utils.ts
index 6bee6bb41e4..a0ed353f928 100644
--- a/frontend/src/lib/utils/neuron.utils.ts
+++ b/frontend/src/lib/utils/neuron.utils.ts
@@ -846,6 +846,9 @@ export const votedNeuronDetails = ({
(compactNeuronInfoMaybe) => compactNeuronInfoMaybe.vote !== undefined
) as CompactNeuronInfo[];
+export const neuronsVotingPower = (neurons?: CompactNeuronInfo[]): bigint =>
+ neurons?.reduce((sum, { votingPower }) => sum + votingPower, 0n) ?? 0n;
+
export const hasEnoughMaturityToStake = ({ fullNeuron }: NeuronInfo): boolean =>
(fullNeuron?.maturityE8sEquivalent ?? 0n) > 0n;
diff --git a/frontend/src/tests/lib/components/proposal-detail/IneligibleNeuronsCard.spec.ts b/frontend/src/tests/lib/components/proposal-detail/IneligibleNeuronsCard.spec.ts
index f111d3ffba2..97a941b55ee 100644
--- a/frontend/src/tests/lib/components/proposal-detail/IneligibleNeuronsCard.spec.ts
+++ b/frontend/src/tests/lib/components/proposal-detail/IneligibleNeuronsCard.spec.ts
@@ -18,7 +18,7 @@ describe("IneligibleNeuronsCard", () => {
});
it("should display texts", () => {
- const { getByText } = render(IneligibleNeuronsCard, {
+ const { getByTestId } = render(IneligibleNeuronsCard, {
props: {
ineligibleNeurons: [
{
@@ -29,18 +29,10 @@ describe("IneligibleNeuronsCard", () => {
minSnsDissolveDelaySeconds: BigInt(NNS_MINIMUM_DISSOLVE_DELAY_TO_VOTE),
},
});
- expect(
- getByText(en.proposal_detail__ineligible.headline)
- ).toBeInTheDocument();
- expect(
- getByText(
- replacePlaceholders(en.proposal_detail__ineligible.text, {
- $minDissolveDelay: secondsToDissolveDelayDuration(
- BigInt(NNS_MINIMUM_DISSOLVE_DELAY_TO_VOTE)
- ),
- })
- )
- ).toBeInTheDocument();
+ expect(getByTestId("ineligible-neurons-description")).toBeInTheDocument();
+ expect(getByTestId("ineligible-neurons-description").textContent).toEqual(
+ "The following neurons are not eligible to vote."
+ );
});
it("should display ineligible neurons with reason 'short'", () => {
diff --git a/frontend/src/tests/lib/components/proposal-detail/MyVotes.spec.ts b/frontend/src/tests/lib/components/proposal-detail/MyVotes.spec.ts
index 615976f7cb6..c0bfd6363a9 100644
--- a/frontend/src/tests/lib/components/proposal-detail/MyVotes.spec.ts
+++ b/frontend/src/tests/lib/components/proposal-detail/MyVotes.spec.ts
@@ -18,22 +18,22 @@ describe("MyVotes", () => {
};
const neuronsVotedForProposal = [noVoted, yesVoted];
- it("should have title when proposal has been voted by some owned neuron", () => {
- const { getByText } = render(MyVotes, {
+ it("should display voted neurons when proposal has been voted by some owned neuron", () => {
+ const { queryAllByTestId } = render(MyVotes, {
props: {
neuronsVotedForProposal,
},
});
- expect(getByText(en.proposal_detail.my_votes)).toBeInTheDocument();
+ expect(queryAllByTestId("neuron-data").length).toEqual(2);
});
- it("should not have title when proposal has not been voted by some owned neuron", () => {
- const { getByText } = render(MyVotes, {
+ it("should not have voted neurons when proposal has not been voted by some owned neuron", () => {
+ const { queryAllByTestId } = render(MyVotes, {
props: {
neuronsVotedForProposal: [],
},
});
- expect(() => getByText(en.proposal_detail.my_votes)).toThrow();
+ expect(queryAllByTestId("neuron-data").length).toEqual(0);
});
it("should render an item per voted neuron", () => {
@@ -101,4 +101,16 @@ describe("MyVotes", () => {
expect(element?.getAttribute("aria-label")).toBeTruthy();
});
+
+ it("should add colour class", () => {
+ const rejectedVotedCount = (neurons: CompactNeuronInfo[]) =>
+ render(MyVotes, {
+ props: {
+ neuronsVotedForProposal: neurons,
+ },
+ }).container.querySelectorAll(".rejected").length;
+
+ expect(rejectedVotedCount([yesVoted])).toBe(0);
+ expect(rejectedVotedCount([noVoted])).toBe(1);
+ });
});
diff --git a/frontend/src/tests/lib/components/proposal-detail/ProposalVotingSection.spec.ts b/frontend/src/tests/lib/components/proposal-detail/ProposalVotingSection.spec.ts
index 78840db0ea5..513ded89e31 100644
--- a/frontend/src/tests/lib/components/proposal-detail/ProposalVotingSection.spec.ts
+++ b/frontend/src/tests/lib/components/proposal-detail/ProposalVotingSection.spec.ts
@@ -78,9 +78,7 @@ describe("ProposalVotingSection", () => {
queryByText(en.proposal_detail.voting_results)
).toBeInTheDocument();
expect(getByTestId("voting-confirmation-toolbar")).toBeInTheDocument();
- expect(
- queryByText(en.proposal_detail__ineligible.headline)
- ).toBeInTheDocument();
+ expect(getByTestId("voting-neuron-select")).toBeInTheDocument();
});
it("should not render vote blocks if reward status has settled", () => {
diff --git a/frontend/src/tests/lib/components/proposal-detail/VotingCard/NnsVotingCard.spec.ts b/frontend/src/tests/lib/components/proposal-detail/VotingCard/NnsVotingCard.spec.ts
index ad3c39e55e9..f3a0fcab078 100644
--- a/frontend/src/tests/lib/components/proposal-detail/VotingCard/NnsVotingCard.spec.ts
+++ b/frontend/src/tests/lib/components/proposal-detail/VotingCard/NnsVotingCard.spec.ts
@@ -1,5 +1,5 @@
import * as agent from "$lib/api/agent.api";
-import VotingCard from "$lib/components/proposal-detail/VotingCard/VotingCard.svelte";
+import NnsVotingCard from "$lib/components/proposal-detail/VotingCard/NnsVotingCard.svelte";
import { SECONDS_IN_YEAR } from "$lib/constants/constants";
import { authStore } from "$lib/stores/auth.store";
import { neuronsStore } from "$lib/stores/neurons.store";
@@ -58,7 +58,7 @@ describe("VotingCard", () => {
proposal: proposalInfo,
}),
} as SelectedProposalContext,
- Component: VotingCard,
+ Component: NnsVotingCard,
},
});
diff --git a/frontend/src/tests/lib/components/proposal-detail/VotingCard/SnsVotingCard.spec.ts b/frontend/src/tests/lib/components/proposal-detail/VotingCard/SnsVotingCard.spec.ts
index 22081176a1d..7a86bc4037a 100644
--- a/frontend/src/tests/lib/components/proposal-detail/VotingCard/SnsVotingCard.spec.ts
+++ b/frontend/src/tests/lib/components/proposal-detail/VotingCard/SnsVotingCard.spec.ts
@@ -11,7 +11,6 @@ import {
mockAuthStoreSubscribe,
mockIdentity,
} from "$tests/mocks/auth.store.mock";
-import en from "$tests/mocks/i18n.mock";
import {
createMockSnsNeuron,
snsNervousSystemParametersMock,
@@ -245,6 +244,26 @@ describe("SnsVotingCard", () => {
expect(queryByTestId("vote-no")).toBeInTheDocument();
});
+ it("should display votable neurons", async () => {
+ snsNeuronsStore.setNeurons({
+ rootCanisterId: mockSnsCanisterId,
+ neurons: [
+ ...testNeurons,
+ // voted neuron
+ {
+ ...createMockSnsNeuron({
+ id: [3],
+ state: NeuronState.Locked,
+ }),
+ },
+ ],
+ certified: true,
+ });
+
+ const { getByTestId } = renderVotingCard();
+ expect(getByTestId("votable-neurons")).toBeInTheDocument();
+ });
+
it("should display my votes", async () => {
snsNeuronsStore.setNeurons({
rootCanisterId: mockSnsCanisterId,
@@ -261,8 +280,28 @@ describe("SnsVotingCard", () => {
certified: true,
});
- const { getByText } = renderVotingCard();
- expect(getByText(en.proposal_detail.my_votes)).toBeInTheDocument();
+ const { getByTestId } = renderVotingCard();
+ expect(getByTestId("voted-neurons")).toBeInTheDocument();
+ });
+
+ it("should display ineligible neurons", async () => {
+ snsNeuronsStore.setNeurons({
+ rootCanisterId: mockSnsCanisterId,
+ neurons: [
+ ...testNeurons,
+ // voted neuron
+ {
+ ...createMockSnsNeuron({
+ id: [3],
+ state: NeuronState.Unspecified,
+ }),
+ },
+ ],
+ certified: true,
+ });
+
+ const { getByTestId } = renderVotingCard();
+ expect(getByTestId("ineligible-neurons")).toBeInTheDocument();
});
it("should display my votes with ballot voting power", async () => {
@@ -315,8 +354,8 @@ describe("SnsVotingCard", () => {
certified: true,
});
- const { getByText } = renderVotingCard();
- expect(getByText(en.proposal_detail.my_votes)).toBeInTheDocument();
+ const { getByTestId } = renderVotingCard();
+ expect(getByTestId("voted-neurons")).toBeInTheDocument();
});
describe("voting", () => {
diff --git a/frontend/src/tests/lib/components/proposal-detail/VotingCard/VotingNeuronSelect.spec.ts b/frontend/src/tests/lib/components/proposal-detail/VotingCard/VotableNeuronList.spec.ts
similarity index 60%
rename from frontend/src/tests/lib/components/proposal-detail/VotingCard/VotingNeuronSelect.spec.ts
rename to frontend/src/tests/lib/components/proposal-detail/VotingCard/VotableNeuronList.spec.ts
index cfa6d37d279..44cc48e2a86 100644
--- a/frontend/src/tests/lib/components/proposal-detail/VotingCard/VotingNeuronSelect.spec.ts
+++ b/frontend/src/tests/lib/components/proposal-detail/VotingCard/VotableNeuronList.spec.ts
@@ -1,14 +1,13 @@
-import VotingNeuronSelect from "$lib/components/proposal-detail/VotingCard/VotingNeuronSelect.svelte";
+import VotableNeuronList from "$lib/components/proposal-detail/VotingCard/VotableNeuronList.svelte";
import { votingNeuronSelectStore } from "$lib/stores/vote-registration.store";
import { formatVotingPower } from "$lib/utils/neuron.utils";
import { nnsNeuronToVotingNeuron } from "$lib/utils/proposals.utils";
-import en from "$tests/mocks/i18n.mock";
import { mockNeuron } from "$tests/mocks/neurons.mock";
import { mockProposalInfo } from "$tests/mocks/proposal.mock";
import { Vote, type NeuronInfo } from "@dfinity/nns";
import { render, waitFor } from "@testing-library/svelte";
-describe("VotingNeuronSelect", () => {
+describe("VotableNeuronList", () => {
const neuron1 = {
...mockNeuron,
neuronId: 111n,
@@ -45,47 +44,44 @@ describe("VotingNeuronSelect", () => {
});
it("should display total voting power of ballots not of neurons", async () => {
- const { queryByText } = render(VotingNeuronSelect);
- const ballotsVotingPower = formatVotingPower(
- ballots[0].votingPower + ballots[1].votingPower + ballots[2].votingPower
- );
- expect(queryByText(ballotsVotingPower)).toBeInTheDocument();
+ const { getByTestId } = render(VotableNeuronList, {
+ props: {
+ voteRegistration: undefined,
+ },
+ });
+ expect(
+ getByTestId("voting-collapsible-toolbar-voting-power").textContent
+ ).toBe("897.00");
});
it("should not display total voting power of neurons", async () => {
- const { queryByText } = render(VotingNeuronSelect);
+ const { getByTestId } = render(VotableNeuronList, {
+ props: {
+ voteRegistration: undefined,
+ },
+ });
const neuronsVotingPower = formatVotingPower(
neurons[0].votingPower + neurons[1].votingPower + neurons[2].votingPower
);
- expect(queryByText(neuronsVotingPower)).toBeNull();
+ expect(
+ getByTestId("voting-collapsible-toolbar-voting-power").textContent
+ ).not.toBe(neuronsVotingPower);
});
it("should recalculate total voting power after selection", async () => {
- const { getByText } = render(VotingNeuronSelect);
-
- votingNeuronSelectStore.toggleSelection(`${neurons[1].neuronId}`);
- const total = formatVotingPower(
- ballots[0].votingPower + ballots[2].votingPower
- );
-
- waitFor(() => expect(getByText(total)).toBeInTheDocument());
- });
-
- describe("No selectable neurons", () => {
- beforeEach(() => {
- votingNeuronSelectStore.set([]);
+ const { getByTestId } = render(VotableNeuronList, {
+ props: {
+ voteRegistration: undefined,
+ },
});
- it("should display no neurons information", () => {
- const { getByTestId } = render(VotingNeuronSelect);
-
+ votingNeuronSelectStore.toggleSelection(`${neurons[1].neuronId}`);
+ // ballots[0].votingPower + ballots[2].votingPower
+ await waitFor(() =>
expect(
- getByTestId("voting-collapsible-toolbar-neurons")?.textContent?.trim()
- ).toEqual(en.proposal_detail__vote.neurons);
- expect(() =>
- getByTestId("voting-collapsible-toolbar-voting-power")
- ).toThrow();
- });
+ getByTestId("voting-collapsible-toolbar-voting-power").textContent
+ ).toBe("598.00")
+ );
});
describe("Has selected neurons", () => {
@@ -101,21 +97,27 @@ describe("VotingNeuronSelect", () => {
);
it("should display voting power", () => {
- const { getByTestId } = render(VotingNeuronSelect);
+ const { getByTestId } = render(VotableNeuronList, {
+ props: {
+ voteRegistration: undefined,
+ },
+ });
expect(
- getByTestId("voting-collapsible-toolbar-voting-power")
- ).not.toBeNull();
+ getByTestId("voting-collapsible-toolbar-voting-power").textContent
+ ).toBe("897.00");
});
it("should display selectable neurons for voting power", () => {
- const { getByTestId } = render(VotingNeuronSelect);
+ const { getByTestId } = render(VotableNeuronList, {
+ props: {
+ voteRegistration: undefined,
+ },
+ });
expect(
- getByTestId("voting-collapsible-toolbar-neurons")
- ?.textContent?.trim()
- .includes(`(${neurons.length}/${neurons.length})`)
- ).toBeTruthy();
+ getByTestId("voting-collapsible-toolbar-neurons")?.textContent
+ ).toBe(`Vote with 3/3 Neurons`);
});
});
});
diff --git a/frontend/src/tests/lib/components/proposal-detail/VotingCard/VotingCard.spec.ts b/frontend/src/tests/lib/components/proposal-detail/VotingCard/VotingCard.spec.ts
new file mode 100644
index 00000000000..9665f0486a6
--- /dev/null
+++ b/frontend/src/tests/lib/components/proposal-detail/VotingCard/VotingCard.spec.ts
@@ -0,0 +1,145 @@
+import VotingCard from "$lib/components/proposal-detail/VotingCard/VotingCard.svelte";
+import { authStore } from "$lib/stores/auth.store";
+import { votingNeuronSelectStore } from "$lib/stores/vote-registration.store";
+import type { CompactNeuronInfo } from "$lib/utils/neuron.utils";
+import { nnsNeuronToVotingNeuron } from "$lib/utils/proposals.utils";
+import { mockAuthStoreSubscribe } from "$tests/mocks/auth.store.mock";
+import { mockNeuron } from "$tests/mocks/neurons.mock";
+import { mockProposalInfo } from "$tests/mocks/proposal.mock";
+import { VotingCardPo } from "$tests/page-objects/VotingCard.page-object";
+import { JestPageObjectElement } from "$tests/page-objects/jest.page-object";
+import { runResolvedPromises } from "$tests/utils/timers.test-utils";
+import { Vote, type NeuronInfo } from "@dfinity/nns";
+import { render } from "@testing-library/svelte";
+import { describe } from "vitest";
+
+describe("VotingCard", () => {
+ const neuron1 = {
+ ...mockNeuron,
+ neuronId: 111n,
+ votingPower: 10_000_000_000n,
+ };
+ const neuron2 = {
+ ...mockNeuron,
+ neuronId: 222n,
+ votingPower: 30_000_000_000n,
+ };
+ const neuron3 = {
+ ...mockNeuron,
+ neuronId: 333n,
+ votingPower: 50_000_000_000n,
+ };
+ const neurons: NeuronInfo[] = [neuron1, neuron2, neuron3];
+ const ballots = neurons.map(({ neuronId, votingPower }) => ({
+ neuronId,
+ // Ballots and neurons have different voting power
+ votingPower: votingPower - 100_000_000n,
+ vote: Vote.No,
+ }));
+ const proposalInfo = {
+ ...mockProposalInfo,
+ ballots,
+ };
+ const yesVoted: CompactNeuronInfo = {
+ idString: "200",
+ votingPower: 200n,
+ vote: Vote.Yes,
+ };
+
+ const renderComponent = async (props = {}) => {
+ const { container } = render(VotingCard, {
+ props: {
+ hasNeurons: true,
+ visible: false,
+ neuronsReady: true,
+ voteRegistration: undefined,
+ neuronsVotedForProposal: [yesVoted],
+ ineligibleNeurons: [
+ {
+ neuronIdString: "111",
+ reason: "since",
+ },
+ ],
+ minSnsDissolveDelaySeconds: 100n,
+ ...props,
+ },
+ });
+
+ await runResolvedPromises();
+
+ return VotingCardPo.under(new JestPageObjectElement(container));
+ };
+
+ beforeEach(() => {
+ votingNeuronSelectStore.set(
+ neurons.map((neuron) =>
+ nnsNeuronToVotingNeuron({ neuron, proposal: proposalInfo })
+ )
+ );
+ });
+
+ it("should display SignIn button", async () => {
+ const po = await renderComponent();
+
+ expect(await po.getSignInButtonPo().isPresent()).toBe(true);
+ });
+
+ describe("Signed in", () => {
+ beforeEach(() => {
+ vi.spyOn(authStore, "subscribe").mockImplementation(
+ mockAuthStoreSubscribe
+ );
+ });
+
+ it("should spinner when neurons not ready", async () => {
+ const po = await renderComponent({
+ neuronsReady: false,
+ });
+ expect(await po.getSpinnerPo().isPresent()).toBe(true);
+ });
+
+ it("should hide spinner when neurons are ready", async () => {
+ const po = await renderComponent({
+ neuronsReady: true,
+ });
+ expect(await po.getSpinnerPo().isPresent()).toBe(false);
+ });
+
+ it("should display all neuron blocks", async () => {
+ const po = await renderComponent();
+
+ expect(await po.getVotableNeurons().isPresent()).toBe(true);
+ expect(await po.getVotedNeurons().isPresent()).toBe(true);
+ expect(await po.getIneligibleNeurons().isPresent()).toBe(true);
+ });
+
+ it("should not display votable neurons block", async () => {
+ votingNeuronSelectStore.reset();
+ const po = await renderComponent({});
+
+ expect(await po.getVotableNeurons().isPresent()).toBe(false);
+ expect(await po.getVotedNeurons().isPresent()).toBe(true);
+ expect(await po.getIneligibleNeurons().isPresent()).toBe(true);
+ });
+
+ it("should not display voted neurons block", async () => {
+ const po = await renderComponent({
+ neuronsVotedForProposal: [],
+ });
+
+ expect(await po.getVotableNeurons().isPresent()).toBe(true);
+ expect(await po.getVotedNeurons().isPresent()).toBe(false);
+ expect(await po.getIneligibleNeurons().isPresent()).toBe(true);
+ });
+
+ it("should not display ineligible neurons block", async () => {
+ const po = await renderComponent({
+ ineligibleNeurons: [],
+ });
+
+ expect(await po.getVotableNeurons().isPresent()).toBe(true);
+ expect(await po.getVotedNeurons().isPresent()).toBe(true);
+ expect(await po.getIneligibleNeurons().isPresent()).toBe(false);
+ });
+ });
+});
diff --git a/frontend/src/tests/lib/utils/neuron.utils.spec.ts b/frontend/src/tests/lib/utils/neuron.utils.spec.ts
index ddd4bc601b1..91b2af85c80 100644
--- a/frontend/src/tests/lib/utils/neuron.utils.spec.ts
+++ b/frontend/src/tests/lib/utils/neuron.utils.spec.ts
@@ -57,11 +57,13 @@ import {
neuronCanBeSplit,
neuronStake,
neuronVotingPower,
+ neuronsVotingPower,
sortNeuronsByCreatedTimestamp,
topicsToFollow,
userAuthorizedNeuron,
validTopUpAmount,
votedNeuronDetails,
+ type CompactNeuronInfo,
type IneligibleNeuronData,
type InvalidState,
type NeuronTagData,
@@ -2138,6 +2140,24 @@ describe("neuron-utils", () => {
});
});
+ describe("votedNeuronDetails", () => {
+ it("should return neurons voting power", () => {
+ const neurons = [
+ {
+ idString: "100",
+ votingPower: 100n,
+ vote: Vote.No,
+ },
+ {
+ idString: "200",
+ votingPower: 200n,
+ vote: Vote.Yes,
+ },
+ ] as CompactNeuronInfo[];
+ expect(neuronsVotingPower(neurons)).toBe(300n);
+ });
+ });
+
describe("neuronCanBeSplit", () => {
it("should return true if neuron has enough stake to be splitted", () => {
const neuron = {
diff --git a/frontend/src/tests/page-objects/SnsVotingCard.page-object.ts b/frontend/src/tests/page-objects/SnsVotingCard.page-object.ts
index 2283e8c09fd..135811ef9ac 100644
--- a/frontend/src/tests/page-objects/SnsVotingCard.page-object.ts
+++ b/frontend/src/tests/page-objects/SnsVotingCard.page-object.ts
@@ -3,7 +3,7 @@ import type { PageObjectElement } from "$tests/types/page-object.types";
import { VotingConfirmationToolbarPo } from "./VotingConfirmationToolbar.page-object";
export class SnsVotingCardPo extends BasePageObject {
- private static readonly TID = "sns-voting-card-component";
+ private static readonly TID = "voting-card-component";
private constructor(root: PageObjectElement) {
super(root);
diff --git a/frontend/src/tests/page-objects/VotingCard.page-object.ts b/frontend/src/tests/page-objects/VotingCard.page-object.ts
index 14f0110628c..9365341a8b3 100644
--- a/frontend/src/tests/page-objects/VotingCard.page-object.ts
+++ b/frontend/src/tests/page-objects/VotingCard.page-object.ts
@@ -13,12 +13,28 @@ export class VotingCardPo extends BasePageObject {
return new VotingCardPo(element.byTestId(VotingCardPo.TID));
}
+ getVotableNeurons(): PageObjectElement {
+ return this.root.byTestId("votable-neurons");
+ }
+
+ getVotedNeurons(): PageObjectElement {
+ return this.root.byTestId("voted-neurons");
+ }
+
+ getIneligibleNeurons(): PageObjectElement {
+ return this.root.byTestId("ineligible-neurons");
+ }
+
getVoteYesButtonPo(): ButtonPo {
return this.getButton("vote-yes");
}
- getVoteNoButtonPo(): ButtonPo {
- return this.getButton("vote-no");
+ getSignInButtonPo(): ButtonPo {
+ return this.getButton("login-button");
+ }
+
+ getSpinnerPo(): PageObjectElement {
+ return this.root.byTestId("loading-neurons-spinner");
}
getConfirmYesButtonPo(): ButtonPo {