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 }} 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..f6ec3595e652 100644 --- a/.github/workflows/sync-generated-files.yml +++ b/.github/workflows/sync-generated-files.yml @@ -5,15 +5,15 @@ on: - main jobs: release: - runs-on: macOS-latest + 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 with: node-version: '16.x' - name: Install dependencies - run: yarn install --immutable --immutable-cache --check-cache + run: yarn install --immutable --immutable-cache - name: Build project run: yarn build - name: Sync project dependency files 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`] = ` - - - -`; 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, 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' + ); }); }); }); diff --git a/packages/styles/scss/_type.scss b/packages/styles/scss/_type.scss index 4e4245a28e65..7f6dcacde295 100644 --- a/packages/styles/scss/_type.scss +++ b/packages/styles/scss/_type.scss @@ -12,6 +12,7 @@ type-style, font-family, default-type, + type-classes, // Variables $caption-01, 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'); }