From 215341d1fcbfe4b9a76665244ed1b8bfe3757e7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karen=20Pinz=C3=A1s=20Morrongiello?= <45268098+kpinzas-sh@users.noreply.github.com> Date: Wed, 11 Aug 2021 17:14:15 -0400 Subject: [PATCH] Add CalloutCard, Caption, CheckableButton, Resizer, VideoThumbnail test modernization --- UNRELEASED.md | 2 +- .../CalloutCard/tests/CalloutCard.test.tsx | 71 +++++++++------ src/components/Caption/tests/Caption.test.tsx | 11 ++- .../tests/CheckableButton.test.tsx | 41 +++++---- .../TextField/components/Resizer/Resizer.tsx | 4 +- .../components/Resizer/tests/Resizer.test.tsx | 71 +++++++-------- .../tests/VideoThumbnail.test.tsx | 88 +++++++------------ 7 files changed, 138 insertions(+), 150 deletions(-) diff --git a/UNRELEASED.md b/UNRELEASED.md index 33b84027ace..00ff647a77a 100644 --- a/UNRELEASED.md +++ b/UNRELEASED.md @@ -46,7 +46,7 @@ Use [the changelog guidelines](https://git.io/polaris-changelog-guidelines) to f - Modernized tests for DualThumb ([#4341](https://github.com/Shopify/polaris-react/pull/4341)) - Modernized tests for AppProvider, AfterInitialMount components([#4315](https://github.com/Shopify/polaris-react/pull/4331)) - Modernized tests for SkeletonBodyTest, SkeletonDisplayTest, SkeletonPage, SkeletonThumbnail, and Spinner components ([#4353](https://github.com/Shopify/polaris-react/pull/4353)) - +- Modernized tests for CalloutCard, Caption, CheckableButton, Resizer, VideoThumbnail ([#4387](https://github.com/Shopify/polaris-react/pull/4387)) - Modernized tests for Message, Menu, Search, SearchDismissOverlay, SearchField, UserMenu and TopBar components. ([#4311](https://github.com/Shopify/polaris-react/pull/4311)) ### Deprecations diff --git a/src/components/CalloutCard/tests/CalloutCard.test.tsx b/src/components/CalloutCard/tests/CalloutCard.test.tsx index b70282eb1f1..b7386f1b6fe 100644 --- a/src/components/CalloutCard/tests/CalloutCard.test.tsx +++ b/src/components/CalloutCard/tests/CalloutCard.test.tsx @@ -1,6 +1,5 @@ import React from 'react'; -// eslint-disable-next-line no-restricted-imports -import {mountWithAppProvider} from 'test-utilities/legacy'; +import {mountWithApp} from 'test-utilities'; import {Button, ButtonGroup} from 'components'; import {CalloutCard} from '../CalloutCard'; @@ -9,56 +8,70 @@ describe('', () => { const illustration = 'https://cdn.shopify.com/s/assets/admin/checkout/settings-customizecart-705f57c725ac05be5a34ec20c05b94298cb8afd10aac7bd9c7ad02030f48cfa0.svg'; const spy = jest.fn(); - const calloutCard = mountWithAppProvider( - -

Content

-
, - ); + + function calloutCardMock() { + return mountWithApp( + +

Content

+
, + ); + } it('renders its children', () => { - expect(calloutCard.find('p').first().contains('Content')).toBe(true); + const calloutCard = calloutCardMock(); + expect(calloutCard.find('p')).toContainReactText('Content'); }); it('renders the title as an h2 element', () => { - expect(calloutCard.find('h2').first().contains('Title')).toBe(true); + const calloutCard = calloutCardMock(); + expect(calloutCard.find('h2')).toContainReactText('Title'); }); it('renders the illustration', () => { - expect(calloutCard.find('img').prop('src')).toBe(illustration); + const calloutCard = calloutCardMock(); + expect(calloutCard).toContainReactComponent('img', { + src: illustration, + }); }); it('renders the primaryAction as an a tag with the given url', () => { - expect(calloutCard.find('a').prop('href')).toBe('https://www.shopify.com'); + const calloutCard = calloutCardMock(); + expect(calloutCard).toContainReactComponent('a', { + href: 'https://www.shopify.com', + }); }); it('renders the primaryAction as an a tag with the given content', () => { - expect(calloutCard.find('a').contains('Customize checkout')).toBe(true); + const calloutCard = calloutCardMock(); + expect(calloutCard.find('a')).toContainReactText('Customize checkout'); }); it('renders a secondary action with the given content in a button group', () => { - expect(calloutCard.find(Button).last().text()).toBe('Secondary action'); - expect(calloutCard.find(ButtonGroup)).toHaveLength(1); + const calloutCard = calloutCardMock(); + expect(calloutCard).toContainReactComponentTimes(ButtonGroup, 1); + expect(calloutCard).toContainReactComponent(Button, { + children: 'Secondary action', + }); }); it('is dismissed', () => { - expect(calloutCard.find(Button)).toHaveLength(3); - - calloutCard.find(Button).first().simulate('click'); - + const calloutCard = calloutCardMock(); + expect(calloutCard).toContainReactComponentTimes(Button, 3); + calloutCard.findAll(Button)[0].trigger('onClick'); expect(spy).toHaveBeenCalled(); }); it('only renders one button when only a primary action is given', () => { - const oneActionCalloutCard = mountWithAppProvider( + const oneActionCalloutCard = mountWithApp( ', () => { , ); - expect(oneActionCalloutCard.find(Button)).toHaveLength(1); + expect(oneActionCalloutCard).toContainReactComponent(Button); }); }); diff --git a/src/components/Caption/tests/Caption.test.tsx b/src/components/Caption/tests/Caption.test.tsx index e0c57760cee..f3c8c5a5a90 100644 --- a/src/components/Caption/tests/Caption.test.tsx +++ b/src/components/Caption/tests/Caption.test.tsx @@ -1,18 +1,17 @@ import React from 'react'; -// eslint-disable-next-line no-restricted-imports -import {mountWithAppProvider} from 'test-utilities/legacy'; +import {mountWithApp} from 'test-utilities'; import {Caption} from '../Caption'; describe('', () => { it('renders a p tag', () => { - const caption = mountWithAppProvider(Caption text); - expect(caption.find('p')).toHaveLength(1); + const caption = mountWithApp(Caption text); + expect(caption).toContainReactComponentTimes('p', 1); }); it('renders its children', () => { const captionMarkup = 'Caption text'; - const caption = mountWithAppProvider({captionMarkup}); - expect(caption.contains(captionMarkup)).toBe(true); + const caption = mountWithApp({captionMarkup}); + expect(caption).toContainReactText(captionMarkup); }); }); diff --git a/src/components/CheckableButton/tests/CheckableButton.test.tsx b/src/components/CheckableButton/tests/CheckableButton.test.tsx index 7f72982bfe9..78298c3ddc9 100644 --- a/src/components/CheckableButton/tests/CheckableButton.test.tsx +++ b/src/components/CheckableButton/tests/CheckableButton.test.tsx @@ -1,6 +1,5 @@ import React from 'react'; -// eslint-disable-next-line no-restricted-imports -import {mountWithAppProvider} from 'test-utilities/legacy'; +import {mountWithApp} from 'test-utilities'; import {Checkbox} from 'components'; import {CheckableButton} from '../CheckableButton'; @@ -18,43 +17,49 @@ describe('', () => { describe('select', () => { it('is passed down to Checkbox', () => { const {selected} = CheckableButtonProps; - const element = mountWithAppProvider( + const element = mountWithApp( , ); - expect(element.find(Checkbox).prop('checked')).toStrictEqual(selected); + expect(element).toContainReactComponent(Checkbox, { + checked: selected, + }); + expect(element).toContainReactComponentTimes(Checkbox, 1); }); }); describe('label', () => { it('is passed down to span', () => { const {label} = CheckableButtonProps; - const element = mountWithAppProvider( + const element = mountWithApp( , ); - expect(element.find('span').last().text()).toStrictEqual(label); + expect(element).toContainReactComponent('span', { + className: 'Label', + children: label, + }); }); }); describe('accessibilityLabel', () => { it('sets the label on the Checkbox', () => { const {accessibilityLabel} = CheckableButtonProps; - const element = mountWithAppProvider( + const element = mountWithApp( , ); - expect(element.find(Checkbox).first().prop('label')).toStrictEqual( - accessibilityLabel, - ); + expect(element).toContainReactComponent(Checkbox, { + label: accessibilityLabel, + }); }); describe('disabled', () => { it('is passed down to checkbox', () => { const {disabled} = CheckableButtonProps; - const element = mountWithAppProvider( + const element = mountWithApp( , ); - expect(element.find(Checkbox).first().prop('disabled')).toStrictEqual( + expect(element).toContainReactComponent(Checkbox, { disabled, - ); + }); }); }); }); @@ -62,21 +67,23 @@ describe('', () => { describe('onToggleAll', () => { it('is called when the CheckableButton is clicked', () => { const spy = jest.fn(); - const element = mountWithAppProvider( + const element = mountWithApp( , ); - element.find('div').first().simulate('click'); + element.find('div')!.trigger('onClick'); expect(spy).toHaveBeenCalled(); }); it('is called when the CheckableButton pressed with spacebar', () => { const spy = jest.fn(); - const element = mountWithAppProvider( + const element = mountWithApp( , ); - element.find(Checkbox).first().simulate('click', { + + element.find(Checkbox)!.find('input')!.trigger('onKeyUp', { keyCode: Key.Space, }); + expect(spy).toHaveBeenCalled(); }); }); diff --git a/src/components/TextField/components/Resizer/Resizer.tsx b/src/components/TextField/components/Resizer/Resizer.tsx index eec889c68c1..276c19548e2 100644 --- a/src/components/TextField/components/Resizer/Resizer.tsx +++ b/src/components/TextField/components/Resizer/Resizer.tsx @@ -35,7 +35,6 @@ export function Resizer({ const minimumLinesMarkup = minimumLines ? (
+
', () => { it('cancels existing animationFrame on update', () => { const cancelAnimationFrameSpy = jest.spyOn(window, 'cancelAnimationFrame'); const contents = 'Contents'; - const resizer = mountWithAppProvider( + const resizer = mountWithApp( ', () => { ); resizer.setProps({currentHeight: 2}); - trigger(resizer.find(EventListener), 'handler'); + resizer.find(EventListener)!.trigger('handler'); expect(cancelAnimationFrameSpy).toHaveBeenCalled(); }); @@ -46,7 +41,7 @@ describe('', () => { it('cancels the animationFrame unmount', () => { const cancelAnimationFrameSpy = jest.spyOn(window, 'cancelAnimationFrame'); const contents = 'Contents'; - const resizer = mountWithAppProvider( + const resizer = mountWithApp( , ); @@ -58,52 +53,47 @@ describe('', () => { describe('contents', () => { it('renders contents', () => { const contents = 'Contents'; - const resizer = mountWithAppProvider( + const resizer = mountWithApp( , ); - const contentsNode = findByTestID(resizer, 'ContentsNode'); - expect(contentsNode.text()).toBe(contents); + expect(resizer.find('div')).toContainReactText(contents); }); it('encodes HTML entities', () => { const contents = `
&\nContents
`; - const resizer = mountWithAppProvider( + const resizer = mountWithApp( , ); - const contentsNode = findByTestID(resizer, 'ContentsNode'); const expectedEncodedContents = '<div>&
Contents</div>
'; - expect(contentsNode.html()).toContain(expectedEncodedContents); + expect(resizer)!.toContainReactHtml(expectedEncodedContents); }); it('ignores carriage returns when rendering content', () => { const contents = `
&\n\r\r\rContents
`; - const resizer = mountWithAppProvider( + const resizer = mountWithApp( , ); - const contentsNode = findByTestID(resizer, 'ContentsNode'); const expectedEncodedContents = '<div>&
Contents</div>
'; - expect(contentsNode.html()).toContain(expectedEncodedContents); + expect(resizer)!.toContainReactHtml(expectedEncodedContents); }); }); describe('minimumLines', () => { it('renders a number of
tags equivalent to minimumLines', () => { const minimumLines = 3; - const resizer = mountWithAppProvider( + const resizer = mountWithApp( , ); - const breakingSpaces = findByTestID(resizer, 'MinimumLines'); - expect(breakingSpaces.html()).toContain('


'); + expect(resizer.find('div'))!.toContainReactHtml('


'); }); it('renders nothing when minimumLines is undefined', () => { - const resizer = mountWithAppProvider( + const resizer = mountWithApp( , ); - const breakingSpaces = findByTestID(resizer, 'MinimumLines'); - expect(breakingSpaces).toHaveLength(0); + expect(resizer.find('div'))!.not.toContainReactHtml('


'); }); }); @@ -118,7 +108,7 @@ describe('', () => { it('is called on mount if minimumLines is provided', () => { const spy = jest.fn(); - mountWithAppProvider( + mountWithApp( ', () => { it('is not called on mount if minimumLines is not provided', () => { const spy = jest.fn(); - mountWithAppProvider( + mountWithApp( , ); animationFrame.runFrame(); @@ -141,7 +131,7 @@ describe('', () => { it('is not called on mount if currentHeight is the same as DOM height', () => { const spy = jest.fn(); - mountWithAppProvider( + mountWithApp( ', () => { it('is called again on resize', () => { const spy = jest.fn(); const currentHeight = 50; - const resizer = mountWithAppProvider( + const resizer = mountWithApp( ', () => { />, ); resizer.setProps({currentHeight: 1}); - trigger(resizer.find(EventListener), 'handler'); + resizer.find(EventListener)?.trigger('handler'); animationFrame.runFrame(); expect(spy).toHaveBeenCalledWith(30); }); @@ -173,7 +163,7 @@ describe('', () => { it('is not called again on resize if minimumLines is not provided', () => { const spy = jest.fn(); const currentHeight = 0; - const resizer = mountWithAppProvider( + const resizer = mountWithApp( ', () => { />, ); resizer.setProps({currentHeight: 1}); - trigger(resizer.find(EventListener), 'handler'); + resizer.find(EventListener)?.trigger('handler'); animationFrame.runFrame(); expect(spy).toHaveBeenCalledTimes(0); }); @@ -190,7 +180,7 @@ describe('', () => { it('is not called again on resize if currentHeight is the same as DOM height', () => { const spy = jest.fn(); const currentHeight = 0; - const resizer = mountWithAppProvider( + const resizer = mountWithApp( ', () => { />, ); resizer.setProps({currentHeight: 1}); - trigger(resizer.find(EventListener), 'handler'); + + resizer.find(EventListener)?.trigger('handler'); animationFrame.runFrame(); expect(spy).toHaveBeenCalledTimes(0); }); @@ -206,23 +197,25 @@ describe('', () => { describe('aria-hidden', () => { it('renders aria-hidden as true', () => { const contents = 'Contents'; - const resizer = mountWithAppProvider( + const resizer = mountWithApp( , ); - const wrapperDiv = findByTestID(resizer, 'ResizerWrapper'); - expect(wrapperDiv.prop('aria-hidden')).toBe(true); + expect(resizer).toContainReactComponent('div', { + className: 'Resizer', + 'aria-hidden': true, + }); }); }); describe('lifecycle', () => { it('mounts safely', () => { expect(() => { - mountWithAppProvider(); + mountWithApp(); }).not.toThrow(); }); it('updates safely', () => { - const resizer = mountWithAppProvider(); + const resizer = mountWithApp(); expect(() => { resizer.setProps({contents: 'new content'}); @@ -230,7 +223,7 @@ describe('', () => { }); it('unmounts safely', () => { - const resizer = mountWithAppProvider(); + const resizer = mountWithApp(); expect(() => { resizer.unmount(); diff --git a/src/components/VideoThumbnail/tests/VideoThumbnail.test.tsx b/src/components/VideoThumbnail/tests/VideoThumbnail.test.tsx index b03b7d357bf..229b4279d1e 100644 --- a/src/components/VideoThumbnail/tests/VideoThumbnail.test.tsx +++ b/src/components/VideoThumbnail/tests/VideoThumbnail.test.tsx @@ -14,11 +14,13 @@ describe('', () => { it('renders with play button and custom overlay', () => { const videoThumbnail = mountWithApp(); + expect(videoThumbnail).toContainReactComponent('div', { + className: 'Thumbnail', + style: { + backgroundImage: `url(${mockProps.thumbnailUrl})`, + }, + }); expect(videoThumbnail.find('button')).not.toBeNull(); - expect( - videoThumbnail.find('div', {className: 'Thumbnail'})!.prop('style')! - .backgroundImage, - ).toBe(`url(${mockProps.thumbnailUrl})`); }); }); @@ -37,41 +39,30 @@ describe('', () => { , ); - const timestamp = videoThumbnail - .find('p', { - className: 'Timestamp', - }) - ?.text(); - - expect(timestamp).toStrictEqual('0:45'); + expect(videoThumbnail).toContainReactComponent('p', { + className: 'Timestamp', + children: '0:45', + }); }); it('renders a timestamp with seconds and minutes only when less than 60 minutes', () => { const videoThumbnail = mountWithApp( , ); - - const timestamp = videoThumbnail - .find('p', { - className: 'Timestamp', - }) - ?.text(); - - expect(timestamp).toStrictEqual('2:15'); + expect(videoThumbnail).toContainReactComponent('p', { + className: 'Timestamp', + children: '2:15', + }); }); it('renders timestamp with seconds, minutes, and hours when greater than 60 minutes', () => { const videoThumbnail = mountWithApp( , ); - - const timestamp = videoThumbnail - .find('p', { - className: 'Timestamp', - }) - ?.text(); - - expect(timestamp).toStrictEqual('1:02:25'); + expect(videoThumbnail).toContainReactComponent('p', { + className: 'Timestamp', + children: '1:02:25', + }); }); }); @@ -106,11 +97,8 @@ describe('', () => { className: 'Progress', }); - const progressIndicator = videoThumbnail.find('div', { + expect(videoThumbnail).toContainReactComponent('div', { className: 'Indicator', - }); - - expect(progressIndicator).toHaveReactProps({ style: expect.objectContaining({ transform: 'scaleX(0)', }), @@ -131,11 +119,8 @@ describe('', () => { className: 'Progress', }); - const progressIndicator = videoThumbnail.find('div', { + expect(videoThumbnail).toContainReactComponent('div', { className: 'Indicator', - }); - - expect(progressIndicator).toHaveReactProps({ style: expect.objectContaining({ transform: 'scaleX(0)', }), @@ -156,11 +141,8 @@ describe('', () => { className: 'Progress', }); - const progressIndicator = videoThumbnail.find('div', { + expect(videoThumbnail).toContainReactComponent('div', { className: 'Indicator', - }); - - expect(progressIndicator).toHaveReactProps({ style: expect.objectContaining({ transform: 'scaleX(0.5)', }), @@ -251,9 +233,9 @@ describe('', () => { accessibilityLabel={accessibilityLabel} />, ); - expect(videoThumbnail.find('button')!.prop('aria-label')).toStrictEqual( - accessibilityLabel, - ); + expect(videoThumbnail).toContainReactComponent('button', { + 'aria-label': accessibilityLabel, + }); }); describe('when videoLength is provided', () => { @@ -265,10 +247,9 @@ describe('', () => { , ); - const actualLabel = videoThumbnail.find('button')!.prop('aria-label'); - const expectedLabel = `${defaultLabelWithDuration} 45 seconds`; - - expect(actualLabel).toStrictEqual(expectedLabel); + expect(videoThumbnail).toContainReactComponent('button', { + 'aria-label': `${defaultLabelWithDuration} 45 seconds`, + }); }); it('sets the default label with time in seconds and minutes when less than 60 minutes', () => { @@ -277,10 +258,9 @@ describe('', () => { , ); - const actualLabel = videoThumbnail.find('button')!.prop('aria-label'); - const expectedLabel = `${defaultLabelWithDuration} 2 minutes and 15 seconds`; - - expect(actualLabel).toStrictEqual(expectedLabel); + expect(videoThumbnail).toContainReactComponent('button', { + 'aria-label': `${defaultLabelWithDuration} 2 minutes and 15 seconds`, + }); }); it('sets the default label with time in seconds, minutes, and hours when greater than 60 minutes', () => { @@ -288,11 +268,9 @@ describe('', () => { const videoThumbnail = mountWithApp( , ); - - const actualLabel = videoThumbnail.find('button')!.prop('aria-label'); - const expectedLabel = `${defaultLabelWithDuration} 1 hour, 2 minutes, and 25 seconds`; - - expect(actualLabel).toStrictEqual(expectedLabel); + expect(videoThumbnail).toContainReactComponent('button', { + 'aria-label': `${defaultLabelWithDuration} 1 hour, 2 minutes, and 25 seconds`, + }); }); }); });