Skip to content

Commit

Permalink
Clean up pages/NnsProposalDetail.spec.ts (#5537)
Browse files Browse the repository at this point in the history
# Motivation

Make the test easier to maintain.

Also there was a bug in the `"should NOT query neurons"` test. Because
the setup was mixing `mutableMockAuthStoreSubscribe` and
`mockAuthStoreSubscribe`, the user was actually signed in.
But
```
      await waitFor(() =>
        expect(governanceApi.queryNeurons).not.toHaveBeenCalled()
      );
```
succeeded before the code had a chance to query the neurons.
This is why we should never use `waitFor` and always use
`runResolvedPromises` instead.

# Changes

1. Import the component as its actual name instead of as
`ProposalDetail`.
2. Use `resetIdentity()` and `setNoIdentity()` instead of mocking the
`authStore`.
3. Don't mock `proposalsStore` or `neuronsStore`.
4. `proposalsApi.queryProposal` instead of mocking the governance
canister.
5. Use a page object.
6. Use `runResolvedPromises` instead of `waitFor`


Drive-by: Fix type with double `Proposal` in
`getProposalProposalSystemInfoSectionPo`.

# Tests

Test only

# Todos

- [ ] Add entry to changelog (if necessary).
not necessary
  • Loading branch information
dskloetd authored Sep 27, 2024
1 parent 9e1f85c commit 563c180
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 71 deletions.
3 changes: 1 addition & 2 deletions frontend/src/tests/e2e/proposals.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,7 @@ test("Test proposals", async ({ page, context }) => {
const nnsProposalPo = appPo.getProposalDetailPo().getNnsProposalPo();

// System info
const systemInfoSectionPo =
nnsProposalPo.getProposalProposalSystemInfoSectionPo();
const systemInfoSectionPo = nnsProposalPo.getProposalSystemInfoSectionPo();

expect(await systemInfoSectionPo.getProposalTypeText()).toBe("Motion");
expect(await systemInfoSectionPo.getProposalTopicText()).toBe("Governance");
Expand Down
123 changes: 55 additions & 68 deletions frontend/src/tests/lib/pages/NnsProposalDetail.spec.ts
Original file line number Diff line number Diff line change
@@ -1,86 +1,68 @@
import { resetNeuronsApiService } from "$lib/api-services/governance.api-service";
import * as agent from "$lib/api/agent.api";
import * as governanceApi from "$lib/api/governance.api";
import ProposalDetail from "$lib/pages/NnsProposalDetail.svelte";
import { authStore } from "$lib/stores/auth.store";
import { neuronsStore } from "$lib/stores/neurons.store";
import { proposalsStore } from "$lib/stores/proposals.store";
import * as proposalsApi from "$lib/api/proposals.api";
import NnsProposalDetail from "$lib/pages/NnsProposalDetail.svelte";
import { actionableProposalsSegmentStore } from "$lib/stores/actionable-proposals-segment.store";
import {
authStoreMock,
mockAuthStoreSubscribe,
mockIdentity,
mutableMockAuthStoreSubscribe,
resetIdentity,
setNoIdentity,
} from "$tests/mocks/auth.store.mock";
import { MockGovernanceCanister } from "$tests/mocks/governance.canister.mock";
import { buildMockNeuronsStoreSubscribe } from "$tests/mocks/neurons.mock";
import {
mockEmptyProposalsStoreSubscribe,
mockProposals,
} from "$tests/mocks/proposals.store.mock";
import { silentConsoleErrors } from "$tests/utils/utils.test-utils";
import type { HttpAgent } from "@dfinity/agent";
import { GovernanceCanister } from "@dfinity/nns";
import { render, waitFor } from "@testing-library/svelte";
import { mock } from "vitest-mock-extended";
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 { render } from "@testing-library/svelte";

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

describe("ProposalDetail", () => {
vi.spyOn(authStore, "subscribe").mockImplementation(
mutableMockAuthStoreSubscribe
);

const mockGovernanceCanister: MockGovernanceCanister =
new MockGovernanceCanister(mockProposals);

describe("NnsProposalDetail", () => {
beforeEach(() => {
silentConsoleErrors();
vi.clearAllMocks();
resetIdentity();
vi.restoreAllMocks();
resetNeuronsApiService();
vi.spyOn(governanceApi, "queryNeurons").mockResolvedValue([]);

vi.spyOn(authStore, "subscribe").mockImplementation(mockAuthStoreSubscribe);

vi.spyOn(proposalsStore, "subscribe").mockImplementation(
mockEmptyProposalsStoreSubscribe
);

vi.spyOn(GovernanceCanister, "create").mockReturnValue(
mockGovernanceCanister
);

vi.spyOn(neuronsStore, "subscribe").mockImplementation(
buildMockNeuronsStoreSubscribe([], false)
);
vi.spyOn(agent, "createAgent").mockResolvedValue(mock<HttpAgent>());
actionableProposalsSegmentStore.set("all");
vi.spyOn(proposalsApi, "queryProposal").mockResolvedValue(mockProposalInfo);
});

const props = {
proposalIdText: `${mockProposals[0].id}`,
proposalIdText: `${mockProposalInfo.id}`,
};

const renderComponent = () => {
const { container } = render(NnsProposalDetail, props);
return NnsProposalPo.under(new JestPageObjectElement(container));
};

describe("logged in user", () => {
beforeEach(() => {
authStoreMock.next({
identity: mockIdentity,
});
resetIdentity();
});

it("should render proposal detail if signed in", async () => {
const { queryByTestId } = render(ProposalDetail, props);
await waitFor(() =>
expect(queryByTestId("proposal-details-grid")).toBeInTheDocument()
const po = renderComponent();
await runResolvedPromises();

expect(await po.isPresent("proposal-details-grid")).toBe(true);
expect(await po.isContentLoaded()).toBe(true);
expect(await po.getProposalSystemInfoSectionPo().isPresent()).toBe(true);
expect(await po.getProposalSummaryPo().isPresent()).toBe(true);
expect(await po.getProposalProposerActionsEntryPo().isPresent()).toBe(
true
);
});

it("should query neurons", async () => {
render(ProposalDetail, props);
await waitFor(() =>
expect(governanceApi.queryNeurons).toHaveBeenCalledWith({
identity: mockIdentity,
certified: true,
includeEmptyNeurons: false,
})
);
renderComponent();
await runResolvedPromises();

expect(governanceApi.queryNeurons).toHaveBeenCalledWith({
identity: mockIdentity,
certified: true,
includeEmptyNeurons: false,
});
expect(governanceApi.queryNeurons).toHaveBeenCalledWith({
identity: mockIdentity,
certified: false,
Expand All @@ -92,22 +74,27 @@ describe("ProposalDetail", () => {

describe("logged out user", () => {
beforeEach(() => {
authStoreMock.next({
identity: undefined,
});
setNoIdentity();
});

it("should render proposal detail if not signed in", async () => {
const { queryByTestId } = render(ProposalDetail, props);
await waitFor(() =>
expect(queryByTestId("proposal-details-grid")).toBeInTheDocument()
const po = renderComponent();
await runResolvedPromises();

expect(await po.isPresent("proposal-details-grid")).toBe(true);
expect(await po.isContentLoaded()).toBe(true);
expect(await po.getProposalSystemInfoSectionPo().isPresent()).toBe(true);
expect(await po.getProposalSummaryPo().isPresent()).toBe(true);
expect(await po.getProposalProposerActionsEntryPo().isPresent()).toBe(
true
);
});

it("should NOT query neurons", async () => {
render(ProposalDetail, props);
await waitFor(() =>
expect(governanceApi.queryNeurons).not.toHaveBeenCalled()
);
renderComponent();
await runResolvedPromises();

expect(governanceApi.queryNeurons).not.toHaveBeenCalled();
});
});
});
2 changes: 1 addition & 1 deletion frontend/src/tests/page-objects/NnsProposal.page-object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class NnsProposalPo extends BasePageObject {
return VotesResultPo.under(this.root);
}

getProposalProposalSystemInfoSectionPo(): ProposalSystemInfoSectionPo {
getProposalSystemInfoSectionPo(): ProposalSystemInfoSectionPo {
return ProposalSystemInfoSectionPo.under(this.root);
}

Expand Down

0 comments on commit 563c180

Please sign in to comment.