Skip to content
This repository has been archived by the owner on Mar 27, 2023. It is now read-only.

Commit

Permalink
fix(react): fix jsdom react testing issues
Browse files Browse the repository at this point in the history
Fixes vmware#5985
- Add isNode check to property syncing in cdscontrol.

Fixes vmware#6525:
- Remove isNode check for aria-reflect, now that all roles are set in connectedCallback

Signed-off-by: Ashley Ryan <[email protected]>
  • Loading branch information
Ashley Ryan authored and ashleyryan committed Feb 4, 2022
1 parent b506727 commit 52fb904
Show file tree
Hide file tree
Showing 9 changed files with 54 additions and 41 deletions.
34 changes: 20 additions & 14 deletions packages/core/docs/react.stories.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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(<CdsButton>My Button</CdsButton>);

// 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

Expand All @@ -130,3 +119,20 @@ window.IntersectionObserver = jest.fn().mockReturnValue({
<a href="https://github.com/vmware/clarity/tree/next/apps" target="_blank" rel="noopener">
<cds-button>Example Apps</cds-button>
</a>

### 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(<CdsButton>My Button</CdsButton>);

// might not work
expect(screen.getByRole('button', { name: 'My Button' })).toBeInTheDocument();

// will work
expect(await screen.findByRole('button', { name: 'My Button' })).toBeInTheDocument();
});
```
9 changes: 9 additions & 0 deletions packages/core/src/internal/utils/environment.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { isBrowser } from './environment';

describe('Environment Helper: ', () => {
describe('isBrowser():', () => {
it('returns true when expected', () => {
expect(isBrowser()).toBe(true);
});
});
});
9 changes: 9 additions & 0 deletions packages/core/src/internal/utils/environment.ts
Original file line number Diff line number Diff line change
@@ -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;
}
7 changes: 5 additions & 2 deletions packages/core/src/internal/utils/events.ts
Original file line number Diff line number Diff line change
@@ -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();
Expand All @@ -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 => {
Expand Down
10 changes: 2 additions & 8 deletions packages/core/src/internal/utils/exists.spec.ts
Original file line number Diff line number Diff line change
@@ -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(): ', () => {
Expand Down Expand Up @@ -91,10 +91,4 @@ describe('Functional Helper: ', () => {
expect(existsIn(['notDefined'], myTestObject)).toEqual(false);
});
});

describe('isBrowser():', () => {
it('returns true when expected', () => {
expect(isBrowser()).toBe(true);
});
});
});
7 changes: 1 addition & 6 deletions packages/core/src/internal/utils/exists.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -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);
}
4 changes: 2 additions & 2 deletions packages/core/src/internal/utils/global.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down
5 changes: 3 additions & 2 deletions packages/core/src/internal/utils/registration.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down
10 changes: 3 additions & 7 deletions packages/core/src/polyfills/aria-reflect.ts
Original file line number Diff line number Diff line change
@@ -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.
*/
Expand Down Expand Up @@ -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',
Expand Down

0 comments on commit 52fb904

Please sign in to comment.