diff --git a/packages/react-ui-smoke-test/cra-template-react-ui/template/src/index.tsx b/packages/react-ui-smoke-test/cra-template-react-ui/template/src/index.tsx index 6090560dec0..5d90d531ec6 100644 --- a/packages/react-ui-smoke-test/cra-template-react-ui/template/src/index.tsx +++ b/packages/react-ui-smoke-test/cra-template-react-ui/template/src/index.tsx @@ -1,13 +1,30 @@ -import React from 'react'; -import { createRoot } from 'react-dom/client'; +import React, {StrictMode} from 'react'; +import { render } from 'react-dom'; import { App } from './App'; import * as serviceWorker from './serviceWorker'; const container = document.getElementById('root'); + +let strictMode = false; +if (process.env.STRICT_MODE === "true") { + strictMode = true; +} + +function StrictModeWrapper(props: {children: React.ReactElement}) { + return strictMode + ? + {props.children} + + : props.children +} + if (container) { - const root = createRoot(container); - root.render(); + render( + + + , + container); } // If you want your app to work offline and load faster, you can change diff --git a/packages/react-ui-smoke-test/smoke.test.ts b/packages/react-ui-smoke-test/smoke.test.ts index fe053382f23..e89bad5e9b3 100644 --- a/packages/react-ui-smoke-test/smoke.test.ts +++ b/packages/react-ui-smoke-test/smoke.test.ts @@ -51,14 +51,14 @@ describe('React-ui smoke test', () => { serveProcess = serveApplication(appDirectory); await openPageOnBrowser(screenshotPath); - expect(console.error).not.toBeCalled(); + expect(console.error).not.toHaveBeenCalled(); }, TIMEOUT, ); it('Render all controls and validations on server side (SSR)', async () => { execSync(`yarn install && yarn server`, { stdio: 'inherit', cwd: path.join(__dirname, 'react-ui-ssr') }); - expect(console.error).not.toBeCalled(); + expect(console.error).not.toHaveBeenCalled(); }); }); diff --git a/packages/react-ui-testing/TestPages/src/ReactTestApplication.jsx b/packages/react-ui-testing/TestPages/src/ReactTestApplication.jsx index 811458f685c..81bda75c3be 100644 --- a/packages/react-ui-testing/TestPages/src/ReactTestApplication.jsx +++ b/packages/react-ui-testing/TestPages/src/ReactTestApplication.jsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { StrictMode } from 'react'; import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; import Layout from './components/Layout'; @@ -30,6 +30,9 @@ let SidePageTestPage; if (process.env.hasSidePage) SidePageTestPage = require('./components/TestPages/SidePageTestPage').default; else SidePageTestPage = () =>
Does not work
; +let strictMode = false; +if (process.env.strictMode === "true") strictMode = true; + import './styles/reset.less'; import './styles/typography.less'; import AutocompleteTestPage from './components/TestPages/AutocompleteTestPage'; @@ -37,36 +40,46 @@ import ToastTestPage from './components/TestPages/ToastTestPage'; import ToggleTestPage from './components/TestPages/ToggleTestPage'; import SwitcherTestPage from './components/TestPages/SwitcherTestPage'; +function StrictModeWrapper(props) { + return strictMode + ? + {props.children} + + : props.children +} + // eslint-disable-next-line import/no-default-export export default function ReactTestApplication() { return ( - - - - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - - + + + + + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + + + + ); } diff --git a/packages/react-ui-testing/TestPages/versions.js b/packages/react-ui-testing/TestPages/versions.js index dc4ca0bb543..f59a367ffb4 100644 --- a/packages/react-ui-testing/TestPages/versions.js +++ b/packages/react-ui-testing/TestPages/versions.js @@ -1,13 +1,14 @@ const shell = require('shelljs'); const semver = require('semver'); const reactUiLocalVersionStub = '9.9.9'; +let reactVersion; const versionsInfo = [ { - react: '17.0.2', + react: reactVersion ?? '17.0.2', '@skbkontur/react-ui': [reactUiLocalVersionStub], dependencies: { - 'react-dom': '17.0.2', + 'react-dom': reactVersion ?? '17.0.2', }, }, ]; diff --git a/packages/react-ui-testing/TestPages/webpack.config.js b/packages/react-ui-testing/TestPages/webpack.config.js index 65ed71dd372..4d7884af083 100644 --- a/packages/react-ui-testing/TestPages/webpack.config.js +++ b/packages/react-ui-testing/TestPages/webpack.config.js @@ -83,6 +83,7 @@ function createConfig(reactVersion, reactUIVersion) { 'process.env.newCombobox': JSON.stringify(semver.satisfies(reactUIVersion, '>=0.7.0')), 'process.env.reactUIVersion': JSON.stringify(reactUIVersion), 'process.env.baseUrl': JSON.stringify(`/${reactVersion}/${reactUIVersion}`), + 'process.env.strictMode': process.env.STRICT_MODE, }), new HtmlWebpackPlugin({ filename: `${reactVersion}/${reactUIVersion}/index.html`, diff --git a/packages/react-ui-validations/.storybook/main.ts b/packages/react-ui-validations/.storybook/main.ts index 90184cd1cca..41ddcbda4f1 100644 --- a/packages/react-ui-validations/.storybook/main.ts +++ b/packages/react-ui-validations/.storybook/main.ts @@ -8,7 +8,7 @@ const config: StorybookConfig = { name: '@storybook/react-webpack5', options: { fastRefresh: !isTestEnv, - strictMode: true, + strictMode: process?.env?.STRICT_MODE === 'true', }, }, core: { diff --git a/packages/react-ui-validations/package.json b/packages/react-ui-validations/package.json index 913e9c25d4e..acf0fa8b4f2 100644 --- a/packages/react-ui-validations/package.json +++ b/packages/react-ui-validations/package.json @@ -75,10 +75,10 @@ "@skbkontur/storybook-addon-live-examples": "0.0.17", "@storybook/addon-a11y": "7.6.18", "@storybook/addon-controls": "7.6.18", + "@storybook/addon-docs": "7.6.18", "@storybook/addon-essentials": "7.6.18", "@storybook/addon-interactions": "^7.6.18", "@storybook/addon-links": "7.6.18", - "@storybook/addon-docs": "7.6.18", "@storybook/blocks": "7.6.18", "@storybook/react": "7.6.18", "@storybook/react-webpack5": "7.6.18", diff --git a/packages/react-ui-validations/tests/test-setup.js b/packages/react-ui-validations/tests/test-setup.js index 444960649cb..331823cc049 100644 --- a/packages/react-ui-validations/tests/test-setup.js +++ b/packages/react-ui-validations/tests/test-setup.js @@ -1,7 +1,7 @@ import { configure } from '@testing-library/react'; import '@testing-library/jest-dom'; -configure({ testIdAttribute: 'data-tid' }); +configure({ testIdAttribute: 'data-tid', reactStrictMode: process?.env?.STRICT_MODE === 'true' }); jest.mock('../src/smoothScrollIntoView', () => { const originalModule = jest.requireActual('../src/smoothScrollIntoView'); diff --git a/packages/react-ui/.storybook/config-stories.ts b/packages/react-ui/.storybook/config-stories.ts index 850492db17f..6890b67b499 100644 --- a/packages/react-ui/.storybook/config-stories.ts +++ b/packages/react-ui/.storybook/config-stories.ts @@ -19,9 +19,8 @@ const config: StorybookConfig = { framework: { name: '@storybook/react-webpack5', options: { - legacyRootApi: true, fastRefresh: true, - strictMode: true, + strictMode: process?.env?.STRICT_MODE === 'true', }, }, core: { diff --git a/packages/react-ui/.storybook/preview.tsx b/packages/react-ui/.storybook/preview.tsx index 81cff15c677..80aaa47957f 100644 --- a/packages/react-ui/.storybook/preview.tsx +++ b/packages/react-ui/.storybook/preview.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { StrictMode } from 'react'; import { MINIMAL_VIEWPORTS } from '@storybook/addon-viewport'; import { Preview } from '@storybook/react'; import { addons } from '@storybook/manager-api'; diff --git a/packages/react-ui/internal/PerformanceMetrics/PerformanceMetrics.tsx b/packages/react-ui/internal/PerformanceMetrics/PerformanceMetrics.tsx deleted file mode 100644 index d210aef5bd1..00000000000 --- a/packages/react-ui/internal/PerformanceMetrics/PerformanceMetrics.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import React from 'react'; -import { createRoot } from 'react-dom/client'; - -import { Button } from '../../components/Button'; -import { Nullable } from '../../typings/utility-types'; -import { Spinner } from '../../components/Spinner'; - -const PANEL_WRAPPER_STYLES = { width: '45%', display: 'inline-block', verticalAlign: 'top' }; - -interface PerformanceMetricsProps { - componentsA: React.ReactElement; - componentsB: React.ReactElement; -} - -export function PerformanceMetrics(props: PerformanceMetricsProps) { - return ( -
-
- -
-
-
- -
-
- -
-
-
- ); -} - -interface PerformanceMetricsPanelProps { - title: string; - component: React.ReactElement; -} -interface PerformanceMetricsPanelState { - mounted: boolean; -} - -class PerformanceMetricsPanel extends React.Component { - public state: PerformanceMetricsPanelState = { - mounted: false, - }; - private container: Nullable; - - public render() { - return ( -
-

{this.props.title}

-
- -
-
-
- ); - } - - public componentDidMount() { - if (this.state.mounted && this.container) { - const root = createRoot(this.container); - root.render(this.props.component); - } - } - - public componentDidUpdate(): void { - if (!this.container) { - return; - } - if (this.state.mounted) { - const root = createRoot(this.container); - root.render(this.props.component); - } else { - const root = createRoot(this.container); - root.unmount(); - } - } - - private setContainerRef = (element: Nullable) => { - this.container = element; - }; - - private toggleMountedState = () => { - this.setState({ - mounted: !this.state.mounted, - }); - }; -} diff --git a/packages/react-ui/internal/PerformanceMetrics/__stories__/PerformanceMetrics.stories.tsx b/packages/react-ui/internal/PerformanceMetrics/__stories__/PerformanceMetrics.stories.tsx deleted file mode 100644 index f4a76e78cd8..00000000000 --- a/packages/react-ui/internal/PerformanceMetrics/__stories__/PerformanceMetrics.stories.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import React from 'react'; - -import { PerformanceMetrics } from '../PerformanceMetrics'; -import { Input } from '../../../components/Input'; -import { Tooltip } from '../../../components/Tooltip'; - -function getTooltipContent() { - return 'Tooltip content'; -} -const INPUTS_COUNT = 150; -const INPUT_WIDTH = 50; -const DUMMY = new Array(INPUTS_COUNT).fill(''); -const WRAPPER_STYLES = { marginRight: 10, marginBottom: 10, display: 'inline-block' }; - -const inputs = ( -
- {DUMMY.map((i, index) => ( -
- -
- ))} -
-); - -const inputsWithTooltip = ( -
- {DUMMY.map((i, index) => ( -
- - - -
- ))} -
-); - -export default { title: 'PerformanceMetrics', parameters: { creevey: { skip: true } } }; - -export const BareInputsVsTooltipInput = () => { - return ( -
- -
- ); -}; -BareInputsVsTooltipInput.storyName = 'Bare Inputs vs Tooltip+Input'; diff --git a/packages/react-ui/package.json b/packages/react-ui/package.json index 35a87cdc761..5c58a197866 100644 --- a/packages/react-ui/package.json +++ b/packages/react-ui/package.json @@ -151,8 +151,8 @@ "selenium-webdriver": "^4.27.0", "semver": "^7.6.2", "serve": "^13.0.2", - "string-replace-loader": "3.1.0", "storybook": "7.6.18", + "string-replace-loader": "3.1.0", "style-loader": "^4.0.0", "stylelint": "^16.6.0", "stylelint-config-standard": "^36.0.0", diff --git a/packages/react-ui/test-setup.js b/packages/react-ui/test-setup.js index 0dc2e0b52fa..1c2d91bbd84 100644 --- a/packages/react-ui/test-setup.js +++ b/packages/react-ui/test-setup.js @@ -9,6 +9,7 @@ Enzyme.configure({ adapter: new Adapter() }); configure({ testIdAttribute: 'data-tid', + reactStrictMode: process?.env?.STRICT_MODE === 'true', }); jest.mock('react-focus-lock', () => (props) =>
{props.children}
); diff --git a/scripts/testing/package-versions.json b/scripts/testing/package-versions.json new file mode 100644 index 00000000000..7ba3e96416f --- /dev/null +++ b/scripts/testing/package-versions.json @@ -0,0 +1,33 @@ +{ + "react": { + "16": { + "react": "^16.0.0", + "react-dom": "^16.0.0", + "@testing-library/react": "^12.1.5" + }, + "17": { + "react": "^17.0.2", + "react-dom": "^17.0.2", + "@testing-library/react": "12.1.5" + }, + "18": { + "react": "^18.3.1", + "react-dom": "^18.3.1", + "@testing-library/react": "15.0.7" + }, + "19": { + "react": "^19.0.0", + "react-dom": "^19.0.0", + "@testing-library/react": "16.2.0", + "@testing-library/dom": "^10.4.0" + } + }, + "typescript": { + "4": { + "typescript": "^4.9.4" + }, + "5": { + "typescript": "^5.8.2" + } + } +} diff --git a/scripts/testing/set-package-versions.js b/scripts/testing/set-package-versions.js new file mode 100644 index 00000000000..50022b23cdd --- /dev/null +++ b/scripts/testing/set-package-versions.js @@ -0,0 +1,63 @@ +const path = require('path'); +const fs = require('fs'); + +const reactVersion = process?.env?.REACT_VERSION; +const tsVersion = process?.env?.TYPESCRIPT_VERSION; + +// эти 2 команды в самом конце закинуть в package.json, чтобы весь механизм завелся +//"preinstall": "node scripts/testing/set-package-versions.js", -- для ci +//"set-testing-package-versions-local": "cross-env REACT_VERSION=17 TYPESCRIPT_VERSION=4 node scripts/testing/set-package-versions.js" -- для Local + +if (!(reactVersion && tsVersion)) { + return; +} + +const packagesPath = path.resolve(__dirname, "..", "..", "packages"); +const {react, typescript} = getJsonFile(path.resolve(__dirname, "package-versions.json")); + +const packagesForReact = react[reactVersion]; +const packagesForTypescript = typescript[tsVersion]; + +const allPackages = {...packagesForReact, ...packagesForTypescript}; + +try { + patchSmokeTestPackage(); + patchSeleniumTestsPackage(); + patchPackageJsons(); +} catch (e) { + //log +} + +function patchPackageJsons() { + const pathToReactUi = path.resolve(packagesPath, "react-ui", "package.json"); + const pathToReactUiValidation = path.resolve(packagesPath, "react-ui-validations", "package.json"); + [pathToReactUi, pathToReactUiValidation].forEach(packagePath => { + const json = getJsonFile(packagePath); + json.devDependencies = {...json.devDependencies, ...allPackages} + writeJsonFile(packagePath, json); + }) +} + +function patchSeleniumTestsPackage() { + const pathToConfig = path.resolve(packagesPath, "react-ui-testing", "TestPages", "versions.js"); + const config = fs.readFileSync(pathToConfig, 'utf8'); + const patchedConfig = config.replace("let reactVersion;", `let reactVersion = ${packagesForReact?.react.replaceAll('^', '')};`) + fs.writeFileSync(pathToConfig, patchedConfig); + console.log(pathToConfig, "patched"); +} + +function patchSmokeTestPackage() { + const pathToConfig = path.resolve(packagesPath, "react-ui-smoke-test", "cra-template-react-ui", "template.json"); + const package = getJsonFile(pathToConfig); + package.package.dependencies = {...package.package.dependencies, ...packagesForReact}; + writeJsonFile(pathToConfig, package); + console.log(pathToConfig, "patched"); +} + +function getJsonFile(path) { + return JSON.parse(fs.readFileSync(path, 'utf8')); +} + +function writeJsonFile(path, content) { + fs.writeFileSync(path, JSON.stringify(content, null, 2) + "\n"); +} diff --git a/yarn.lock b/yarn.lock index a53aea53f62..35da755e8e3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19983,7 +19983,7 @@ string-replace-loader@3.1.0, string-replace-loader@^3.1.0: loader-utils "^2.0.0" schema-utils "^3.0.0" -"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -20001,6 +20001,15 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string-width@^3.0.0, string-width@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" @@ -20127,7 +20136,7 @@ stringify-object@^3.2.0: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -20148,6 +20157,13 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^7.0.1, strip-ansi@^7.1.0: version "7.1.0" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -22015,7 +22031,7 @@ wordwrap@^1.0.0: resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -22033,6 +22049,15 @@ wrap-ansi@^5.1.0: string-width "^3.0.0" strip-ansi "^5.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"