From ce4edc301d0bb383074ab88c43c61ec5696505de Mon Sep 17 00:00:00 2001 From: Josefina Mancilla <32556167+jnm2377@users.noreply.github.com> Date: Fri, 14 Jan 2022 16:42:24 -0600 Subject: [PATCH 1/8] feat(DatePicker, DatePickerInput): refactors to functional component (#10224) * feat(DatePickerInput): refactors input to function * Update packages/react/src/components/DatePickerInput/next/DatePickerInput.js Co-authored-by: Taylor Jones * fix: clean up * feat: add date picker v11 story and index * feat: date picker ref changes not working yet * feat: date picker refactor * feat: date-picker v11 tests * fix: next datepicker stories * fix: component did update useEffect * chore: remove console.log * fix: test import * fix: icon click events * fix: component prop updates * fix: deprecated props * fix: prop useEffect updates * chore: update tests * chore: remove test * Update packages/react/src/components/DatePicker/next/DatePicker-test.js Co-authored-by: Josh Black * Update packages/react/src/components/DatePicker/next/DatePicker.js Co-authored-by: Josh Black * Update packages/react/src/components/DatePicker/next/DatePicker.js Co-authored-by: Josh Black * Update packages/react/src/components/DatePicker/next/DatePicker.js Co-authored-by: Josh Black * fix: format * fix: update classnames Co-authored-by: Taylor Jones Co-authored-by: Josh Black Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../react/src/components/DatePicker/index.js | 10 +- .../DatePicker/next/DatePicker-test.js | 228 ++++++ .../components/DatePicker/next/DatePicker.js | 649 ++++++++++++++++++ .../DatePicker/next/DatePicker.stories.js | 3 +- .../src/components/DatePickerInput/index.js | 10 +- .../DatePickerInput/next/DatePickerInput.js | 294 ++++++++ 6 files changed, 1191 insertions(+), 3 deletions(-) create mode 100644 packages/react/src/components/DatePicker/next/DatePicker-test.js create mode 100644 packages/react/src/components/DatePicker/next/DatePicker.js create mode 100644 packages/react/src/components/DatePickerInput/next/DatePickerInput.js diff --git a/packages/react/src/components/DatePicker/index.js b/packages/react/src/components/DatePicker/index.js index 766467c59ac7..9d84a7bfcede 100644 --- a/packages/react/src/components/DatePicker/index.js +++ b/packages/react/src/components/DatePicker/index.js @@ -5,5 +5,13 @@ * LICENSE file in the root directory of this source tree. */ +import * as FeatureFlags from '@carbon/feature-flags'; +import { default as DatePickerNext } from './next/DatePicker'; +import { default as DatePickerClassic } from './DatePicker'; + +const DatePicker = FeatureFlags.enabled('enable-v11-release') + ? DatePickerNext + : DatePickerClassic; + +export default DatePicker; export { default as DatePickerSkeleton } from './DatePicker.Skeleton'; -export default from './DatePicker'; diff --git a/packages/react/src/components/DatePicker/next/DatePicker-test.js b/packages/react/src/components/DatePicker/next/DatePicker-test.js new file mode 100644 index 000000000000..58e615ef8d0e --- /dev/null +++ b/packages/react/src/components/DatePicker/next/DatePicker-test.js @@ -0,0 +1,228 @@ +/** + * Copyright IBM Corp. 2016, 2018 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import DatePicker from './DatePicker'; +import { mount } from 'enzyme'; +import DatePickerInput from '../../DatePickerInput/next/DatePickerInput'; + +const prefix = 'bx'; + +function getFlatpickrCalendar() { + return document.querySelector(`.${prefix}--date-picker__calendar`); +} + +describe('DatePicker', () => { + describe('Renders as expected', () => { + let wrapper; + let datepicker; + + beforeEach(() => { + wrapper = mount( + {}} + className="extra-class" + dateFormat="m/d/Y"> + + + + ); + datepicker = wrapper.childAt(0); + }); + + it('should add extra classes that are passed via className', () => { + expect(datepicker.hasClass('extra-class')).toBe(true); + }); + + it('should add the date picker type as expected', () => { + expect(wrapper.props().datePickerType).toEqual(undefined); + wrapper.setProps({ datePickerType: 'simple' }); + expect(wrapper.props().datePickerType).toEqual('simple'); + }); + + it('should add the date format as expected', () => { + expect(wrapper.props().dateFormat).toEqual('m/d/Y'); + wrapper.setProps({ dateFormat: 'd/m/Y' }); + expect(wrapper.props().dateFormat).toEqual('d/m/Y'); + }); + + it('has the value as expected', () => { + expect(wrapper.props().value).toEqual(undefined); + wrapper.setProps({ value: '11/08/2017' }); + expect(wrapper.props().value).toEqual('11/08/2017'); + }); + + it('should render the children as expected', () => { + expect(wrapper.props().children.length).toEqual(2); + }); + }); + + describe('Simple date picker', () => { + let wrapper; + + beforeEach(() => { + wrapper = mount( + + + + ); + }); + + it('has the value as expected', () => { + expect(wrapper.props().value).toEqual(undefined); + wrapper.setProps({ value: '11/08/2017' }); + expect(wrapper.props().value).toEqual('11/08/2017'); + }); + + it('should not initialize a calendar', () => { + expect(getFlatpickrCalendar()).not.toBeInTheDocument(); + }); + }); + + describe('Single date picker', () => { + let wrapper; + beforeEach(() => { + wrapper = mount( + {}} + datePickerType="single" + className="extra-class"> + + + ); + }); + + it('should initialize a calendar', () => { + expect(getFlatpickrCalendar()).toBeInTheDocument(); + }); + + it('should update the classnames', () => { + expect( + getFlatpickrCalendar().classList.contains( + `${prefix}--date-picker__calendar` + ) + ).toBe(true); + }); + + it('has the value as expected', () => { + expect(wrapper.props().value).toEqual(undefined); + wrapper.setProps({ value: '11/08/2017' }); + expect(wrapper.props().value).toEqual('11/08/2017'); + }); + }); + + describe('Date picker with locale', () => { + let wrapper; + let wrapperNoLocale; + beforeEach(() => { + wrapper = mount( + {}} + datePickerType="range" + className="extra-class" + locale="es"> + + + + ); + + wrapperNoLocale = mount( + {}} + datePickerType="range" + className="extra-class"> + + + + ); + }); + + it('has the range date picker locale', () => { + const datepicker = wrapper.find('DatePicker'); + expect(datepicker.props().locale).toBe('es'); + }); + + it('has the range date picker without locale defined', () => { + const datepicker = wrapperNoLocale.find('DatePicker'); + expect(datepicker.props().locale).toBe(undefined); + }); + }); + + describe('Date picker with minDate and maxDate', () => { + let mockConsoleError; + let wrapper; + + beforeEach(() => { + mockConsoleError = jest.spyOn(console, 'error'); + wrapper = mount( + {}} + datePickerType="range" + className="extra-class" + minDate="01/01/2018" + maxDate="01/30/2018"> + + + + ); + }); + + afterEach(() => { + mockConsoleError.mockRestore(); + }); + + it('has the range date picker with min and max dates', () => { + const datepicker = wrapper.find('DatePicker'); + expect(datepicker.props().minDate).toBe('01/01/2018'); + expect(datepicker.props().maxDate).toBe('01/30/2018'); + }); + + it('should not have "console.error" being created', () => { + expect(mockConsoleError).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/packages/react/src/components/DatePicker/next/DatePicker.js b/packages/react/src/components/DatePicker/next/DatePicker.js new file mode 100644 index 000000000000..19aa34d3a133 --- /dev/null +++ b/packages/react/src/components/DatePicker/next/DatePicker.js @@ -0,0 +1,649 @@ +/** + * Copyright IBM Corp. 2016, 2018 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import PropTypes from 'prop-types'; +import React, { useEffect, useRef } from 'react'; +import cx from 'classnames'; +import flatpickr from 'flatpickr'; +import l10n from 'flatpickr/dist/l10n/index'; +import DatePickerInput from '../../DatePickerInput'; +import carbonFlatpickrAppendToPlugin from '../plugins/appendToPlugin'; +import carbonFlatpickrFixEventsPlugin from '../plugins/fixEventsPlugin'; +import carbonFlatpickrRangePlugin from '../plugins/rangePlugin'; +import { match, keys } from '../../../internal/keyboard'; +import { usePrefix } from '../../../internal/usePrefix'; +import { useSavedCallback } from '../../../internal/useSavedCallback'; + +// Weekdays shorthand for english locale +l10n.en.weekdays.shorthand.forEach((_day, index) => { + const currentDay = l10n.en.weekdays.shorthand; + if (currentDay[index] === 'Thu' || currentDay[index] === 'Th') { + currentDay[index] = 'Th'; + } else { + currentDay[index] = currentDay[index].charAt(0); + } +}); + +const forEach = Array.prototype.forEach; + +/** + * @param {number} monthNumber The month number. + * @param {boolean} shorthand `true` to use shorthand month. + * @param {Locale} locale The Flatpickr locale data. + * @returns {string} The month string. + */ +const monthToStr = (monthNumber, shorthand, locale) => + locale.months[shorthand ? 'shorthand' : 'longhand'][monthNumber]; + +/** + * @param {object} config Plugin configuration. + * @param {boolean} [config.shorthand] `true` to use shorthand month. + * @param {string} config.selectorFlatpickrMonthYearContainer The CSS selector for the container of month/year selection UI. + * @param {string} config.selectorFlatpickrYearContainer The CSS selector for the container of year selection UI. + * @param {string} config.selectorFlatpickrCurrentMonth The CSS selector for the text-based month selection UI. + * @param {string} config.classFlatpickrCurrentMonth The CSS class for the text-based month selection UI. + * @returns {Plugin} A Flatpickr plugin to use text instead of ` + ) : ( + + ); + + return ( +
+ {labelText && ( + + )} +
+ {input} + +
+ {invalid && ( +
{invalidText}
+ )} + {warn &&
{warnText}
} + {helperText &&
{helperText}
} +
+ ); +}); + +DatePickerInput.propTypes = { + /** + * The type of the date picker: + * + * * `simple` - Without calendar dropdown. + * * `single` - With calendar dropdown and single date. + * * `range` - With calendar dropdown and a date range. + */ + datePickerType: PropTypes.oneOf(['simple', 'single', 'range']), + + /** + * Specify whether or not the input should be disabled + */ + disabled: PropTypes.bool, + + /** + * Provide text that is used alongside the control label for additional help + */ + helperText: PropTypes.node, + + /** + * Specify if the label should be hidden + */ + hideLabel: PropTypes.bool, + + /** + * The description of the calendar icon. + */ + iconDescription: deprecate( + PropTypes.string, + `\nThe prop \`iconDescriptionInput\` for DatePickerInput has been deprecated and is no longer used` + ), + + /** + * Specify an id that uniquely identifies the `` + */ + id: PropTypes.string.isRequired, + + /** + * Specify whether or not the input should be invalid + */ + invalid: PropTypes.bool, + + /** + * Specify the text to be rendered when the input is invalid + */ + invalidText: PropTypes.node, + + /** + * Provide the text that will be read by a screen reader when visiting this + * control + */ + labelText: PropTypes.node.isRequired, + + /** + * Specify an `onChange` handler that is called whenever a change in the + * input field has occurred + */ + onChange: PropTypes.func, + + /** + * Provide a function to be called when the input field is clicked + */ + onClick: PropTypes.func, + + /** + * Provide a function to be called when the input field is clicked + */ + openCalendar: deprecate( + PropTypes.func, + `\nThe prop \`openCalendar\` for DatePickerInput has been deprecated and is no longer used` + ), + + /** + * Provide a regular expression that the input value must match + */ + pattern: (props, propName, componentName) => { + if (props[propName] === undefined) { + return; + } + try { + new RegExp(props[propName]); + } catch (e) { + return new Error( + `Invalid value of prop '${propName}' supplied to '${componentName}', it should be a valid regular expression` + ); + } + }, + + /** + * Specify the placeholder text + */ + placeholder: PropTypes.string, + + /** + * Specify the size of the Date Picker Input. Currently supports either `sm`, 'md' (default) or 'lg` as an option. + * TODO V11: remove `xl` (replaced with lg) + */ + size: PropTypes.oneOf(['sm', 'md', 'lg', 'xl']), + + /** + * Specify the type of the `` + */ + type: PropTypes.string, + + /** + * Specify whether the control is currently in warning state + */ + warn: PropTypes.bool, + + /** + * Provide the text that is displayed when the control is in warning state + */ + warnText: PropTypes.node, +}; + +function DatePickerIcon({ datePickerType, invalid, warn, ...rest }) { + const prefix = usePrefix(); + + if (datePickerType === 'simple' && !invalid && !warn) { + return null; + } + + if (invalid) { + return ( + + ); + } + + if (!invalid && warn) { + return ( + + ); + } + + return ( + + ); +} + +DatePickerIcon.propTypes = { + /** + * The type of the date picker: + * + * * `simple` - Without calendar dropdown. + * * `single` - With calendar dropdown and single date. + * * `range` - With calendar dropdown and a date range. + */ + datePickerType: PropTypes.oneOf(['simple', 'single', 'range']), + + /** + * Specify whether or not the input should be invalid + */ + invalid: PropTypes.bool, + + /** + * Specify whether the control is currently in warning state + */ + warn: PropTypes.bool, +}; + +export default DatePickerInput; From edcf7be7fcc42f9d4a228b714b2164fd34667cea Mon Sep 17 00:00:00 2001 From: carbon-bot Date: Fri, 14 Jan 2022 23:14:08 +0000 Subject: [PATCH 2/8] chore(project): sync generated files --- packages/upgrade/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/upgrade/README.md b/packages/upgrade/README.md index cc1d1cfb48b7..a34a777b703f 100644 --- a/packages/upgrade/README.md +++ b/packages/upgrade/README.md @@ -1,6 +1,6 @@ # @carbon/upgrade -> A tool for upgrading projects that use Carbon +> A tool for upgrading Carbon versions ## Getting started From 1d3cc3b0ac37a2c65cbeaceadd294f910b12370d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 18 Jan 2022 13:45:37 -0600 Subject: [PATCH 3/8] chore(deps): update actions/checkout action to v2 (#10465) Co-authored-by: Renovate Bot --- .github/workflows/release.yml | 2 +- .github/workflows/sync-generated-files.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a5e4b3656e04..1f84e6fdd803 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,7 +11,7 @@ jobs: name: Create Release runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: Use Node.js 16.x uses: actions/setup-node@v2.5.1 diff --git a/.github/workflows/sync-generated-files.yml b/.github/workflows/sync-generated-files.yml index 91616db710ce..14bccb0c0b75 100644 --- a/.github/workflows/sync-generated-files.yml +++ b/.github/workflows/sync-generated-files.yml @@ -7,7 +7,7 @@ jobs: release: runs-on: macOS-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: Use Node.js 16.x uses: actions/setup-node@v2.5.1 with: From 730927a90c5c72c8925641be2b5cb3d820fa7ea4 Mon Sep 17 00:00:00 2001 From: Abbey Hart Date: Tue, 18 Jan 2022 14:46:02 -0600 Subject: [PATCH 4/8] test(react): update toggle tests to use react testing library (#10452) * chore: check in progress * test(react): update Toggle tests to rtl Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../src/components/Toggle/Toggle-test.js | 165 +++++++----------- 1 file changed, 60 insertions(+), 105 deletions(-) diff --git a/packages/react/src/components/Toggle/Toggle-test.js b/packages/react/src/components/Toggle/Toggle-test.js index a1cb2a8f498e..39b6659bc79e 100644 --- a/packages/react/src/components/Toggle/Toggle-test.js +++ b/packages/react/src/components/Toggle/Toggle-test.js @@ -7,131 +7,86 @@ import React from 'react'; import Toggle from '../Toggle'; -import { mount } from 'enzyme'; -import { settings } from 'carbon-components'; - -const { prefix } = settings; -describe('Toggle', () => { - const commonProps = { - 'aria-label': 'Toggle label', - labelA: 'Off', - labelB: 'On', - labelText: 'Toggle label', - }; - - describe('Renders as expected', () => { - const wrapper = mount(); - - const input = wrapper.find('input'); - - it('Switch and label Ids should match', () => { - const toggleLabel = wrapper.find(`.${prefix}--toggle__label`); - expect(input.id).toEqual(toggleLabel.htmlFor); - }); - - it('should set defaultChecked as expected', () => { - expect(input.props().defaultChecked).toEqual(false); - wrapper.setProps({ defaultToggled: true }); - expect(wrapper.find('input').props().defaultChecked).toEqual(true); - }); - - it('Can set defaultToggled state', () => { - wrapper.setProps({ defaultToggled: true }); - expect( - wrapper.find(`.${prefix}--toggle-input`).props().defaultChecked - ).toEqual(true); +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import '../../../../components/scss/components/toggle/_toggle.scss'; + +describe('Toggle RTL', () => { + describe('Behaviors', () => { + it('toggles on click', () => { + render(); + expect(screen.getByText('Off')).toBeVisible(); + expect(screen.getByText('On')).not.toBeVisible(); + userEvent.click(screen.getByRole('checkbox')); + expect(screen.getByText('On')).toBeVisible(); + expect(screen.getByText('Off')).not.toBeVisible(); }); - it('Should add extra classes that are passed via className', () => { - wrapper.setProps({ className: 'extra-class' }); - expect(wrapper.find('div').hasClass('extra-class')).toEqual(true); + it('toggles on keydown - enter', () => { + render(); + expect(screen.getByText('Off')).toBeVisible(); + expect(screen.getByText('On')).not.toBeVisible(); + userEvent.type(screen.getByRole('checkbox'), 'enter'); + expect(screen.getByText('On')).toBeVisible(); + expect(screen.getByText('Off')).not.toBeVisible(); }); - it('Can be disabled', () => { - wrapper.setProps({ disabled: true }); - expect(wrapper.find(`.${prefix}--toggle-input`).props().disabled).toEqual( - true - ); + it('toggles on keydown - space', () => { + render(); + expect(screen.getByText('Off')).toBeVisible(); + expect(screen.getByText('On')).not.toBeVisible(); + userEvent.type(screen.getByRole('checkbox'), 'space'); + expect(screen.getByText('On')).toBeVisible(); + expect(screen.getByText('Off')).not.toBeVisible(); }); + }); - it('Can have a labelA', () => { - wrapper.setProps({ labelA: 'labelA-test' }); - expect(wrapper.find(`.${prefix}--toggle__text--off`).text()).toEqual( - 'labelA-test' + describe('Props', () => { + it('add custom class name to wrapper div', () => { + const { container } = render( + ); + expect(container.firstChild).toHaveClass('custom-class'); }); - it('Can have a labelB', () => { - wrapper.setProps({ labelB: 'labelB-test' }); - expect(wrapper.find(`.${prefix}--toggle__text--on`).text()).toEqual( - 'labelB-test' - ); + it('sets toggled based on defaultToggled on render', () => { + render(); + expect(screen.getByText('On')).toBeVisible(); }); - }); - - it('toggled prop sets checked prop on input', () => { - const wrapper = mount(); - - const input = () => wrapper.find('input'); - expect(input().props().checked).toEqual(true); - wrapper.setProps({ toggled: false }); - expect(input().props().checked).toEqual(false); - }); - - describe('events', () => { - it('passes along onChange to ', () => { + it('calls onChange when the control is changed', () => { const onChange = jest.fn(); - const id = 'test-input'; - const wrapper = mount( - - ); - - const input = wrapper.find('input'); - const inputElement = input.instance(); - - inputElement.checked = true; - wrapper.find('input').simulate('change'); - - expect( - onChange.mock.calls.map((call) => - call.map((arg, i) => (i > 0 ? arg : arg.target)) - ) - ).toEqual([[inputElement]]); + render(); + userEvent.click(screen.getByRole('checkbox')); + expect(onChange).toHaveBeenCalled(); }); - it('should invoke onToggle with expected arguments', () => { + it('calls onToggle when toggled', () => { const onToggle = jest.fn(); - const id = 'test-input'; - const wrapper = mount( - - ); - - const input = wrapper.find('input'); - const inputElement = input.instance(); - - inputElement.checked = true; - wrapper.find('input').simulate('change'); - - const call = onToggle.mock.calls[0]; - - expect(call[0]).toEqual(true); - expect(call[1]).toEqual(id); - expect(call[2].target).toBe(inputElement); + render(); + userEvent.click(screen.getByRole('checkbox')); + expect(onToggle).toHaveBeenCalled(); }); - }); - describe('ToggleSmall', () => { - const wrapper = mount(); + it('takes in custom labels for toggled and untoggled states', () => { + render(); + expect(screen.getByText('test On')).toBeInTheDocument(); + expect(screen.getByText('test Off')).toBeInTheDocument(); + }); - it('Sets the `ToggleSmall` className', () => { - const input = wrapper.find('input'); - expect(input.hasClass(`${prefix}--toggle-input--small`)).toEqual(true); + it('sets toggled based on toggled prop', () => { + const { rerender } = render(); + expect(screen.getByText('Off')).toBeVisible(); + rerender(); + expect(screen.getByText('On')).toBeVisible(); }); - it('Renders a checkmark SVG', () => { - const svg = wrapper.find(`.${prefix}--toggle__check`); - expect(svg.length).toBe(1); + it('passes extra props to input', () => { + render(); + expect(screen.getByRole('checkbox')).toHaveAttribute( + 'aria-disabled', + 'true' + ); }); }); }); From f58d8fae69133ce7fdb07852deac9dc2b05b0a9c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 18 Jan 2022 22:02:00 +0000 Subject: [PATCH 5/8] chore(deps): update cla-assistant/github-action action to v2.1.3 (#10455) Co-authored-by: Renovate Bot Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .github/workflows/dco.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dco.yml b/.github/workflows/dco.yml index 1ee3e7bd9369..3ed3884b0876 100644 --- a/.github/workflows/dco.yml +++ b/.github/workflows/dco.yml @@ -11,7 +11,7 @@ jobs: steps: - name: "DCO Assistant" if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the DCO document and I hereby sign the DCO.') || github.event_name == 'pull_request_target' - uses: cla-assistant/github-action@v2.1.2-beta + uses: cla-assistant/github-action@v2.1.3-beta env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} From e2b8b307cde3d85a68e7731878f99c3b7fd9faa7 Mon Sep 17 00:00:00 2001 From: DAK <40970507+dakahn@users.noreply.github.com> Date: Tue, 18 Jan 2022 16:58:08 -0600 Subject: [PATCH 6/8] fix(Notifications): add close icon to HCM media queries (#10447) Co-authored-by: Josh Black Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../scss/components/notification/_inline-notification.scss | 3 +++ .../scss/components/notification/_toast-notification.scss | 3 +++ 2 files changed, 6 insertions(+) diff --git a/packages/styles/scss/components/notification/_inline-notification.scss b/packages/styles/scss/components/notification/_inline-notification.scss index c15a9f3c3464..62bd4c20b149 100644 --- a/packages/styles/scss/components/notification/_inline-notification.scss +++ b/packages/styles/scss/components/notification/_inline-notification.scss @@ -324,5 +324,8 @@ .#{$prefix}--inline-notification__icon { @include high-contrast-mode('icon-fill'); } + .#{$prefix}--inline-notification__close-icon { + @include high-contrast-mode('icon-fill'); + } /* stylelint-enable */ } diff --git a/packages/styles/scss/components/notification/_toast-notification.scss b/packages/styles/scss/components/notification/_toast-notification.scss index 8cbeda15645b..bd872e2d5576 100644 --- a/packages/styles/scss/components/notification/_toast-notification.scss +++ b/packages/styles/scss/components/notification/_toast-notification.scss @@ -255,6 +255,9 @@ .#{$prefix}--toast-notification__close-button:focus { @include high-contrast-mode('focus'); } + .#{$prefix}--toast-notification__close-icon { + @include high-contrast-mode('icon-fill'); + } .#{$prefix}--toast-notification__icon { @include high-contrast-mode('icon-fill'); } From f0b689fa0cd241251863280ac86d59eb6a75cd34 Mon Sep 17 00:00:00 2001 From: Terry Yao <61534773+yaoterry@users.noreply.github.com> Date: Wed, 19 Jan 2022 07:47:50 +0800 Subject: [PATCH 7/8] fix(ExpandableTile): fix devtool warning message for handleClick prop (#10460) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- packages/react/src/components/Tile/Tile.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react/src/components/Tile/Tile.js b/packages/react/src/components/Tile/Tile.js index 54625b0080e4..eb00eef6ddce 100644 --- a/packages/react/src/components/Tile/Tile.js +++ b/packages/react/src/components/Tile/Tile.js @@ -629,6 +629,7 @@ export class ExpandableTile extends Component { expanded, // eslint-disable-line tileMaxHeight, // eslint-disable-line tilePadding, // eslint-disable-line + handleClick, // eslint-disable-line onKeyUp, tileCollapsedIconText, tileExpandedIconText, From 7a0a0828073c6729ba1d0af2f22c94eee1f0975c Mon Sep 17 00:00:00 2001 From: Taylor Jones Date: Wed, 19 Jan 2022 10:50:34 -0600 Subject: [PATCH 8/8] test(breadcrumb): refactor enzyme tests to react testing library (#10300) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../Breadcrumb/__tests__/Breadcrumb-test.js | 143 +++++------- .../__snapshots__/Breadcrumb-test.js.snap | 215 ------------------ 2 files changed, 53 insertions(+), 305 deletions(-) delete mode 100644 packages/react/src/components/Breadcrumb/__tests__/__snapshots__/Breadcrumb-test.js.snap diff --git a/packages/react/src/components/Breadcrumb/__tests__/Breadcrumb-test.js b/packages/react/src/components/Breadcrumb/__tests__/Breadcrumb-test.js index 24ebf2a9c5c5..b3155244f2fa 100644 --- a/packages/react/src/components/Breadcrumb/__tests__/Breadcrumb-test.js +++ b/packages/react/src/components/Breadcrumb/__tests__/Breadcrumb-test.js @@ -5,112 +5,75 @@ * LICENSE file in the root directory of this source tree. */ -import { cleanup, render } from '@testing-library/react'; import React from 'react'; -import { mount } from 'enzyme'; +import { screen, render } from '@testing-library/react'; +import '@testing-library/jest-dom'; import { settings } from 'carbon-components'; +import Breadcrumb from '../'; +import BreadcrumbItem from '../BreadcrumbItem'; const { prefix } = settings; describe('Breadcrumb', () => { - let Breadcrumb; - let BreadcrumbItem; + describe('API', () => { + it('should accept a `aria-label` for nav element', () => { + render(); + expect(screen.getByLabelText('test-label')).toBeInTheDocument(); + }); - beforeEach(() => { - const BreadcrumbEntrypoint = require('../'); - Breadcrumb = BreadcrumbEntrypoint.Breadcrumb; - BreadcrumbItem = BreadcrumbEntrypoint.BreadcrumbItem; - }); + it('should provide a default `aria-label` for nav element', () => { + render(); + expect(screen.getByLabelText('Breadcrumb')).toBeInTheDocument(); + }); - it('should render', () => { - const wrapper = mount( - - - Breadcrumb 1 - - - ); - expect(wrapper).toMatchSnapshot(); - }); + it('should accept `children` of BreadcrumbItem', () => { + render( + + A + B + C + + ); + expect(screen.getByText('A')).toBeInTheDocument(); + expect(screen.getByText('B')).toBeInTheDocument(); + expect(screen.getByText('C')).toBeInTheDocument(); + }); - it('should support rendering without a trailing slash', () => { - const wrapper = mount( - - - Breadcrumb 1 - - - ); - expect(wrapper).toMatchSnapshot(); - }); + it('should accept a `noTrailingSlash` and omit the trailing slash', () => { + render( + + A + B + C + + ); - it('should support rendering a custom component as a breadcrumb item', () => { - const CustomComponent = jest.fn(({ children, href, ...rest }) => ( - - {children} - - )); + // The slashes are implemented with pseudo elements that can't be detected in jsdom. + // So we have to settle here for just validating against the class. Pseudo elements + // should be tested in the browser/e2e tests. + // https://testing-library.com/docs/dom-testing-library/api-configuration/#computedstylesupportspseudoelements + // https://github.com/jsdom/jsdom/issues/1928 + expect(screen.getByRole('list')).toHaveClass( + `${prefix}--breadcrumb--no-trailing-slash` + ); + }); - mount( - - A - B - - C - - - ); + it('should accept a `className` for outermost DOM node', () => { + const { container } = render(); - expect(CustomComponent).toHaveBeenCalled(); - expect(CustomComponent).toHaveBeenCalledWith( - expect.objectContaining({ - className: `${prefix}--link`, - }), - {} - ); - }); + expect(container.firstChild).toHaveClass('test'); + }); - it('should support rendering the current page', () => { - const manual = mount( - - A - B - - C - - - ); - expect(manual).toMatchSnapshot(); + it('should apply additional props to the outermost element', () => { + const { container } = render(); - const aria = mount( - - A - B - - C - - - ); - expect(aria).toMatchSnapshot(); - }); + expect(container.firstChild).toHaveAttribute('data-testid', 'test'); + }); - describe('Component API', () => { - afterEach(cleanup); + it('should accept a `ref` for the outermost element', () => { + const ref = jest.fn(); + const { container } = render(); - it('should accept a `ref` for the outermost node', () => { - const ref = jest.fn(() => React.createRef()); - const { container } = render( - - A - B - - C - - - ); - expect(ref).toHaveBeenCalled(); expect(ref).toHaveBeenCalledWith(container.firstChild); }); }); diff --git a/packages/react/src/components/Breadcrumb/__tests__/__snapshots__/Breadcrumb-test.js.snap b/packages/react/src/components/Breadcrumb/__tests__/__snapshots__/Breadcrumb-test.js.snap deleted file mode 100644 index d04e3a30e883..000000000000 --- a/packages/react/src/components/Breadcrumb/__tests__/__snapshots__/Breadcrumb-test.js.snap +++ /dev/null @@ -1,215 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Breadcrumb should render 1`] = ` - - - -`; - -exports[`Breadcrumb should support rendering the current page 1`] = ` - - - -`; - -exports[`Breadcrumb should support rendering the current page 2`] = ` - - - -`; - -exports[`Breadcrumb should support rendering without a trailing slash 1`] = ` - - - -`;