diff --git a/packages/core/docs/react.stories.mdx b/packages/core/docs/react.stories.mdx index ddb30d9689..9e1ac7f26e 100644 --- a/packages/core/docs/react.stories.mdx +++ b/packages/core/docs/react.stories.mdx @@ -98,20 +98,9 @@ const Component = () => { ## Testing React Testing Library is [recommended by the React team](https://reactjs.org/docs/testing.html) -for unit testing React components. Because of the way web components are rendered, the synchronous -`get` methods of RTL might not work, use the asynchronous `find` ones instead. - -```javascript -test('my test', async () => { - render(My Button); - - // might not work - expect(screen.getByRole('button', { name: 'My Button' })).toBeInTheDocument(); - - // will work - expect(await screen.findByRole('button', { name: 'My Button' })).toBeInTheDocument(); -}); -``` +for unit testing React components. By default, RTL runs in jest using jsdom, a node-based implementation +of browser standards. It does not have implementations of all the latest browser features, +so there may issues rendering and interacting with Clarity components. ### IntersectionObserver @@ -130,3 +119,20 @@ window.IntersectionObserver = jest.fn().mockReturnValue({ Example Apps + +### Finding a Clarity element + +Because of the way web components are rendered, the synchronous +`get` methods of RTL might not work, use the asynchronous `find` ones instead. + +```javascript +test('my test', async () => { + render(My Button); + + // might not work + expect(screen.getByRole('button', { name: 'My Button' })).toBeInTheDocument(); + + // will work + expect(await screen.findByRole('button', { name: 'My Button' })).toBeInTheDocument(); +}); +``` diff --git a/packages/core/src/internal/utils/environment.spec.ts b/packages/core/src/internal/utils/environment.spec.ts new file mode 100644 index 0000000000..3db27a41e1 --- /dev/null +++ b/packages/core/src/internal/utils/environment.spec.ts @@ -0,0 +1,9 @@ +import { isBrowser } from './environment'; + +describe('Environment Helper: ', () => { + describe('isBrowser():', () => { + it('returns true when expected', () => { + expect(isBrowser()).toBe(true); + }); + }); +}); diff --git a/packages/core/src/internal/utils/environment.ts b/packages/core/src/internal/utils/environment.ts new file mode 100644 index 0000000000..9410a8e386 --- /dev/null +++ b/packages/core/src/internal/utils/environment.ts @@ -0,0 +1,9 @@ +import { isNil } from '../utils/identity.js'; + +export function isBrowser(win = window) { + return !isNil(win); +} + +export function isJestTest() { + return (globalThis as any)?.process?.env?.JEST_WORKER_ID !== undefined; +} diff --git a/packages/core/src/internal/utils/events.ts b/packages/core/src/internal/utils/events.ts index 6b24289e7d..4cb7046222 100644 --- a/packages/core/src/internal/utils/events.ts +++ b/packages/core/src/internal/utils/events.ts @@ -1,9 +1,11 @@ /* - * Copyright (c) 2016-2021 VMware, Inc. All Rights Reserved. + * Copyright (c) 2016-2022 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ +import { isJestTest } from './environment.js'; + export function stopEvent(event: Event) { event.preventDefault(); event.stopPropagation(); @@ -29,7 +31,8 @@ export const getElementUpdates = ( const updatedProp = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(element), propertyKey) as any; - if (updatedProp) { + // Jest and JSDom breaks defining a new property, so skip + if (updatedProp && !isJestTest()) { Object.defineProperty(element, propertyKey, { get: updatedProp.get, set: val => { diff --git a/packages/core/src/internal/utils/exists.spec.ts b/packages/core/src/internal/utils/exists.spec.ts index 7df24ab5fd..19145ca173 100644 --- a/packages/core/src/internal/utils/exists.spec.ts +++ b/packages/core/src/internal/utils/exists.spec.ts @@ -1,10 +1,10 @@ /* - * Copyright (c) 2016-2020 VMware, Inc. All Rights Reserved. + * Copyright (c) 2016-2022 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ -import { existsIn, existsInWindow, isBrowser } from './exists.js'; +import { existsIn, existsInWindow } from './exists.js'; describe('Functional Helper: ', () => { describe('existsInWindow(): ', () => { @@ -91,10 +91,4 @@ describe('Functional Helper: ', () => { expect(existsIn(['notDefined'], myTestObject)).toEqual(false); }); }); - - describe('isBrowser():', () => { - it('returns true when expected', () => { - expect(isBrowser()).toBe(true); - }); - }); }); diff --git a/packages/core/src/internal/utils/exists.ts b/packages/core/src/internal/utils/exists.ts index aa104d40a8..b1523588c1 100644 --- a/packages/core/src/internal/utils/exists.ts +++ b/packages/core/src/internal/utils/exists.ts @@ -1,11 +1,10 @@ /* - * Copyright (c) 2016-2021 VMware, Inc. All Rights Reserved. + * Copyright (c) 2016-2022 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ import curryN from 'ramda/es/curryN.js'; -import isNil from 'ramda/es/isNil.js'; import path from 'ramda/es/path.js'; import __ from './__.js'; @@ -26,7 +25,3 @@ export function elementExists(tagName: string, registry?: any): boolean { } export const existsInWindow = existsIn(__, window); - -export function isBrowser(win = window) { - return !isNil(win); -} diff --git a/packages/core/src/internal/utils/global.ts b/packages/core/src/internal/utils/global.ts index ec9d25abc8..380fe6fb30 100644 --- a/packages/core/src/internal/utils/global.ts +++ b/packages/core/src/internal/utils/global.ts @@ -1,10 +1,10 @@ /* - * Copyright (c) 2016-2021 VMware, Inc. All Rights Reserved. + * Copyright (c) 2016-2022 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ -import { isBrowser } from './exists.js'; +import { isBrowser } from './environment.js'; import { getAngularVersion, getReactVersion, getVueVersion, getAngularJSVersion } from './framework.js'; import { FeatureSupportMatrix, browserFeatures } from './supports.js'; import { LogService } from '../services/log.service.js'; diff --git a/packages/core/src/internal/utils/registration.ts b/packages/core/src/internal/utils/registration.ts index 4962ccbaa4..a0bedffb24 100644 --- a/packages/core/src/internal/utils/registration.ts +++ b/packages/core/src/internal/utils/registration.ts @@ -1,11 +1,12 @@ /* - * Copyright (c) 2016-2021 VMware, Inc. All Rights Reserved. + * Copyright (c) 2016-2022 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ import curryN from 'ramda/es/curryN.js'; -import { elementExists, existsInWindow, isBrowser } from './exists.js'; +import { isBrowser } from './environment.js'; +import { elementExists, existsInWindow } from './exists.js'; import { CDSState, setupCDSGlobal } from './global.js'; import { isStorybook } from './framework.js'; import { LogService } from '../services/log.service.js'; diff --git a/packages/core/src/polyfills/aria-reflect.ts b/packages/core/src/polyfills/aria-reflect.ts index 0bce43d341..e2a3aea9de 100644 --- a/packages/core/src/polyfills/aria-reflect.ts +++ b/packages/core/src/polyfills/aria-reflect.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2021 VMware, Inc. All Rights Reserved. + * Copyright (c) 2016-2022 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ @@ -59,19 +59,15 @@ declare global { let roleRegistered = false; let ariaRegistered = false; -function isNode() { - return (globalThis as any)?.process?.env?.JEST_WORKER_ID !== undefined; // Jest and JSDom breaks on property reflection -} - // eslint-disable-next-line -if (!roleRegistered && !Element.prototype.hasOwnProperty('role') && !isNode()) { +if (!roleRegistered && !Element.prototype.hasOwnProperty('role')) { reflect(Element.prototype, 'role', 'role'); roleRegistered = true; } // https://www.w3.org/TR/wai-aria-1.0/states_and_properties // eslint-disable-next-line -if (!ariaRegistered && !Element.prototype.hasOwnProperty('ariaLabel') && !isNode()) { +if (!ariaRegistered && !Element.prototype.hasOwnProperty('ariaLabel')) { ariaRegistered = true; [ 'ActiveDescendant',