diff --git a/explorer/src/lib/containers/__tests__/StatisticsPanel.spec.js b/explorer/src/lib/containers/__tests__/StatisticsPanel.spec.js new file mode 100644 index 0000000000..a87e5dc4bd --- /dev/null +++ b/explorer/src/lib/containers/__tests__/StatisticsPanel.spec.js @@ -0,0 +1,75 @@ +import { afterAll, afterEach, describe, expect, it, vi } from "vitest"; +import { cleanup, render } from "@testing-library/svelte"; +import { get } from "svelte/store"; + +import { duskAPI } from "$lib/services"; +import { appStore } from "$lib/stores"; +import { apiMarketData, apiNodeLocations, apiStats } from "$lib/mock-data"; + +import { StatisticsPanel } from ".."; + +describe("StatisticsPanel", () => { + vi.useFakeTimers(); + + const STATS_FETCH_INTERVAL = 5000; + const { network } = get(appStore); + const getMarketDataSpy = vi + .spyOn(duskAPI, "getMarketData") + .mockResolvedValue({ + currentPrice: apiMarketData.market_data.current_price, + marketCap: apiMarketData.market_data.market_cap, + }); + const getNodeLocationsSpy = vi + .spyOn(duskAPI, "getNodeLocations") + .mockResolvedValue(apiNodeLocations.data); + const getStatsSpy = vi.spyOn(duskAPI, "getStats").mockResolvedValue(apiStats); + + afterEach(() => { + cleanup(); + getMarketDataSpy.mockClear(); + getNodeLocationsSpy.mockClear(); + getStatsSpy.mockClear(); + }); + + afterAll(() => { + vi.useRealTimers(); + getMarketDataSpy.mockRestore(); + getNodeLocationsSpy.mockRestore(); + getStatsSpy.mockRestore(); + }); + + it("should render the StatisticsPanel, query for the necessary info, start polling for stats and stop the polling when unmounted", async () => { + const { container, unmount } = render(StatisticsPanel); + + expect(container.firstChild).toMatchSnapshot(); + expect(getMarketDataSpy).toHaveBeenCalledTimes(1); + expect(getMarketDataSpy).toHaveBeenNthCalledWith(1, network); + expect(getNodeLocationsSpy).toHaveBeenCalledTimes(1); + expect(getNodeLocationsSpy).toHaveBeenNthCalledWith(1, network); + expect(getStatsSpy).toHaveBeenCalledTimes(1); + expect(getStatsSpy).toHaveBeenNthCalledWith(1, network); + + await vi.advanceTimersByTimeAsync(1); + + // snapshot with received data from APIs + expect(container.firstChild).toMatchSnapshot(); + + await vi.advanceTimersByTimeAsync(STATS_FETCH_INTERVAL - 1); + + expect(getStatsSpy).toHaveBeenCalledTimes(2); + expect(getStatsSpy).toHaveBeenNthCalledWith(2, network); + + await vi.advanceTimersByTimeAsync(STATS_FETCH_INTERVAL); + + expect(getStatsSpy).toHaveBeenCalledTimes(3); + expect(getStatsSpy).toHaveBeenNthCalledWith(3, network); + + unmount(); + + await vi.advanceTimersByTimeAsync(STATS_FETCH_INTERVAL * 10); + + expect(getStatsSpy).toHaveBeenCalledTimes(3); + expect(getNodeLocationsSpy).toHaveBeenCalledTimes(1); + expect(getMarketDataSpy).toHaveBeenCalledTimes(1); + }); +}); diff --git a/explorer/src/lib/containers/__tests__/__snapshots__/StatisticsPanel.spec.js.snap b/explorer/src/lib/containers/__tests__/__snapshots__/StatisticsPanel.spec.js.snap new file mode 100644 index 0000000000..1190179973 --- /dev/null +++ b/explorer/src/lib/containers/__tests__/__snapshots__/StatisticsPanel.spec.js.snap @@ -0,0 +1,2290 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`StatisticsPanel > should render the StatisticsPanel, query for the necessary info, start polling for stats and stop the polling when unmounted 1`] = ` +
+
+
+
+
+
+ + + + + + + + - - - + + + +
+ + + Dusk Price + +
+
+
+ + + + + + + + - - - + + + +
+ + + Total Market Cap + +
+ +
+
+
+
+ + + + + + + + - - - + + + +
+ + + Current Staked Amount + +
+
+
+ + + + + + + + - - - + + + +
+ + + Next Epoch Staked Amount + +
+ +
+
+
+
+ + + + + + + + - - - + + + +
+ + + Last Block + +
+
+
+ + + + + + + + - - - + + + +
+ + + TX Last 100 Blocks + +
+ +
+
+
+
+ + + + + + + + - - - + + + +
+ + + Provisioners + +
+
+
+ + + + + + + + - - - + + + +
+ + + Next Epoch Provisioners + +
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+`; + +exports[`StatisticsPanel > should render the StatisticsPanel, query for the necessary info, start polling for stats and stop the polling when unmounted 2`] = ` +
+
+
+
+
+
+ + + + + + + 0.368 + + +
+ + + Dusk Price + +
+
+
+ + + + + + + 168M + + +
+ + + Total Market Cap + +
+ +
+
+
+
+ + + + + + + 58.2M + + +
+ + + Current Staked Amount + +
+
+
+ + + + + + + 2.6M + + +
+ + + Next Epoch Staked Amount + +
+ +
+
+
+
+ + + + + + + 487,596 + + +
+ + + Last Block + +
+
+
+ + + + + + + 10 + + +
+ + + TX Last 100 Blocks + +
+ +
+
+
+
+ + + + + + + 945 + + +
+ + + Provisioners + +
+
+
+ + + + + + + 34 + + +
+ + + Next Epoch Provisioners + +
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+`; diff --git a/explorer/src/lib/containers/statistics-panel/StatisticsPanel.svelte b/explorer/src/lib/containers/statistics-panel/StatisticsPanel.svelte index 8dc6a4441f..fa212eac88 100644 --- a/explorer/src/lib/containers/statistics-panel/StatisticsPanel.svelte +++ b/explorer/src/lib/containers/statistics-panel/StatisticsPanel.svelte @@ -7,6 +7,8 @@ mdiCurrencyUsd, mdiSwapVertical, } from "@mdi/js"; + import { onDestroy, onMount } from "svelte"; + import { createCurrencyFormatter, luxToDusk } from "$lib/dusk/currency"; import { createCompactFormatter } from "$lib/dusk/value"; import { duskIcon } from "$lib/dusk/icons"; @@ -20,7 +22,6 @@ } from "$lib/dusk/svelte-stores"; import { onNetworkChange } from "$lib/lifecyles"; import "./StatisticsPanel.css"; - import { onMount } from "svelte"; const valueFormatter = createCurrencyFormatter("en", "DUSK", 0); const millionFormatter = createCompactFormatter("en"); @@ -53,6 +54,7 @@ onNetworkChange(pollingStatsDataStore.start); onNetworkChange(getNodeLocations); onNetworkChange(getMarketData); + onDestroy(pollingStatsDataStore.stop); $: ({ data } = $nodeLocationsStore); diff --git a/explorer/src/routes/+page.svelte b/explorer/src/routes/+page.svelte index c9834ee1b6..fd9ea06f87 100644 --- a/explorer/src/routes/+page.svelte +++ b/explorer/src/routes/+page.svelte @@ -1,4 +1,6 @@ diff --git a/explorer/src/routes/__tests__/__snapshots__/page.spec.js.snap b/explorer/src/routes/__tests__/__snapshots__/page.spec.js.snap new file mode 100644 index 0000000000..4ed04fc62e --- /dev/null +++ b/explorer/src/routes/__tests__/__snapshots__/page.spec.js.snap @@ -0,0 +1,1093 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`home page > should render the home page, start polling for the latest chain info and stop the polling when the component is destroyed 1`] = ` +
+
+
+
+
+
+
+ + + + + + + + - - - + + + +
+ + + Dusk Price + +
+
+
+ + + + + + + + - - - + + + +
+ + + Total Market Cap + +
+ +
+
+
+
+ + + + + + + + - - - + + + +
+ + + Current Staked Amount + +
+
+
+ + + + + + + + - - - + + + +
+ + + Next Epoch Staked Amount + +
+ +
+
+
+
+ + + + + + + + - - - + + + +
+ + + Last Block + +
+
+
+ + + + + + + + - - - + + + +
+ + + TX Last 100 Blocks + +
+ +
+
+
+
+ + + + + + + + - - - + + + +
+ + + Provisioners + +
+
+
+ + + + + + + + - - - + + + +
+ + + Next Epoch Provisioners + +
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+
+

+ Blocks +

+ + + +
+ + + +
+ + + + + +
+
+

+ Transactions +

+ + + +
+ + + +
+ + + + +
+ +
+`; diff --git a/explorer/src/routes/__tests__/page.spec.js b/explorer/src/routes/__tests__/page.spec.js new file mode 100644 index 0000000000..c03f3e97c7 --- /dev/null +++ b/explorer/src/routes/__tests__/page.spec.js @@ -0,0 +1,57 @@ +import { afterAll, afterEach, describe, expect, it, vi } from "vitest"; +import { cleanup, render } from "@testing-library/svelte"; +import { get } from "svelte/store"; + +import { duskAPI } from "$lib/services"; +import { transformBlock, transformTransaction } from "$lib/chain-info"; +import { apiLatestChainInfo } from "$lib/mock-data"; +import { appStore } from "$lib/stores"; + +import HomePage from "../+page.svelte"; + +describe("home page", () => { + vi.useFakeTimers(); + + const { fetchInterval, network } = get(appStore); + const getLatestChainInfoSpy = vi + .spyOn(duskAPI, "getLatestChainInfo") + .mockResolvedValue({ + blocks: apiLatestChainInfo.data.blocks.map(transformBlock), + transactions: + apiLatestChainInfo.data.transactions.map(transformTransaction), + }); + + afterEach(() => { + cleanup(); + getLatestChainInfoSpy.mockClear(); + }); + + afterAll(() => { + getLatestChainInfoSpy.mockRestore(); + vi.useRealTimers(); + }); + + it("should render the home page, start polling for the latest chain info and stop the polling when the component is destroyed", async () => { + const { container, unmount } = render(HomePage); + + expect(container.firstChild).toMatchSnapshot(); + expect(getLatestChainInfoSpy).toHaveBeenCalledTimes(1); + expect(getLatestChainInfoSpy).toHaveBeenNthCalledWith(1, network); + + await vi.advanceTimersByTimeAsync(fetchInterval); + + expect(getLatestChainInfoSpy).toHaveBeenCalledTimes(2); + expect(getLatestChainInfoSpy).toHaveBeenNthCalledWith(2, network); + + await vi.advanceTimersByTimeAsync(fetchInterval); + + expect(getLatestChainInfoSpy).toHaveBeenCalledTimes(3); + expect(getLatestChainInfoSpy).toHaveBeenNthCalledWith(3, network); + + unmount(); + + await vi.advanceTimersByTimeAsync(fetchInterval * 10); + + expect(getLatestChainInfoSpy).toHaveBeenCalledTimes(3); + }); +});