From 64d04cde27b5761af30993db637de3ab983fc005 Mon Sep 17 00:00:00 2001 From: Andrea Scartabelli Date: Mon, 5 Aug 2024 17:08:33 +0200 Subject: [PATCH] explorer: Added MediaQueryList mocks --- explorer/CHANGELOG.md | 2 + .../components/__tests__/BlocksCard.spec.js | 3 +- .../__tests__/TransactionsCard.spec.js | 3 +- .../__snapshots__/BlocksCard.spec.js.snap | 31 - .../components/blocks-card/BlocksCard.svelte | 11 +- .../LatestBlocksCard.svelte | 8 +- .../LatestTransactionsCard.svelte | 11 +- .../transactions-card/TransactionsCard.svelte | 6 +- explorer/src/lib/dusk/mocks/MediaQueryList.js | 104 +- .../src/lib/dusk/mocks/MediaQueryListEvent.js | 26 + explorer/src/lib/dusk/mocks/index.js | 1 + .../__tests__/changeMediaQueryMatches.spec.js | 27 + .../test-helpers/changeMediaQueryMatches.js | 14 + explorer/src/lib/dusk/test-helpers/index.js | 1 + .../src/lib/stores/__tests__/appStore.spec.js | 41 +- explorer/src/lib/stores/appStore.js | 21 +- explorer/src/routes/+page.svelte | 6 +- explorer/src/routes/__tests__/layout.spec.js | 2 +- explorer/src/routes/blocks/+page.svelte | 8 +- .../__tests__/__snapshots__/page.spec.js.snap | 1605 +++++++++++++++ .../src/routes/blocks/__tests__/page.spec.js | 16 + explorer/src/routes/blocks/block/+page.svelte | 3 +- .../__tests__/__snapshots__/page.spec.js.snap | 828 ++++++++ .../blocks/block/__tests__/page.spec.js | 17 + explorer/src/routes/transactions/+page.svelte | 8 +- .../__tests__/__snapshots__/page.spec.js.snap | 1800 +++++++++++++++++ .../transactions/__tests__/page.spec.js | 20 + explorer/vite-setup.js | 14 +- 28 files changed, 4498 insertions(+), 139 deletions(-) create mode 100644 explorer/src/lib/dusk/mocks/MediaQueryListEvent.js create mode 100644 explorer/src/lib/dusk/test-helpers/__tests__/changeMediaQueryMatches.spec.js create mode 100644 explorer/src/lib/dusk/test-helpers/changeMediaQueryMatches.js diff --git a/explorer/CHANGELOG.md b/explorer/CHANGELOG.md index 9e7b7b447b..429de0df31 100644 --- a/explorer/CHANGELOG.md +++ b/explorer/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Add conditional rendering for layout changes based on screen size [#2061] - Add accessible name to the gas used progress bar [#2037] - Add accessible name to the nav bar button on mobile [#2036] - Implement warning for stale market data [#1892] @@ -39,6 +40,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#2037]: https://github.com/dusk-network/rusk/issues/2037 [#2039]: https://github.com/dusk-network/rusk/issues/2039 [#2056]: https://github.com/dusk-network/rusk/issues/2056 +[#2061]: https://github.com/dusk-network/rusk/issues/2061 diff --git a/explorer/src/lib/components/__tests__/BlocksCard.spec.js b/explorer/src/lib/components/__tests__/BlocksCard.spec.js index 7c752b643f..77731fcadd 100644 --- a/explorer/src/lib/components/__tests__/BlocksCard.spec.js +++ b/explorer/src/lib/components/__tests__/BlocksCard.spec.js @@ -4,7 +4,6 @@ import { compose, mapWith, take } from "lamb"; import { gqlBlocks } from "$lib/mock-data"; import { transformBlock } from "$lib/chain-info"; -import { appStore } from "$lib/stores"; import { BlocksCard } from ".."; describe("Blocks Card", () => { @@ -17,8 +16,8 @@ describe("Blocks Card", () => { const baseProps = { blocks: null, error: null, + isSmallScreen: false, loading: false, - appStore: appStore }; const baseOptions = { props: baseProps, diff --git a/explorer/src/lib/components/__tests__/TransactionsCard.spec.js b/explorer/src/lib/components/__tests__/TransactionsCard.spec.js index 56fcdcf580..e7f7bc10bb 100644 --- a/explorer/src/lib/components/__tests__/TransactionsCard.spec.js +++ b/explorer/src/lib/components/__tests__/TransactionsCard.spec.js @@ -4,7 +4,6 @@ import { compose, mapWith, take } from "lamb"; import { gqlTransactions } from "$lib/mock-data"; import { transformTransaction } from "$lib/chain-info"; -import { appStore } from "$lib/stores"; import { TransactionsCard } from ".."; @@ -17,9 +16,9 @@ describe("Transactions Card", () => { const baseProps = { error: null, + isSmallScreen: false, loading: false, txns: null, - appStore: appStore }; const baseOptions = { props: baseProps, diff --git a/explorer/src/lib/components/__tests__/__snapshots__/BlocksCard.spec.js.snap b/explorer/src/lib/components/__tests__/__snapshots__/BlocksCard.spec.js.snap index b730965b42..df4f9f7f4e 100644 --- a/explorer/src/lib/components/__tests__/__snapshots__/BlocksCard.spec.js.snap +++ b/explorer/src/lib/components/__tests__/__snapshots__/BlocksCard.spec.js.snap @@ -745,36 +745,5 @@ exports[`Blocks Card > should render the \`BlocksCard\` component 1`] = ` - -`; - -exports[`Blocks Card > should render the \`BlocksCard\` component with the mobile layout 1`] = ` -
-
-

- Blocks — 0 Displayed Items -

- - -
- - -
`; diff --git a/explorer/src/lib/components/blocks-card/BlocksCard.svelte b/explorer/src/lib/components/blocks-card/BlocksCard.svelte index 1cbabab4cc..325abfe698 100644 --- a/explorer/src/lib/components/blocks-card/BlocksCard.svelte +++ b/explorer/src/lib/components/blocks-card/BlocksCard.svelte @@ -14,8 +14,8 @@ /** @type {Boolean} */ export let loading; - /** @type {AppStore} */ - export let appStore; + /** @type {boolean} */ + export let isSmallScreen; const ITEMS_TO_DISPLAY = 15; @@ -47,16 +47,13 @@ label: "Show More", }} > - {#if $appStore.isSmallScreen} + {#if isSmallScreen}
{#each displayedBlocks as block (block)} {/each}
{:else} - + {/if} diff --git a/explorer/src/lib/components/latest-blocks-card/LatestBlocksCard.svelte b/explorer/src/lib/components/latest-blocks-card/LatestBlocksCard.svelte index 99254f63bf..20d3099000 100644 --- a/explorer/src/lib/components/latest-blocks-card/LatestBlocksCard.svelte +++ b/explorer/src/lib/components/latest-blocks-card/LatestBlocksCard.svelte @@ -17,8 +17,8 @@ /** @type {Boolean} */ export let loading; - /** @type {AppStore} */ - export let appStore; + /** @type {boolean} */ + export let isSmallScreen; $: classes = makeClassName(["latest-blocks-card", className]); @@ -36,11 +36,11 @@ label: "All Blocks", }} > - {#if $appStore.isSmallScreen} + {#if isSmallScreen} {#each blocks as block (block)} {/each} {:else} - + {/if} diff --git a/explorer/src/lib/components/latest-transactions-card/LatestTransactionsCard.svelte b/explorer/src/lib/components/latest-transactions-card/LatestTransactionsCard.svelte index 0e67230975..108b7c4ca1 100644 --- a/explorer/src/lib/components/latest-transactions-card/LatestTransactionsCard.svelte +++ b/explorer/src/lib/components/latest-transactions-card/LatestTransactionsCard.svelte @@ -27,8 +27,8 @@ /** @type {Boolean} */ export let displayTooltips = false; - /** @type {AppStore} */ - export let appStore; + /** @type {boolean} */ + export let isSmallScreen; $: classes = makeClassName(["latest-transactions-card", className]); @@ -48,7 +48,7 @@ } : undefined} > - {#if $appStore.isSmallScreen} + {#if isSmallScreen} {#each txns as txn (txn)} {/each} {:else} - + {/if} diff --git a/explorer/src/lib/components/transactions-card/TransactionsCard.svelte b/explorer/src/lib/components/transactions-card/TransactionsCard.svelte index b60e6f7556..b4f3ca8c36 100644 --- a/explorer/src/lib/components/transactions-card/TransactionsCard.svelte +++ b/explorer/src/lib/components/transactions-card/TransactionsCard.svelte @@ -18,8 +18,8 @@ /** @type {Boolean} */ export let loading; - /** @type {AppStore} */ - export let appStore; + /** @type {boolean} */ + export let isSmallScreen; const ITEMS_TO_DISPLAY = 15; @@ -51,7 +51,7 @@ label: "Show More", }} > - {#if $appStore.isSmallScreen} + {#if isSmallScreen}
{#each displayedTxns as txn (txn)} diff --git a/explorer/src/lib/dusk/mocks/MediaQueryList.js b/explorer/src/lib/dusk/mocks/MediaQueryList.js index 890a741bf3..28fca92a1a 100644 --- a/explorer/src/lib/dusk/mocks/MediaQueryList.js +++ b/explorer/src/lib/dusk/mocks/MediaQueryList.js @@ -1,38 +1,68 @@ -export default class MediaQueryList { - /** - * @param {String} query - */ - constructor(query) { - this.matches = false; - this.media = query; - this.listeners = []; +import { afterAll } from "vitest"; + +const controllers = new Set(); + +afterAll(() => { + controllers.forEach((controller) => { + controller.abort(); + controllers.delete(controller); + }); +}); + +/** + * Mocks the `MediaQueryList` object and listens to the + * "DuskMediaQueryMatchesChange" custom event. + * Fire one manually or with the `changeMediaQueryMatches` + * helper function to simulate media query changes. + */ +export default class MediaQueryList extends EventTarget { + #matches; + + #media; + + /** + * @param {string} mediaQuery + * @param {boolean} initialMatches + */ + constructor(mediaQuery, initialMatches) { + super(); + + this.#matches = initialMatches; + this.#media = mediaQuery; + + const abortController = new AbortController(); + + controllers.add(abortController); + + global.addEventListener("DuskMediaQueryMatchesChange", this, { + signal: abortController.signal, + }); + } + + get matches() { + return this.#matches; + } + + get media() { + return this.#media; + } + + /** @param {CustomEvent<{ media: string, matches: boolean }>} evt */ + handleEvent(evt) { + const { detail, type } = evt; + + if ( + type === "DuskMediaQueryMatchesChange" && + detail.media === this.#media + ) { + this.#matches = detail.matches; + + this.dispatchEvent( + new MediaQueryListEvent("change", { + matches: this.#matches, + media: this.#media, + }) + ); } - - /** - * @param {String} event - * @param {Function} callback - */ - addEventListener(event, callback) { - if (event === 'change') { - this.listeners.push(callback); - } - } - - /** - * @param {String} event - * @param {Function} callback - */ - removeEventListener(event, callback) { - if (event === 'change') { - this.listeners = this.listeners.filter(listener => listener !== callback); - } - } - - /** - * @param {Boolean} matches - */ - change(matches) { - this.matches = matches; - this.listeners.forEach(listener => listener({ matches })); - } - } \ No newline at end of file + } +} diff --git a/explorer/src/lib/dusk/mocks/MediaQueryListEvent.js b/explorer/src/lib/dusk/mocks/MediaQueryListEvent.js new file mode 100644 index 0000000000..6f076c1137 --- /dev/null +++ b/explorer/src/lib/dusk/mocks/MediaQueryListEvent.js @@ -0,0 +1,26 @@ +import { pickIn } from "lamb"; + +export default class MediaQueryListEvent extends Event { + #matches; + + #media; + + /** + * @param {string} type + * @param {MediaQueryListEventInit} options + */ + constructor(type, options) { + super(type, pickIn(options, ["bubbles", "cancelable", "composed"])); + + this.#matches = options.matches; + this.#media = options.media; + } + + get matches() { + return this.#matches; + } + + get media() { + return this.#media; + } +} diff --git a/explorer/src/lib/dusk/mocks/index.js b/explorer/src/lib/dusk/mocks/index.js index cf6664d7c2..f31648fc8d 100644 --- a/explorer/src/lib/dusk/mocks/index.js +++ b/explorer/src/lib/dusk/mocks/index.js @@ -1,2 +1,3 @@ export { default as IntersectionObserver } from "./IntersectionObserver"; export { default as MediaQueryList } from "./MediaQueryList"; +export { default as MediaQueryListEvent } from "./MediaQueryListEvent"; diff --git a/explorer/src/lib/dusk/test-helpers/__tests__/changeMediaQueryMatches.spec.js b/explorer/src/lib/dusk/test-helpers/__tests__/changeMediaQueryMatches.spec.js new file mode 100644 index 0000000000..1c0e6a3aaa --- /dev/null +++ b/explorer/src/lib/dusk/test-helpers/__tests__/changeMediaQueryMatches.spec.js @@ -0,0 +1,27 @@ +import { describe, expect, it } from "vitest"; + +import { changeMediaQueryMatches } from ".."; + +describe("changeMediaQueryMatches", () => { + it('should dispatch "DuskMediaQueryMatchesChange" custom events', () => { + const media = "(max-width: 1024px)"; + const matches = true; + + /** @param {Event} evt */ + const handler = (evt) => { + expect(evt).toBeInstanceOf(CustomEvent); + expect(evt.type).toBe("DuskMediaQueryMatchesChange"); + + // @ts-ignore see https://github.com/Microsoft/TypeScript/issues/28357 + expect(evt.detail).toStrictEqual({ matches, media }); + }; + + global.addEventListener("DuskMediaQueryMatchesChange", handler); + + changeMediaQueryMatches(media, matches); + + global.removeEventListener("DuskMediaQueryMatchesChange", handler); + + expect.assertions(3); + }); +}); diff --git a/explorer/src/lib/dusk/test-helpers/changeMediaQueryMatches.js b/explorer/src/lib/dusk/test-helpers/changeMediaQueryMatches.js new file mode 100644 index 0000000000..ec0b6e16ad --- /dev/null +++ b/explorer/src/lib/dusk/test-helpers/changeMediaQueryMatches.js @@ -0,0 +1,14 @@ +/** + * Helper to fire "DuskMediaQueryMatchesChange" custom + * events that are listened by our `MediaQueryList` mock. + * + * @param {string} media + * @param {boolean} matches + */ +export default function changeMediaQueryMatches(media, matches) { + dispatchEvent( + new CustomEvent("DuskMediaQueryMatchesChange", { + detail: { matches, media }, + }) + ); +} diff --git a/explorer/src/lib/dusk/test-helpers/index.js b/explorer/src/lib/dusk/test-helpers/index.js index 307c8f5ed6..1a8924b35f 100644 --- a/explorer/src/lib/dusk/test-helpers/index.js +++ b/explorer/src/lib/dusk/test-helpers/index.js @@ -1,3 +1,4 @@ +export { default as changeMediaQueryMatches } from "./changeMediaQueryMatches"; export { default as mockReadableStore } from "./mockReadableStore"; export { default as renderWithSimpleContent } from "./renderWithSimpleContent"; export { default as renderWithSlots } from "./renderWithSlots"; diff --git a/explorer/src/lib/stores/__tests__/appStore.spec.js b/explorer/src/lib/stores/__tests__/appStore.spec.js index 4abc951909..1314b714d7 100644 --- a/explorer/src/lib/stores/__tests__/appStore.spec.js +++ b/explorer/src/lib/stores/__tests__/appStore.spec.js @@ -1,6 +1,7 @@ import { afterAll, beforeEach, describe, expect, it, vi } from "vitest"; import { get } from "svelte/store"; -import appStore from "../appStore"; + +import { changeMediaQueryMatches } from "$lib/dusk/test-helpers"; describe("appStore", () => { const originalTouchStart = window.ontouchstart; @@ -40,8 +41,8 @@ describe("appStore", () => { chainInfoEntries: Number(env.VITE_CHAIN_INFO_ENTRIES), darkMode: false, fetchInterval: Number(env.VITE_REFETCH_INTERVAL), - isSmallScreen: false, hasTouchSupport: false, + isSmallScreen: false, marketDataFetchInterval: Number(env.VITE_MARKET_DATA_REFETCH_INTERVAL), network: expectedNetworks[0].value, networks: expectedNetworks, @@ -104,27 +105,31 @@ describe("appStore", () => { expect(get(appStore).darkMode).toBe(true); }); - it.only("should update the `isSmallScreen` property when the window width changes respective to the provided media query", async () => { - let changeCallback; + it("should set the `isSmallScreen` property to `false` when the related media query doesn't match", async () => { + const { appStore } = await import(".."); - const mqAddListenerSpy = vi.spyOn(MediaQueryList.prototype, "addEventListener").mockImplementation((eventName, callback) => { - if (eventName === "change") { - changeCallback = callback; - } - }); + expect(get(appStore).isSmallScreen).toBe(false); + }); - + it("should set the `isSmallScreen` property to `true` when the related media query matches", async () => { + const mqMatchesSpy = vi + .spyOn(MediaQueryList.prototype, "matches", "get") + .mockReturnValue(true); - Object.defineProperty(window, 'innerWidth', { - writable: true, - configurable: true, - value: 150, - }); + const { appStore } = await import(".."); + + expect(get(appStore).isSmallScreen).toBe(true); + + mqMatchesSpy.mockRestore(); + }); + + it("should update the `isSmallScreen` property when the media query match changes", async () => { + const { appStore } = await import(".."); - window.dispatchEvent(new Event('resize')); + expect(get(appStore).isSmallScreen).toBe(false); - expect(mqAddListenerSpy).toHaveBeenCalledOnce(); + changeMediaQueryMatches("(max-width: 1024px)", true); - mqAddListenerSpy.mockRestore(); + expect(get(appStore).isSmallScreen).toBe(true); }); }); diff --git a/explorer/src/lib/stores/appStore.js b/explorer/src/lib/stores/appStore.js index d2a5aa2309..5acb8f1f8c 100644 --- a/explorer/src/lib/stores/appStore.js +++ b/explorer/src/lib/stores/appStore.js @@ -6,7 +6,7 @@ const networks = [ { label: "Testnet", value: import.meta.env.VITE_DUSK_TESTNET_NODE }, ]; -const mql = window.matchMedia("(max-width: 1024px)"); +const maxWidthMediaQuery = window.matchMedia("(max-width: 1024px)"); const browserDefaults = browser ? { @@ -23,7 +23,7 @@ const initialState = { chainInfoEntries: Number(import.meta.env.VITE_CHAIN_INFO_ENTRIES), fetchInterval: Number(import.meta.env.VITE_REFETCH_INTERVAL) || 1000, hasTouchSupport: "ontouchstart" in window || navigator.maxTouchPoints > 0, - isSmallScreen: mql.matches, + isSmallScreen: maxWidthMediaQuery.matches, marketDataFetchInterval: Number(import.meta.env.VITE_MARKET_DATA_REFETCH_INTERVAL) || 120000, network: networks[0].value, @@ -38,18 +38,11 @@ const initialState = { const store = writable(initialState); const { set, subscribe } = store; -mql.addEventListener("change", (event) => { - if(event.matches){ - set({ - ...get(store), - isSmallScreen: true, - }); - } else { - set({ - ...get(store), - isSmallScreen: false, - }); - } +maxWidthMediaQuery.addEventListener("change", (event) => { + set({ + ...get(store), + isSmallScreen: event.matches, + }); }); /** @param {string} network */ diff --git a/explorer/src/routes/+page.svelte b/explorer/src/routes/+page.svelte index de495dc968..46f2e489a1 100644 --- a/explorer/src/routes/+page.svelte +++ b/explorer/src/routes/+page.svelte @@ -21,7 +21,7 @@ onDestroy(pollingDataStore.stop); $: ({ data, error, isLoading } = $pollingDataStore); - $: ({ chainInfoEntries, network } = $appStore); + $: ({ chainInfoEntries, isSmallScreen, network } = $appStore); const retry = () => { pollingDataStore.start(network, chainInfoEntries); @@ -38,8 +38,8 @@ className="tables-layout" blocks={data?.blocks} {error} + {isSmallScreen} loading={isLoading} - {appStore} /> diff --git a/explorer/src/routes/__tests__/layout.spec.js b/explorer/src/routes/__tests__/layout.spec.js index 90c4cdadf4..9302e384ee 100644 --- a/explorer/src/routes/__tests__/layout.spec.js +++ b/explorer/src/routes/__tests__/layout.spec.js @@ -112,7 +112,7 @@ describe("Main layout", () => { vi.useRealTimers(); }); - it("should use the default delay for the tooltip if the device ha touch support", async () => { + it("should use the default delay for the tooltip if the device has touch support", async () => { const defaultDelayShow = 500; vi.useFakeTimers(); diff --git a/explorer/src/routes/blocks/+page.svelte b/explorer/src/routes/blocks/+page.svelte index 6aa5268225..f2c77070d2 100644 --- a/explorer/src/routes/blocks/+page.svelte +++ b/explorer/src/routes/blocks/+page.svelte @@ -19,7 +19,11 @@ onDestroy(pollingDataStore.stop); $: ({ data, error, isLoading } = $pollingDataStore); - $: ({ blocksListEntries, network: currentNetwork } = $appStore); + $: ({ + blocksListEntries, + isSmallScreen, + network: currentNetwork, + } = $appStore);
@@ -28,6 +32,6 @@ blocks={data} {error} loading={isLoading} - {appStore} + {isSmallScreen} />
diff --git a/explorer/src/routes/blocks/__tests__/__snapshots__/page.spec.js.snap b/explorer/src/routes/blocks/__tests__/__snapshots__/page.spec.js.snap index d918ec4b31..d2de0352fd 100644 --- a/explorer/src/routes/blocks/__tests__/__snapshots__/page.spec.js.snap +++ b/explorer/src/routes/blocks/__tests__/__snapshots__/page.spec.js.snap @@ -1,5 +1,1610 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +exports[`Blocks page > should render the Blocks page with the mobile layout 1`] = ` +
+
+
+

+ Blocks — 15 Displayed Items +

+ + +
+ +
+
+ +
+
+ + block +
+ +
+ + 1,365,454 + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + average fee paid +
+ +
+ 0 + DUSK +
+ +
+ + gas used +
+ +
+
+
+
+
+ +
+ + txn(s) +
+ +
+ 0 +
+ +
+ + rewards +
+ +
+ 16 + DUSK +
+
+ +
+
+ + block +
+ +
+ + 1,365,453 + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + average fee paid +
+ +
+ 0 + DUSK +
+ +
+ + gas used +
+ +
+
+
+
+
+ +
+ + txn(s) +
+ +
+ 0 +
+ +
+ + rewards +
+ +
+ 16 + DUSK +
+
+ +
+
+ + block +
+ +
+ + 1,365,452 + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + average fee paid +
+ +
+ 0 + DUSK +
+ +
+ + gas used +
+ +
+
+
+
+
+ +
+ + txn(s) +
+ +
+ 0 +
+ +
+ + rewards +
+ +
+ 16 + DUSK +
+
+ +
+
+ + block +
+ +
+ + 1,365,451 + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + average fee paid +
+ +
+ 0 + DUSK +
+ +
+ + gas used +
+ +
+
+
+
+
+ +
+ + txn(s) +
+ +
+ 0 +
+ +
+ + rewards +
+ +
+ 16 + DUSK +
+
+ +
+
+ + block +
+ +
+ + 1,365,450 + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + average fee paid +
+ +
+ 0 + DUSK +
+ +
+ + gas used +
+ +
+
+
+
+
+ +
+ + txn(s) +
+ +
+ 0 +
+ +
+ + rewards +
+ +
+ 16 + DUSK +
+
+ +
+
+ + block +
+ +
+ + 1,365,449 + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + average fee paid +
+ +
+ 0 + DUSK +
+ +
+ + gas used +
+ +
+
+
+
+
+ +
+ + txn(s) +
+ +
+ 0 +
+ +
+ + rewards +
+ +
+ 16 + DUSK +
+
+ +
+
+ + block +
+ +
+ + 1,365,448 + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + average fee paid +
+ +
+ 0 + DUSK +
+ +
+ + gas used +
+ +
+
+
+
+
+ +
+ + txn(s) +
+ +
+ 0 +
+ +
+ + rewards +
+ +
+ 16 + DUSK +
+
+ +
+
+ + block +
+ +
+ + 1,365,447 + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + average fee paid +
+ +
+ 0 + DUSK +
+ +
+ + gas used +
+ +
+
+
+
+
+ +
+ + txn(s) +
+ +
+ 0 +
+ +
+ + rewards +
+ +
+ 16 + DUSK +
+
+ +
+
+ + block +
+ +
+ + 1,365,446 + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + average fee paid +
+ +
+ 0 + DUSK +
+ +
+ + gas used +
+ +
+
+
+
+
+ +
+ + txn(s) +
+ +
+ 0 +
+ +
+ + rewards +
+ +
+ 16 + DUSK +
+
+ +
+
+ + block +
+ +
+ + 1,365,445 + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + average fee paid +
+ +
+ 0 + DUSK +
+ +
+ + gas used +
+ +
+
+
+
+
+ +
+ + txn(s) +
+ +
+ 0 +
+ +
+ + rewards +
+ +
+ 16 + DUSK +
+
+ +
+
+ + block +
+ +
+ + 1,365,444 + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + average fee paid +
+ +
+ 0 + DUSK +
+ +
+ + gas used +
+ +
+
+
+
+
+ +
+ + txn(s) +
+ +
+ 0 +
+ +
+ + rewards +
+ +
+ 16 + DUSK +
+
+ +
+
+ + block +
+ +
+ + 1,365,443 + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + average fee paid +
+ +
+ 0 + DUSK +
+ +
+ + gas used +
+ +
+
+
+
+
+ +
+ + txn(s) +
+ +
+ 0 +
+ +
+ + rewards +
+ +
+ 16 + DUSK +
+
+ +
+
+ + block +
+ +
+ + 1,365,442 + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + average fee paid +
+ +
+ 0 + DUSK +
+ +
+ + gas used +
+ +
+
+
+
+
+ +
+ + txn(s) +
+ +
+ 0 +
+ +
+ + rewards +
+ +
+ 16 + DUSK +
+
+ +
+
+ + block +
+ +
+ + 1,365,441 + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + average fee paid +
+ +
+ 0 + DUSK +
+ +
+ + gas used +
+ +
+
+
+
+
+ +
+ + txn(s) +
+ +
+ 0 +
+ +
+ + rewards +
+ +
+ 16 + DUSK +
+
+ +
+
+ + block +
+ +
+ + 1,365,440 + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + average fee paid +
+ +
+ 0 + DUSK +
+ +
+ + gas used +
+ +
+
+
+
+
+ +
+ + txn(s) +
+ +
+ 0 +
+ +
+ + rewards +
+ +
+ 16 + DUSK +
+
+
+ +
+ + +
+ +
+`; + exports[`Blocks page > should render the Blocks page, start polling for blocks and stop the polling when unmounted 1`] = `
{ expect(getBlocksSpy).toHaveBeenCalledTimes(3); }); + + it("should render the Blocks page with the mobile layout", async () => { + const { container } = render(Blocks); + + changeMediaQueryMatches("(max-width: 1024px)", true); + + expect(get(appStore).isSmallScreen).toBe(true); + + expect(getBlocksSpy).toHaveBeenCalledTimes(1); + expect(getBlocksSpy).toHaveBeenNthCalledWith(1, network, blocksListEntries); + + await vi.advanceTimersByTimeAsync(1); + + expect(container.firstChild).toMatchSnapshot(); + }); }); diff --git a/explorer/src/routes/blocks/block/+page.svelte b/explorer/src/routes/blocks/block/+page.svelte index 7423dc2169..218b84820a 100644 --- a/explorer/src/routes/blocks/block/+page.svelte +++ b/explorer/src/routes/blocks/block/+page.svelte @@ -30,6 +30,7 @@ $navigating.complete.then(updateData); } + $: ({ isSmallScreen } = $appStore); $: ({ data, error, isLoading } = $dataStore); @@ -45,8 +46,8 @@ {error} loading={isLoading} isOnHomeScreen={false} + {isSmallScreen} displayTooltips={true} - {appStore} />
diff --git a/explorer/src/routes/blocks/block/__tests__/__snapshots__/page.spec.js.snap b/explorer/src/routes/blocks/block/__tests__/__snapshots__/page.spec.js.snap index 108776d9ab..104827c559 100644 --- a/explorer/src/routes/blocks/block/__tests__/__snapshots__/page.spec.js.snap +++ b/explorer/src/routes/blocks/block/__tests__/__snapshots__/page.spec.js.snap @@ -673,3 +673,831 @@ exports[`Block Details > should render the Block Details page and query the nece `; + +exports[`Block Details > should render the Transaction section of the Block Details page with the mobile layout 1`] = ` +
+
+
+
+

+ Block Details +

+ +
+ +
+
+
+ + + + + + height +
+ +
+ + + + + + + + + + + 495,868 + + + + + + + + + + + +
+
+ + + + + + hash +
+ +
+ bd5c99bb720b03500e89f103fe66113ba62f2e124ed9651563f38fd15977719f +
+
+ + + + + + timestamp +
+ +
+ +
+
+ + + + + + transactions +
+ +
+ 2 +
+
+ + + + + + block fees paid +
+ +
+ 0.000580718 + DUSK +
+
+ + + + + + block reward +
+ +
+ 16 + DUSK +
+
+ + + + + + block gas limit +
+ +
+ 5,000,000,000 +
+
+ + + + + + gas used +
+ +
+ 580,718 + +
+
+
+ +
+
+ + + + + + average fee paid +
+ +
+ 0.000000001 + DUSK +
+
+ + + + + + state root hash +
+ +
+ + 20bb0a677b93f084afadfd34bec3ac3feee33a020b81d9549afa2268e8543acb + +
+
+
+ + +
+ +
+ +
+
+
+

+ Transactions +

+ +
+ +
+ +
+
+ + + + + + ID +
+ +
+ + 3a3f6f90a1012ae751b4448bcb8e98...ba2b18170239bd69fcf8e2e37f0602 + +
+ +
+ + + + + + relative time +
+ +
+ +
+ +
+ + + + + + Gas Price +
+ +
+ 1 +
+ +
+ + + + + + Gas Limit +
+ +
+ 500,000,000 +
+ +
+ + + + + + Fee +
+ +
+ 0.000290866 + DUSK +
+ +
+ + + + + + Status +
+ +
+ + success + + +
+ +
+ + + + + + Type +
+ +
+ + transfer + + +
+
+ +
+
+ + + + + + ID +
+ +
+ + 07bfabea1d94c16f2dc3697fa642f6...a6e81bf76b9644efbb6e2723b76d00 + +
+ +
+ + + + + + relative time +
+ +
+ +
+ +
+ + + + + + Gas Price +
+ +
+ 1 +
+ +
+ + + + + + Gas Limit +
+ +
+ 500,000,000 +
+ +
+ + + + + + Fee +
+ +
+ 0.000289852 + DUSK +
+ +
+ + + + + + Status +
+ +
+ + success + + +
+ +
+ + + + + + Type +
+ +
+ + transfer + + +
+
+ + +
+ + +
+ + +
+
+`; diff --git a/explorer/src/routes/blocks/block/__tests__/page.spec.js b/explorer/src/routes/blocks/block/__tests__/page.spec.js index eab8654a56..39050fd756 100644 --- a/explorer/src/routes/blocks/block/__tests__/page.spec.js +++ b/explorer/src/routes/blocks/block/__tests__/page.spec.js @@ -1,9 +1,11 @@ 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 } from "$lib/chain-info"; import { gqlBlock } from "$lib/mock-data"; +import { changeMediaQueryMatches } from "$lib/dusk/test-helpers"; import BlockDetails from "../+page.svelte"; @@ -37,4 +39,19 @@ describe("Block Details", () => { // snapshot with received data from APIs expect(container.firstChild).toMatchSnapshot(); }); + + it("should render the Transaction section of the Block Details page with the mobile layout", async () => { + const { appStore } = await import("$lib/stores"); + const { container } = render(BlockDetails); + + changeMediaQueryMatches("(max-width: 1024px)", true); + + expect(get(appStore).isSmallScreen).toBe(true); + + expect(getBlockSpy).toHaveBeenCalledTimes(1); + + await vi.advanceTimersByTimeAsync(1); + + expect(container.firstChild).toMatchSnapshot(); + }); }); diff --git a/explorer/src/routes/transactions/+page.svelte b/explorer/src/routes/transactions/+page.svelte index b55be87908..dc2a0823b7 100644 --- a/explorer/src/routes/transactions/+page.svelte +++ b/explorer/src/routes/transactions/+page.svelte @@ -19,7 +19,11 @@ onDestroy(pollingDataStore.stop); $: ({ data, error, isLoading } = $pollingDataStore); - $: ({ network: currentNetwork, transactionsListEntries } = $appStore); + $: ({ + isSmallScreen, + network: currentNetwork, + transactionsListEntries, + } = $appStore);
@@ -29,6 +33,6 @@ txns={data} {error} loading={isLoading} - {appStore} + {isSmallScreen} />
diff --git a/explorer/src/routes/transactions/__tests__/__snapshots__/page.spec.js.snap b/explorer/src/routes/transactions/__tests__/__snapshots__/page.spec.js.snap index 1d3519ff85..4de3b3ca4c 100644 --- a/explorer/src/routes/transactions/__tests__/__snapshots__/page.spec.js.snap +++ b/explorer/src/routes/transactions/__tests__/__snapshots__/page.spec.js.snap @@ -1,5 +1,1805 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +exports[`Transactions page > should render the Transactions page with the mobile layout 1`] = ` +
+
+
+

+ Transactions — 15 Displayed Items +

+ + +
+ +
+
+ +
+
+ + ID +
+ +
+ + 070280c69500df7d1b40942981a3b5...f9f71ba62f96d63e322994efca2a0e + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + Gas Price +
+ +
+ 1 +
+ +
+ + Gas Limit +
+ +
+ 50,000,000 +
+ +
+ + Fee +
+ +
+ 0.000215552 + DUSK +
+ +
+ + Status +
+ +
+ + success + + +
+ +
+ + Type +
+ +
+ + transfer + + +
+
+ +
+
+ + ID +
+ +
+ + 534f753d5a420fddc21c84d76ff26b...48ea75b450c082759d155153259c00 + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + Gas Price +
+ +
+ 1 +
+ +
+ + Gas Limit +
+ +
+ 50,000,000 +
+ +
+ + Fee +
+ +
+ 0.000215617 + DUSK +
+ +
+ + Status +
+ +
+ + success + + +
+ +
+ + Type +
+ +
+ + transfer + + +
+
+ +
+
+ + ID +
+ +
+ + c6f13af20c23b8bc55d22a416a191e...a47128b4d7dc3ac6fce5fc68ebb102 + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + Gas Price +
+ +
+ 1 +
+ +
+ + Gas Limit +
+ +
+ 50,000,000 +
+ +
+ + Fee +
+ +
+ 0.000214413 + DUSK +
+ +
+ + Status +
+ +
+ + success + + +
+ +
+ + Type +
+ +
+ + transfer + + +
+
+ +
+
+ + ID +
+ +
+ + 31c7dce26a5a6ef1392f53630b8e27...1f10eaeea2685c5a37dbbf7bcb4c04 + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + Gas Price +
+ +
+ 1 +
+ +
+ + Gas Limit +
+ +
+ 500,000,000 +
+ +
+ + Fee +
+ +
+ 0.000291769 + DUSK +
+ +
+ + Status +
+ +
+ + success + + +
+ +
+ + Type +
+ +
+ + transfer + + +
+
+ +
+
+ + ID +
+ +
+ + 4fa6e913c083aa595530b1f6c010c7...8121307c991ea6782f9e9e4dd5510d + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + Gas Price +
+ +
+ 1 +
+ +
+ + Gas Limit +
+ +
+ 500,000,000 +
+ +
+ + Fee +
+ +
+ 0.000290764 + DUSK +
+ +
+ + Status +
+ +
+ + success + + +
+ +
+ + Type +
+ +
+ + transfer + + +
+
+ +
+
+ + ID +
+ +
+ + d1a7928a435021d87ea3649bff57c8...c7b5c6c68081a61fea5779ccdb2e04 + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + Gas Price +
+ +
+ 1 +
+ +
+ + Gas Limit +
+ +
+ 500,000,000 +
+ +
+ + Fee +
+ +
+ 0.000291961 + DUSK +
+ +
+ + Status +
+ +
+ + success + + +
+ +
+ + Type +
+ +
+ + transfer + + +
+
+ +
+
+ + ID +
+ +
+ + 004ca8683c315b9270e04d3768dfb5...f65d92a9469ca31a5d97cff9718b06 + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + Gas Price +
+ +
+ 1 +
+ +
+ + Gas Limit +
+ +
+ 500,000,000 +
+ +
+ + Fee +
+ +
+ 0.000292039 + DUSK +
+ +
+ + Status +
+ +
+ + success + + +
+ +
+ + Type +
+ +
+ + transfer + + +
+
+ +
+
+ + ID +
+ +
+ + b5a77063e45dd90b97b2c30b4cd670...4ae60c4b8e3ea9fd0d0b4496253a05 + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + Gas Price +
+ +
+ 1 +
+ +
+ + Gas Limit +
+ +
+ 500,000,000 +
+ +
+ + Fee +
+ +
+ 0.000290406 + DUSK +
+ +
+ + Status +
+ +
+ + success + + +
+ +
+ + Type +
+ +
+ + transfer + + +
+
+ +
+
+ + ID +
+ +
+ + b263d9d594439be92bb9349bd97f55...60956419f2f4a32925639d80b06e0b + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + Gas Price +
+ +
+ 1 +
+ +
+ + Gas Limit +
+ +
+ 500,000,000 +
+ +
+ + Fee +
+ +
+ 0.000291537 + DUSK +
+ +
+ + Status +
+ +
+ + success + + +
+ +
+ + Type +
+ +
+ + transfer + + +
+
+ +
+
+ + ID +
+ +
+ + b4525cb82f5cd56fcf8ceb2eb30f64...3567e82abb8265dd12daf5275d7709 + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + Gas Price +
+ +
+ 1 +
+ +
+ + Gas Limit +
+ +
+ 500,000,000 +
+ +
+ + Fee +
+ +
+ 0.000291361 + DUSK +
+ +
+ + Status +
+ +
+ + success + + +
+ +
+ + Type +
+ +
+ + transfer + + +
+
+ +
+
+ + ID +
+ +
+ + 40fb9d20eb9e6ffb27be4914f49cdf...e2fdcc88a7b17f9499ff516584df08 + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + Gas Price +
+ +
+ 1 +
+ +
+ + Gas Limit +
+ +
+ 500,000,000 +
+ +
+ + Fee +
+ +
+ 0.000290385 + DUSK +
+ +
+ + Status +
+ +
+ + success + + +
+ +
+ + Type +
+ +
+ + transfer + + +
+
+ +
+
+ + ID +
+ +
+ + b5ad0ec014ac415dc8ea214f9baf55...126558afc8e142f8223504f807910b + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + Gas Price +
+ +
+ 1 +
+ +
+ + Gas Limit +
+ +
+ 500,000,000 +
+ +
+ + Fee +
+ +
+ 0.000290795 + DUSK +
+ +
+ + Status +
+ +
+ + success + + +
+ +
+ + Type +
+ +
+ + transfer + + +
+
+ +
+
+ + ID +
+ +
+ + 56504a6d6236fbd64671d86e6f60f2...e1ce09f7ee9ebc13b593ba14520c00 + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + Gas Price +
+ +
+ 1 +
+ +
+ + Gas Limit +
+ +
+ 500,000,000 +
+ +
+ + Fee +
+ +
+ 0.000290449 + DUSK +
+ +
+ + Status +
+ +
+ + success + + +
+ +
+ + Type +
+ +
+ + transfer + + +
+
+ +
+
+ + ID +
+ +
+ + d65e4ebe379d0d67142e80b377b41e...fa7d6e9acd3e034e6d63d5026ea001 + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + Gas Price +
+ +
+ 1 +
+ +
+ + Gas Limit +
+ +
+ 500,000,000 +
+ +
+ + Fee +
+ +
+ 0.000290555 + DUSK +
+ +
+ + Status +
+ +
+ + success + + +
+ +
+ + Type +
+ +
+ + transfer + + +
+
+ +
+
+ + ID +
+ +
+ + 6c0ac7828bd57ddf18834505b0cd64...91ed6504dd7224a3094e10b1febf06 + +
+ +
+ + relative time +
+ +
+ +
+ +
+ + Gas Price +
+ +
+ 1 +
+ +
+ + Gas Limit +
+ +
+ 500,000,000 +
+ +
+ + Fee +
+ +
+ 0.000291983 + DUSK +
+ +
+ + Status +
+ +
+ + success + + +
+ +
+ + Type +
+ +
+ + transfer + + +
+
+
+ +
+ + +
+ +
+`; + exports[`Transactions page > should render the Transactions page, start polling for blocks and stop the polling when unmounted 1`] = `
{ expect(getTransactionSpy).toHaveBeenCalledTimes(3); }); + + it("should render the Transactions page with the mobile layout", async () => { + const { container } = render(Transactions); + + changeMediaQueryMatches("(max-width: 1024px)", true); + + expect(get(appStore).isSmallScreen).toBe(true); + + expect(getTransactionSpy).toHaveBeenCalledTimes(1); + expect(getTransactionSpy).toHaveBeenNthCalledWith( + 1, + network, + transactionsListEntries + ); + + await vi.advanceTimersByTimeAsync(1); + + expect(container.firstChild).toMatchSnapshot(); + }); }); diff --git a/explorer/vite-setup.js b/explorer/vite-setup.js index 1d1ac682f4..9baada8813 100644 --- a/explorer/vite-setup.js +++ b/explorer/vite-setup.js @@ -8,7 +8,11 @@ import { readable } from "svelte/store"; import { ResizeObserver } from "@juggle/resize-observer"; import "jsdom-worker"; -import { IntersectionObserver, MediaQueryList } from "./src/lib/dusk/mocks"; +import { + IntersectionObserver, + MediaQueryList, + MediaQueryListEvent, +} from "./src/lib/dusk/mocks"; /* * Mocking deprecated `atob` and `btoa` functions in Node. @@ -24,10 +28,10 @@ vi.spyOn(global, "btoa").mockImplementation((data) => // Adding missing bits in JSDOM vi.mock("./src/lib/dusk/mocks/IntersectionObserver"); -vi.mock("./src/lib/dusk/mocks/MediaQueryList"); global.IntersectionObserver = IntersectionObserver; global.ResizeObserver = ResizeObserver; +global.MediaQueryListEvent = MediaQueryListEvent; global.MediaQueryList = MediaQueryList; const elementMethods = ["scrollBy", "scrollTo", "scrollIntoView"]; @@ -121,7 +125,7 @@ vi.mock("$app/stores", () => { }); // Define matchMedia property -Object.defineProperty(window, 'matchMedia', { +Object.defineProperty(window, "matchMedia", { + value: (query) => new MediaQueryList(query, false), writable: true, - value: query => new MediaQueryList(query), -}); \ No newline at end of file +});