From 0c4afc418290eb7e5ddf1141c17f920180b4cf8b Mon Sep 17 00:00:00 2001 From: Jordan Lawrence Date: Tue, 24 Dec 2024 15:53:34 +0000 Subject: [PATCH 1/2] fix(releases): hiding the calendar in type picker when not scheduled type --- .../releases/tool/detail/ReleaseTypePicker.tsx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/sanity/src/core/releases/tool/detail/ReleaseTypePicker.tsx b/packages/sanity/src/core/releases/tool/detail/ReleaseTypePicker.tsx index 031de4d71a5..3bba587c407 100644 --- a/packages/sanity/src/core/releases/tool/detail/ReleaseTypePicker.tsx +++ b/packages/sanity/src/core/releases/tool/detail/ReleaseTypePicker.tsx @@ -108,9 +108,7 @@ export function ReleaseTypePicker(props: {release: ReleaseDocument}): JSX.Elemen }, [inputValue, isPublishDateInPast, publishDate, release.publishAt, releaseType, t, tRelease]) const handleButtonReleaseTypeChange = useCallback((pickedReleaseType: ReleaseType) => { - if (pickedReleaseType === 'scheduled') { - setDateInputOpen(true) - } + setDateInputOpen(pickedReleaseType === 'scheduled') setReleaseType(pickedReleaseType) const nextPublishAt = pickedReleaseType === 'scheduled' ? new Date() : undefined @@ -136,6 +134,11 @@ export function ReleaseTypePicker(props: {release: ReleaseDocument}): JSX.Elemen } }, []) + const handleOnPickerClick = () => { + if (open) close() + else setOpen(true) + } + const PopoverContent = () => { return ( @@ -199,7 +202,7 @@ export function ReleaseTypePicker(props: {release: ReleaseDocument}): JSX.Elemen isReleaseScheduled || release.state === 'archived' || release.state === 'published' } mode="bleed" - onClick={() => setOpen(!open)} + onClick={handleOnPickerClick} padding={2} ref={buttonRef} tooltipProps={{ @@ -209,10 +212,11 @@ export function ReleaseTypePicker(props: {release: ReleaseDocument}): JSX.Elemen selected={open} tone={getReleaseTone({...release, metadata: {...release.metadata, releaseType}})} style={{borderRadius: '999px'}} + data-testid="release-type-picker" > {isUpdating ? ( - + ) : ( Date: Tue, 24 Dec 2024 15:53:52 +0000 Subject: [PATCH 2/2] test(releases): adding tests for ReleaseTypePicker --- .../detail/__tests__/ReleaseDetail.test.tsx | 11 - .../__tests__/ReleaseTypePicker.test.tsx | 201 ++++++++++++++++++ 2 files changed, 201 insertions(+), 11 deletions(-) create mode 100644 packages/sanity/src/core/releases/tool/detail/__tests__/ReleaseTypePicker.test.tsx diff --git a/packages/sanity/src/core/releases/tool/detail/__tests__/ReleaseDetail.test.tsx b/packages/sanity/src/core/releases/tool/detail/__tests__/ReleaseDetail.test.tsx index 10a32c2fdc6..1f6ac051bf6 100644 --- a/packages/sanity/src/core/releases/tool/detail/__tests__/ReleaseDetail.test.tsx +++ b/packages/sanity/src/core/releases/tool/detail/__tests__/ReleaseDetail.test.tsx @@ -157,7 +157,6 @@ describe('ReleaseDetail', () => { describe('after releases have loaded', () => { describe('with unpublished release', () => { - const currentDate = new Date().toISOString() beforeEach(async () => { vi.clearAllMocks() }) @@ -167,16 +166,6 @@ describe('after releases have loaded', () => { fireEvent.click(screen.getByTestId('release-menu-button')) screen.getByTestId('archive-release-menu-item') }) - - // eslint-disable-next-line no-warning-comments - // TODO: unsure if this will work this way in the future - /*it('should navigate to release review changes screen', () => { - expect(screen.getByTestId('review-button').closest('button')).not.toBeDisabled() - fireEvent.click(screen.getByTestId('review-button')) - expect(mockRouterNavigate).toHaveBeenCalledWith({ - path: '/test-release-id?screen=review', - }) - })*/ } describe('with pending document validation', () => { diff --git a/packages/sanity/src/core/releases/tool/detail/__tests__/ReleaseTypePicker.test.tsx b/packages/sanity/src/core/releases/tool/detail/__tests__/ReleaseTypePicker.test.tsx new file mode 100644 index 00000000000..739c86487fa --- /dev/null +++ b/packages/sanity/src/core/releases/tool/detail/__tests__/ReleaseTypePicker.test.tsx @@ -0,0 +1,201 @@ +import {fireEvent, render, screen, waitFor, within} from '@testing-library/react' +import {beforeEach, describe, expect, it, vi} from 'vitest' + +import {getByDataUi, queryByDataUi} from '../../../../../../test/setup/customQueries' +import {createTestProvider} from '../../../../../../test/testUtils/TestProvider' +import {useTimeZoneMockReturn} from '../../../../scheduledPublishing/hooks/__tests__/__mocks__/useTimeZone.mock' +import { + activeASAPRelease, + activeScheduledRelease, + activeUndecidedRelease, + publishedASAPRelease, +} from '../../../__fixtures__/release.fixture' +import {releasesUsEnglishLocaleBundle} from '../../../i18n' +import { + mockUseReleaseOperations, + useReleaseOperationsMockReturn, +} from '../../../store/__tests__/__mocks/useReleaseOperations.mock' +import {ReleaseTypePicker} from '../ReleaseTypePicker' + +vi.mock('../../../store/useReleaseOperations', () => ({ + useReleaseOperations: vi.fn(() => useReleaseOperationsMockReturn), +})) + +vi.mock('../../../../scheduledPublishing/hooks/useTimeZone', async (importOriginal) => ({ + ...(await importOriginal()), + useTimeZone: vi.fn(() => useTimeZoneMockReturn), +})) + +const renderComponent = async (release = activeASAPRelease) => { + const wrapper = await createTestProvider({ + resources: [releasesUsEnglishLocaleBundle], + }) + + render(, {wrapper}) + + await waitFor(() => { + expect(screen.getByTestId('release-type-picker')).toBeInTheDocument() + }) +} + +const mockUpdateRelease = vi.fn() + +describe('ReleaseTypePicker', () => { + beforeEach(() => { + vi.clearAllMocks() + mockUseReleaseOperations.mockReturnValue({ + ...useReleaseOperationsMockReturn, + updateRelease: mockUpdateRelease.mockResolvedValue({}), + }) + }) + + describe('renders the label for different release types', () => { + it('renders the button and displays for ASAP release', async () => { + await renderComponent() + + expect(screen.getByText('ASAP')).toBeInTheDocument() + }) + + it('renders the button and displays for undecided release', async () => { + await renderComponent(activeUndecidedRelease) + + expect(screen.getByText('Undecided')).toBeInTheDocument() + }) + + it('renders the button and displays the date for scheduled release', async () => { + await renderComponent(activeScheduledRelease) + + expect(screen.getByText('Oct 10, 2023', {exact: false})).toBeInTheDocument() + }) + }) + + describe('interacting with the popup content', () => { + it('opens the popover when the button is clicked', async () => { + await renderComponent() + + const pickerButton = screen.getByRole('button') + fireEvent.click(pickerButton) + getByDataUi(document.body, 'Popover') + }) + + it('does not show calendar for ASAP and undecided releases', async () => { + await renderComponent() + + const pickerButton = screen.getByRole('button') + fireEvent.click(pickerButton) + expect(screen.queryByTestId('date-input')).not.toBeInTheDocument() + expect(queryByDataUi(document.body, 'Calendar')).not.toBeInTheDocument() + + const scheduledTab = screen.getByText('Undecided') + fireEvent.click(scheduledTab) + expect(screen.queryByTestId('date-input')).not.toBeInTheDocument() + expect(queryByDataUi(document.body, 'Calendar')).not.toBeInTheDocument() + }) + + it('switches to "Scheduled" release type and displays the date input', async () => { + await renderComponent() + + const pickerButton = screen.getByRole('button') + fireEvent.click(pickerButton) + const scheduledTab = screen.getByText('At time') + fireEvent.click(scheduledTab) + expect(screen.getByTestId('date-input')).toBeInTheDocument() + expect(getByDataUi(document.body, 'Calendar')).toBeInTheDocument() + }) + + it('hides calendar when moving back from scheduled option', async () => { + await renderComponent() + + const pickerButton = screen.getByRole('button') + fireEvent.click(pickerButton) + const scheduledTab = screen.getByText('At time') + fireEvent.click(scheduledTab) + const asapTab = screen.getByText('ASAP') + fireEvent.click(asapTab) + + expect(screen.queryByTestId('date-input')).not.toBeInTheDocument() + expect(queryByDataUi(document.body, 'Calendar')).not.toBeInTheDocument() + }) + + it('sets the selected scheduled time when popup closed', async () => { + await renderComponent() + + const pickerButton = screen.getByRole('button') + fireEvent.click(pickerButton) + const scheduledTab = screen.getByText('At time') + fireEvent.click(scheduledTab) + + const Calendar = getByDataUi(document.body, 'CalendarMonth') + + // Select the 10th day in the calendar + fireEvent.click(within(Calendar).getByText('10')) + expect(mockUpdateRelease).not.toHaveBeenCalled() + + // Close the popup and check if the release is updated + fireEvent.click(screen.getByTestId('release-type-picker')) + expect(mockUpdateRelease).toHaveBeenCalledTimes(1) + expect(mockUpdateRelease).toHaveBeenCalledWith({ + ...activeASAPRelease, + metadata: expect.objectContaining({ + ...activeASAPRelease.metadata, + releaseType: 'scheduled', + intendedPublishAt: expect.stringMatching(/^\d{4}-\d{2}-10T\d{2}:\d{2}:\d{2}\.\d{3}Z$/), + }), + }) + }) + + it('sets the release type to undecided when undecided is selected', async () => { + await renderComponent() + + const pickerButton = screen.getByRole('button') + fireEvent.click(pickerButton) + const undecidedTab = screen.getByText('Undecided') + fireEvent.click(undecidedTab) + fireEvent.click(screen.getByTestId('release-type-picker')) + expect(mockUpdateRelease).toHaveBeenCalledTimes(1) + expect(mockUpdateRelease).toHaveBeenCalledWith({ + ...activeASAPRelease, + metadata: expect.objectContaining({ + ...activeASAPRelease.metadata, + intendedPublishAt: undefined, + releaseType: 'undecided', + }), + }) + }) + }) + + describe('picker behavior based on release state', () => { + it('disables the picker for archived releases', async () => { + await renderComponent({...activeASAPRelease, state: 'archived'}) + + const pickerButton = screen.getByRole('button') + expect(pickerButton).toBeDisabled() + }) + + it('disables the picker for published releases', async () => { + await renderComponent(publishedASAPRelease) + + const pickerButton = screen.getByRole('button') + expect(pickerButton).toBeDisabled() + }) + + it('shows a spinner when updating the release', async () => { + // keep promise pending + mockUseReleaseOperations.mockReturnValue({ + ...useReleaseOperationsMockReturn, + updateRelease: vi.fn().mockImplementation(() => { + return new Promise(() => {}) + }), + }) + await renderComponent() + + const pickerButton = screen.getByRole('button') + fireEvent.click(pickerButton) + fireEvent.click(screen.getByText('Undecided')) + fireEvent.click(screen.getByTestId('release-type-picker')) + + // Check if the spinner is displayed while updating + screen.getByTestId('updating-release-spinner') + }) + }) +})