Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,13 @@ jobs:
- name: Run linter
run: yarn lint

- name: Run unit tests
- name: Run unit tests (react 16)
run: yarn test-unit

- name: Run unit tests (react 18)
run: yarn test-unit-react18


build:
name: Build on ubuntu-latest
runs-on: ubuntu-latest
Expand Down
13 changes: 9 additions & 4 deletions scripts/jest/polyfills/mutation_observer.js
Original file line number Diff line number Diff line change
Expand Up @@ -292,10 +292,15 @@ var MutationObserver = /** @class */ (function () {
var mutations = observer.takeRecords();
if (mutations.length) { // fire away
// `act` to support hooks-based callbacks
act(
// calling the listener with context is not spec but currently consistent with FF and WebKit
() => observer._listener(mutations, observer)
);
try {
act(
// calling the listener with context is not spec but currently consistent with FF and WebKit
() => observer._listener(mutations, observer)
);
} catch (error) {
// Fallback for React 18 compatibility issues - call listener directly
observer._listener(mutations, observer);
}
}
};
MutationObserver.prototype.searchSubtree = function (mutations, $target, $oldstate, config) {
Expand Down
10 changes: 8 additions & 2 deletions scripts/jest/setup/throw_on_console_error_react18.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,16 @@ const originalConsoleError = console.error;

// Override console.error to ignore specific React 18 warnings
console.error = (message) => {
// Ignore the findDOMNode deprecation warning from React 18
// Ignore specific React 18 deprecation warnings
if (
typeof message === 'string' &&
message.includes('findDOMNode is deprecated')
(message.includes('findDOMNode is deprecated') ||
message.includes(
'Support for defaultProps will be removed from function components'
) ||
message.includes(
'Support for defaultProps will be removed from memo components'
))
) {
// Just log the warning without throwing
originalConsoleError('Warning suppressed for React 18 tests:', message);
Expand Down
33 changes: 33 additions & 0 deletions src-docs/src/views/split_button/split_button_example.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ const splitButtonBasicSnippet = `<OuiSplitButton
>Basic Split Button</OuiSplitButton>
`;

import SplitButtonSimple from './split_button_simple';
const splitButtonSimpleSource = require('!!raw-loader!./split_button_simple');
const splitButtonSimpleHtml = renderToHtml(SplitButtonSimple);
const splitButtonSimpleSnippet = `<OuiSplitButton
options={[]} initiallyOpen
onClick={() => console.log("Primary clicked")}
>Simple Split Button</OuiSplitButton>
`;

import SplitButtonComplex from './split_button_complex';
const splitButtonComplexSource = require('!!raw-loader!./split_button_complex');
const splitButtonComplexHtml = renderToHtml(SplitButtonComplex);
Expand Down Expand Up @@ -180,6 +189,30 @@ export const SplitButtonExample = {
snippet: splitButtonBasicSnippet,
demo: <SplitButtonBasic />,
},
{
source: [
{
type: GuideSectionTypes.JS,
code: splitButtonSimpleSource,
},
{
type: GuideSectionTypes.HTML,
code: splitButtonSimpleHtml,
},
],
text: (
<div>
<p>
When no options are provided, SplitButton displays a simple Button
in it&apos;s place, even if other dropdown options are present (like
<OuiCode>intiallyOpen</OuiCode>)
</p>
</div>
),
props: { OuiSplitButton },
snippet: splitButtonSimpleSnippet,
demo: <SplitButtonSimple />,
},
{
title: 'More complex',
source: [
Expand Down
18 changes: 18 additions & 0 deletions src-docs/src/views/split_button/split_button_simple.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* copyright opensearch contributors
* spdx-license-identifier: apache-2.0
*/

import React from 'react';

import { OuiSplitButton } from '../../../../src/components';

export default () => {
const primaryClick = () => console.log('Primary clicked');

return (
<OuiSplitButton options={[]} initiallyOpen onClick={primaryClick}>
Basic Split Button
</OuiSplitButton>
);
};
4 changes: 3 additions & 1 deletion src-docs/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,9 @@ const webpackConfig = {
// /app/ represents the entire docker environment
watchFiles: isPuppeteer
? {
ignored: '**/*',
options: {
ignored: '**/*',
},
}
: undefined,
client: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`OuiKeyboardAccessible adds accessibility attributes tabindex and role 1`] = `
<div
role="button"
tabindex="0"
/>
<div>
<div
role="button"
tabindex="0"
/>
</div>
`;

exports[`OuiKeyboardAccessible doesn't override pre-existing accessibility attributes role 1`] = `
<div
role="button"
tabindex="0"
/>
<div>
<div
role="button"
tabindex="0"
/>
</div>
`;

exports[`OuiKeyboardAccessible doesn't override pre-existing accessibility attributes tabindex 1`] = `
<div
role="button"
tabindex="1"
/>
<div>
<div
role="button"
tabindex="1"
/>
</div>
`;
56 changes: 34 additions & 22 deletions src/components/accessibility/keyboard_accessible.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

/* eslint-disable jsx-a11y/tabindex-no-positive */
import React from 'react';
import { render, shallow } from 'enzyme';
import { render, fireEvent } from '@testing-library/react';

import { OuiKeyboardAccessible } from './keyboard_accessible';

Expand Down Expand Up @@ -62,7 +62,9 @@ describe('OuiKeyboardAccessible', () => {
const component = <OuiKeyboardAccessible />; // eslint-disable-line @typescript-eslint/no-unused-vars

expect(consoleStub).toBeCalled();
expect(consoleStub.mock.calls[0][0]).toMatch(
// React 18 formats PropTypes errors differently than React 16
const errorMessage = consoleStub.mock.calls[0].join(' ');
expect(errorMessage).toMatch(
'needs to wrap an element with which the user interacts.'
);
});
Expand All @@ -76,9 +78,9 @@ describe('OuiKeyboardAccessible', () => {
);

expect(consoleStub).toBeCalled();
expect(consoleStub.mock.calls[0][0]).toMatch(
"doesn't need to be used on a button."
);
// React 18 formats PropTypes errors differently than React 16
const errorMessage = consoleStub.mock.calls[0].join(' ');
expect(errorMessage).toMatch("doesn't need to be used on a button.");
});

test('when the child is a link with an href', () => {
Expand All @@ -92,7 +94,9 @@ describe('OuiKeyboardAccessible', () => {
);

expect(consoleStub).toBeCalled();
expect(consoleStub.mock.calls[0][0]).toMatch(
// React 18 formats PropTypes errors differently than React 16
const errorMessage = consoleStub.mock.calls[0].join(' ');
expect(errorMessage).toMatch(
"doesn't need to be used on a link if it has a href attribute."
);
});
Expand All @@ -106,7 +110,9 @@ describe('OuiKeyboardAccessible', () => {
);

expect(consoleStub).toBeCalled();
expect(consoleStub.mock.calls[0][0]).toMatch(
// React 18 formats PropTypes errors differently than React 16
const errorMessage = consoleStub.mock.calls[0].join(' ');
expect(errorMessage).toMatch(
'needs to wrap an element which has an onClick prop assigned.'
);
});
Expand All @@ -123,7 +129,9 @@ describe('OuiKeyboardAccessible', () => {
);

expect(consoleStub).toBeCalled();
expect(consoleStub.mock.calls[0][0]).toMatch(
// React 18 formats PropTypes errors differently than React 16
const errorMessage = consoleStub.mock.calls[0].join(' ');
expect(errorMessage).toMatch(
"child's onClick prop needs to be a function."
);
});
Expand Down Expand Up @@ -156,49 +164,50 @@ describe('OuiKeyboardAccessible', () => {

describe('adds accessibility attributes', () => {
test('tabindex and role', () => {
const $button = render(
const { container } = render(
<OuiKeyboardAccessible>
<div onClick={noop} />
</OuiKeyboardAccessible>
);

expect($button).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
});

describe("doesn't override pre-existing accessibility attributes", () => {
test('tabindex', () => {
const $button = render(
const { container } = render(
<OuiKeyboardAccessible>
<div onClick={noop} tabIndex={1} />
</OuiKeyboardAccessible>
);

expect($button).toMatchSnapshot();
expect(container).toMatchSnapshot();
});

test('role', () => {
const $button = render(
const { container } = render(
<OuiKeyboardAccessible>
<div onClick={noop} role="button" tabIndex={0} />
</OuiKeyboardAccessible>
);

expect($button).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
});

describe('calls onClick', () => {
test('on ENTER keyup', () => {
const onClickHandler = jest.fn();

const $button = shallow(
const { container } = render(
<OuiKeyboardAccessible>
<div data-div onClick={onClickHandler} />
</OuiKeyboardAccessible>
);

$button.find('[data-div]').simulate('keyup', {
const divElement = container.querySelector('[data-div]') as HTMLElement;
fireEvent.keyUp(divElement, {
key: keys.ENTER,
});

Expand All @@ -208,13 +217,14 @@ describe('OuiKeyboardAccessible', () => {
test('on SPACE keyup', () => {
const onClickHandler = jest.fn();

const $button = shallow(
const { container } = render(
<OuiKeyboardAccessible>
<div data-div onClick={onClickHandler} />
</OuiKeyboardAccessible>
);

$button.find('[data-div]').simulate('keyup', {
const divElement = container.querySelector('[data-div]') as HTMLElement;
fireEvent.keyUp(divElement, {
key: keys.SPACE,
});

Expand All @@ -226,13 +236,14 @@ describe('OuiKeyboardAccessible', () => {
test('onKeyUp handler is called', () => {
const onKeyUpHandler = jest.fn();

const $button = shallow(
const { container } = render(
<OuiKeyboardAccessible>
<div data-div onKeyUp={onKeyUpHandler} />
</OuiKeyboardAccessible>
);

$button.find('[data-div]').simulate('keyup', {
const divElement = container.querySelector('[data-div]') as HTMLElement;
fireEvent.keyUp(divElement, {
keyCode: 0,
});

Expand All @@ -242,13 +253,14 @@ describe('OuiKeyboardAccessible', () => {
test('onKeyDown handler is called', () => {
const onKeyDownHandler = jest.fn();

const $button = shallow(
const { container } = render(
<OuiKeyboardAccessible>
<div data-div onKeyDown={onKeyDownHandler} />
</OuiKeyboardAccessible>
);

$button.find('[data-div]').simulate('keydown', {
const divElement = container.querySelector('[data-div]') as HTMLElement;
fireEvent.keyDown(divElement, {
keyCode: 0,
});

Expand Down
Loading
Loading