diff --git a/docs/pages/integration-test/masonry.js b/docs/pages/integration-test/masonry.js index ca2d43dd8c..4f1089a43d 100644 --- a/docs/pages/integration-test/masonry.js +++ b/docs/pages/integration-test/masonry.js @@ -20,8 +20,15 @@ function booleanize(value: string): boolean { export default function TestPage(): Node { const router = useRouter(); - const { constrained, finiteLength, flexible, offsetTop, scrollContainer, virtualize } = - router.query; + const { + constrained, + finiteLength, + flexible, + manualFetch, + offsetTop, + scrollContainer, + virtualize, + } = router.query; return ( @@ -30,6 +37,7 @@ export default function TestPage(): Node { finiteLength={booleanize(finiteLength)} flexible={booleanize(flexible)} initialItems={generateExampleItems({ name: 'InitialPin' })} + manualFetch={booleanize(manualFetch)} MasonryComponent={Masonry} measurementStore={measurementStore} offsetTop={offsetTop} diff --git a/playwright/masonry/resize-reflow.spec.mjs b/playwright/masonry/resize-reflow.spec.mjs new file mode 100644 index 0000000000..a0bf3ce20c --- /dev/null +++ b/playwright/masonry/resize-reflow.spec.mjs @@ -0,0 +1,65 @@ +// @flow strict +import { expect, test } from '@playwright/test'; +import countColumns from './utils/countColumns.mjs'; +import getServerURL from './utils/getServerURL.mjs'; +import resizeWidth from './utils/resizeWidth.mjs'; +import waitForRenderedItems from './utils/waitForRenderedItems.mjs'; + +const PIN_SIZE = 240; +const GRID_WIDTH = 1000; + +test.describe('Masonry: Resize', () => { + test('Rerenders Masonry after a resize', async ({ page }) => { + await page.setViewportSize({ width: GRID_WIDTH, height: 800 }); + + // Use manual fetching so we don't end up counting columns while we're + // measuring more content. + await page.goto(getServerURL({ virtualize: true, manualFetch: true })); + + await waitForRenderedItems(page, { targetItems: 20 }); + + const expectedColumns = Math.floor(GRID_WIDTH / PIN_SIZE); + const actualColumns = await countColumns(page); + expect(actualColumns).toEqual(expectedColumns); + + // Trigger a resize. + await resizeWidth(page, GRID_WIDTH - PIN_SIZE); + + await waitForRenderedItems(page, { targetItems: 0 }); + await waitForRenderedItems(page, { targetItems: 18 }); + + const newExpectedColumns = Math.floor((GRID_WIDTH - PIN_SIZE) / PIN_SIZE); + const newActualColumns = await countColumns(page); + expect(newActualColumns).toEqual(newExpectedColumns); + }); + + test('Rerenders Masonry after a resize with scroll container', async ({ + page, + }) => { + await page.setViewportSize({ width: GRID_WIDTH, height: 800 }); + + // Use manual fetching so we don't end up counting columns while we're + // measuring more content. + await page.goto( + getServerURL({ + virtualize: true, + manualFetch: true, + scrollContainer: true, + }) + ); + + await waitForRenderedItems(page, { targetItems: 16 }); + + // Trigger a resize. + const expectedColumns = Math.floor(GRID_WIDTH / PIN_SIZE); + expect(await countColumns(page)).toEqual(expectedColumns); + + await resizeWidth(page, GRID_WIDTH - PIN_SIZE); + + await waitForRenderedItems(page, { targetItems: 0 }); + await waitForRenderedItems(page, { targetItems: 12 }); + + const newExpectedColumns = Math.floor((GRID_WIDTH - PIN_SIZE) / PIN_SIZE); + expect(await countColumns(page)).toEqual(newExpectedColumns); + }); +}); diff --git a/playwright/masonry/utils/countColumns.mjs b/playwright/masonry/utils/countColumns.mjs new file mode 100644 index 0000000000..79713ecfae --- /dev/null +++ b/playwright/masonry/utils/countColumns.mjs @@ -0,0 +1,25 @@ +// @flow strict +import selectors from './selectors.mjs'; + +// Count the number of columns of items in the grid by iterating over all items +// and counting the number of unique x-offsets. +export default async function countColumns( + // $FlowFixMe[unclear-type] flow-typed def for playwright is…lacking + page /*: Object */ + // $FlowFixMe[unclear-type] flow-typed def for playwright is…lacking +) /*: Promise */ { + return await page.evaluate((gridItemsSelector) => { + const itemLeftMap = {}; + const gridItems = document.querySelectorAll(gridItemsSelector); + + for (let i = 0; i < gridItems.length; i += 1) { + const itemRect = gridItems[i].getBoundingClientRect(); + + itemLeftMap[itemRect.x] = itemLeftMap[itemRect.x] || []; + + itemLeftMap[itemRect.x].push(itemRect); + } + + return Object.keys(itemLeftMap).length; + }, selectors.gridItem); +} diff --git a/playwright/masonry/utils/getServerURL.mjs b/playwright/masonry/utils/getServerURL.mjs index bb5bcd5ac5..5c0ee36ea9 100644 --- a/playwright/masonry/utils/getServerURL.mjs +++ b/playwright/masonry/utils/getServerURL.mjs @@ -15,6 +15,7 @@ type Options = ?{| constrained?: boolean, finiteLength?: boolean, flexible?: boolean, + manualFetch?: boolean, offsetTop?: number, scrollContainer?: boolean, virtualize?: boolean,