diff --git a/package-lock.json b/package-lock.json index 974c8bd629..de5da53997 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50470,7 +50470,8 @@ }, "devDependencies": { "@instructure/ui-babel-preset": "8.53.2", - "@instructure/ui-test-utils": "8.53.2" + "@testing-library/jest-dom": "^6.1.4", + "@testing-library/react": "^14.0.0" }, "peerDependencies": { "react": ">=16.8 <=18", diff --git a/packages/ui-react-utils/package.json b/packages/ui-react-utils/package.json index 6eb16df08e..7f2073f365 100644 --- a/packages/ui-react-utils/package.json +++ b/packages/ui-react-utils/package.json @@ -23,7 +23,8 @@ "license": "MIT", "devDependencies": { "@instructure/ui-babel-preset": "8.53.2", - "@instructure/ui-test-utils": "8.53.2" + "@testing-library/jest-dom": "^6.1.4", + "@testing-library/react": "^14.0.0" }, "dependencies": { "@babel/runtime": "^7.23.2", diff --git a/packages/ui-react-utils/src/__tests__/ComponentIdentifier.test.tsx b/packages/ui-react-utils/src/__new-tests__/ComponentIdentifier.test.tsx similarity index 75% rename from packages/ui-react-utils/src/__tests__/ComponentIdentifier.test.tsx rename to packages/ui-react-utils/src/__new-tests__/ComponentIdentifier.test.tsx index 5e2697b4a1..2d46fbf825 100644 --- a/packages/ui-react-utils/src/__tests__/ComponentIdentifier.test.tsx +++ b/packages/ui-react-utils/src/__new-tests__/ComponentIdentifier.test.tsx @@ -24,10 +24,21 @@ import React, { Component, ReactNode } from 'react' import PropTypes from 'prop-types' -import { mount, expect, stub } from '@instructure/ui-test-utils' + +import { render } from '@testing-library/react' +import '@testing-library/jest-dom' + import { ComponentIdentifier } from '../ComponentIdentifier' -describe('ComponentIdentifier', async () => { +describe('ComponentIdentifier', () => { + beforeAll(() => { + // Mocking console warnings to prevent test output pollution + jest.spyOn(console, 'warn').mockImplementation(() => {}) + }) + afterAll(() => { + jest.restoreAllMocks() + }) + class Trigger extends ComponentIdentifier { static displayName = 'Trigger' } @@ -53,9 +64,9 @@ describe('ComponentIdentifier', async () => { } } - it('should render only child', async () => { + it('should render only child', () => { let buttonRef: HTMLButtonElement - await mount( + render( @@ -63,28 +74,24 @@ describe('ComponentIdentifier', async () => { ) - expect(buttonRef!.textContent).to.equal('Click Me') + expect(buttonRef!.textContent).toEqual('Click Me') }) - it('should not error when no children provided', async () => { - let error = false - try { - await mount( + it('should not error when no children provided', () => { + const renderApp = () => + render( ) - } catch (e) { - error = true - } - expect(error).to.be.false() + expect(renderApp).not.toThrow() }) - it('should pass props', async () => { + it('should pass props', () => { let buttonRef: HTMLButtonElement | null - const onClick = stub() - await mount( + const onClick = jest.fn() + render( @@ -92,7 +99,7 @@ describe('ComponentIdentifier', async () => { ) - await buttonRef!.click() - expect(onClick).to.have.been.called() + buttonRef!.click() + expect(onClick).toHaveBeenCalled() }) }) diff --git a/packages/ui-react-utils/src/__tests__/DeterministicIdContext.test.tsx b/packages/ui-react-utils/src/__new-tests__/DeterministicIdContext.test.tsx similarity index 56% rename from packages/ui-react-utils/src/__tests__/DeterministicIdContext.test.tsx rename to packages/ui-react-utils/src/__new-tests__/DeterministicIdContext.test.tsx index 7195859946..b053e65401 100644 --- a/packages/ui-react-utils/src/__tests__/DeterministicIdContext.test.tsx +++ b/packages/ui-react-utils/src/__new-tests__/DeterministicIdContext.test.tsx @@ -23,10 +23,10 @@ */ import React from 'react' -import ReactDOM from 'react-dom' -import ReactTestUtils from 'react-dom/test-utils' -import { expect, mount } from '@instructure/ui-test-utils' +import { render, screen } from '@testing-library/react' +import '@testing-library/jest-dom' + import { withDeterministicId, DeterministicIdContextProvider, @@ -39,7 +39,11 @@ class TestComponent extends React.Component< React.PropsWithChildren > { render() { - return
{this.props.children}
+ return ( +
+ {this.props.children} +
+ ) } } @@ -53,73 +57,70 @@ class WrapperComponent extends React.Component { } } -const uniqueIds = (el: { getDOMNode: () => Element }) => { - const idList = Array.from(el.getDOMNode().children).map((el) => el.id) - +const uniqueIds = (el: Element) => { + const idList = Array.from(el.children).map((child) => child.id) return new Set(idList).size === idList.length } describe('DeterministicIdContext', () => { - it('can be found and tested with ReactTestUtils', async () => { - const rootNode = document.createElement('div') - document.body.appendChild(rootNode) + it('can be found and tested with ReactTestUtils', () => { + render() + const testComponent = screen.getByTestId('test-component') - // eslint-disable-next-line react/no-render-return-value - const rendered = ReactDOM.render(, rootNode) - ReactTestUtils.findRenderedComponentWithType( - rendered as any, - (TestComponent as any).originalType - ) + expect(testComponent).toBeInTheDocument() + expect(testComponent.id).toBeDefined() }) - it('should generate unique ids without Provider wrapper', async () => { - const el = await mount( -
- - - - - + it('should generate unique ids without Provider wrapper', () => { + render( +
+ + + + +
) + const el = screen.getByTestId('test-components') - expect(uniqueIds(el)).to.be.true() + expect(uniqueIds(el)).toBe(true) }) - it('should generate unique ids when components are rendered both out and inside of provider', async () => { - const el = await mount( -
+ it('should generate unique ids when components are rendered both out and inside of provider', () => { + render( +
- - - + + + - - + +
) + const el = screen.getByTestId('test-components') - expect(uniqueIds(el)).to.be.true() + expect(uniqueIds(el)).toBe(true) }) - //skipping this test because it will fail either in strictmode or normal mode - it('should generate unique ids with provider only', async () => { + it('should generate unique ids with provider only', () => { const Wrapper = ({ children }: any) => { return ( -
{children}
+
{children}
) } const children = [] for (let i = 0; i < 10; i++) { - children.push() + children.push() } - const el = await mount({children}) + render({children}) + const el = screen.getByTestId('wrapper') - expect(uniqueIds(el)).to.be.true() + expect(uniqueIds(el)).toBe(true) }) }) diff --git a/packages/ui-react-utils/src/__tests__/callRenderProp.test.tsx b/packages/ui-react-utils/src/__new-tests__/callRenderProp.test.tsx similarity index 68% rename from packages/ui-react-utils/src/__tests__/callRenderProp.test.tsx rename to packages/ui-react-utils/src/__new-tests__/callRenderProp.test.tsx index f3c642acb7..159f1cc7e9 100644 --- a/packages/ui-react-utils/src/__tests__/callRenderProp.test.tsx +++ b/packages/ui-react-utils/src/__new-tests__/callRenderProp.test.tsx @@ -24,36 +24,38 @@ import React from 'react' import PropTypes from 'prop-types' -import { expect, mount } from '@instructure/ui-test-utils' + +import { render } from '@testing-library/react' +import '@testing-library/jest-dom' + import { callRenderProp } from '../callRenderProp' -describe('callRenderProp', async () => { - /* eslint-disable mocha/no-synchronous-tests */ +describe('callRenderProp', () => { it('strings', () => { - expect(callRenderProp('foo')).to.equal('foo') + expect(callRenderProp('foo')).toEqual('foo') }) it('numbers', () => { - expect(callRenderProp(2)).to.equal(2) + expect(callRenderProp(2)).toEqual(2) }) it('arrays', () => { const prop = ['foo', 'bar', 'baz'] - expect(callRenderProp(prop)).to.deep.equal(prop) - expect(callRenderProp([])).to.deep.equal([]) + + expect(callRenderProp(prop)).toStrictEqual(prop) + expect(callRenderProp([])).toStrictEqual([]) }) it('booleans', () => { - expect(callRenderProp(false)).to.equal(false) + expect(callRenderProp(false)).toEqual(false) }) it('JSX literals', () => { const Foo = () =>
hello
- expect(callRenderProp()).to.deep.equal() + expect(callRenderProp()).toStrictEqual() }) - /* eslint-enable mocha/no-synchronous-tests */ - it('React classes', async () => { + it('React classes', () => { class Foo extends React.Component { render() { return
hello
@@ -61,23 +63,24 @@ describe('callRenderProp', async () => { } const Result = callRenderProp(Foo) - expect(Result).to.deep.equal() + expect(Result).toStrictEqual() - const subject = await mount(Result) - expect(subject.getDOMNode()).to.exist() + const { getByText } = render(Result) + expect(getByText('hello')).toBeInTheDocument() }) - it('functions', async () => { + it('functions', () => { const Baz = function () { return 'some text' } const result = callRenderProp(Baz) - const subject = await mount(
{result}
) + const { getByText } = render(
{result}
) - expect(subject.getDOMNode()).to.have.text('some text') + expect(getByText('some text')).toBeInTheDocument() }) - it('fat arrow functions', async () => { + + it('fat arrow functions', () => { const Baz = () => 'some text' // in this test we are trying to test that it works with fat arrow functions, @@ -91,23 +94,23 @@ describe('callRenderProp', async () => { const result = callRenderProp(Baz) - const subject = await mount(
{result}
) + const { getByText } = render(
{result}
) - expect(subject.getDOMNode()).to.have.text('some text') + expect(getByText('some text')).toBeInTheDocument() }) - describe('passing props', async () => { - it('should pass props correctly to functions', async () => { + describe('passing props', () => { + it('should pass props correctly to functions', () => { const someFunc = ({ shape }: { shape: string }) =>
{shape}
const result = callRenderProp(someFunc, { shape: 'rectangle' }) - const subject = await mount(
{result}
) + const { getByText } = render(
{result}
) - expect(subject.getDOMNode()).to.have.text('rectangle') + expect(getByText('rectangle')).toBeInTheDocument() }) - it('should pass props correctly to React classes', async () => { + it('should pass props correctly to React classes', () => { type FooProps = { shape?: string } class Foo extends React.Component { static propTypes = { @@ -125,9 +128,9 @@ describe('callRenderProp', async () => { const result = callRenderProp(Foo, { shape: 'rectangle' }) - const subject = await mount(
{result}
) + const { getByText } = render(
{result}
) - expect(subject.getDOMNode()).to.have.text('rectangle') + expect(getByText('rectangle')).toBeInTheDocument() }) }) }) diff --git a/packages/ui-react-utils/src/__tests__/deprecated.test.tsx b/packages/ui-react-utils/src/__new-tests__/deprecated.test.tsx similarity index 56% rename from packages/ui-react-utils/src/__tests__/deprecated.test.tsx rename to packages/ui-react-utils/src/__new-tests__/deprecated.test.tsx index bae54a6857..5bdcb79c0d 100644 --- a/packages/ui-react-utils/src/__tests__/deprecated.test.tsx +++ b/packages/ui-react-utils/src/__new-tests__/deprecated.test.tsx @@ -25,7 +25,8 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' -import { expect, mount, stub, spy } from '@instructure/ui-test-utils' +import { render } from '@testing-library/react' +import '@testing-library/jest-dom' import { deprecated } from '../deprecated' @@ -53,83 +54,115 @@ class TestComponent extends Component { } } -describe('@deprecated', async () => { - describe('deprecated props', async () => { +describe('@deprecated', () => { + describe('deprecated props', () => { const DeprecatedComponent = deprecated('2.1.0', { foo: 'bar', baz: true })(TestComponent) - it('should warn when suggesting new prop when using old prop', async () => { - const consoleWarn = spy(console, 'warn') + it('should warn when suggesting new prop when using old prop', () => { + const consoleWarningSpy = jest + .spyOn(console, 'warn') + .mockImplementation(() => {}) - const warning = + render() + + const expectedWarningMessage = 'Warning: [TestComponent] `foo` is deprecated and will be removed in version 2.1.0. Use `bar` instead. ' - await mount() + expect(consoleWarningSpy).toHaveBeenCalledWith( + expect.stringContaining(expectedWarningMessage), + expect.any(String) + ) - expect(consoleWarn.firstCall.args[0]).to.be.equal(warning) + consoleWarningSpy.mockRestore() }) - it('should warn when using old prop with no new prop', async () => { - const consoleWarn = stub(console, 'warn') + it('should warn when using old prop with no new prop', () => { + const consoleWarningSpy = jest + .spyOn(console, 'warn') + .mockImplementation(() => {}) + + render() - const warning = + const expectedWarningMessage = 'Warning: [TestComponent] `baz` is deprecated and will be removed in version 2.1.0.' - await mount() + expect(consoleWarningSpy).toHaveBeenCalledWith( + expect.stringContaining(expectedWarningMessage), + expect.any(String) + ) - expect(consoleWarn).to.have.been.calledWithMatch(warning) + consoleWarningSpy.mockRestore() }) - it('should not output a warning using new prop', async () => { - const consoleWarn = stub(console, 'warn') + it('should not output a warning using new prop', () => { + const consoleWarningSpy = jest + .spyOn(console, 'warn') + .mockImplementation(() => {}) + + render() - await mount() + expect(consoleWarningSpy).not.toHaveBeenCalled() - expect(consoleWarn).to.not.have.been.called() + consoleWarningSpy.mockRestore() }) }) - describe('deprecated component', async () => { + describe('deprecated component', () => { const DeprecatedComponent = deprecated('3.4.0')(TestComponent) - it('should warn that the entire component is deprecated if no old props are supplied', async () => { - const consoleWarn = stub(console, 'warn') + it('should warn that the entire component is deprecated if no old props are supplied', () => { + const consoleWarningSpy = jest + .spyOn(console, 'warn') + .mockImplementation(() => {}) - const warning = + render() + + const expectedWarningMessage = 'Warning: [TestComponent] is deprecated and will be removed in version 3.4.0.' - await mount() + expect(consoleWarningSpy).toHaveBeenCalledWith( + expect.stringContaining(expectedWarningMessage), + expect.any(String) + ) - expect(consoleWarn).to.have.been.calledWithMatch(warning) + consoleWarningSpy.mockRestore() }) }) - describe('deprecated component with a changed package message', async () => { + describe('deprecated component with a changed package message', () => { const DeprecatedComponent = deprecated( '5.0.0', null, deprecated.changedPackageWarning('ui-forms', 'ui-number-input') )(TestComponent) - it('should warn that the component is deprecated and output a warning that the package changed', async () => { - const consoleWarn = stub(console, 'warn') + it('should warn that the component is deprecated and output a warning that the package changed', () => { + const consoleWarningSpy = jest + .spyOn(console, 'warn') + .mockImplementation(() => {}) + + const expectedWarningMessage = + 'Warning: [TestComponent] is deprecated and will be removed in version 5.0.0. It has been moved from @instructure/ui-forms to @instructure/ui-number-input.' - const warning = [ - 'Warning: [TestComponent] is deprecated and will be removed in version 5.0.0.', - `It has been moved from @instructure/ui-forms to @instructure/ui-number-input.` - ].join(' ') + render() - await mount() + expect(consoleWarningSpy).toHaveBeenCalledWith( + expect.stringContaining(expectedWarningMessage), + expect.any(String) + ) - expect(consoleWarn).to.have.been.calledWithMatch(warning) + consoleWarningSpy.mockRestore() }) }) - describe('component with deprecated prop values', async () => { - it('should not warn when an allowed prop value is supplied', async () => { - const consoleWarn = stub(console, 'warn') + describe('component with deprecated prop values', () => { + it('should not warn when an allowed prop value is supplied', () => { + const consoleWarningSpy = jest + .spyOn(console, 'warn') + .mockImplementation(() => {}) type DeprecatedPropValueComponentProps = { color: string } @@ -150,13 +183,17 @@ describe('@deprecated', async () => { } } - await mount() + render() - expect(consoleWarn).to.not.have.been.called() + expect(consoleWarningSpy).not.toHaveBeenCalled() + + consoleWarningSpy.mockRestore() }) - it('should warn when a forbidden prop value is supplied', async () => { - const consoleWarn = stub(console, 'warn') + it('should warn when a forbidden prop value is supplied', () => { + const consoleWarningSpy = jest + .spyOn(console, 'warn') + .mockImplementation(() => {}) const color = 'orange' type DeprecatedPropValueComponentProps = { @@ -179,15 +216,22 @@ describe('@deprecated', async () => { } } - await mount() + render() + + const expectedWarningMessage = `The '${color}' value for the \`color\` prop is deprecated.` - const warning = `The '${color}' value for the \`color\` prop is deprecated.` + expect(consoleWarningSpy).toHaveBeenCalledWith( + expect.stringContaining(expectedWarningMessage), + expect.any(String) + ) - expect(consoleWarn).to.have.been.calledWithMatch(warning) + consoleWarningSpy.mockRestore() }) - it('should warn with additional message text when a forbidden prop value is supplied and has message text', async () => { - const consoleWarn = stub(console, 'warn') + it('should warn with additional message text when a forbidden prop value is supplied and has message text', () => { + const consoleWarningSpy = jest + .spyOn(console, 'warn') + .mockImplementation(() => {}) const color = 'gold' const message = 'It will be removed in v8.0.0.' @@ -212,16 +256,23 @@ describe('@deprecated', async () => { } } - await mount() + render() + + const expectedWarningMessage = `The '${color}' value for the \`color\` prop is deprecated. ${message}` - const warning = `The '${color}' value for the \`color\` prop is deprecated. ${message}` + expect(consoleWarningSpy).toHaveBeenCalledWith( + expect.stringContaining(expectedWarningMessage), + expect.any(String) + ) - expect(consoleWarn).to.have.been.calledWithMatch(warning) + consoleWarningSpy.mockRestore() }) - it('should call functional message with the correct props', async () => { - stub(console, 'warn') - const messageStub = stub() + it('should call functional message with the correct props', () => { + const consoleWarningSpy = jest + .spyOn(console, 'warn') + .mockImplementation(() => {}) + const messageMock = jest.fn() const color = 'gold' type DeprecatedPropValueComponentProps = { @@ -232,7 +283,7 @@ describe('@deprecated', async () => { color: deprecated.deprecatePropValues( PropTypes.oneOf(['red', 'yellow', 'blue', 'orange', 'gold']), ['blue', 'orange', 'gold'], - messageStub + messageMock ) } @@ -245,17 +296,22 @@ describe('@deprecated', async () => { } } - await mount() + render() - const { props, propName, propValue } = messageStub.lastCall.args[0] + const { props, propName, propValue } = messageMock.mock.calls[0][0] - expect(props).to.deep.equal({ color }) - expect(propName).to.equal('color') - expect(propValue).to.equal(color) + expect(props).toEqual({ color }) + expect(propName).toBe('color') + expect(propValue).toBe(color) + expect(consoleWarningSpy).toHaveBeenCalled() + + consoleWarningSpy.mockRestore() }) - it('should warn with a completely custom message when provided message is functional and prop value is forbidden', async () => { - const consoleWarn = stub(console, 'warn') + it('should warn with a completely custom message when provided message is functional and prop value is forbidden', () => { + const consoleWarningSpy = jest + .spyOn(console, 'warn') + .mockImplementation(() => {}) const color = 'gold' type DeprecatedPropValueComponentProps = { @@ -286,11 +342,16 @@ describe('@deprecated', async () => { } } - await mount() + render() + + const expectedWarningMessage = `The ${color} value for color has been deprecated. Use the FooBar component with the 'baz' prop set instead.` - const warning = `The ${color} value for color has been deprecated. Use the FooBar component with the 'baz' prop set instead.` + expect(consoleWarningSpy).toHaveBeenCalledWith( + expect.stringContaining(expectedWarningMessage), + expect.any(String) + ) - expect(consoleWarn).to.have.been.calledWithMatch(warning) + consoleWarningSpy.mockRestore() }) }) }) diff --git a/packages/ui-react-utils/src/__tests__/experimental.test.tsx b/packages/ui-react-utils/src/__new-tests__/experimental.test.tsx similarity index 54% rename from packages/ui-react-utils/src/__tests__/experimental.test.tsx rename to packages/ui-react-utils/src/__new-tests__/experimental.test.tsx index 94d7388b9c..bee0c73a39 100644 --- a/packages/ui-react-utils/src/__tests__/experimental.test.tsx +++ b/packages/ui-react-utils/src/__new-tests__/experimental.test.tsx @@ -25,9 +25,11 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' -import { expect, mount, spy } from '@instructure/ui-test-utils' +import { render } from '@testing-library/react' +import '@testing-library/jest-dom' import { experimental } from '../experimental' + type TestComponentProps = { bar: string qux: string @@ -52,62 +54,85 @@ class TestComponent extends Component { } } -describe('@experimental', async () => { - describe('experimental props', async () => { +describe('@experimental', () => { + describe('experimental props', () => { const ExperimentalComponent = experimental(['bar'])(TestComponent) - it('should warn when using an experimental prop', async () => { - const consoleWarn = spy(console, 'warn') - await mount() - await expect(consoleWarn).to.have.been.calledWithMatch( - [ - 'Warning: [TestComponent] ', - 'The `bar` prop is experimental and its API could change significantly in a future release.' - ].join('') + it('should warn when using an experimental prop', () => { + const consoleWarningSpy = jest + .spyOn(console, 'warn') + .mockImplementation(() => {}) + render() + + const expectedWarningMessage = + 'Warning: [TestComponent] The `bar` prop is experimental and its API could change significantly in a future release.' + + expect(consoleWarningSpy).toHaveBeenCalledWith( + expect.stringContaining(expectedWarningMessage), + expect.any(String) ) + + consoleWarningSpy.mockRestore() }) - it('should not output a warning using a non-experimental prop', async () => { - const consoleWarn = spy(console, 'warn') + it('should not output a warning using a non-experimental prop', () => { + const consoleWarningSpy = jest + .spyOn(console, 'warn') + .mockImplementation(() => {}) + render() - await mount() + expect(consoleWarningSpy).not.toHaveBeenCalled() - await expect(consoleWarn).to.not.have.been.called() + consoleWarningSpy.mockRestore() }) - it('should not output a warning for an experimental prop when dangerously ignored', async () => { - const consoleWarn = spy(console, 'warn') + it('should not output a warning for an experimental prop when dangerously ignored', () => { + const consoleWarningSpy = jest + .spyOn(console, 'warn') + .mockImplementation(() => {}) - await mount( + render( ) - await expect(consoleWarn).to.not.have.been.called() + expect(consoleWarningSpy).not.toHaveBeenCalled() + + consoleWarningSpy.mockRestore() }) }) - describe('experimental component', async () => { + describe('experimental component', () => { const ExperimentalComponent = experimental()(TestComponent) - it('should warn that the entire component is experimental if no props are supplied', async () => { - const consoleWarn = spy(console, 'warn') - await mount() - const warning = + it('should warn that the entire component is experimental if no props are supplied', () => { + const consoleWarningSpy = jest + .spyOn(console, 'warn') + .mockImplementation(() => {}) + render() + + const expectedWarningMessage = 'Warning: [TestComponent] is experimental and its API could change significantly in a future release.' - await expect(consoleWarn).to.have.been.calledWithMatch(warning) + expect(consoleWarningSpy).toHaveBeenCalledWith( + expect.stringContaining(expectedWarningMessage), + expect.any(String) + ) + + consoleWarningSpy.mockRestore() }) - it('should not output a warning for a component when dangerously ignored', async () => { - const consoleWarn = spy(console, 'warn') - await mount( - - ) + it('should not output a warning for a component when dangerously ignored', () => { + const consoleWarningSpy = jest + .spyOn(console, 'warn') + .mockImplementation(() => {}) + render() + + expect(consoleWarningSpy).not.toHaveBeenCalled() - await expect(consoleWarn).to.not.have.been.called() + consoleWarningSpy.mockRestore() }) }) }) diff --git a/packages/ui-react-utils/src/__tests__/getInteraction.test.ts b/packages/ui-react-utils/src/__new-tests__/getInteraction.test.tsx similarity index 82% rename from packages/ui-react-utils/src/__tests__/getInteraction.test.ts rename to packages/ui-react-utils/src/__new-tests__/getInteraction.test.tsx index 6d80d1f3da..96f84ad47a 100644 --- a/packages/ui-react-utils/src/__tests__/getInteraction.test.ts +++ b/packages/ui-react-utils/src/__new-tests__/getInteraction.test.tsx @@ -22,8 +22,7 @@ * SOFTWARE. */ -import { expect } from '@instructure/ui-test-utils' - +import '@testing-library/jest-dom' import { getInteraction, InteractionType } from '../getInteraction' describe('getInteraction', () => { @@ -33,7 +32,7 @@ describe('getInteraction', () => { bar: 'bar' } - expect(getInteraction({ props })).to.equal('enabled') + expect(getInteraction({ props })).toEqual('enabled') }) it('should return `interaction` value when `interaction` is specified', () => { @@ -41,15 +40,15 @@ describe('getInteraction', () => { interaction: 'enabled' } - expect(getInteraction({ props })).to.equal('enabled') + expect(getInteraction({ props })).toEqual('enabled') props.interaction = 'disabled' - expect(getInteraction({ props })).to.equal('disabled') + expect(getInteraction({ props })).toEqual('disabled') props.interaction = 'readonly' - expect(getInteraction({ props })).to.equal('readonly') + expect(getInteraction({ props })).toEqual('readonly') }) it('should give preference to interaction even when disabled and readonly are also specified', () => { @@ -59,17 +58,17 @@ describe('getInteraction', () => { readOnly: true } - expect(getInteraction({ props })).to.equal('enabled') + expect(getInteraction({ props })).toEqual('enabled') props.disabled = false props.interaction = 'disabled' - expect(getInteraction({ props })).to.equal('disabled') + expect(getInteraction({ props })).toEqual('disabled') props.readOnly = false props.interaction = 'readonly' - expect(getInteraction({ props })).to.equal('readonly') + expect(getInteraction({ props })).toEqual('readonly') }) it("should return 'disabled' when `disabled` prop is set and `interaction` is not specified", () => { @@ -77,7 +76,7 @@ describe('getInteraction', () => { disabled: true } - expect(getInteraction({ props })).to.equal('disabled') + expect(getInteraction({ props })).toEqual('disabled') }) it("should return 'disabled' when both `disabled` and `readonly` props are set and `interaction` is not specified", () => { @@ -86,7 +85,7 @@ describe('getInteraction', () => { readOnly: true } - expect(getInteraction({ props })).to.equal('disabled') + expect(getInteraction({ props })).toEqual('disabled') }) it("should return 'readonly' when `readonly` prop is set and `interaction` and `disabled` are not specified", () => { @@ -94,7 +93,7 @@ describe('getInteraction', () => { disabled: true } - expect(getInteraction({ props })).to.equal('disabled') + expect(getInteraction({ props })).toEqual('disabled') }) it('should not include `disabled` if it is not listed in the interactionTypes', () => { @@ -103,7 +102,7 @@ describe('getInteraction', () => { readOnly: true } - expect(getInteraction({ props, interactionTypes: ['readonly'] })).to.equal( + expect(getInteraction({ props, interactionTypes: ['readonly'] })).toEqual( 'readonly' ) }) @@ -113,7 +112,7 @@ describe('getInteraction', () => { readOnly: true } - expect(getInteraction({ props, interactionTypes: ['disabled'] })).to.equal( + expect(getInteraction({ props, interactionTypes: ['disabled'] })).toEqual( 'enabled' ) }) diff --git a/packages/ui-react-utils/src/__tests__/hack.test.tsx b/packages/ui-react-utils/src/__new-tests__/hack.test.tsx similarity index 63% rename from packages/ui-react-utils/src/__tests__/hack.test.tsx rename to packages/ui-react-utils/src/__new-tests__/hack.test.tsx index e154e6e320..e4c7e222c2 100644 --- a/packages/ui-react-utils/src/__tests__/hack.test.tsx +++ b/packages/ui-react-utils/src/__new-tests__/hack.test.tsx @@ -25,7 +25,8 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' -import { expect, mount, spy } from '@instructure/ui-test-utils' +import { render } from '@testing-library/react' +import '@testing-library/jest-dom' import { hack } from '../hack' @@ -53,27 +54,37 @@ class TestComponent extends Component { } } -describe('@hack', async () => { - describe('hack props', async () => { +describe('@hack', () => { + describe('hack props', () => { const HackComponent = hack(['bar'])(TestComponent) - it('should warn when using an hack prop', async () => { - const consoleWarn = spy(console, 'warn') - await mount() - await expect(consoleWarn).to.have.been.calledWithMatch( - [ - 'Warning: [TestComponent] ', - 'The `bar` prop is a temporary hack and will be removed in a future release.' - ].join('') + it('should warn when using an hack prop', () => { + const consoleWarningSpy = jest + .spyOn(console, 'warn') + .mockImplementation(() => {}) + render() + + const expectedWarningMessage = + 'Warning: [TestComponent] The `bar` prop is a temporary hack and will be removed in a future release.' + + expect(consoleWarningSpy).toHaveBeenCalledWith( + expect.stringContaining(expectedWarningMessage), + expect.any(String) ) + + consoleWarningSpy.mockRestore() }) - it('should not output a warning using a non-hack prop', async () => { - const consoleWarn = spy(console, 'warn') + it('should not output a warning using a non-hack prop', () => { + const consoleWarningSpy = jest + .spyOn(console, 'warn') + .mockImplementation(() => {}) + + render() - await mount() + expect(consoleWarningSpy).not.toHaveBeenCalled() - await expect(consoleWarn).to.not.have.been.called() + consoleWarningSpy.mockRestore() }) }) }) diff --git a/packages/ui-react-utils/src/__tests__/omitProps.test.ts b/packages/ui-react-utils/src/__new-tests__/omitProps.test.tsx similarity index 88% rename from packages/ui-react-utils/src/__tests__/omitProps.test.ts rename to packages/ui-react-utils/src/__new-tests__/omitProps.test.tsx index 62b90a8dd3..3e9807d3f1 100644 --- a/packages/ui-react-utils/src/__tests__/omitProps.test.ts +++ b/packages/ui-react-utils/src/__new-tests__/omitProps.test.tsx @@ -23,12 +23,11 @@ */ import PropTypes from 'prop-types' -import { expect } from '@instructure/ui-test-utils' +import '@testing-library/jest-dom' import { omitProps } from '../omitProps' describe('omitProps', () => { it('should work with PropTypes', () => { - //arrange const propTypes = { prop1: PropTypes.string.isRequired, prop2: PropTypes.number @@ -44,14 +43,12 @@ describe('omitProps', () => { excessiveProp: 'excessiveValue' } - //act const actualResult = omitProps(inputProps, propTypes) - //assert - expect(actualResult).to.be.eql(expectedResult) + expect(actualResult).toEqual(expectedResult) }) + it('should work with PropTypes and exclude the given keys', () => { - //arrange const propTypes = { prop1: PropTypes.string.isRequired, prop2: PropTypes.number @@ -68,14 +65,12 @@ describe('omitProps', () => { excessiveProp2: 'excessiveValue2' } - //act const actualResult = omitProps(inputProps, propTypes, ['excessiveProp1']) - //assert - expect(actualResult).to.be.eql(expectedResult) + expect(actualResult).toEqual(expectedResult) }) + it('should work with an input of a list allowed prop names', () => { - //arrange const allowedPropKeys = ['prop1', 'prop2'] const inputProps = { @@ -90,14 +85,12 @@ describe('omitProps', () => { excessiveProp2: 'excessiveValue2' } - //act const actualResult = omitProps(inputProps, allowedPropKeys) - //assert - expect(actualResult).to.be.eql(expectedResult) + expect(actualResult).toEqual(expectedResult) }) + it('should work with an input of a list allowed prop names and exclude the given keys', () => { - //arrange const allowedPropKeys = ['prop1', 'prop2'] const inputProps = { @@ -111,12 +104,10 @@ describe('omitProps', () => { excessiveProp2: 'excessiveValue2' } - //act const actualResult = omitProps(inputProps, allowedPropKeys, [ 'excessiveProp1' ]) - //assert - expect(actualResult).to.be.eql(expectedResult) + expect(actualResult).toEqual(expectedResult) }) }) diff --git a/packages/ui-react-utils/src/__tests__/passthroughProps.test.ts b/packages/ui-react-utils/src/__new-tests__/passthroughProps.test.tsx similarity index 79% rename from packages/ui-react-utils/src/__tests__/passthroughProps.test.ts rename to packages/ui-react-utils/src/__new-tests__/passthroughProps.test.tsx index 10dbb32f5b..d495c6db0b 100644 --- a/packages/ui-react-utils/src/__tests__/passthroughProps.test.ts +++ b/packages/ui-react-utils/src/__new-tests__/passthroughProps.test.tsx @@ -22,24 +22,23 @@ * SOFTWARE. */ -import { expect } from '@instructure/ui-test-utils' +import '@testing-library/jest-dom' import { passthroughProps } from '../passthroughProps' -describe('passthroughProps', async () => { - /* eslint-disable mocha/no-synchronous-tests */ +describe('passthroughProps', () => { it('should passthrough standard dom attributes', () => { const props = { id: 'myId', title: 'My title' } - expect(Object.keys(passthroughProps(props)).length).to.equal(2) + expect(Object.keys(passthroughProps(props)).length).toEqual(2) }) it('should passthrough data attributes', () => { const props = { 'data-test': true } - expect(Object.keys(passthroughProps(props)).length).to.equal(1) + expect(Object.keys(passthroughProps(props)).length).toEqual(1) }) it('should passthrough valid react props', () => { @@ -47,7 +46,7 @@ describe('passthroughProps', async () => { ref: () => {}, innerHTML: 'hello world' } - expect(Object.keys(passthroughProps(props)).length).to.equal(2) + expect(Object.keys(passthroughProps(props)).length).toEqual(2) }) it('should passthrough props prefixed with "on"', () => { @@ -56,14 +55,14 @@ describe('passthroughProps', async () => { onCustomCallback: () => {}, onChange: () => {} } - expect(Object.keys(passthroughProps(props)).length).to.equal(3) + expect(Object.keys(passthroughProps(props)).length).toEqual(3) }) it('should omit invalid props', () => { const props = { myCustomProp: 'hello' } - expect(Object.keys(passthroughProps(props)).length).to.equal(0) + expect(Object.keys(passthroughProps(props)).length).toEqual(0) }) it('should omit certain react props', () => { @@ -73,7 +72,7 @@ describe('passthroughProps', async () => { children: 'hello world', theme: { themeVar: 'myColor' } } - expect(Object.keys(passthroughProps(props)).length).to.equal(0) + expect(Object.keys(passthroughProps(props)).length).toEqual(0) }) it('should passthrough and omit correct props', () => { @@ -90,7 +89,7 @@ describe('passthroughProps', async () => { onChange: null } - expect(passthroughProps(props)).to.deep.equal({ + expect(passthroughProps(props)).toEqual({ id: 'myId', title: 'My title', 'data-test': true, @@ -98,5 +97,4 @@ describe('passthroughProps', async () => { onChange: null }) }) - /* eslint-enable mocha/no-synchronous-tests */ }) diff --git a/packages/ui-react-utils/src/__tests__/pickProps.test.ts b/packages/ui-react-utils/src/__new-tests__/pickProps.test.tsx similarity index 91% rename from packages/ui-react-utils/src/__tests__/pickProps.test.ts rename to packages/ui-react-utils/src/__new-tests__/pickProps.test.tsx index 21c26f5dbd..b44981b26c 100644 --- a/packages/ui-react-utils/src/__tests__/pickProps.test.ts +++ b/packages/ui-react-utils/src/__new-tests__/pickProps.test.tsx @@ -23,12 +23,11 @@ */ import PropTypes from 'prop-types' -import { expect } from '@instructure/ui-test-utils' +import '@testing-library/jest-dom' import { pickProps } from '../pickProps' describe('pickProps', () => { it('should work with propTypes', () => { - //arrange const propTypes = { prop1: PropTypes.string.isRequired, prop2: PropTypes.number @@ -44,11 +43,10 @@ describe('pickProps', () => { prop1: 'hello', prop2: 42 } - //act + const actualResult = pickProps(inputProps, propTypes) - //assert - expect(actualResult).to.be.eql(expectedResult) + expect(actualResult).toEqual(expectedResult) }) it('should add the `include` keys to the result with PropTypes', () => { @@ -70,7 +68,7 @@ describe('pickProps', () => { const actualResult = pickProps(inputProps, propTypes, ['excessiveProp2']) - expect(actualResult).to.be.eql(expectedResult) + expect(actualResult).toEqual(expectedResult) }) it('should work with an input of a list allowed prop names', () => { @@ -87,7 +85,7 @@ describe('pickProps', () => { const actualResult = pickProps(inputProps, allowedPropKeys) - expect(actualResult).to.be.eql(expectedResult) + expect(actualResult).toEqual(expectedResult) }) it('should add the `include` keys to the result with a list allowed prop names', () => { @@ -108,6 +106,6 @@ describe('pickProps', () => { 'excessiveProp2' ]) - expect(actualResult).to.be.eql(expectedResult) + expect(actualResult).toEqual(expectedResult) }) }) diff --git a/packages/ui-react-utils/src/__tests__/safeCloneElement.test.tsx b/packages/ui-react-utils/src/__new-tests__/safeCloneElement.test.tsx similarity index 66% rename from packages/ui-react-utils/src/__tests__/safeCloneElement.test.tsx rename to packages/ui-react-utils/src/__new-tests__/safeCloneElement.test.tsx index eeb7bc3d9e..3d7518108c 100644 --- a/packages/ui-react-utils/src/__tests__/safeCloneElement.test.tsx +++ b/packages/ui-react-utils/src/__new-tests__/safeCloneElement.test.tsx @@ -25,11 +25,12 @@ import React, { ReactElement, ReactNode } from 'react' import { createChainedFunction } from '@instructure/ui-utils' -import { expect, mount, stub, spy, within } from '@instructure/ui-test-utils' +import { render, screen } from '@testing-library/react' +import '@testing-library/jest-dom' import { safeCloneElement } from '../safeCloneElement' -describe('safeCloneElement', async () => { +describe('safeCloneElement', () => { const SafeClone = function

({ element, props, @@ -42,53 +43,53 @@ describe('safeCloneElement', async () => { return safeCloneElement(element, props, children) } - it('should preserve refs', async () => { - const origRef = stub() - const cloneRef = stub() + it('should preserve refs', () => { + const origRef = jest.fn() + const cloneRef = jest.fn() - await mount( + render( } props={{ ref: cloneRef }} /> ) - expect(origRef).to.have.been.called() - expect(cloneRef).to.have.been.called() + expect(origRef).toHaveBeenCalled() + expect(cloneRef).toHaveBeenCalled() }) - it('should preserve event handlers', async () => { - const onClickA = spy() - const onClickB = spy() + it('should preserve event handlers', () => { + const onClickA = jest.fn() + const onClickB = jest.fn() - const subject = await mount( + render( } props={{ onClick: onClickB }} /> ) - const button = within(subject.getDOMNode()) - await button.click() + const button = screen.getByRole('button') + button.click() - expect(onClickA).to.have.been.called() - expect(onClickB).to.have.been.called() + expect(onClickA).toHaveBeenCalled() + expect(onClickB).toHaveBeenCalled() }) - it('should preserve already chained functions', async () => { - const onClickA = spy() - const onClickB = spy() - const onClickC = spy() + it('should preserve already chained functions', () => { + const onClickA = jest.fn() + const onClickB = jest.fn() + const onClickC = jest.fn() - const subject = await mount( + render( } props={{ onClick: createChainedFunction(onClickB, onClickC) }} /> ) - const button = within(subject.getDOMNode()) - await button.click() + const button = screen.getByRole('button') + button.click() - expect(onClickA).to.have.been.called() - expect(onClickB).to.have.been.called() - expect(onClickC).to.have.been.called() + expect(onClickA).toHaveBeenCalled() + expect(onClickB).toHaveBeenCalled() + expect(onClickC).toHaveBeenCalled() }) }) diff --git a/packages/ui-react-utils/tsconfig.build.json b/packages/ui-react-utils/tsconfig.build.json index 5e7089554a..adb2431594 100644 --- a/packages/ui-react-utils/tsconfig.build.json +++ b/packages/ui-react-utils/tsconfig.build.json @@ -10,9 +10,6 @@ { "path": "../ui-babel-preset/tsconfig.build.json" }, - { - "path": "../ui-test-utils/tsconfig.build.json" - }, { "path": "../console/tsconfig.build.json" },