Skip to content

Commit

Permalink
tests for route and page
Browse files Browse the repository at this point in the history
  • Loading branch information
yhabib committed Jan 8, 2025
1 parent 7218afc commit ce550be
Show file tree
Hide file tree
Showing 4 changed files with 258 additions and 55 deletions.
145 changes: 99 additions & 46 deletions frontend/src/tests/lib/pages/Portfolio.spec.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,35 @@
import * as icrcLedgerApi from "$lib/api/icrc-ledger.api";
import {
CKBTC_UNIVERSE_CANISTER_ID,
CKTESTBTC_UNIVERSE_CANISTER_ID,
} from "$lib/constants/ckbtc-canister-ids.constants";
import { CKETH_UNIVERSE_CANISTER_ID } from "$lib/constants/cketh-canister-ids.constants";
import { CKUSDC_UNIVERSE_CANISTER_ID } from "$lib/constants/ckusdc-canister-ids.constants";
import Portfolio from "$lib/pages/Portfolio.svelte";
import { icpAccountBalancesStore } from "$lib/stores/icp-account-balances.store";
import { icpSwapTickersStore } from "$lib/stores/icp-swap.store";
import { resetIdentity, setNoIdentity } from "$tests/mocks/auth.store.mock";
import {
mockCkBTCToken,
mockCkTESTBTCToken,
} from "$tests/mocks/ckbtc-accounts.mock";
import { mockCkETHToken } from "$tests/mocks/cketh-accounts.mock";
import { mockMainAccount } from "$tests/mocks/icp-accounts.store.mock";
import { mockIcpSwapTicker } from "$tests/mocks/icp-swap.mock";
import { mockCkUSDCToken } from "$tests/mocks/tokens.mock";
import { PortfolioPagePo } from "$tests/page-objects/PortfolioPage.page-object";
import { JestPageObjectElement } from "$tests/page-objects/jest.page-object";
import { setAccountsForTesting } from "$tests/utils/accounts.test-utils";
import { isNullish } from "@dfinity/utils";
import { render } from "@testing-library/svelte";

