From 81bc1d9c94dd04fc8290e65f18f008011e1847d9 Mon Sep 17 00:00:00 2001 From: Jordan Lawrence Date: Thu, 19 Dec 2024 20:45:31 +0000 Subject: [PATCH 1/3] fix: resolving issues with virtual lists having zero height in release summary --- .../detail/__tests__/ReleaseSummary.test.tsx | 168 ++++++++++-------- .../testUtils/setupVirtualisedEnvironment.ts | 38 ++++ 2 files changed, 130 insertions(+), 76 deletions(-) create mode 100644 packages/sanity/test/testUtils/setupVirtualisedEnvironment.ts diff --git a/packages/sanity/src/core/releases/tool/detail/__tests__/ReleaseSummary.test.tsx b/packages/sanity/src/core/releases/tool/detail/__tests__/ReleaseSummary.test.tsx index 9a877e1750b..8a358c4362e 100644 --- a/packages/sanity/src/core/releases/tool/detail/__tests__/ReleaseSummary.test.tsx +++ b/packages/sanity/src/core/releases/tool/detail/__tests__/ReleaseSummary.test.tsx @@ -1,8 +1,10 @@ import {act, fireEvent, render, screen, within} from '@testing-library/react' +import React, {type PropsWithChildren, useState} from 'react' import {route, RouterProvider} from 'sanity/router' import {beforeEach, describe, expect, it, vi} from 'vitest' import {getByDataUi} from '../../../../../../test/setup/customQueries' +import {setupVirtualisedEnvironment} from '../../../../../../test/testUtils/setupVirtualisedEnvironment' import {createTestProvider} from '../../../../../../test/testUtils/TestProvider' import {DefaultPreview} from '../../../../components/previews/general/DefaultPreview' import { @@ -78,6 +80,16 @@ const releaseDocuments: DocumentInRelease[] = [ }, ] +const ScrollContainer: React.FC = ({children}) => { + const [ref, setRef] = useState(null) + + return ( +
+ {React.cloneElement(children as React.ReactElement, {scrollContainerRef: {current: ref}})} +
+ ) +} + const renderTest = async (props: Partial) => { const wrapper = await createTestProvider({ resources: [releasesUsEnglishLocaleBundle], @@ -91,88 +103,90 @@ const renderTest = async (props: Partial) => { onNavigate={vi.fn()} router={route.create('/', [route.create('/:releaseId'), route.intents('/intents')])} > - + + ], + }, + }} + release={activeASAPRelease} + {...props} + /> + , { wrapper, @@ -181,6 +195,8 @@ const renderTest = async (props: Partial) => { } describe('ReleaseSummary', () => { + setupVirtualisedEnvironment() + describe('for an active release', () => { beforeEach(async () => { await renderTest({}) diff --git a/packages/sanity/test/testUtils/setupVirtualisedEnvironment.ts b/packages/sanity/test/testUtils/setupVirtualisedEnvironment.ts new file mode 100644 index 00000000000..5648d60df07 --- /dev/null +++ b/packages/sanity/test/testUtils/setupVirtualisedEnvironment.ts @@ -0,0 +1,38 @@ +import {afterEach, beforeEach, vi} from 'vitest' + +export const setupVirtualisedEnvironment = ( + dataTestId?: string, + rectWidth: number = 350, + rectHeight: number = 800, +) => { + const originalGetBoundingClientRect = Element.prototype.getBoundingClientRect + + const getDOMRect = (width: number, height: number) => ({ + width, + height, + top: 0, + left: 0, + bottom: 0, + right: 0, + x: 0, + y: 0, + toJSON: () => {}, + }) + + beforeEach(() => { + // Virtual list will return an empty list of items unless we have some size, + // so we need to mock getBoundingClientRect to return a size for the list. + // Not pretty, but it's what they recommend for testing outside of browsers: + // https://github.com/TanStack/virtual/issues/641 + Element.prototype.getBoundingClientRect = vi.fn(function (this: Element) { + if (!dataTestId || this.getAttribute('data-testid') === dataTestId) { + return getDOMRect(rectWidth, rectHeight) + } + return getDOMRect(0, 0) + }) + }) + + afterEach(() => { + Element.prototype.getBoundingClientRect = originalGetBoundingClientRect + }) +} From 4c5620a0f4fe45e548589ea28956683f27d411c8 Mon Sep 17 00:00:00 2001 From: Jordan Lawrence Date: Fri, 20 Dec 2024 14:05:39 +0000 Subject: [PATCH 2/3] test: resolving virtual list test issues for ReleasesOverview table --- .../detail/__tests__/ReleaseSummary.test.tsx | 10 ++-- .../__tests__/ReleasesOverview.test.tsx | 56 +++++++++++++++---- ...dEnvironment.ts => setupVirtualListEnv.ts} | 2 +- 3 files changed, 50 insertions(+), 18 deletions(-) rename packages/sanity/test/testUtils/{setupVirtualisedEnvironment.ts => setupVirtualListEnv.ts} (95%) diff --git a/packages/sanity/src/core/releases/tool/detail/__tests__/ReleaseSummary.test.tsx b/packages/sanity/src/core/releases/tool/detail/__tests__/ReleaseSummary.test.tsx index 8a358c4362e..cb949bb1d66 100644 --- a/packages/sanity/src/core/releases/tool/detail/__tests__/ReleaseSummary.test.tsx +++ b/packages/sanity/src/core/releases/tool/detail/__tests__/ReleaseSummary.test.tsx @@ -1,10 +1,10 @@ import {act, fireEvent, render, screen, within} from '@testing-library/react' -import React, {type PropsWithChildren, useState} from 'react' +import {cloneElement, type FC, type PropsWithChildren, type ReactElement, useState} from 'react' import {route, RouterProvider} from 'sanity/router' import {beforeEach, describe, expect, it, vi} from 'vitest' import {getByDataUi} from '../../../../../../test/setup/customQueries' -import {setupVirtualisedEnvironment} from '../../../../../../test/testUtils/setupVirtualisedEnvironment' +import {setupVirtualListEnv} from '../../../../../../test/testUtils/setupVirtualListEnv' import {createTestProvider} from '../../../../../../test/testUtils/TestProvider' import {DefaultPreview} from '../../../../components/previews/general/DefaultPreview' import { @@ -80,12 +80,12 @@ const releaseDocuments: DocumentInRelease[] = [ }, ] -const ScrollContainer: React.FC = ({children}) => { +const ScrollContainer: FC = ({children}) => { const [ref, setRef] = useState(null) return (
- {React.cloneElement(children as React.ReactElement, {scrollContainerRef: {current: ref}})} + {cloneElement(children as ReactElement, {scrollContainerRef: {current: ref}})}
) } @@ -195,7 +195,7 @@ const renderTest = async (props: Partial) => { } describe('ReleaseSummary', () => { - setupVirtualisedEnvironment() + setupVirtualListEnv() describe('for an active release', () => { beforeEach(async () => { diff --git a/packages/sanity/src/core/releases/tool/overview/__tests__/ReleasesOverview.test.tsx b/packages/sanity/src/core/releases/tool/overview/__tests__/ReleasesOverview.test.tsx index 84c76bf2955..43e0e2f1fcd 100644 --- a/packages/sanity/src/core/releases/tool/overview/__tests__/ReleasesOverview.test.tsx +++ b/packages/sanity/src/core/releases/tool/overview/__tests__/ReleasesOverview.test.tsx @@ -1,9 +1,12 @@ import {act, fireEvent, render, screen, waitFor, within} from '@testing-library/react' import {format, set} from 'date-fns' +import {useState} from 'react' +// import {usePerspective} from 'sanity' import {useRouter} from 'sanity/router' import {beforeEach, describe, expect, it, vi} from 'vitest' import {getByDataUi, queryByDataUi} from '../../../../../../test/setup/customQueries' +import {setupVirtualListEnv} from '../../../../../../test/testUtils/setupVirtualListEnv' import {createTestProvider} from '../../../../../../test/testUtils/TestProvider' import { getLocalTimeZoneMockReturn, @@ -77,11 +80,34 @@ vi.mock('../../../../scheduledPublishing/hooks/useTimeZone', async (importOrigin default: vi.fn(() => useTimeZoneMockReturn), })) +const getWrapper = () => + createTestProvider({ + resources: [releasesUsEnglishLocaleBundle], + }) + +/** + * To resolve issues with size render with Virtual list (as described + * here: https://github.com/TanStack/virtual/issues/641), must rerender + * ReleasesOverview once the exact height wrapper has mounted + */ +const TestComponent = () => { + const [hasWrapperRendered, setHasWrapperRendered] = useState(false) + const updateWrapperRendered = () => setHasWrapperRendered(true) + + return ( +
+ +
+ ) +} + describe('ReleasesOverview', () => { beforeEach(() => { mockUseReleases.mockRestore() }) + setupVirtualListEnv() + describe('when loading releases', () => { beforeEach(async () => { mockUseReleases.mockReturnValue({...useReleasesMockReturn, loading: true}) @@ -90,7 +116,7 @@ describe('ReleasesOverview', () => { resources: [releasesUsEnglishLocaleBundle], }) - return render(, {wrapper}) + return render(, {wrapper}) }) it('does not show releases table but shows loader', () => { @@ -124,7 +150,7 @@ describe('ReleasesOverview', () => { resources: [releasesUsEnglishLocaleBundle], }) - return render(, {wrapper}) + return render(, {wrapper}) }) it('shows a message about releases', () => { @@ -165,8 +191,18 @@ describe('ReleasesOverview', () => { let activeRender: ReturnType + const rerender = async () => { + activeRender.unmount() + + const wrapper = await getWrapper() + + return render(, {wrapper}) + } + beforeEach(async () => { mockUseTimeZone.mockRestore() + mockGetLocaleTimeZone.mockRestore() + mockUsePerspective.mockRestore() mockUseReleases.mockReturnValue({ ...useReleasesMockReturn, archivedReleases: [archivedScheduledRelease, publishedASAPRelease], @@ -184,12 +220,10 @@ describe('ReleasesOverview', () => { ), }) - const wrapper = await createTestProvider({ - resources: [releasesUsEnglishLocaleBundle], - }) + const wrapper = await getWrapper() return act(() => { - activeRender = render(, {wrapper}) + activeRender = render(, {wrapper}) }) }) @@ -249,7 +283,7 @@ describe('ReleasesOverview', () => { expect(usePerspectiveMockReturn.setPerspective).toHaveBeenCalledWith('rASAP') }) - it('will show pinned release in release list', () => { + it('will show pinned release in release list', async () => { mockUsePerspective.mockReturnValue({ ...usePerspectiveMockReturn, selectedPerspective: activeASAPRelease, @@ -257,7 +291,7 @@ describe('ReleasesOverview', () => { }) // re-render to apply the update to global bundle id - activeRender.rerender() + await rerender() const releaseRows = screen.getAllByTestId('table-row') const pinnedReleaseRow = releaseRows[0] @@ -329,7 +363,7 @@ describe('ReleasesOverview', () => { within(getByDataUi(document.body, 'DialogCard')).getByText('Select time zone') }) - it('shows dates with timezone abbreviation when it is not the locale', () => { + it('shows dates with timezone abbreviation when it is not the locale', async () => { mockGetLocaleTimeZone.mockReturnValue({ abbreviation: 'NST', // Not Sanity Time namePretty: 'Not Sanity Time', @@ -340,7 +374,7 @@ describe('ReleasesOverview', () => { value: 'Not Sanity Time', }) - activeRender.rerender() + await rerender() const scheduledReleaseRow = screen.getAllByTestId('table-row')[2] @@ -355,8 +389,6 @@ describe('ReleasesOverview', () => { // spoof a timezone that is 8 hours ahead of UTC zoneDateToUtc: vi.fn((date) => set(date, {hours: new Date(date).getHours() - 8})), }) - - activeRender.rerender() }) it('shows today as having no releases', () => { diff --git a/packages/sanity/test/testUtils/setupVirtualisedEnvironment.ts b/packages/sanity/test/testUtils/setupVirtualListEnv.ts similarity index 95% rename from packages/sanity/test/testUtils/setupVirtualisedEnvironment.ts rename to packages/sanity/test/testUtils/setupVirtualListEnv.ts index 5648d60df07..394b11d712a 100644 --- a/packages/sanity/test/testUtils/setupVirtualisedEnvironment.ts +++ b/packages/sanity/test/testUtils/setupVirtualListEnv.ts @@ -1,6 +1,6 @@ import {afterEach, beforeEach, vi} from 'vitest' -export const setupVirtualisedEnvironment = ( +export const setupVirtualListEnv = ( dataTestId?: string, rectWidth: number = 350, rectHeight: number = 800, From cdb12bb4c28aa33421da72136d4c69d63952b8fc Mon Sep 17 00:00:00 2001 From: Jordan Lawrence Date: Fri, 20 Dec 2024 14:08:09 +0000 Subject: [PATCH 3/3] refactor: tidy to ReleasesOverview.test --- .../releases/tool/overview/__tests__/ReleasesOverview.test.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/sanity/src/core/releases/tool/overview/__tests__/ReleasesOverview.test.tsx b/packages/sanity/src/core/releases/tool/overview/__tests__/ReleasesOverview.test.tsx index 43e0e2f1fcd..fc8e079e4f3 100644 --- a/packages/sanity/src/core/releases/tool/overview/__tests__/ReleasesOverview.test.tsx +++ b/packages/sanity/src/core/releases/tool/overview/__tests__/ReleasesOverview.test.tsx @@ -1,7 +1,6 @@ import {act, fireEvent, render, screen, waitFor, within} from '@testing-library/react' import {format, set} from 'date-fns' import {useState} from 'react' -// import {usePerspective} from 'sanity' import {useRouter} from 'sanity/router' import {beforeEach, describe, expect, it, vi} from 'vitest' @@ -201,8 +200,6 @@ describe('ReleasesOverview', () => { beforeEach(async () => { mockUseTimeZone.mockRestore() - mockGetLocaleTimeZone.mockRestore() - mockUsePerspective.mockRestore() mockUseReleases.mockReturnValue({ ...useReleasesMockReturn, archivedReleases: [archivedScheduledRelease, publishedASAPRelease],