diff --git a/package-lock.json b/package-lock.json
index b99728aaf6..89bb26c1ba 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -49791,7 +49791,8 @@
},
"devDependencies": {
"@instructure/ui-babel-preset": "8.46.1",
- "@instructure/ui-test-utils": "8.46.1"
+ "@instructure/ui-test-utils": "8.46.1",
+ "react-dom": "^18.2.0"
},
"peerDependencies": {
"react": ">=16.8 <=18"
@@ -51011,7 +51012,8 @@
"devDependencies": {
"@instructure/ui-babel-preset": "8.46.1",
"@instructure/ui-test-utils": "8.46.1",
- "@types/hoist-non-react-statics": "^3.3.3"
+ "@types/hoist-non-react-statics": "^3.3.3",
+ "react-dom": "^18.2.0"
},
"peerDependencies": {
"react": ">=16.8 <=18"
diff --git a/packages/emotion/package.json b/packages/emotion/package.json
index 75e1eaad01..2b70e5a2bf 100644
--- a/packages/emotion/package.json
+++ b/packages/emotion/package.json
@@ -38,7 +38,8 @@
},
"devDependencies": {
"@instructure/ui-babel-preset": "8.46.1",
- "@instructure/ui-test-utils": "8.46.1"
+ "@instructure/ui-test-utils": "8.46.1",
+ "react-dom": "^18.2.0"
},
"peerDependencies": {
"react": ">=16.8 <=18"
diff --git a/packages/emotion/src/__tests__/withStyle.test.tsx b/packages/emotion/src/__tests__/withStyle.test.tsx
index f687bd2699..8c601bed99 100644
--- a/packages/emotion/src/__tests__/withStyle.test.tsx
+++ b/packages/emotion/src/__tests__/withStyle.test.tsx
@@ -24,6 +24,8 @@
/** @jsx jsx */
import React from 'react'
+import ReactDOM from 'react-dom'
+import ReactTestUtils from 'react-dom/test-utils'
import PropTypes from 'prop-types'
import { expect, match, mount, stub, within } from '@instructure/ui-test-utils'
@@ -136,6 +138,28 @@ describe('@withStyle', async () => {
}
}
+ class WrapperComponent extends React.Component {
+ render() {
+ return (
+
+
+
+ )
+ }
+ }
+
+ it('can be found and tested with ReactTestUtils', async () => {
+ const rootNode = document.createElement('div')
+ document.body.appendChild(rootNode)
+
+ // eslint-disable-next-line react/no-render-return-value
+ const rendered = ReactDOM.render(, rootNode)
+ ReactTestUtils.findRenderedComponentWithType(
+ rendered as any,
+ (ThemeableComponent as any).originalType
+ )
+ })
+
describe('with theme provided by InstUISettingsProvider', async () => {
it('should add css class suffixed with label', async () => {
const subject = await mount(
diff --git a/packages/emotion/src/withStyle.tsx b/packages/emotion/src/withStyle.tsx
index 71d626781a..4636dea963 100644
--- a/packages/emotion/src/withStyle.tsx
+++ b/packages/emotion/src/withStyle.tsx
@@ -173,6 +173,7 @@ const withStyle = decorator(
> & {
generateComponentTheme?: GenerateComponentTheme
allowedProps?: string[]
+ originalType?: WithStyleComponent
} = forwardRef((props, ref) => {
const theme = useTheme()
@@ -243,6 +244,10 @@ const withStyle = decorator(
hoistNonReactStatics(WithStyle, ComposedComponent)
+ // added so it can be tested with ReactTestUtils
+ // more info: https://github.com/facebook/react/issues/13455
+ WithStyle.originalType = ComposedComponent
+
// we have to pass these on, because sometimes users
// access propTypes of the component in other components
// eslint-disable-next-line react/forbid-foreign-prop-types
diff --git a/packages/ui-i18n/package.json b/packages/ui-i18n/package.json
index 4132778aa4..9d09dd16a0 100644
--- a/packages/ui-i18n/package.json
+++ b/packages/ui-i18n/package.json
@@ -25,7 +25,8 @@
"devDependencies": {
"@instructure/ui-babel-preset": "8.46.1",
"@instructure/ui-test-utils": "8.46.1",
- "@types/hoist-non-react-statics": "^3.3.3"
+ "@types/hoist-non-react-statics": "^3.3.3",
+ "react-dom": "^18.2.0"
},
"dependencies": {
"@babel/runtime": "^7.23.2",
diff --git a/packages/ui-i18n/src/__tests__/bidirectional.test.tsx b/packages/ui-i18n/src/__tests__/bidirectional.test.tsx
index 0c98e77e04..46a10c8bd7 100644
--- a/packages/ui-i18n/src/__tests__/bidirectional.test.tsx
+++ b/packages/ui-i18n/src/__tests__/bidirectional.test.tsx
@@ -23,6 +23,8 @@
*/
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 { bidirectional, BidirectionalProps } from '../bidirectional'
@@ -39,12 +41,34 @@ class BidirectionalComponent extends React.Component {
}
}
+class WrapperComponent extends React.Component {
+ render() {
+ return (
+
+
+
+ )
+ }
+}
+
describe('@bidirectional', async () => {
it('should take on the direction of the document by default', async () => {
const subject = await mount()
expect(subject.getDOMNode().getAttribute('data-dir')).to.equal('ltr')
})
+ it('can be found and tested with ReactTestUtils', async () => {
+ const rootNode = document.createElement('div')
+ document.body.appendChild(rootNode)
+
+ // eslint-disable-next-line react/no-render-return-value
+ const rendered = ReactDOM.render(, rootNode)
+ ReactTestUtils.findRenderedComponentWithType(
+ rendered as any,
+ (BidirectionalComponent as any).originalType
+ )
+ })
+
it('should set the text direction via props', async () => {
const subject = await mount()
expect(subject.getDOMNode().getAttribute('data-dir')).to.equal('rtl')
diff --git a/packages/ui-i18n/src/bidirectional.tsx b/packages/ui-i18n/src/bidirectional.tsx
index dabb55a30f..8a80766474 100644
--- a/packages/ui-i18n/src/bidirectional.tsx
+++ b/packages/ui-i18n/src/bidirectional.tsx
@@ -22,6 +22,11 @@
* SOFTWARE.
*/
import React, { ForwardedRef, forwardRef, PropsWithChildren } from 'react'
+import type {
+ ForwardRefExoticComponent,
+ PropsWithoutRef,
+ RefAttributes
+} from 'react'
import { decorator } from '@instructure/ui-decorator'
import { DIRECTION, TextDirectionContext } from './TextDirectionContext'
import hoistNonReactStatics from 'hoist-non-react-statics'
@@ -101,9 +106,13 @@ const bidirectional: BidirectionalType = decorator((ComposedComponent) => {
}
}
- const BidirectionalForwardingRef = forwardRef(
- (props, ref) =>
- )
+ const BidirectionalForwardingRef: ForwardRefExoticComponent<
+ PropsWithoutRef> & RefAttributes
+ > & {
+ originalType?: React.ComponentClass
+ } = forwardRef((props, ref) => (
+
+ ))
if (process.env.NODE_ENV !== 'production') {
const displayName = ComposedComponent.displayName || ComposedComponent.name
BidirectionalForwardingRef.displayName = `BidirectionalForwardingRef(${displayName})`
@@ -114,6 +123,11 @@ const bidirectional: BidirectionalType = decorator((ComposedComponent) => {
BidirectionalForwardingRef.propTypes = ComposedComponent.propTypes
// @ts-expect-error These static fields exist on InstUI components
BidirectionalForwardingRef.allowedProps = ComposedComponent.allowedProps
+
+ // added so it can be tested with ReactTestUtils
+ // more info: https://github.com/facebook/react/issues/13455
+ BidirectionalForwardingRef.originalType = ComposedComponent
+
return BidirectionalForwardingRef
}) as BidirectionalType
diff --git a/packages/ui-react-utils/src/DeterministicIdContext/withDeterministicId.tsx b/packages/ui-react-utils/src/DeterministicIdContext/withDeterministicId.tsx
index 07e45c01f9..fa7005032b 100644
--- a/packages/ui-react-utils/src/DeterministicIdContext/withDeterministicId.tsx
+++ b/packages/ui-react-utils/src/DeterministicIdContext/withDeterministicId.tsx
@@ -21,11 +21,11 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
-import React, {
- forwardRef,
+import React, { forwardRef, useContext } from 'react'
+import type {
+ ForwardRefExoticComponent,
PropsWithoutRef,
- RefAttributes,
- useContext
+ RefAttributes
} from 'react'
import hoistNonReactStatics from 'hoist-non-react-statics'
@@ -49,33 +49,33 @@ type WithDeterministicIdProps = {
*/
const withDeterministicId = decorator((ComposedComponent: InstUIComponent) => {
type Props = PropsWithoutRef> & RefAttributes
- const WithDeterministicId = forwardRef(
- (props: Props, ref: React.ForwardedRef) => {
- const componentName =
- ComposedComponent.componentId ||
- ComposedComponent.displayName ||
- ComposedComponent.name
- const instanceCounterMap = useContext(DeterministicIdContext)
- const deterministicId = (instanceName = componentName) =>
- generateId(instanceName, instanceCounterMap)
+ const WithDeterministicId: ForwardRefExoticComponent & {
+ originalType?: React.ComponentClass
+ } = forwardRef((props: Props, ref: React.ForwardedRef) => {
+ const componentName =
+ ComposedComponent.componentId ||
+ ComposedComponent.displayName ||
+ ComposedComponent.name
+ const instanceCounterMap = useContext(DeterministicIdContext)
+ const deterministicId = (instanceName = componentName) =>
+ generateId(instanceName, instanceCounterMap)
- if (props.deterministicId) {
- warn(
- false,
- `Manually passing the "deterministicId" property is not allowed on the ${componentName} component.\n`,
- props.deterministicId
- )
- }
-
- return (
-
+ if (props.deterministicId) {
+ warn(
+ false,
+ `Manually passing the "deterministicId" property is not allowed on the ${componentName} component.\n`,
+ props.deterministicId
)
}
- )
+
+ return (
+
+ )
+ })
hoistNonReactStatics(WithDeterministicId, ComposedComponent)
@@ -89,6 +89,10 @@ const withDeterministicId = decorator((ComposedComponent: InstUIComponent) => {
//@ts-expect-error fix this
WithDeterministicId.allowedProps = ComposedComponent.allowedProps
+ // added so it can be tested with ReactTestUtils
+ // more info: https://github.com/facebook/react/issues/13455
+ WithDeterministicId.originalType = ComposedComponent
+
if (process.env.NODE_ENV !== 'production') {
WithDeterministicId.displayName = `WithDeterministicId(${ComposedComponent.displayName})`
}
diff --git a/packages/ui-react-utils/src/__tests__/DeterministicIdContext.test.tsx b/packages/ui-react-utils/src/__tests__/DeterministicIdContext.test.tsx
index cfae13ba74..7195859946 100644
--- a/packages/ui-react-utils/src/__tests__/DeterministicIdContext.test.tsx
+++ b/packages/ui-react-utils/src/__tests__/DeterministicIdContext.test.tsx
@@ -23,6 +23,8 @@
*/
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 {
@@ -41,6 +43,16 @@ class TestComponent extends React.Component<
}
}
+class WrapperComponent extends React.Component {
+ render() {
+ return (
+
+
+
+ )
+ }
+}
+
const uniqueIds = (el: { getDOMNode: () => Element }) => {
const idList = Array.from(el.getDOMNode().children).map((el) => el.id)
@@ -48,6 +60,18 @@ const uniqueIds = (el: { getDOMNode: () => Element }) => {
}
describe('DeterministicIdContext', () => {
+ it('can be found and tested with ReactTestUtils', async () => {
+ const rootNode = document.createElement('div')
+ document.body.appendChild(rootNode)
+
+ // eslint-disable-next-line react/no-render-return-value
+ const rendered = ReactDOM.render(, rootNode)
+ ReactTestUtils.findRenderedComponentWithType(
+ rendered as any,
+ (TestComponent as any).originalType
+ )
+ })
+
it('should generate unique ids without Provider wrapper', async () => {
const el = await mount(