Skip to content
Merged
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: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"lint-sass": "yarn stylelint \"**/*.scss\" --quiet-deprecation-warnings",
"test": "yarn lint && yarn test-unit",
"test-ci": "yarn test && yarn test-cypress",
"test-unit": "cross-env NODE_ENV=test jest --config ./scripts/jest/config.json",
"test-unit": "cross-env NODE_ENV=test jest --config ./scripts/jest/config.js",
"test-a11y": "node ./scripts/a11y-testing",
"test-staged": "yarn lint && node scripts/test-staged.js",
"test-cypress": "node ./scripts/cypress",
Expand Down Expand Up @@ -116,6 +116,7 @@
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.21.5",
"@babel/template": "^7.21.9",
"@cfaester/enzyme-adapter-react-18": "^0.7.0",
"@cypress/code-coverage": "^3.10.0",
"@cypress/react": "^7.0.3",
"@cypress/react18": "^2.0.0",
Expand All @@ -142,7 +143,8 @@
"@svgr/plugin-svgo": "^8.0.1",
"@testing-library/dom": "^8.12.0",
"@testing-library/jest-dom": "^5.16.3",
"@testing-library/react": "^12.1.5",
"@testing-library/react": "^14.0.0",
"@testing-library/react-16-17": "npm:@testing-library/react@^12.1.5",
"@testing-library/react-hooks": "^7.0.2",
"@testing-library/user-event": "^13.5.0",
"@types/classnames": "^2.2.10",
Expand Down
69 changes: 69 additions & 0 deletions scripts/jest/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
const getCacheDirectory =
require('jest-config/build/getCacheDirectory').default;

// Set REACT_VERSION env variable to latest if empty or invalid
if (!['16', '17', '18'].includes(process.env.REACT_VERSION)) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could replace this with the utility function but Jest 24 doesn't support TypeScript config files

process.env.REACT_VERSION = '18';
}

const reactVersion = process.env.REACT_VERSION;

console.log(`Running tests on React v${reactVersion}`);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like this but hopefully we can move it to the test script when available :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm kind of okay with it here, but yeah, having it in the individual test scripts would be helpful for thrown errors.

Copy link
Contributor

@cee-chen cee-chen Jul 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I may need to take a step back here to ask what our goal is with running our test suites across multiple versions of Kibana. 🤔 I thought we were doing it for Cypress as a very basic smoke test that rendering worked, especially for portals etc. which were most affected by the React 18 upgrade.

Running all our jest suites on multiple versions is going to fairly significantly impact our CI times. What are our plans to mitigate that, and what precisely are our goals for those tests?

edit: Just want to clarify the above is not a change request or a blocker, I just want to make sure we've thought this through!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We publish our library as compatible with React 16, 17 and (soon) 18. We should make sure it works and will continue to work with all changes we make no matter what EUI-compatible React version you're using.

The time to run all unit and e2e tests on multiple versions of react scales linearly, but that's okay. @1Copenut and I already discussed ways to parallelize it, so the total time to run tests should equal the longest single (unit or e2e) test run. Of course that may differ when the number of resources is limited due to, for example, building multiple PR environments at the same time. In this case we will prioritize builds on main.

Copy link
Contributor

@cee-chen cee-chen Jul 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Gotcha, thank you for explaining! Parallelization makes total sense. One other option could also be to run non-React18 tests (i.e., older versions that we "support" but aren't first-class citizens) on a daily/night cron job instead of per-PR. I'm not sure if that makes more sense than parallelization though - do you have a preference?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The nice thing here, we can do pretty much whichever we want. Thinking out loud a second, breaking these into parallel runs shouldn't be too difficult in Builldkite. Instead of running a consolidated test command, we can set up the job with steps and multiple commands that each pass a version flag. We can increase resources if we exhaust the agent, or if the time isn't to our liking, def. run the older version tests on a cron.


/** @type {import('jest').Config} */
const config = {
rootDir: '../../',
roots: [
'<rootDir>/src/',
'<rootDir>/src-docs/src/components',
'<rootDir>/scripts/babel',
'<rootDir>/scripts/tests',
'<rootDir>/scripts/eslint-plugin',
],
collectCoverageFrom: [
'src/{components,services,global_styling}/**/*.{ts,tsx,js,jsx}',
'!src/{components,services,global_styling}/**/*.{testenv,spec,a11y,stories}.{ts,tsx,js,jsx}',
'!src/{components,services,global_styling}/index.ts',
'!src/{components,services,global_styling}/**/*/index.ts',
'!src/components/date_picker/react-datepicker/**/*.{js,jsx}',
],
moduleNameMapper: {
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
'<rootDir>/scripts/jest/mocks/file_mock.js',
'\\.(css|less|scss)$': '<rootDir>/scripts/jest/mocks/style_mock.js',
},
setupFiles: [
'<rootDir>/scripts/jest/setup/enzyme.js',
'<rootDir>/scripts/jest/setup/throw_on_console_error.js',
'<rootDir>/scripts/jest/setup/mocks.js',
],
setupFilesAfterEnv: [
'<rootDir>/scripts/jest/setup/polyfills.js',
'<rootDir>/scripts/jest/setup/unmount_enzyme.js',
],
coverageDirectory: '<rootDir>/reports/jest-coverage',
coverageReporters: ['json', 'html'],
moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],
testMatch: ['**/*.test.js', '**/*.test.ts', '**/*.test.tsx'],
transform: {
'^.+\\.(js|tsx?)$': 'babel-jest',
},
snapshotSerializers: [
'<rootDir>/node_modules/enzyme-to-json/serializer',
'<rootDir>/scripts/jest/setup/emotion',
],
// react version and user permissions aware cache directory
cacheDirectory: `${getCacheDirectory()}_react-${reactVersion}`,
};