describe("Portfolio page", () => {
describe.skip("Portfolio page", () => {
const renderPage = () => {
const { container } = render(Portfolio);

return PortfolioPagePo.under(new JestPageObjectElement(container));
};

beforeEach(() => {
resetIdentity();
});

describe("when not logged in", () => {
beforeEach(() => {
setNoIdentity();
Expand All @@ -27,65 +42,103 @@ describe("Portfolio page", () => {

it("should display the UsdValueBanner with a placeholder text", async () => {
const po = renderPage();
expect(await po.getUsdValueBannerPo().getIcpPrice()).toBe("-/-");
expect(await po.getUsdValueBannerPo().getPrimaryAmount()).toBe("$-/-");
expect(await po.getUsdValueBannerPo().getSecondaryAmount()).toBe(
"-/- ICP"
);
});
});

it("should show the NoTokensCard", async () => {
const po = renderPage();
expect(await po.getNoTokensCardPo().isPresent()).toBe(true);
describe("when logged in", () => {
const icpBalanceE8s = 1805000000n; // $180.5
const ckBTCBalanceE8s = 1205000000n; // $120.5
const ckETHBalanceUlps = 2005000000n; // $200.5
const ckUSDCBalanceE8s = 205000000n; // $20.5

beforeEach(() => {
resetIdentity();

setAccountsForTesting({
main: { ...mockMainAccount, balanceUlps: icpBalanceE8s },
});

vi.spyOn(icrcLedgerApi, "queryIcrcToken").mockImplementation(
async ({ canisterId }) => {
const tokenMap = {
[CKBTC_UNIVERSE_CANISTER_ID.toText()]: mockCkBTCToken,
[CKTESTBTC_UNIVERSE_CANISTER_ID.toText()]: mockCkTESTBTCToken,
[CKETH_UNIVERSE_CANISTER_ID.toText()]: mockCkETHToken,
[CKUSDC_UNIVERSE_CANISTER_ID.toText()]: mockCkUSDCToken,
};
if (isNullish(tokenMap[canisterId.toText()])) {
throw new Error(
`Token not found for canister ${canisterId.toText()}`
);
}
return tokenMap[canisterId.toText()];
}
);
// vi.spyOn(AuthClient, "create").mockImplementation(
// async (): Promise<AuthClient> => mockAuthClient
// );
vi.spyOn(icrcLedgerApi, "queryIcrcBalance").mockImplementation(
async ({ canisterId }) => {
const balancesMap = {
[CKBTC_UNIVERSE_CANISTER_ID.toText()]: ckBTCBalanceE8s,
[CKTESTBTC_UNIVERSE_CANISTER_ID.toText()]: ckBTCBalanceE8s,
[CKETH_UNIVERSE_CANISTER_ID.toText()]: ckETHBalanceUlps,
[CKUSDC_UNIVERSE_CANISTER_ID.toText()]: ckUSDCBalanceE8s,
};
return balancesMap[canisterId.toText()];
}
);

icpSwapTickersStore.set([
{
...mockIcpSwapTicker,
base_id: CKUSDC_UNIVERSE_CANISTER_ID.toText(),
last_price: "10.00",
},
]);
});
});

describe.skip("when logged in", () => {
it("should not display the login card when the user is logged in", async () => {
const page = renderPage();
expect(await page.getLoginCard().isPresent()).toBe(false);
});

it("should show total USD value banner", async () => {
it("should display the UsdValueBanner with value of 0 when no assets but there are prices", async () => {
icpAccountBalancesStore.resetForTesting();
const po = renderPage();

expect(await po.getUsdValueBannerPo().isPresent()).toBe(true);
expect(await po.getUsdValueBannerPo().getPrimaryAmount()).toBe("$0.00");
expect(await po.getUsdValueBannerPo().getSecondaryAmount()).toBe(
"0.00 ICP"
);
expect(
await po.getUsdValueBannerPo().getTotalsTooltipIconPo().isPresent()
).toBe(false);
});

it("should show total usd value", async () => {
const token1 = createusertoken({
universeid: principal(1),
balanceinusd: 2,
});
const token2 = createusertoken({
universeid: principal(2),
balanceinusd: 3,
});
const po = renderpage([token1, token2]);
it("should display the UsdValueBanner with placeholder text when no assets and no prices", async () => {
// tokensStore.setTokens();
icpSwapTickersStore.set([]);
const po = renderPage();

expect(await po.getusdvaluebannerpo().ispresent()).tobe(true);
expect(await po.getusdvaluebannerpo().getprimaryamount()).tobe("$5.00");
expect(
await po.getusdvaluebannerpo().gettotalstooltipiconpo().ispresent()
).tobe(false);
expect(await po.getUsdValueBannerPo().getPrimaryAmount()).toBe("$-/-");
expect(await po.getUsdValueBannerPo().getSecondaryAmount()).toBe(
"-/- ICP"
);
});

it("should ignore tokens with unknown balance in USD when adding up the total", async () => {
const token1 = createUserToken({
universeId: principal(1),
balanceInUsd: 3,
});
const token2 = createUserToken({
universeId: principal(2),
balanceInUsd: undefined,
});
const token3 = createUserToken({
universeId: principal(3),
balanceInUsd: 5,
});
const po = renderPage([token1, token2, token3]);
it.skip("should display the UsdValueBanner with total of assets: tokens and neurons", async () => {
const po = renderPage();

expect(await po.getUsdValueBannerPo().isPresent()).toBe(true);
expect(await po.getUsdValueBannerPo().getPrimaryAmount()).toBe("$8.00");
expect(
await po.getUsdValueBannerPo().getTotalsTooltipIconPo().isPresent()
).toBe(true);
expect(await po.getUsdValueBannerPo().getPrimaryAmount()).toBe("$180.50");
expect(await po.getUsdValueBannerPo().getSecondaryAmount()).toBe(
"18.05 ICP"
);
});
});
});
9 changes: 0 additions & 9 deletions frontend/src/tests/page-objects/PortfolioPage.page-object.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { UsdValueBannerPo } from "$tests/page-objects/UsdValueBanner.page-object";
import { BasePageObject } from "$tests/page-objects/base.page-object";
import type { PageObjectElement } from "$tests/types/page-object.types";
import { NoNeuronsCardPo } from "./NoNeuronsCard.page-object";

export class PortfolioPagePo extends BasePageObject {
private static readonly TID = "portfolio-page-component";
Expand All @@ -17,12 +16,4 @@ export class PortfolioPagePo extends BasePageObject {
getUsdValueBannerPo(): UsdValueBannerPo {
return UsdValueBannerPo.under(this.root);
}

getNoTokensCard(): PageObjectElement {
return this.getElement("no-tokens-card");
}

getNoNeuronsCardPoTokensCard(): NoNeuronsCardPo {
return NoNeuronsCardPo.under(this.root);
}
}
15 changes: 15 additions & 0 deletions frontend/src/tests/page-objects/PortfolioRoute.page-object copy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { PortfolioPagePo } from "$tests/page-objects/PortfolioPage.page-object";
import { BasePageObject } from "$tests/page-objects/base.page-object";
import type { PageObjectElement } from "$tests/types/page-object.types";

export class PortfolioRoutePo extends BasePageObject {
private static readonly TID = "portfolio-route-component";

static under(element: PageObjectElement): PortfolioRoutePo {
return new PortfolioRoutePo(element.byTestId(PortfolioRoutePo.TID));
}

getPortfolioPagePo(): PortfolioPagePo {
return PortfolioPagePo.under(this.root);
}
}
144 changes: 144 additions & 0 deletions frontend/src/tests/routes/app/portfolio/page.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import * as icrcLedgerApi from "$lib/api/icrc-ledger.api";
import {
CKBTC_UNIVERSE_CANISTER_ID,
CKTESTBTC_UNIVERSE_CANISTER_ID,
} from "$lib/constants/ckbtc-canister-ids.constants";
import { CKETH_UNIVERSE_CANISTER_ID } from "$lib/constants/cketh-canister-ids.constants";
import {
CKUSDC_INDEX_CANISTER_ID,
CKUSDC_LEDGER_CANISTER_ID,
CKUSDC_UNIVERSE_CANISTER_ID,
} from "$lib/constants/ckusdc-canister-ids.constants";
import { defaultIcrcCanistersStore } from "$lib/stores/default-icrc-canisters.store";
import { icpSwapTickersStore } from "$lib/stores/icp-swap.store";
import { tokensStore } from "$lib/stores/tokens.store";
import PortfolioRoute from "$routes/(app)/(nns)/portfolio/+page.svelte";
import { resetIdentity } from "$tests/mocks/auth.store.mock";
import {
mockCkBTCToken,
mockCkTESTBTCToken,
} from "$tests/mocks/ckbtc-accounts.mock";
import { mockCkETHToken } from "$tests/mocks/cketh-accounts.mock";
import { mockMainAccount } from "$tests/mocks/icp-accounts.store.mock";
import { mockIcpSwapTicker } from "$tests/mocks/icp-swap.mock";
import { mockCkUSDCToken } from "$tests/mocks/tokens.mock";
import { PortfolioRoutePo } from "$tests/page-objects/PortfolioRoute.page-object copy";
import { JestPageObjectElement } from "$tests/page-objects/jest.page-object";
import { setAccountsForTesting } from "$tests/utils/accounts.test-utils";
import { setCkETHCanisters } from "$tests/utils/cketh.test-utils";
import { runResolvedPromises } from "$tests/utils/timers.test-utils";
import { AuthClient } from "@dfinity/auth-client";
import { isNullish } from "@dfinity/utils";
import { render } from "@testing-library/svelte";
import { mock } from "vitest-mock-extended";

vi.mock("$lib/api/sns-ledger.api");
vi.mock("$lib/api/icrc-ledger.api");
vi.mock("$lib/api/ckbtc-minter.api");

describe("Portfolio page", () => {
const mockAuthClient = mock<AuthClient>();
mockAuthClient.login.mockResolvedValue(undefined);

const icpBalanceE8s = 100n * 100_000_000n; // 100ICP -> $1000
const ckBTCBalanceE8s = 1n * 100_000_000_000_000_000n; // 1BTC -> $100_000
const ckETHBalanceUlps = 1n * 100_000_000_000_000_000_000_000n; // 1ETH -> $1000
const ckUSDCBalanceE8s = 1n * 1_000_000n; // 1USDC -> $1

const renderPage = async () => {
const { container } = render(PortfolioRoute);
await runResolvedPromises();

return PortfolioRoutePo.under(new JestPageObjectElement(container));
};

beforeEach(() => {
resetIdentity();

vi.spyOn(icrcLedgerApi, "queryIcrcToken").mockImplementation(
async ({ canisterId }) => {
const tokenMap = {
[CKBTC_UNIVERSE_CANISTER_ID.toText()]: mockCkBTCToken,
[CKTESTBTC_UNIVERSE_CANISTER_ID.toText()]: mockCkTESTBTCToken,
[CKETH_UNIVERSE_CANISTER_ID.toText()]: mockCkETHToken,
[CKUSDC_UNIVERSE_CANISTER_ID.toText()]: mockCkUSDCToken,
};
if (isNullish(tokenMap[canisterId.toText()])) {
throw new Error(
`Token not found for canister ${canisterId.toText()}`
);
}
return tokenMap[canisterId.toText()];
}
);
vi.spyOn(AuthClient, "create").mockImplementation(
async (): Promise<AuthClient> => mockAuthClient
);
vi.spyOn(icrcLedgerApi, "queryIcrcBalance").mockImplementation(
async ({ canisterId }) => {
const balancesMap = {
[CKBTC_UNIVERSE_CANISTER_ID.toText()]: ckBTCBalanceE8s,
[CKTESTBTC_UNIVERSE_CANISTER_ID.toText()]: ckBTCBalanceE8s,
[CKETH_UNIVERSE_CANISTER_ID.toText()]: ckETHBalanceUlps,
[CKUSDC_UNIVERSE_CANISTER_ID.toText()]: ckUSDCBalanceE8s,
};

if (isNullish(balancesMap[canisterId.toText()])) {
throw new Error(
`Account not found for canister ${canisterId.toText()}`
);
}
return balancesMap[canisterId.toText()];
}
);

setAccountsForTesting({
main: { ...mockMainAccount, balanceUlps: icpBalanceE8s },
});
setCkETHCanisters();
defaultIcrcCanistersStore.setCanisters({
ledgerCanisterId: CKUSDC_LEDGER_CANISTER_ID,
indexCanisterId: CKUSDC_INDEX_CANISTER_ID,
});
tokensStore.setToken({
canisterId: CKUSDC_UNIVERSE_CANISTER_ID,
token: mockCkUSDCToken,
});
vi.spyOn(icrcLedgerApi, "icrcTransfer").mockResolvedValue(1234n);

icpSwapTickersStore.set([
{
...mockIcpSwapTicker,
base_id: CKBTC_UNIVERSE_CANISTER_ID.toText(),
last_price: "100000.00",
},
{
...mockIcpSwapTicker,
base_id: CKTESTBTC_UNIVERSE_CANISTER_ID.toText(),
last_price: "100000.00",
},
{
...mockIcpSwapTicker,
base_id: CKETH_UNIVERSE_CANISTER_ID.toText(),
last_price: "1000.00",
},
{
...mockIcpSwapTicker,
base_id: CKUSDC_UNIVERSE_CANISTER_ID.toText(),
last_price: "10.00",
},
]);
});

it("should display the UsdValueBanner with total of assets: tokens and neurons", async () => {
const po = await renderPage();
const portfolioPagePo = po.getPortfolioPagePo();

expect(await portfolioPagePo.getUsdValueBannerPo().getPrimaryAmount()).toBe(
"$202’001.00"
);
expect(
await portfolioPagePo.getUsdValueBannerPo().getSecondaryAmount()
).toBe("20’200.10 ICP");
});
});

0 comments on commit ce550be

Please sign in to comment.