diff --git a/.eslintrc.js b/.eslintrc.js index 66b25a11..d37cd07f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -3,15 +3,21 @@ module.exports = { env: { node: true }, - 'extends': [ + plugins: ['testing-library'], + extends: [ 'plugin:vue/essential', '@vue/standard', - '@nuxtjs' + '@nuxtjs', + 'plugin:testing-library/recommended', + 'plugin:testing-library/vue' ], rules: { 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', - 'curly': 'off' + curly: 'off', + 'testing-library/no-debug': 'error', + 'testing-library/prefer-screen-queries': 'error', + 'testing-library/await-fire-event': 'error' }, parserOptions: { parser: 'babel-eslint' @@ -23,10 +29,7 @@ module.exports = { }, overrides: [ { - files: [ - '**/__tests__/*.{j,t}s?(x)', - '**/tests/*.{j,t}s?(x)' - ], + files: ['**/__tests__/*.{j,t}s?(x)', '**/tests/*.{j,t}s?(x)'], env: { jest: true } diff --git a/babel.config.js b/babel.config.js index 28460893..c61b6267 100644 --- a/babel.config.js +++ b/babel.config.js @@ -6,7 +6,7 @@ module.exports = { ], env: { test: { - plugins: ['transform-es2015-modules-commonjs'] + // plugins: ['transform-es2015-modules-commonjs'] } } } diff --git a/jest.config.js b/jest.config.js index e03e1bb7..d2c950c2 100644 --- a/jest.config.js +++ b/jest.config.js @@ -29,5 +29,6 @@ module.exports = { watchPlugins: [ 'jest-watch-typeahead/filename', 'jest-watch-typeahead/testname' - ] + ], + testEnvironmentOptions: { resources: 'usable' } } diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 00000000..29037a62 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "paths": { + "~/*": ["./*"], + "@/*": ["./*"], + "~~/*": ["./*"], + "@@/*": ["./*"] + } + }, + "exclude": ["node_modules", ".nuxt", "dist"] +} diff --git a/package.json b/package.json index 0bb0e3ac..d5455650 100644 --- a/package.json +++ b/package.json @@ -147,6 +147,7 @@ "eslint-loader": "^3.0.3", "eslint-plugin-nuxt": ">=0.4.2", "eslint-plugin-prettier": "^3.1.2", + "eslint-plugin-testing-library": "^3.3.1", "jest": "^25.1.0", "prettier": "^1.19.1", "rimraf": "^3.0.2", diff --git a/packages/chakra-ui-core/src/CAccordion/tests/CAccordion.test.js b/packages/chakra-ui-core/src/CAccordion/tests/CAccordion.test.js index f6031289..68126a71 100644 --- a/packages/chakra-ui-core/src/CAccordion/tests/CAccordion.test.js +++ b/packages/chakra-ui-core/src/CAccordion/tests/CAccordion.test.js @@ -1,5 +1,5 @@ import { CAccordion, CAccordionItem, CAccordionHeader, CAccordionPanel, CAccordionIcon } from '..' -import { render, userEvent, fireEvent } from '@/tests/test-utils' +import { render, userEvent, screen } from '@/tests/test-utils' const renderComponent = (props) => { const base = { @@ -10,9 +10,8 @@ const renderComponent = (props) => { } it('should render correctly', () => { - const { asFragment } = renderComponent( - { - template: ` + const { asFragment } = renderComponent({ + template: ` Section 1 title @@ -20,13 +19,12 @@ it('should render correctly', () => { ` - } - ) + }) expect(asFragment()).toMatchSnapshot() }) it('uncontrolled: It opens the accordion panel', () => { - const { getByTestId } = renderComponent({ + renderComponent({ template: ` @@ -35,14 +33,13 @@ it('uncontrolled: It opens the accordion panel', () => { ` - } - ) - const button = getByTestId('button') + }) + const button = screen.getByTestId('button') expect(button).toHaveAttribute('aria-expanded', 'true') }) -it('uncontrolled: toggles the accordion on click', () => { - const { getByText } = renderComponent({ +it('uncontrolled: toggles the accordion on click', async () => { + renderComponent({ template: ` @@ -52,19 +49,17 @@ it('uncontrolled: toggles the accordion on click', () => { ` }) - const trigger = getByText('Trigger') - - userEvent.click(trigger) - expect(trigger).toHaveAttribute('aria-expanded', 'true') + await userEvent.click(screen.getByText('Trigger')) + expect(screen.getByText('Trigger')).toHaveAttribute('aria-expanded', 'true') // you can't toggle an accordion without passing `allowToggle` - userEvent.click(trigger) - expect(trigger).toHaveAttribute('aria-expanded', 'true') + await userEvent.click(screen.getByText('Trigger')) + expect(screen.getByText('Trigger')).toHaveAttribute('aria-expanded', 'true') }) // test the only one accordion can be visible + is not togglable -it('only one accordion can be visible + is not togglable', () => { - const { getByText } = renderComponent({ +it('only one accordion can be visible + is not togglable', async () => { + renderComponent({ template: ` @@ -78,21 +73,19 @@ it('only one accordion can be visible + is not togglable', () => { ` }) - const firstAccordion = getByText('First section') - - userEvent.click(firstAccordion) - expect(firstAccordion).toHaveAttribute('aria-expanded', 'true') + await userEvent.click(screen.getByText('First section')) + expect(screen.getByText('First section')).toHaveAttribute('aria-expanded', 'true') - userEvent.click(firstAccordion) - expect(firstAccordion).toHaveAttribute('aria-expanded', 'true') + await userEvent.click(screen.getByText('First section')) + expect(screen.getByText('First section')).toHaveAttribute('aria-expanded', 'true') }) // test the only one accordion can be visible + is togglable -it('only one accordion can be visible + is togglable', () => { - const { getByText } = renderComponent({ +it('only one accordion can be visible + is togglable', async () => { + renderComponent({ template: ` - + First section Panel 1 @@ -102,21 +95,19 @@ it('only one accordion can be visible + is togglable', () => { ` }) - const firstAccordion = getByText('First section') - // TODO: Why its not working? - // fireEvent.click(firstAccordion) - // expect(firstAccordion).toHaveAttribute('aria-expanded', 'false') + await userEvent.click(screen.getByText('First section')) + expect(screen.getByText('First section')).not.toHaveAttribute('aria-expanded') // false or null? - userEvent.click(firstAccordion) - expect(firstAccordion).toHaveAttribute('aria-expanded', 'true') + await userEvent.click(screen.getByText('First section')) + expect(screen.getByText('First section')).toHaveAttribute('aria-expanded', 'true') }) // test that multiple accordions can be opened + is togglable -it('multiple accordions can be opened + is togglable', () => { - const { getByText } = renderComponent({ +it('multiple accordions can be opened + is togglable', async () => { + renderComponent({ template: ` - + First section Panel 1 @@ -128,19 +119,16 @@ it('multiple accordions can be opened + is togglable', () => { ` }) - const firstAccordion = getByText('First section') - const secondAccordion = getByText('Second section') + expect(screen.getByText('First section')).toHaveAttribute('aria-expanded', 'true') + expect(screen.getByText('Second section')).toHaveAttribute('aria-expanded', 'true') - userEvent.click(firstAccordion) - expect(firstAccordion).toHaveAttribute('aria-expanded', 'true') - - userEvent.click(secondAccordion) - expect(firstAccordion).toHaveAttribute('aria-expanded', 'true') + await userEvent.click(screen.getByText('First section')) + expect(screen.getByText('First section')).not.toHaveAttribute('aria-expanded') }) // it has the proper aria attributes it('has the proper aria attributes', () => { - const { getByText, getByTestId } = renderComponent({ + renderComponent({ template: ` @@ -149,16 +137,48 @@ it('has the proper aria attributes', () => { ` }) - const button = getByText('Section 1 title') - const panel = getByTestId('panel1') + const button = screen.getByText('Section 1 title') + const panel = screen.getByTestId('panel1') expect(button).toHaveAttribute('aria-controls') expect(button).toHaveAttribute('aria-expanded') expect(panel).toHaveAttribute('aria-labelledby') }) -// test that tab moves focus to the next focusable element -it('tab moves focus to the next focusable element', () => { - const { getByText } = renderComponent({ +it('tab moves focus to the next focusable element', async () => { + renderComponent({ + template: ` + + + First section + Panel 1 + + + Second section + Panel 2 + + + Last section + Panel 3 + + ` + }) + + const first = screen.getByText('First section') + const second = screen.getByText('Second section') + const last = screen.getByText('Last section') + + await userEvent.tab() + expect(first).toHaveFocus() + + await userEvent.tab() + expect(second).toHaveFocus() + + await userEvent.tab() + expect(last).toHaveFocus() +}) + +it('shift+tab moves focus to the previous focusable element', async () => { + renderComponent({ template: ` @@ -176,23 +196,25 @@ it('tab moves focus to the next focusable element', () => { ` }) - const first = getByText('First section') - const second = getByText('Second section') - const last = getByText('Last section') + const first = screen.getByText('First section') + const second = screen.getByText('Second section') + const last = screen.getByText('Last section') - userEvent.tab() + await userEvent.tab() expect(first).toHaveFocus() - userEvent.tab() + await userEvent.tab() expect(second).toHaveFocus() - userEvent.tab() + await userEvent.tab() expect(last).toHaveFocus() + + await userEvent.tab({ shift: true }) // shift+tab + expect(second).toHaveFocus() }) -// test that aria-contols for button is same as id for panel it('aria-contols for button is same as id for panel', () => { - const { getByText, getByTestId } = renderComponent({ + renderComponent({ template: ` @@ -202,14 +224,13 @@ it('aria-contols for button is same as id for panel', () => { ` }) - const button = getByText('Section 1 title') - const panel = getByTestId('panel1') + const button = screen.getByText('Section 1 title') + const panel = screen.getByTestId('panel1') expect(button.getAttribute('aria-controls')).toEqual(panel.getAttribute('id')) }) -// test that aria-expanded is true/false when accordion is open/closed it('aria-expanded is true/false when accordion is open/closed', () => { - const { getByText } = renderComponent({ + renderComponent({ template: ` @@ -223,13 +244,12 @@ it('aria-expanded is true/false when accordion is open/closed', () => { ` }) - const button = getByText('Section 1 title') + const button = screen.getByText('Section 1 title') expect(button).toHaveAttribute('aria-expanded', 'true') }) -// test that panel has role=region and aria-labelledby it('panel has role=region and aria-labelledby', () => { - const { getByTestId } = renderComponent({ + renderComponent({ template: ` @@ -238,34 +258,8 @@ it('panel has role=region and aria-labelledby', () => { ` }) - const panel = getByTestId('panel1') + const panel = screen.getByTestId('panel1') expect(panel).toHaveAttribute('aria-labelledby') expect(panel).toHaveAttribute('role', 'region') }) - -// eslint-disable-next-line no-undef -xit('arrow up & down moves focus to next/previous accordion', () => { - const { getByText } = renderComponent({ - template: ` - - - Section 1 title - Panel 1 - - - Section 2 title - Panel 2 - - ` - }) - - const first = getByText('Section 1 title') - const second = getByText('Section 2 title') - - fireEvent.keyDown(first, { key: 'ArrowDown', keyCode: 40 }) - expect(second).toHaveFocus() - - fireEvent.keyDown(second, { key: 'ArrowUp', keyCode: 38 }) - expect(first).toHaveFocus() -}) diff --git a/packages/chakra-ui-core/src/CAlert/tests/CAlert.test.js b/packages/chakra-ui-core/src/CAlert/tests/CAlert.test.js index 57306430..bfbeea3c 100644 --- a/packages/chakra-ui-core/src/CAlert/tests/CAlert.test.js +++ b/packages/chakra-ui-core/src/CAlert/tests/CAlert.test.js @@ -1,14 +1,12 @@ import { CAlert, CAlertIcon, CAlertTitle, CAlertDescription, CStack } from '../..' -import icons from '../../lib/internal-icons' -import { render, defaultProviders } from '@/tests/test-utils' +import { render, screen } from '@/tests/test-utils' const renderComponent = (props) => { const base = { components: { CAlert, CAlertTitle, CAlertDescription, CAlertIcon, CStack }, - provide: () => defaultProviders({ $chakraIcons: { add: icons.add } }), template: ` - + alert title alert description `, @@ -16,23 +14,12 @@ const renderComponent = (props) => { } return render(base) } + it('should render correctly', () => { const { asFragment } = renderComponent() expect(asFragment()).toMatchSnapshot() }) -it('should display title', () => { - const { getByText } = renderComponent() - - expect(getByText('alert title')).toBeInTheDocument() -}) - -it('should display description', () => { - const { getByText } = renderComponent() - - expect(getByText('alert description')).toBeInTheDocument() -}) - it('should override icon if set explicitly', () => { const { asFragment } = renderComponent({ template: ` @@ -44,17 +31,6 @@ it('should override icon if set explicitly', () => { expect(asFragment()).toMatchSnapshot() }) -it('should have role=alert', () => { - const { getByRole } = renderComponent({ - template: ` - - - ` - }) - - getByRole('alert') -}) - it('should render correct variant styles', () => { const { asFragment } = renderComponent({ template: ` @@ -81,3 +57,26 @@ it('should render correct variant styles', () => { expect(asFragment()).toMatchSnapshot() }) + +it('should display title', () => { + renderComponent() + + expect(screen.getByText('alert title')).toBeInTheDocument() +}) + +it('should display description', () => { + renderComponent() + + expect(screen.getByText('alert description')).toBeInTheDocument() +}) + +it('should have role=alert', () => { + renderComponent({ + template: ` + + + ` + }) + + screen.getByRole('alert') +}) diff --git a/packages/chakra-ui-core/src/CAlert/tests/__snapshots__/CAlert.test.js.snap b/packages/chakra-ui-core/src/CAlert/tests/__snapshots__/CAlert.test.js.snap index c631a8ae..1f3960a7 100644 --- a/packages/chakra-ui-core/src/CAlert/tests/__snapshots__/CAlert.test.js.snap +++ b/packages/chakra-ui-core/src/CAlert/tests/__snapshots__/CAlert.test.js.snap @@ -44,39 +44,11 @@ exports[`should render correct variant styles 1`] = ` viewBox="0 0 24 24" > - - - - - - - - - - - - - - - + Data uploaded to the server. Fire on! @@ -94,39 +66,11 @@ exports[`should render correct variant styles 1`] = ` viewBox="0 0 24 24" > - - - - - - - - - - - - - - - + Data uploaded to the server. Fire on! @@ -144,39 +88,11 @@ exports[`should render correct variant styles 1`] = ` viewBox="0 0 24 24" > - - - - - - - - - - - - - - - + Data uploaded to the server. Fire on! @@ -194,39 +110,11 @@ exports[`should render correct variant styles 1`] = ` viewBox="0 0 24 24" > - - - - - - - - - - - - - - - + Data uploaded to the server. Fire on! @@ -251,36 +139,10 @@ exports[`should render correctly 1`] = ` > - - - - - - - - - - - - - + diff --git a/packages/chakra-ui-core/src/CAlertDialog/tests/CAlertDialog.test.js b/packages/chakra-ui-core/src/CAlertDialog/tests/CAlertDialog.test.js index 26fed9ee..43ee113f 100644 --- a/packages/chakra-ui-core/src/CAlertDialog/tests/CAlertDialog.test.js +++ b/packages/chakra-ui-core/src/CAlertDialog/tests/CAlertDialog.test.js @@ -1,6 +1,5 @@ -import Vue from 'vue' import { CButton, CAlertDialog, CAlertDialogContent, CAlertDialogBody, CAlertDialogFooter, CAlertDialogOverlay, CAlertDialogHeader } from '../..' -import { render, userEvent, fireEvent, waitMs } from '@/tests/test-utils' +import { render, userEvent, fireEvent, wait, screen } from '@/tests/test-utils' import { useId } from '@/packages/chakra-ui-core/src/utils' // mocks @@ -49,18 +48,19 @@ it('should render correctly', async () => { const inlineAttrs = 'isOpen' const { asFragment } = renderComponent({ inlineAttrs }) - await Vue.nextTick() - - expect(asFragment(document.body.innerHTML)).toMatchSnapshot() + await wait(() => { + expect(asFragment(document.body.innerHTML)).toMatchSnapshot() + }) }) test('clicking the close button calls the onClose callback', async () => { const onClose = jest.fn() const inlineAttrs = 'isOpen :on-close="close"' - const { getByTestId } = renderComponent({ inlineAttrs, methods: { close: onClose } }) + renderComponent({ inlineAttrs, methods: { close: onClose } }) - await Vue.nextTick() - userEvent.click(getByTestId('close-btn')) + await wait(async () => { + await userEvent.click(screen.getByTestId('close-btn')) + }) expect(onClose).toHaveBeenCalled() }) @@ -68,12 +68,12 @@ test('clicking the close button calls the onClose callback', async () => { test('pressing "esc" calls the onClose callback', async () => { const onClose = jest.fn() const inlineAttrs = ':isOpen="isOpen" :on-close="close"' - const { getByTestId } = renderComponent({ inlineAttrs, data: () => ({ isOpen: true }), methods: { close: onClose } }) - - await Vue.nextTick() - const inputInside = getByTestId('inputInsideDrawer') + renderComponent({ inlineAttrs, data: () => ({ isOpen: true }), methods: { close: onClose } }) - fireEvent.keyDown(inputInside, { key: 'Escape' }) + await wait(async () => { + const inputInside = screen.getByTestId('inputInsideDrawer') + await fireEvent.keyDown(inputInside, { key: 'Escape' }) + }) expect(onClose).toHaveBeenCalled() }) @@ -81,12 +81,12 @@ test('pressing "esc" calls the onClose callback', async () => { test('clicking overlay calls the onClose callback', async () => { const onClose = jest.fn() const inlineAttrs = ':isOpen="isOpen" :on-close="close"' - const { getByTestId } = renderComponent({ inlineAttrs, data: () => ({ isOpen: true }), methods: { close: onClose } }) - - await Vue.nextTick() - const overlay = getByTestId('overlay') + renderComponent({ inlineAttrs, data: () => ({ isOpen: true }), methods: { close: onClose } }) - userEvent.click(overlay) + await wait(async () => { + const overlay = screen.getByTestId('overlay') + await userEvent.click(overlay) + }) expect(onClose).toHaveBeenCalled() }) @@ -96,11 +96,11 @@ it('should have proper aria', async () => { const inlineAttrs = 'isOpen' renderComponent({ inlineAttrs }) - await Vue.nextTick() - const dialog = document.querySelector('section') - await waitMs() + let dialog + await wait(() => { + dialog = screen.getByRole('alertdialog') + }) - expect(dialog).toHaveAttribute('role', 'alertdialog') expect(dialog).toHaveAttribute('aria-modal', 'true') expect(dialog).toHaveAttribute('aria-labelledby', 'alert-dialog-1-label') expect(dialog).toHaveAttribute('aria-describedby', 'alert-dialog-1-desc') diff --git a/packages/chakra-ui-core/src/CAspectRatioBox/tests/CAspectRatioBox.test.js b/packages/chakra-ui-core/src/CAspectRatioBox/tests/CAspectRatioBox.test.js index 20da297d..01cc167e 100644 --- a/packages/chakra-ui-core/src/CAspectRatioBox/tests/CAspectRatioBox.test.js +++ b/packages/chakra-ui-core/src/CAspectRatioBox/tests/CAspectRatioBox.test.js @@ -1,6 +1,5 @@ import { CAspectRatioBox, CBox } from '../..' -import { render } from '@/tests/test-utils' - +import { render, screen, getElementStyles } from '@/tests/test-utils' const renderComponent = (props) => { const inlineAttrs = (props && props.inlineAttrs) || '' const base = { @@ -19,13 +18,27 @@ it('should render correctly', () => { const inlineAttrs = ':ratio="1"' const { asFragment } = renderComponent({ inlineAttrs }) expect(asFragment()).toMatchSnapshot() + + const [, emotionClassName] = [...screen.getByTestId('aspectRatioBox').classList] + const pseudoStyles = getElementStyles(`.${emotionClassName}:before`) + + expect(pseudoStyles).toContain(` + padding-bottom: 100% + `.trim()) }) it('should have correct styles', () => { const inlineAttrs = ':ratio="2"' - const { getByTestId } = renderComponent({ inlineAttrs }) - const image = getByTestId('image') - const aspectRatioBox = getByTestId('aspectRatioBox') + renderComponent({ inlineAttrs }) + const image = screen.getByTestId('image') + const aspectRatioBox = screen.getByTestId('aspectRatioBox') + + const [, emotionClassName] = [...aspectRatioBox.classList] // second className has the pseudo styles + const pseudoStyles = getElementStyles(`.${emotionClassName}:before`) + + expect(pseudoStyles).toContain(` + padding-bottom: 50% + `.trim()) expect(aspectRatioBox).toHaveStyle(` max-width: 400px; @@ -40,7 +53,4 @@ it('should have correct styles', () => { top: 0px; left: 0px; `) - - // TODO: we can't test pseudo elements.. so better test styles? - // aspectRatioBox padding-bottom }) diff --git a/packages/chakra-ui-core/src/CAvatar/CAvatar.js b/packages/chakra-ui-core/src/CAvatar/CAvatar.js index d98d0574..73a2a274 100644 --- a/packages/chakra-ui-core/src/CAvatar/CAvatar.js +++ b/packages/chakra-ui-core/src/CAvatar/CAvatar.js @@ -201,7 +201,6 @@ const CAvatar = { if (!canUseDOM) { return } - const image = new window.Image() image.src = src @@ -210,7 +209,7 @@ const CAvatar = { this.$emit('load', event) } - image.onError = (event) => { + image.onerror = (event) => { this.hasLoaded = false this.$emit('error', event) } @@ -252,7 +251,7 @@ const CAvatar = { }) } - if (this.src && !this.hasLoaded) { + if (!this.src || (this.src && !this.hasLoaded)) { if (this.name) { return h(CAvatarName, { props: { diff --git a/packages/chakra-ui-core/src/CAvatar/tests/CAvatar.test.js b/packages/chakra-ui-core/src/CAvatar/tests/CAvatar.test.js index 79b87d60..f29229c1 100644 --- a/packages/chakra-ui-core/src/CAvatar/tests/CAvatar.test.js +++ b/packages/chakra-ui-core/src/CAvatar/tests/CAvatar.test.js @@ -1,45 +1,82 @@ import { CAvatar, CAvatarBadge } from '..' -import { render, fireEvent } from '@/tests/test-utils' +import { render, wait, waitMs, screen } from '@/tests/test-utils' +const LOAD_FAILURE_SRC = 'LOAD_FAILURE_SRC' +const LOAD_SUCCESS_SRC = 'LOAD_SUCCESS_SRC' + +beforeAll(() => { + process.browser = true // Mock process.browser for CAvatar created() +}) + +beforeAll(() => { + // Mock Img + // eslint-disable-next-line accessor-pairs + Object.defineProperty(global.Image.prototype, 'src', { + set (src) { + if (src === LOAD_FAILURE_SRC) { + setTimeout(() => this.onerror(new Error('mocked error'))) + } else if (src === LOAD_SUCCESS_SRC) { + setTimeout(() => this.onload()) + } + } + }) +}) const renderComponent = (props) => { const base = { components: { CAvatar, CAvatarBadge }, - template: '', + template: '', ...props } return render(base) } -it('should render correctly', () => { +it('should render correctly', async () => { const { asFragment } = renderComponent() + + await waitMs() // wait for img.onsuccess to be called. + expect(asFragment()).toMatchSnapshot() }) -it("should render default avatar if name is not provided and image didn't load", async () => { - const { container, asFragment } = renderComponent({ template: '' }) - const image = container.querySelector('img') +it('Avatar with AvatarBadge renders correctly', async () => { + const { asFragment } = renderComponent({ + template: ` + + + + ` + }) - if (image) { - await fireEvent.error(image) - } + await waitMs() // wait for img.onsuccess to be called. expect(asFragment()).toMatchSnapshot() }) -// TODO: change mounted logic in avatar -xit('should render image if loaded correctly', () => { - const { getByAltText } = renderComponent() +it('renders an image', async () => { + renderComponent({ template: '' }) - expect(getByAltText('Mesut Koca')).toBeInTheDocument() + await wait(() => { + expect(screen.getByAltText(/Mesut Koca/i)).toBeInTheDocument() + }) }) -// TODO: change mounted logic in avatar -xit("should render avatar name as fallback if image didn't loaded correctly", async () => { - const { getByAltText, queryByAltText, getByText } = renderComponent() - const image = getByAltText('Mesut Koca') +it('renders a name avatar if no src', async () => { + renderComponent({ template: '' }) + + await wait(() => { + expect(screen.getByLabelText(/Mesut Koca/i)).toBeInTheDocument() + expect(screen.getByText('MK')).toBeInTheDocument() + }) +}) - await fireEvent.error(image) +it('renders a name avatar if src fails', async () => { + renderComponent({ template: '' }) - expect(queryByAltText('Mesut Koca')).not.toBeInTheDocument() - expect(getByText('MK')).toBeInTheDocument() + await wait(() => { + expect(screen.queryByAltText(/Mesut Koca/i)).not.toBeInTheDocument() + expect(screen.getByText('MK')).toBeInTheDocument() + }) }) diff --git a/packages/chakra-ui-core/src/CAvatar/tests/__snapshots__/CAvatar.test.js.snap b/packages/chakra-ui-core/src/CAvatar/tests/__snapshots__/CAvatar.test.js.snap index bf5dae1f..35592779 100644 --- a/packages/chakra-ui-core/src/CAvatar/tests/__snapshots__/CAvatar.test.js.snap +++ b/packages/chakra-ui-core/src/CAvatar/tests/__snapshots__/CAvatar.test.js.snap @@ -1,63 +1,38 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`should render correctly 1`] = ` +exports[`Avatar with AvatarBadge renders correctly 1`] = `
+ Mesut Koca
- MK -
+ class="css-mwkd9l" + data-chakra-component="CAvatarBadge" + />
`; -exports[`should render default avatar if name is not provided and image didn't load 1`] = ` +exports[`should render correctly 1`] = `
-
- - - - - - - - - - - - - - - - - - - - -
+ Mesut Koca
`; diff --git a/packages/chakra-ui-core/src/CAvatarGroup/tests/CAvatarGroup.test.js b/packages/chakra-ui-core/src/CAvatarGroup/tests/CAvatarGroup.test.js index 9cbed35f..dd803db2 100644 --- a/packages/chakra-ui-core/src/CAvatarGroup/tests/CAvatarGroup.test.js +++ b/packages/chakra-ui-core/src/CAvatarGroup/tests/CAvatarGroup.test.js @@ -1,5 +1,26 @@ import { CAvatar, CAvatarGroup } from '../..' -import { render } from '@/tests/test-utils' +import { render, waitMs } from '@/tests/test-utils' + +const LOAD_FAILURE_SRC = 'LOAD_FAILURE_SRC' +const LOAD_SUCCESS_SRC = 'LOAD_SUCCESS_SRC' + +beforeAll(() => { + process.browser = true // Mock process.browser for CAvatar created() +}) + +beforeAll(() => { + // Mock Img + // eslint-disable-next-line accessor-pairs + Object.defineProperty(global.Image.prototype, 'src', { + set (src) { + if (src === LOAD_FAILURE_SRC) { + setTimeout(() => this.onerror(new Error('mocked error'))) + } else if (src === LOAD_SUCCESS_SRC) { + setTimeout(() => this.onload()) + } + } + }) +}) const renderComponent = (props) => { const base = { @@ -11,15 +32,15 @@ const renderComponent = (props) => { `, ...props @@ -27,8 +48,11 @@ const renderComponent = (props) => { return render(base) } -it('should render correctly', () => { +it('should render correctly', async () => { const { asFragment } = renderComponent() + + await waitMs() // wait for img.onsuccess to be called. + expect(asFragment()).toMatchSnapshot() }) diff --git a/packages/chakra-ui-core/src/CAvatarGroup/tests/__snapshots__/CAvatarGroup.test.js.snap b/packages/chakra-ui-core/src/CAvatarGroup/tests/__snapshots__/CAvatarGroup.test.js.snap index d539866a..f7fbaa6b 100644 --- a/packages/chakra-ui-core/src/CAvatarGroup/tests/__snapshots__/CAvatarGroup.test.js.snap +++ b/packages/chakra-ui-core/src/CAvatarGroup/tests/__snapshots__/CAvatarGroup.test.js.snap @@ -10,25 +10,23 @@ exports[`should render correctly 1`] = ` class="css-1jwki60" data-chakra-component="CAvatar" > -
- MK -
+ Mesut Koca
-
- EY -
+ Evan You
{ expect(asFragment()).toMatchSnapshot() }) -it('should display children', () => { - const { getByText } = renderComponent() - - expect(getByText('500')).toBeInTheDocument() -}) - it('should apply variant styles corectly', () => { const { asFragment } = renderComponent({ template: ` diff --git a/packages/chakra-ui-core/src/CBox/tests/CBox.test.js b/packages/chakra-ui-core/src/CBox/tests/CBox.test.js index 61060dad..cbc4caa0 100644 --- a/packages/chakra-ui-core/src/CBox/tests/CBox.test.js +++ b/packages/chakra-ui-core/src/CBox/tests/CBox.test.js @@ -1,5 +1,5 @@ import CBox from '../' -import { render } from '@/tests/test-utils' +import { render, screen } from '@/tests/test-utils' const renderComponent = (props) => { const inlineAttrs = (props && props.inlineAttrs) || '' @@ -22,9 +22,9 @@ it('should change the style', () => { d="flex" :w="['auto']" px="5" py="5" shadow="lg" my="5" mb="5" rounded="sm" font-family="body" background-color="blue.200" color="blue.700"` - const { asFragment, getByTestId } = renderComponent({ inlineAttrs }) + const { asFragment } = renderComponent({ inlineAttrs }) - const box = getByTestId('box') + const box = screen.getByTestId('box') expect(asFragment()).toMatchSnapshot() expect(box).toHaveStyle('display: flex') diff --git a/packages/chakra-ui-core/src/CBreadcrumb/tests/CBreadcrumb.test.js b/packages/chakra-ui-core/src/CBreadcrumb/tests/CBreadcrumb.test.js index 4bbeaa0d..32bc26bd 100644 --- a/packages/chakra-ui-core/src/CBreadcrumb/tests/CBreadcrumb.test.js +++ b/packages/chakra-ui-core/src/CBreadcrumb/tests/CBreadcrumb.test.js @@ -1,5 +1,5 @@ import { CBreadcrumb, CBreadcrumbItem, CBreadcrumbLink, CBreadcrumbSeparator } from '..' -import { render } from '@/tests/test-utils' +import { render, screen } from '@/tests/test-utils' const renderComponent = (props) => { const base = { @@ -49,7 +49,7 @@ it('should display custom seperator ', () => { }) it('should have the proper aria-attributes', () => { - const { getByText, getAllByRole, getByLabelText } = renderComponent({ + renderComponent({ template: ` @@ -65,12 +65,12 @@ it('should have the proper aria-attributes', () => { }) // surrounding `nav` has aria-label="breadcrumb" - getByLabelText('breadcrumb', { selector: 'nav' }) + screen.getByLabelText('breadcrumb', { selector: 'nav' }) // `isCurrentPage` link has aria-current="page" - const currentPageLink = getByText('Contact') + const currentPageLink = screen.getByText('Contact') expect(currentPageLink).toHaveAttribute('aria-current', 'page') // separator receives presentation="role" - expect(getAllByRole('presentation')).toHaveLength(2) + expect(screen.getAllByRole('presentation')).toHaveLength(2) }) diff --git a/packages/chakra-ui-core/src/CButton/tests/CButton.test.js b/packages/chakra-ui-core/src/CButton/tests/CButton.test.js index 2f976f9e..578394cd 100644 --- a/packages/chakra-ui-core/src/CButton/tests/CButton.test.js +++ b/packages/chakra-ui-core/src/CButton/tests/CButton.test.js @@ -1,5 +1,5 @@ import { CButton } from '../..' -import { render } from '@/tests/test-utils' +import { render, screen } from '@/tests/test-utils' const renderComponent = (props) => { const base = { @@ -17,26 +17,19 @@ it('should render correctly', () => { expect(asFragment()).toMatchSnapshot() }) -it('should display children', () => { - const { getByText } = renderComponent({ template: 'Works' }) - expect(getByText('Works')).toBeInTheDocument() -}) - it('should display button with left icon', () => { - const { container, asFragment } = renderComponent({ template: 'Email' }) - expect(container.querySelector('button > svg')).toBeInTheDocument() + const { asFragment } = renderComponent({ template: 'Email' }) expect(asFragment()).toMatchSnapshot() }) it('should display button with right icon', () => { - const { container, asFragment } = renderComponent({ template: 'Email' }) - expect(container.querySelector('button > svg')).toBeInTheDocument() + const { asFragment } = renderComponent({ template: 'Email' }) expect(asFragment()).toMatchSnapshot() }) it('should display spinner and hide text', () => { - const { getByTestId, container } = renderComponent({ template: 'CButton' }) - const button = getByTestId('btn') + const { container } = renderComponent({ template: 'CButton' }) + const button = screen.getByTestId('btn') expect(button).toHaveAttribute('disabled') expect(button).toHaveAttribute('aria-disabled', 'true') @@ -47,15 +40,15 @@ it('should display spinner and hide text', () => { }) it('should display spinner with text', () => { - const { getByText, container } = renderComponent({ template: 'Button' }) + const { container } = renderComponent({ template: 'Button' }) - expect(getByText('Submitting')).toBeInTheDocument() + expect(screen.getByText('Submitting')).toBeInTheDocument() const spinner = container.querySelector('[data-chakra-component=CSpinner]') expect(spinner).toBeInTheDocument() }) it('should display a disabled button', () => { - const { getByText } = renderComponent({ template: 'Button' }) + renderComponent({ template: 'Button' }) - expect(getByText('Button')).toHaveAttribute('disabled') + expect(screen.getByText('Button')).toHaveAttribute('disabled') }) diff --git a/packages/chakra-ui-core/src/CButtonGroup/tests/CButtonGroup.test.js b/packages/chakra-ui-core/src/CButtonGroup/tests/CButtonGroup.test.js index f87efd27..eb6ef1a4 100644 --- a/packages/chakra-ui-core/src/CButtonGroup/tests/CButtonGroup.test.js +++ b/packages/chakra-ui-core/src/CButtonGroup/tests/CButtonGroup.test.js @@ -21,9 +21,3 @@ it('should render correctly', () => { const { asFragment } = renderComponent() expect(asFragment()).toMatchSnapshot() }) - -it('should display children', () => { - const { getByText } = renderComponent() - expect(getByText('Button1')).toBeInTheDocument() - expect(getByText('Button2')).toBeInTheDocument() -}) diff --git a/packages/chakra-ui-core/src/CCheckbox/tests/CCheckbox.test.js b/packages/chakra-ui-core/src/CCheckbox/tests/CCheckbox.test.js index d91864b9..f1edcb51 100644 --- a/packages/chakra-ui-core/src/CCheckbox/tests/CCheckbox.test.js +++ b/packages/chakra-ui-core/src/CCheckbox/tests/CCheckbox.test.js @@ -1,5 +1,5 @@ import CCheckbox from '..' -import { render, userEvent } from '@/tests/test-utils' +import { render, userEvent, screen } from '@/tests/test-utils' jest.mock('@/packages/chakra-ui-core/src/utils/generators.js', () => { return { @@ -13,7 +13,7 @@ const renderComponent = (props) => { const inlineAttrs = (props && props.inlineAttrs) || '' const base = { components: { CCheckbox }, - template: `checkbox`, + template: `check`, ...props } return render(base) @@ -26,42 +26,42 @@ it('should render correctly', () => { it('should display a disabled checkbox', () => { const inlineAttrs = 'isDisabled' - const { getByText, container } = renderComponent({ inlineAttrs }) - const input = container.querySelector('input') + renderComponent({ inlineAttrs }) + const input = screen.getByLabelText('check') expect(input).toHaveAttribute('disabled') - expect(getByText('checkbox').parentNode).toHaveStyle('cursor: not-allowed;') + expect(screen.getByText('check').parentNode).toHaveStyle('cursor: not-allowed;') }) it('should display a checkbox with a checked state', () => { const inlineAttrs = 'isChecked' - const { container } = renderComponent({ inlineAttrs }) - const input = container.querySelector('input') + renderComponent({ inlineAttrs }) + const input = screen.getByLabelText('check') expect(input).toBeChecked() }) it('should display a checkbox with an unchecked state', () => { const inlineAttrs = ':isChecked="false"' - const { container } = renderComponent({ inlineAttrs }) - const input = container.querySelector('input') + renderComponent({ inlineAttrs }) + const input = screen.getByLabelText('check') expect(input).not.toBeChecked() }) it('should have a checked state when setting defaultIsChecked', () => { const inlineAttrs = 'defaultIsChecked' - const { container } = renderComponent({ inlineAttrs }) - const input = container.querySelector('input') + renderComponent({ inlineAttrs }) + const input = screen.getByLabelText('check') expect(input).toBeChecked() }) test('Uncontrolled - should not check if disabled', async () => { const inlineAttrs = 'isDisabled' - const { container, getByText } = renderComponent({ inlineAttrs }) - const input = container.querySelector('input') - const checkbox = getByText('checkbox') + renderComponent({ inlineAttrs }) + const input = screen.getByLabelText('check') // input + const checkbox = screen.getByText('check') // div with text expect(input).toBeDisabled() @@ -71,9 +71,9 @@ test('Uncontrolled - should not check if disabled', async () => { }) test('Uncontrolled - should check and uncheck', async () => { - const { container, getByText } = renderComponent() - const input = container.querySelector('input') - const checkbox = getByText('checkbox') + renderComponent() + const input = screen.getByLabelText('check') // input + const checkbox = screen.getByText('check') // div with text // click the first time, it's checked await userEvent.click(checkbox) @@ -85,23 +85,21 @@ test('Uncontrolled - should check and uncheck', async () => { }) test('properly handles v-model', async () => { - const { getByText, container } = renderComponent( - { - data: () => ({ - enable: false - }), - template: ` + renderComponent({ + data: () => ({ + enable: false + }), + template: `
{{enable ? 'enabled' : 'disabled'}} - + check
` - } - ) - const input = container.querySelector('input') + }) + const input = screen.getByLabelText('check') // input - expect(getByText('disabled')).toBeInTheDocument() + expect(screen.getByText('disabled')).toBeInTheDocument() await userEvent.click(input) - expect(getByText('enabled')).toBeInTheDocument() + expect(screen.getByText('enabled')).toBeInTheDocument() }) diff --git a/packages/chakra-ui-core/src/CCheckbox/tests/__snapshots__/CCheckbox.test.js.snap b/packages/chakra-ui-core/src/CCheckbox/tests/__snapshots__/CCheckbox.test.js.snap index 92141cec..3f97af56 100644 --- a/packages/chakra-ui-core/src/CCheckbox/tests/__snapshots__/CCheckbox.test.js.snap +++ b/packages/chakra-ui-core/src/CCheckbox/tests/__snapshots__/CCheckbox.test.js.snap @@ -46,7 +46,7 @@ exports[`should render correctly 1`] = ` class="css-np4rym" data-chakra-component="CBox" > - checkbox + check
diff --git a/packages/chakra-ui-core/src/CCheckboxGroup/tests/CCheckboxGroup.test.js b/packages/chakra-ui-core/src/CCheckboxGroup/tests/CCheckboxGroup.test.js index 522f3f16..71549b95 100644 --- a/packages/chakra-ui-core/src/CCheckboxGroup/tests/CCheckboxGroup.test.js +++ b/packages/chakra-ui-core/src/CCheckboxGroup/tests/CCheckboxGroup.test.js @@ -1,5 +1,5 @@ import { CBox, CCheckbox, CCheckboxGroup } from '../..' -import { render } from '@/tests/test-utils' +import { render, screen, wait } from '@/tests/test-utils' // mocks import { useId } from '@/packages/chakra-ui-core/src/utils' @@ -33,20 +33,18 @@ it('should render correctly', () => { }) it('should display children', () => { - const { getByText } = renderComponent() - expect(getByText('One')).toBeInTheDocument() - expect(getByText('Two')).toBeInTheDocument() - expect(getByText('Three')).toBeInTheDocument() + renderComponent() + expect(screen.getByText('One')).toBeInTheDocument() + expect(screen.getByText('Two')).toBeInTheDocument() + expect(screen.getByText('Three')).toBeInTheDocument() }) test('selectedValues prop works', () => { - const { getByTestId } = renderComponent() + renderComponent() - const one = getByTestId('one').querySelector('input') - const two = getByTestId('two').querySelector('input') - const three = getByTestId('three').querySelector('input') - - expect(one).not.toBeChecked() - expect(two).toBeChecked() - expect(three).not.toBeChecked() + wait(() => { + expect(screen.getByLabelText('One')).not.toBeChecked() + expect(screen.getByLabelText('Two')).toBeChecked() + expect(screen.getByLabelText('Three')).not.toBeChecked() + }) }) diff --git a/packages/chakra-ui-core/src/CCircularProgress/tests/CCircularProgress.test.js b/packages/chakra-ui-core/src/CCircularProgress/tests/CCircularProgress.test.js index f8007f41..280c0c3c 100644 --- a/packages/chakra-ui-core/src/CCircularProgress/tests/CCircularProgress.test.js +++ b/packages/chakra-ui-core/src/CCircularProgress/tests/CCircularProgress.test.js @@ -1,5 +1,5 @@ import { CCircularProgress, CCircularProgressLabel } from '../..' -import { render } from '@/tests/test-utils' +import { render, screen } from '@/tests/test-utils' const renderComponent = (props) => { const base = { @@ -20,26 +20,26 @@ it('should render correctly', () => { }) it('should display a label', () => { - const { queryByText } = renderComponent({ + renderComponent({ template: ` 40% ` }) - expect(queryByText('40%')).toBeInTheDocument() + expect(screen.getByText('40%')).toBeInTheDocument() }) test('a11y - progress has a "role" set to "progressbar"', () => { - const { queryByRole } = renderComponent() + renderComponent() - expect(queryByRole('progressbar')).toBeInTheDocument() + expect(screen.queryByRole('progressbar')).toBeInTheDocument() }) test('a11y - progress has a "aria-valuenow" set to the percentage completion value', () => { - const { queryByTestId } = renderComponent() + renderComponent() - expect(queryByTestId('CircularProgress')).toHaveAttribute( + expect(screen.queryByTestId('CircularProgress')).toHaveAttribute( 'aria-valuenow', '40' ) diff --git a/packages/chakra-ui-core/src/CCloseButton/tests/CloseButton.test.js b/packages/chakra-ui-core/src/CCloseButton/tests/CloseButton.test.js index 836800b2..65961321 100644 --- a/packages/chakra-ui-core/src/CCloseButton/tests/CloseButton.test.js +++ b/packages/chakra-ui-core/src/CCloseButton/tests/CloseButton.test.js @@ -1,5 +1,5 @@ import CloseButton from '../' -import { render } from '@/tests/test-utils' +import { render, screen } from '@/tests/test-utils' const renderComponent = (props) => { const base = { @@ -14,18 +14,18 @@ it('should render correctly', () => { expect(asFragment()).toMatchSnapshot() }) it('should allow setting a custom aria-label for the button', () => { - const { container } = renderComponent({ template: '' }) + renderComponent({ template: '' }) - expect(container.querySelector('button')).toHaveAttribute( + expect(screen.getByLabelText('my aria label')).toHaveAttribute( 'aria-label', 'my aria label' ) }) test('a11y - should have aria-label set to "Close"', () => { - const { container } = renderComponent() + renderComponent() - expect(container.querySelector('button')).toHaveAttribute( + expect(screen.getByLabelText('Close')).toHaveAttribute( 'aria-label', 'Close' ) diff --git a/packages/chakra-ui-core/src/CCode/tests/CCode.test.js b/packages/chakra-ui-core/src/CCode/tests/CCode.test.js index d7151b2d..ffe67e55 100644 --- a/packages/chakra-ui-core/src/CCode/tests/CCode.test.js +++ b/packages/chakra-ui-core/src/CCode/tests/CCode.test.js @@ -1,5 +1,5 @@ import CCode from '..' -import { render } from '@/tests/test-utils' +import { render, screen } from '@/tests/test-utils' const renderComponent = (props) => { const base = { @@ -16,7 +16,7 @@ it('should render correctly', () => { }) it('should display children', () => { - const { getByText } = renderComponent() + renderComponent() - expect(getByText('content')).toBeInTheDocument() + expect(screen.getByText('content')).toBeInTheDocument() }) diff --git a/packages/chakra-ui-core/src/CControlBox/tests/CControlBox.test.js b/packages/chakra-ui-core/src/CControlBox/tests/CControlBox.test.js index 9e375198..1fd25dc1 100644 --- a/packages/chakra-ui-core/src/CControlBox/tests/CControlBox.test.js +++ b/packages/chakra-ui-core/src/CControlBox/tests/CControlBox.test.js @@ -1,5 +1,5 @@ import { CVisuallyHidden, CControlBox, CBox } from '../..' -import { render, userEvent } from '@/tests/test-utils' +import { render, userEvent, screen } from '@/tests/test-utils' const renderComponent = (props) => { const inlineAttrs = (props && props.inlineAttrs) || '' @@ -43,9 +43,9 @@ it('should render correctly', () => { }) test('Uncontrolled radio - should be checked always', async () => { - const { getByTestId } = renderComponent({ type: 'radio' }) - const control = getByTestId('control') - const hiddenControl = getByTestId('hiddenControl') + renderComponent({ type: 'radio' }) + const control = screen.getByTestId('control') + const hiddenControl = screen.getByTestId('hiddenControl') // click the first time, it's checked await userEvent.click(control) @@ -57,9 +57,9 @@ test('Uncontrolled radio - should be checked always', async () => { }) test('Uncontrolled checkbox - should toggle', async () => { - const { getByTestId } = renderComponent({ type: 'checkbox' }) - const control = getByTestId('control') - const hiddenControl = getByTestId('hiddenControl') + renderComponent({ type: 'checkbox' }) + const control = screen.getByTestId('control') + const hiddenControl = screen.getByTestId('hiddenControl') // click the first time, it's checked await userEvent.click(control) @@ -72,9 +72,9 @@ test('Uncontrolled checkbox - should toggle', async () => { test('controlled checkbox - v-model works', async () => { const inlineAttrs = ':checked="checked"' - const { getByTestId } = renderComponent({ inlineAttrs, type: 'checkbox', data: () => ({ checked: true }) }) - const control = getByTestId('control') - const hiddenControl = getByTestId('hiddenControl') + renderComponent({ inlineAttrs, type: 'checkbox', data: () => ({ checked: true }) }) + const control = screen.getByTestId('control') + const hiddenControl = screen.getByTestId('hiddenControl') // click the first time, it's checked expect(hiddenControl).toBeChecked() @@ -86,9 +86,9 @@ test('controlled checkbox - v-model works', async () => { test('controlled radio - v-model works', async () => { const inlineAttrs = ':checked="checked"' - const { getByTestId } = renderComponent({ inlineAttrs, type: 'radio', data: () => ({ checked: true }) }) - const control = getByTestId('control') - const hiddenControl = getByTestId('hiddenControl') + renderComponent({ inlineAttrs, type: 'radio', data: () => ({ checked: true }) }) + const control = screen.getByTestId('control') + const hiddenControl = screen.getByTestId('hiddenControl') // click the first time, it's checked expect(hiddenControl).toBeChecked() diff --git a/packages/chakra-ui-core/src/CDrawer/tests/CDrawer.test.js b/packages/chakra-ui-core/src/CDrawer/tests/CDrawer.test.js index 01d397c8..0087ba68 100644 --- a/packages/chakra-ui-core/src/CDrawer/tests/CDrawer.test.js +++ b/packages/chakra-ui-core/src/CDrawer/tests/CDrawer.test.js @@ -1,6 +1,5 @@ -import Vue from 'vue' import { CInput, CButton, CDrawer, CDrawerBody, CDrawerFooter, CDrawerHeader, CDrawerOverlay, CDrawerContent, CDrawerCloseButton } from '../../' -import { render, userEvent, fireEvent, waitMs } from '@/tests/test-utils' +import { render, userEvent, fireEvent, waitMs, wait, screen } from '@/tests/test-utils' import { useId } from '@/packages/chakra-ui-core/src/utils' // mocks @@ -49,7 +48,7 @@ it('should render correctly', async () => { const inlineAttrs = 'isOpen' const { asFragment } = renderComponent({ inlineAttrs }) - await Vue.nextTick() + await waitMs() // render expect(asFragment(document.body.innerHTML)).toMatchSnapshot() }) @@ -57,10 +56,11 @@ it('should render correctly', async () => { test('clicking the close button calls the onClose callback', async () => { const onClose = jest.fn() const inlineAttrs = 'isOpen :on-close="close"' - const { getByTestId } = renderComponent({ inlineAttrs, methods: { close: onClose } }) + renderComponent({ inlineAttrs, methods: { close: onClose } }) - await Vue.nextTick() - userEvent.click(getByTestId('close-btn')) + await wait(() => { + userEvent.click(screen.getByTestId('close-btn')) + }) expect(onClose).toHaveBeenCalled() }) @@ -68,12 +68,12 @@ test('clicking the close button calls the onClose callback', async () => { test('pressing "esc" calls the onClose callback', async () => { const onClose = jest.fn() const inlineAttrs = ':isOpen="isOpen" :on-close="close"' - const { getByTestId } = renderComponent({ inlineAttrs, data: () => ({ isOpen: true }), methods: { close: onClose } }) + renderComponent({ inlineAttrs, data: () => ({ isOpen: true }), methods: { close: onClose } }) - await Vue.nextTick() - const inputInside = getByTestId('inputInsideDrawer') - - fireEvent.keyDown(inputInside, { key: 'Escape' }) + await wait(async () => { + const inputInside = screen.getByTestId('inputInsideDrawer') + await fireEvent.keyDown(inputInside, { key: 'Escape' }) + }) expect(onClose).toHaveBeenCalled() }) @@ -81,39 +81,41 @@ test('pressing "esc" calls the onClose callback', async () => { test('clicking overlay calls the onClose callback', async () => { const onClose = jest.fn() const inlineAttrs = ':isOpen="isOpen" :on-close="close"' - const { getByTestId } = renderComponent({ inlineAttrs, data: () => ({ isOpen: true }), methods: { close: onClose } }) - - await Vue.nextTick() - const overlay = getByTestId('overlay') + renderComponent({ inlineAttrs, data: () => ({ isOpen: true }), methods: { close: onClose } }) - userEvent.click(overlay) + await wait(async () => { + const overlay = screen.getByTestId('overlay') + await fireEvent.click(overlay) + }) expect(onClose).toHaveBeenCalled() }) test('focuses the initial focus ref when opened - initialFocusRef', async () => { const inlineAttrs = 'isOpen :on-close="close" :initialFocusRef="()=>$refs.inputInsideDrawer"' - const { getByTestId } = renderComponent({ inlineAttrs }) + renderComponent({ inlineAttrs }) - await Vue.nextTick() - const inputInside = getByTestId('inputInsideDrawer') + await waitMs() // render - await waitMs() - expect(inputInside).toHaveFocus() + await wait(() => { + expect(screen.getByTestId('inputInsideDrawer')).toHaveFocus() + }) }) test('returns focus when closed - finalFocusRef', async () => { const inlineAttrs = ':isOpen="isOpen" :on-close="close" :finalFocusRef="$refs.inputOutsideDrawer"' - const { getByTestId } = renderComponent({ inlineAttrs, data: () => ({ isOpen: true }) }) + renderComponent({ inlineAttrs, data: () => ({ isOpen: true }) }) + + await waitMs() // render - await Vue.nextTick() - const inputOutside = getByTestId('inputOutsideDrawer') - const closeButton = getByTestId('close-btn') + const inputOutside = screen.getByTestId('inputOutsideDrawer') + const closeButton = screen.getByTestId('close-btn') - await userEvent.click(closeButton) - await waitMs() + await fireEvent.click(closeButton) - expect(inputOutside).toHaveFocus() + await wait(() => { + expect(inputOutside).toHaveFocus() + }) }) it('should have proper aria', async () => { @@ -121,12 +123,12 @@ it('should have proper aria', async () => { const inlineAttrs = 'isOpen' renderComponent({ inlineAttrs }) - await Vue.nextTick() - const dialog = document.querySelector('section') - await waitMs() + await wait(() => { + const dialog = screen.getByRole('dialog') - expect(dialog).toHaveAttribute('role', 'dialog') - expect(dialog).toHaveAttribute('aria-modal', 'true') - expect(dialog).toHaveAttribute('aria-labelledby', 'drawer-1-header') - expect(dialog).toHaveAttribute('aria-describedby', 'drawer-1-body') + expect(dialog).toHaveAttribute('role', 'dialog') + expect(dialog).toHaveAttribute('aria-modal', 'true') + expect(dialog).toHaveAttribute('aria-labelledby', 'drawer-1-header') + expect(dialog).toHaveAttribute('aria-describedby', 'drawer-1-body') + }) }) diff --git a/packages/chakra-ui-core/src/CEditable/tests/CEditable.test.js b/packages/chakra-ui-core/src/CEditable/tests/CEditable.test.js index 0cd18dc7..550f653e 100644 --- a/packages/chakra-ui-core/src/CEditable/tests/CEditable.test.js +++ b/packages/chakra-ui-core/src/CEditable/tests/CEditable.test.js @@ -1,6 +1,6 @@ import { CEditable, CEditableInput, CEditablePreview } from '../..' import { useId } from '../../utils' -import { render, userEvent, fireEvent } from '@/tests/test-utils' +import { render, userEvent, fireEvent, screen } from '@/tests/test-utils' // mocks jest.mock('@/packages/chakra-ui-core/src/utils/generators.js') @@ -29,9 +29,9 @@ it('should render correctly', () => { it('should render correctly - input', async () => { useId.mockReturnValueOnce('1') const inlineAttrs = 'defaultValue="testing" ' - const { asFragment, getByTestId } = renderComponent({ inlineAttrs }) + const { asFragment } = renderComponent({ inlineAttrs }) - const preview = getByTestId('preview') + const preview = screen.getByTestId('preview') await userEvent.click(preview) expect(asFragment(document.body.innerHTML)).toMatchSnapshot() @@ -44,82 +44,87 @@ it('uncontrolled: handles callbacks correctly', async () => { const onEdit = jest.fn() const inlineAttrs = '@edit="onEdit" @change="onChange" @cancel="onCancel" @submit="onSubmit" defaultValue="Hello "' - const { getByTestId } = renderComponent({ inlineAttrs, methods: { onChange, onCancel, onSubmit, onEdit } }) + renderComponent({ inlineAttrs, methods: { onChange, onCancel, onSubmit, onEdit } }) - const preview = getByTestId('preview') + const preview = screen.getByTestId('preview') await userEvent.click(preview) - const input = getByTestId('input') + const input = screen.getByTestId('input') // calls `onEdit` when preview is focused - fireEvent.focus(preview) + await fireEvent.focus(preview) expect(onEdit).toHaveBeenCalled() // calls `onChange` with input on change - userEvent.type(input, 'World') + await userEvent.type(input, 'World') expect(onChange).toHaveBeenCalledWith('Hello World') // calls `onCancel` with previous value when "esc" pressed - fireEvent.keyDown(input, { key: 'Escape' }) + await fireEvent.keyDown(input, { key: 'Escape' }) expect(onCancel).toHaveBeenCalledWith('Hello ') // calls `onSubmit` with previous value when "enter" pressed after cancelling - fireEvent.keyDown(input, { key: 'Enter' }) + await fireEvent.keyDown(input, { key: 'Enter' }) expect(onSubmit).toHaveBeenCalledWith('Hello ') // TODO: ⚠️ we should make controlledInput for vue + // we didn't change the v-model but input.value changes // remove this line, previous input value stays and next 2 expect fails input.value = 'Hello ' // returns new value when submitting without cancelling - userEvent.type(input, 'World') - fireEvent.keyDown(input, { key: 'Enter' }) + await userEvent.type(input, 'World') + await fireEvent.keyDown(input, { key: 'Enter' }) expect(onSubmit).toHaveBeenCalledWith('Hello World') // cancelling now returns new value - fireEvent.keyDown(input, { key: 'Escape' }) + await fireEvent.keyDown(input, { key: 'Escape' }) expect(onCancel).toHaveBeenCalledWith('Hello ') }) it('controlled: handles callbacks correctly', async () => { + useId.mockReturnValueOnce('1') const onChange = jest.fn() const onCancel = jest.fn() const onSubmit = jest.fn() const onEdit = jest.fn() const inlineAttrs = '@edit="onEdit" @change="onChange" @cancel="onCancel" @submit="onSubmit" defaultValue="Hello "' - const { getByTestId } = renderComponent({ inlineAttrs, methods: { onChange, onCancel, onSubmit, onEdit } }) + renderComponent({ inlineAttrs, methods: { onChange, onCancel, onSubmit, onEdit } }) - const preview = getByTestId('preview') + const preview = screen.getByTestId('preview') - await userEvent.click(preview) - const input = getByTestId('input') + await fireEvent.touch(preview) + const input = screen.getByTestId('input') // calls `onEdit` when preview is focused - fireEvent.focus(preview) + await fireEvent.focus(preview) expect(onEdit).toHaveBeenCalled() // calls `onSubmit` with `value` - fireEvent.keyDown(input, { key: 'Enter' }) + await fireEvent.keyDown(input, { key: 'Enter' }) expect(onSubmit).toHaveBeenCalledWith('Hello ') // calls `onCancel` with `value` - fireEvent.keyDown(input, { key: 'Escape' }) + await fireEvent.keyDown(input, { key: 'Escape' }) expect(onSubmit).toHaveBeenCalledWith('Hello ') // calls `onChange` with new input on change - userEvent.type(input, 'World') + // await fireEvent.update(input, 'Hello World') // changes all value + await userEvent.type(input, 'World') // continues typing with previous value + + await fireEvent.keyDown(input, { key: 'Escape' }) expect(onChange).toHaveBeenCalledWith('Hello World') }) test('has the proper aria attributes', async () => { const inlineAttrs = 'defaultValue=""' - const { getByTestId } = renderComponent({ inlineAttrs }) + renderComponent({ inlineAttrs }) - const preview = getByTestId('preview') + const preview = screen.getByTestId('preview') await userEvent.click(preview) - const input = getByTestId('input') + const input = screen.getByTestId('input') // preview and input do not have aria-disabled when `CEditable` is not disabled expect(preview).not.toHaveAttribute('aria-disabled') @@ -128,9 +133,9 @@ test('has the proper aria attributes', async () => { test('has the proper aria attributes when disabled', () => { const inlineAttrs = 'isDisabled defaultValue=""' - const { getByTestId } = renderComponent({ inlineAttrs }) + renderComponent({ inlineAttrs }) - const preview = getByTestId('preview') + const preview = screen.getByTestId('preview') // preview does not have aria-disabled when `CEditable` is not disabled expect(preview).toHaveAttribute('aria-disabled', 'true') diff --git a/packages/chakra-ui-core/src/CFlex/tests/CFlex.test.js b/packages/chakra-ui-core/src/CFlex/tests/CFlex.test.js index 6dfb2495..e5abcb5b 100644 --- a/packages/chakra-ui-core/src/CFlex/tests/CFlex.test.js +++ b/packages/chakra-ui-core/src/CFlex/tests/CFlex.test.js @@ -1,5 +1,5 @@ import CFlex from '..' -import { render } from '@/tests/test-utils' +import { render, screen } from '@/tests/test-utils' const renderComponent = (props) => { const inlineAttrs = (props && props.inlineAttrs) || '' @@ -19,11 +19,11 @@ it('should render correctly', () => { it('should change styles', () => { const inlineAttrs = 'align="center" justify="center" direction="column"' - const { asFragment, getByTestId } = renderComponent({ inlineAttrs }) + const { asFragment } = renderComponent({ inlineAttrs }) expect(asFragment()).toMatchSnapshot() - const flex = getByTestId('flex') + const flex = screen.getByTestId('flex') expect(flex).toHaveStyle('display: flex') expect(flex).toHaveStyle('align-items: center') expect(flex).toHaveStyle('justify-content: center') diff --git a/packages/chakra-ui-core/src/CIconButton/tests/CIconButton.test.js b/packages/chakra-ui-core/src/CIconButton/tests/CIconButton.test.js index 53ea5187..ab963093 100644 --- a/packages/chakra-ui-core/src/CIconButton/tests/CIconButton.test.js +++ b/packages/chakra-ui-core/src/CIconButton/tests/CIconButton.test.js @@ -1,5 +1,5 @@ import CIconButton from '..' -import { render } from '@/tests/test-utils' +import { render, screen } from '@/tests/test-utils' const renderComponent = (props) => { const inlineAttrs = (props && props.inlineAttrs) || '' @@ -19,15 +19,15 @@ it('should render correctly', () => { it('should display spinner and hide the icon', () => { const inlineAttrs = 'isLoading' - const { container, getByTestId } = renderComponent({ inlineAttrs }) + const { container } = renderComponent({ inlineAttrs }) - const button = getByTestId('btn') + const button = screen.getByTestId('btn') expect(button).toHaveAttribute('disabled') expect(button).toHaveAttribute('aria-disabled', 'true') // TODO: find a way to easily grab the spinner element - // Maybe? expect(getByTestId('Spinner')).toBeInTheDocument() + // Maybe? expect(screen.getByTestId('Spinner')).toBeInTheDocument() expect(button).toHaveStyle('opacity: 0.4') expect(container.querySelector('button > div')).toBeInTheDocument() }) diff --git a/packages/chakra-ui-core/src/CImage/CImage.js b/packages/chakra-ui-core/src/CImage/CImage.js index 17c75186..934ac10b 100644 --- a/packages/chakra-ui-core/src/CImage/CImage.js +++ b/packages/chakra-ui-core/src/CImage/CImage.js @@ -55,7 +55,7 @@ const CImage = { this.$emit('load', event) } - image.onError = (event) => { + image.onerror = (event) => { this.hasLoaded = false this.$emit('error', event) } diff --git a/packages/chakra-ui-core/src/CImage/tests/CImage.test.js b/packages/chakra-ui-core/src/CImage/tests/CImage.test.js new file mode 100644 index 00000000..3b6feaff --- /dev/null +++ b/packages/chakra-ui-core/src/CImage/tests/CImage.test.js @@ -0,0 +1,47 @@ +import { CImage } from '../..' +import { render, wait, waitMs, screen } from '@/tests/test-utils' +const LOAD_FAILURE_SRC = 'LOAD_FAILURE_SRC' +const LOAD_SUCCESS_SRC = 'LOAD_SUCCESS_SRC' + +beforeAll(() => { + process.browser = true // Mock process.browser for CAvatar created() +}) + +beforeAll(() => { + // Mock Img + // eslint-disable-next-line accessor-pairs + Object.defineProperty(global.Image.prototype, 'src', { + set (src) { + if (src === LOAD_FAILURE_SRC) { + setTimeout(() => this.onerror(new Error('mocked error'))) + } else if (src === LOAD_SUCCESS_SRC) { + setTimeout(() => this.onload()) + } + } + }) +}) + +const renderComponent = (props) => { + const base = { + components: { CImage }, + template: '', + ...props + } + return render(base) +} + +it('should render correctly', async () => { + const { asFragment } = renderComponent() + + await waitMs() // wait for img.onsuccess to be called. + + expect(asFragment()).toMatchSnapshot() +}) + +it('fallback src works', async () => { + renderComponent({ template: '' }) + + await wait(() => { + expect(screen.getByAltText(/Mesut Koca/i)).toHaveAttribute('src', 'LOAD_FALLBACK_SRC') + }) +}) diff --git a/packages/chakra-ui-core/src/CImage/tests/__snapshots__/CImage.test.js.snap b/packages/chakra-ui-core/src/CImage/tests/__snapshots__/CImage.test.js.snap new file mode 100644 index 00000000..23f8c25b --- /dev/null +++ b/packages/chakra-ui-core/src/CImage/tests/__snapshots__/CImage.test.js.snap @@ -0,0 +1,13 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` + + Mesut Koca + +`; diff --git a/packages/chakra-ui-core/src/CInput/CInput.js b/packages/chakra-ui-core/src/CInput/CInput.js index 24efb167..c1f27eab 100644 --- a/packages/chakra-ui-core/src/CInput/CInput.js +++ b/packages/chakra-ui-core/src/CInput/CInput.js @@ -90,7 +90,7 @@ const CInput = { }, attrs: { 'aria-readonly': this.isReadOnly, - 'read-only': this.formControl.isReadOnly, + readonly: this.formControl.isReadOnly, disabled: this.formControl.isDisabled, 'aria-disabled': this.formControl.isDisabled, 'aria-invalid': this.formControl.isInvalid, diff --git a/packages/chakra-ui-core/src/CInput/tests/CInput.test.js b/packages/chakra-ui-core/src/CInput/tests/CInput.test.js new file mode 100644 index 00000000..31295c19 --- /dev/null +++ b/packages/chakra-ui-core/src/CInput/tests/CInput.test.js @@ -0,0 +1,40 @@ +import { CInput } from '../..' +import { render, screen, userEvent } from '@/tests/test-utils' + +const renderComponent = (props) => { + const inlineAttrs = (props && props.inlineAttrs) || '' + const base = { + data: () => ({ text: 'hello' }), + components: { CInput }, + template: ``, + ...props + } + return render(base) +} + +test('should render correctly', () => { + const { asFragment } = renderComponent() + expect(asFragment()).toMatchSnapshot() +}) + +test('v-model works', () => { + renderComponent() + const input = screen.getByTestId('input') + + userEvent.type(input, ' world') + expect(input).toHaveValue('hello world') +}) + +test('readonly input renders correctly', () => { + renderComponent({ inlineAttrs: 'isReadOnly' }) + const input = screen.getByTestId('input') + + expect(input).toHaveAttribute('readonly') +}) + +test('disabled input renders correctly', () => { + renderComponent({ inlineAttrs: 'isDisabled' }) + const input = screen.getByTestId('input') + + expect(input).toHaveAttribute('disabled') +}) diff --git a/packages/chakra-ui-core/src/CInput/tests/__snapshots__/CInput.test.js.snap b/packages/chakra-ui-core/src/CInput/tests/__snapshots__/CInput.test.js.snap new file mode 100644 index 00000000..bd670d80 --- /dev/null +++ b/packages/chakra-ui-core/src/CInput/tests/__snapshots__/CInput.test.js.snap @@ -0,0 +1,12 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` + + + +`; diff --git a/packages/chakra-ui-core/src/CList/tests/CList.test.js b/packages/chakra-ui-core/src/CList/tests/CList.test.js new file mode 100644 index 00000000..b8b2cfa5 --- /dev/null +++ b/packages/chakra-ui-core/src/CList/tests/CList.test.js @@ -0,0 +1,24 @@ +import { CList, CListItem, CListIcon } from '../..' +import { render } from '@/tests/test-utils' + +const renderComponent = (props) => { + const base = { + components: { CList, CListItem, CListIcon }, + template: ` + + + Lorem ipsum dolor sit amet, consectetur adipisicing elit + + + Assumenda, quia temporibus eveniet a libero incidunt suscipit + + `, + ...props + } + return render(base) +} + +it('should render correctly', () => { + const { asFragment } = renderComponent() + expect(asFragment()).toMatchSnapshot() +}) diff --git a/packages/chakra-ui-core/src/CList/tests/__snapshots__/CList.test.js.snap b/packages/chakra-ui-core/src/CList/tests/__snapshots__/CList.test.js.snap new file mode 100644 index 00000000..4b7e4ce6 --- /dev/null +++ b/packages/chakra-ui-core/src/CList/tests/__snapshots__/CList.test.js.snap @@ -0,0 +1,51 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` + +
    +
  • + + + + + + Lorem ipsum dolor sit amet, consectetur adipisicing elit + +
  • +
  • + + + + + + Assumenda, quia temporibus eveniet a libero incidunt suscipit + +
  • +
+
+`; diff --git a/tests/test-utils/test-utils.js b/tests/test-utils/test-utils.js index 563f9b0d..e12b043f 100644 --- a/tests/test-utils/test-utils.js +++ b/tests/test-utils/test-utils.js @@ -1,9 +1,9 @@ import '@testing-library/jest-dom/extend-expect' -import { render } from '@testing-library/vue' +import * as vtl from '@testing-library/vue' +import userEvent from '@testing-library/user-event' import icons from '@/packages/chakra-ui-core/src/lib/internal-icons' import theme from '@/packages/chakra-ui-core/src/lib/theme' - const defaultProviders = options => ({ $chakraTheme: () => theme, $chakraColorMode: () => 'light', @@ -11,11 +11,11 @@ const defaultProviders = options => ({ ...options }) -const customRender = (component, ...rest) => { +const render = (component, ...rest) => { const defaults = { provide: () => defaultProviders() } - const utils = render({ ...defaults, ...component }, ...rest) + const utils = vtl.render({ ...defaults, ...component }, ...rest) return { ...utils, asFragment: (innerHTML = utils.container.innerHTML) => { @@ -32,13 +32,48 @@ const customRender = (component, ...rest) => { } } -export function waitMs (ms = 0) { +/** + * Wait for given ms + * + * @param {number} duration + */ +function waitMs (ms = 0) { return new Promise(resolve => setTimeout(resolve, ms)) } -export { default as userEvent } from '@testing-library/user-event' -export { fireEvent } from '@testing-library/vue' +/** + * Get styles from document.styleSheets + * + * @param {String} selector + * + * @example className usage + * getElementStyles('.anyClassName') + * + * @example Emotion Classname + * const [className1, className2] = [...screen.getByTestId('aspectRatioBox').classList] + * const styles = getElementStyles(`.${className1}`) + * const pseudoStyles = getElementStyles(`.${className2}:before`) + */ +export function getElementStyles (selector) { + selector = new RegExp(selector) + let styles = [] + let i; let j; const sel = selector + for (i = 0; i < document.styleSheets.length; ++i) { + for (j = 0; j < document.styleSheets[i].cssRules.length; ++j) { + if (sel.test(document.styleSheets[i].cssRules[j].selectorText)) { + // let selectorText = document.styleSheets[i].cssRules[j].selectorText + const cssText = document.styleSheets[i].cssRules[j].style.cssText + styles += cssText + } + } + } + return styles +} + +export * from '@testing-library/vue' export { - customRender as render, + render, + userEvent, + waitMs, defaultProviders } diff --git a/yarn.lock b/yarn.lock index d29f93c9..700d5a23 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4585,6 +4585,16 @@ dependencies: "@types/yargs-parser" "*" +"@typescript-eslint/experimental-utils@^2.29.0": + version "2.34.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz#d3524b644cdb40eebceca67f8cf3e4cc9c8f980f" + integrity sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA== + dependencies: + "@types/json-schema" "^7.0.3" + "@typescript-eslint/typescript-estree" "2.34.0" + eslint-scope "^5.0.0" + eslint-utils "^2.0.0" + "@typescript-eslint/experimental-utils@^2.5.0": version "2.26.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.26.0.tgz#063390c404d9980767d76274df386c0aa675d91d" @@ -4608,6 +4618,19 @@ semver "^6.3.0" tsutils "^3.17.1" +"@typescript-eslint/typescript-estree@2.34.0": + version "2.34.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz#14aeb6353b39ef0732cc7f1b8285294937cf37d5" + integrity sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg== + dependencies: + debug "^4.1.1" + eslint-visitor-keys "^1.1.0" + glob "^7.1.6" + is-glob "^4.0.1" + lodash "^4.17.15" + semver "^7.3.2" + tsutils "^3.17.1" + "@vue/babel-helper-vue-jsx-merge-props@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.0.0.tgz#048fe579958da408fb7a8b2a3ec050b50a661040" @@ -10128,6 +10151,13 @@ eslint-plugin-standard@^4.0.0, eslint-plugin-standard@^4.0.1: resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-4.0.1.tgz#ff0519f7ffaff114f76d1bd7c3996eef0f6e20b4" integrity sha512-v/KBnfyaOMPmZc/dmc6ozOdWqekGp7bBGq4jLAecEfPGmfKiWS4sA8sC0LqiV9w5qmXAtXVn4M3p1jSyhY85SQ== +eslint-plugin-testing-library@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-testing-library/-/eslint-plugin-testing-library-3.3.1.tgz#aab204bb19b634ee50a9da550649a51723ebb423" + integrity sha512-0Ubug+v9hJDb0OEHc6e2p5/7Q4xhaCZiYLc05hybja8Yd2t+2y1Q+UDwKz+JiDAHoPgE7y2B2G3jn+u9kqJTGw== + dependencies: + "@typescript-eslint/experimental-utils" "^2.29.0" + eslint-plugin-unicorn@^16.0.0: version "16.1.1" resolved "https://registry.yarnpkg.com/eslint-plugin-unicorn/-/eslint-plugin-unicorn-16.1.1.tgz#012c598d71914ef30f5d386dd85110e59f2ef999" @@ -20064,6 +20094,11 @@ semver@^7.1.2, semver@^7.1.3: resolved "https://registry.yarnpkg.com/semver/-/semver-7.1.3.tgz#e4345ce73071c53f336445cfc19efb1c311df2a6" integrity sha512-ekM0zfiA9SCBlsKa2X1hxyxiI4L3B6EbVJkkdgQXnSEEaHlGdvyodMruTiulSRWMMB4NeIuYNMC9rTKTz97GxA== +semver@^7.3.2: + version "7.3.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" + integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== + semver@~5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"