if (['16', '17'].includes(reactVersion)) {
config.moduleNameMapper[
'^@testing-library/react((\\\\/.*)?)$'
] = `@testing-library/react-16-17$1`;
config.moduleNameMapper['^react((\\/.*)?)$'] = `react-${reactVersion}$1`;
config.moduleNameMapper[
'^react-dom((\\/.*)?)$'
] = `react-dom-${reactVersion}$1`;
}

module.exports = config;
53 changes: 0 additions & 53 deletions scripts/jest/config.json

This file was deleted.

16 changes: 15 additions & 1 deletion scripts/jest/setup/enzyme.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,18 @@
import { configure } from 'enzyme';
import Adapter from '@wojtekmaj/enzyme-adapter-react-17';

// Pick Enzyme adapter based on which React version is currently being tested.
// It has to be directly compared against process.env.REACT_VERSION
// for tree-shaking to work.
let Adapter;
if (process.env.REACT_VERSION === '18') {
Adapter = require('@cfaester/enzyme-adapter-react-18').default;

// set IS_REACT_ACT_ENVIRONMENT to silence "The current testing environment
// is not configured to support act()" errors for now
// TODO: Remove when enzyme tests are replaced with RTL
global.IS_REACT_ACT_ENVIRONMENT = true;
} else {
Adapter = require('@wojtekmaj/enzyme-adapter-react-17');
}

configure({ adapter: new Adapter() });
5 changes: 5 additions & 0 deletions scripts/jest/setup/polyfills.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { MutationObserver, MutationNotifier } from '../polyfills/mutation_observer';
import util from 'util';

// polyfill window.MutationObserver and intersect jsdom's relevant methods
// from https://github.com/aurelia/pal-nodejs
// https://github.com/aurelia/pal-nodejs/blob/56396ff7c7693669dbafc8e9e49ee6bc29472f12/src/nodejs-pal-builder.ts#L63

Object.defineProperty(global, 'TextEncoder', {
value: util.TextEncoder,
});
Comment on lines +8 to +10
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tkajtoch Can you add a comment explaining why this polyfill had to be added?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I'll do that in the code!


const undos = [];
afterAll(() => {
while (undos.length) {
Expand Down
13 changes: 11 additions & 2 deletions src/components/drag_and_drop/droppable.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@

import React from 'react';
import { mount, ReactWrapper } from 'enzyme';
import { resetServerContext } from '@hello-pangea/dnd';

import { findTestSubject } from '../../test';
import { requiredProps } from '../../test/required_props';
import {
findTestSubject,
requiredProps,
invokeOnReactVersion,
} from '../../test';

import { EuiDragDropContext, EuiDroppable } from './';
import { EuiDroppableContext } from './droppable';
Expand All @@ -24,6 +28,11 @@ function snapshotDragDropContext(component: ReactWrapper) {
}

describe('EuiDroppable', () => {
afterEach(() => {
// Resetting DND server context is only required in older versions of React
invokeOnReactVersion(['16', '17'], resetServerContext);
});

test('is rendered', () => {
const handler = jest.fn();
jest.mock('react', () => {
Expand Down
4 changes: 2 additions & 2 deletions src/components/form/form.styles.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ describe('euiCustomControl', () => {
expect(result.current).toMatchInlineSnapshot(`
"
padding: 7px;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it comes from different whitespace serializing in the latest @testing-library/react?

border: 1px solid #f5f7fc;
background: #FFF no-repeat center;

Expand All @@ -200,7 +200,7 @@ describe('euiCustomControl', () => {
expect(result.current).toMatchInlineSnapshot(`
"
padding: 15px;

border: 1px solid #f5f7fc;
background: #FFF no-repeat center;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import React from 'react';
import { fireEvent } from '@testing-library/dom';
import { fireEvent } from '@testing-library/react';
import { render } from '../../../test/rtl';
import { requiredProps } from '../../../test/required_props';

Expand Down
1 change: 1 addition & 0 deletions src/test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ export {
} from './react_warnings';
export { sleep } from './sleep';
export * from './emotion-prefix';
export * from './react_version';
Copy link
Contributor

@cee-chen cee-chen Jul 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have some slight concerns here. Why do we want to make these utilities publicly available to consumers?

And if we don't, can we please move this to src/test/internal/ instead?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This definitely shouldn't be publicly available and won't even work when used outside test environment. I honestly thought none of src/test things are included in the build, but I just noticed that's not the case. I'll move it to src/test/internal in a new PR!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect, thanks Tomasz!

38 changes: 38 additions & 0 deletions src/test/react_version.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

export type ReactVersion = '16' | '17' | '18';

/**
* Get major version of React that's currently used.
*
*/
export const getReactVersion = (): ReactVersion => {
const reactVersion = process.env.REACT_VERSION;
if (reactVersion !== undefined && ['16', '17', '18'].includes(reactVersion)) {
return reactVersion as ReactVersion;
}

return '18';
};

/**
* Invoke passed function when running on specified version(s) of React
*/
export const invokeOnReactVersion = (
versionOrVersions: ReactVersion | ReactVersion[],
func: Function
) => {
if (!Array.isArray(versionOrVersions)) {
versionOrVersions = [versionOrVersions];
}

if (versionOrVersions.includes(getReactVersion())) {
func();
}
};
Loading