diff --git a/package.json b/package.json index 9f8c3a57c3d5e..7f056511d77fd 100644 --- a/package.json +++ b/package.json @@ -157,11 +157,11 @@ "@elastic/search-ui": "1.24.1", "@elastic/search-ui-app-search-connector": "1.24.1", "@elastic/search-ui-engines-connector": "1.24.1", - "@emotion/cache": "11.11.0", - "@emotion/css": "11.11.0", - "@emotion/react": "11.11.1", - "@emotion/serialize": "1.1.2", - "@emotion/styled": "11.11.0", + "@emotion/cache": "11.14.0", + "@emotion/css": "11.13.5", + "@emotion/react": "11.14.0", + "@emotion/serialize": "1.3.3", + "@emotion/styled": "11.14.1", "@faker-js/faker": "9.7.0", "@formatjs/icu-messageformat-parser": "2.11.1", "@formatjs/intl": "2.10.2", diff --git a/src/core/packages/chrome/browser-components/src/classic/__snapshots__/collapsible_nav.test.tsx.snap b/src/core/packages/chrome/browser-components/src/classic/__snapshots__/collapsible_nav.test.tsx.snap index c84762e9ae7cc..2e8a9254c4ed4 100644 --- a/src/core/packages/chrome/browser-components/src/classic/__snapshots__/collapsible_nav.test.tsx.snap +++ b/src/core/packages/chrome/browser-components/src/classic/__snapshots__/collapsible_nav.test.tsx.snap @@ -745,7 +745,7 @@ exports[`CollapsibleNav renders the default nav 1`] = ` , - "ctr": 2, + "ctr": 1, "insertionPoint": undefined, "isSpeedy": true, "key": "css", @@ -765,11 +765,9 @@ exports[`CollapsibleNav renders the default nav 1`] = ` isStringTag={false} serialized={ Object { - "map": undefined, "name": "1751mc5-navCss", "next": undefined, "styles": "@media (max-height: 240px){overflow-y:auto;};label:navCss;", - "toString": [Function], } } /> @@ -846,7 +844,7 @@ exports[`CollapsibleNav renders the default nav 2`] = ` , - "ctr": 2, + "ctr": 1, "insertionPoint": undefined, "isSpeedy": true, "key": "css", @@ -866,11 +864,9 @@ exports[`CollapsibleNav renders the default nav 2`] = ` isStringTag={false} serialized={ Object { - "map": undefined, "name": "1751mc5-navCss", "next": undefined, "styles": "@media (max-height: 240px){overflow-y:auto;};label:navCss;", - "toString": [Function], } } /> diff --git a/src/core/packages/chrome/navigation/packaging/package.json b/src/core/packages/chrome/navigation/packaging/package.json index 8ad1c12da6bb1..24337bad99748 100644 --- a/src/core/packages/chrome/navigation/packaging/package.json +++ b/src/core/packages/chrome/navigation/packaging/package.json @@ -7,8 +7,8 @@ "types": "index.d.ts", "peerDependencies": { "@elastic/eui": ">=112.0.0", - "@emotion/css": ">=11.0.0", - "@emotion/react": ">=11.0.0", + "@emotion/css": ">=11.13.5", + "@emotion/react": ">=11.14.0", "react": ">=18.0.0", "react-dom": ">=18.0.0" }, diff --git a/src/core/packages/chrome/navigation/src/__tests__/__snapshots__/both_modes.test.tsx.snap b/src/core/packages/chrome/navigation/src/__tests__/__snapshots__/both_modes.test.tsx.snap index bb914aee80e11..b1a62356ca22f 100644 --- a/src/core/packages/chrome/navigation/src/__tests__/__snapshots__/both_modes.test.tsx.snap +++ b/src/core/packages/chrome/navigation/src/__tests__/__snapshots__/both_modes.test.tsx.snap @@ -187,7 +187,7 @@ exports[`Both modes should render the side navigation 1`] = ` class="euiPopover emotion-euiPopover-block" >
{ ); expect(container.innerHTML).toMatchInlineSnapshot( - `"

Hello!

"` + `"

Hello!

"` ); }); @@ -92,7 +92,7 @@ describe('BannersList', () => { // Two new banners should be rendered expect(container.innerHTML).toMatchInlineSnapshot( - `"

First Banner!

Second banner!

"` + `"

First Banner!

Second banner!

"` ); // Original banner should be unmounted expect(unmount).toHaveBeenCalled(); diff --git a/src/platform/packages/shared/kbn-css-utils/public/use_memo_css.ts b/src/platform/packages/shared/kbn-css-utils/public/use_memo_css.ts index d33eaaa8e7e34..64ce865bd3dc3 100644 --- a/src/platform/packages/shared/kbn-css-utils/public/use_memo_css.ts +++ b/src/platform/packages/shared/kbn-css-utils/public/use_memo_css.ts @@ -8,7 +8,7 @@ */ import { useMemo } from 'react'; -import type { CSSInterpolation } from '@emotion/css'; +import type { CSSInterpolation } from '@emotion/serialize'; import type { UseEuiTheme } from '@elastic/eui'; import { useEuiTheme } from '@elastic/eui'; diff --git a/src/platform/packages/shared/kbn-test/jest-preset.js b/src/platform/packages/shared/kbn-test/jest-preset.js index a0bad6a2d75af..869126bd3563a 100644 --- a/src/platform/packages/shared/kbn-test/jest-preset.js +++ b/src/platform/packages/shared/kbn-test/jest-preset.js @@ -96,6 +96,7 @@ module.exports = { snapshotSerializers: [ '/src/platform/packages/shared/react/kibana_mount/test_helpers/react_mount_serializer.ts', 'enzyme-to-json/serializer', + '/src/platform/packages/shared/kbn-test/src/jest/setup/enzyme_emotion_serializer.js', '/src/platform/packages/shared/kbn-test/src/jest/setup/emotion.js', ], diff --git a/src/platform/packages/shared/kbn-test/src/jest/setup/enzyme_emotion_serializer.js b/src/platform/packages/shared/kbn-test/src/jest/setup/enzyme_emotion_serializer.js new file mode 100644 index 0000000000000..b2ec6f6eb2293 --- /dev/null +++ b/src/platform/packages/shared/kbn-test/src/jest/setup/enzyme_emotion_serializer.js @@ -0,0 +1,92 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +/** + * Custom serializer to handle Emotion-styled components in Enzyme shallow renders. + * This must run BEFORE enzyme-to-json to properly transform Emotion components. + * + * The problem: When using Enzyme's shallow() with Emotion-styled components, + * the component's internal structure (ForwardRef, __EMOTION_TYPE_PLEASE_DO_NOT_USE__) + * gets exposed in snapshots. This serializer intercepts those components and + * transforms them to match the expected format before enzyme-to-json processes them. + */ + +module.exports = { + test(val) { + // Skip if not an object + if (!val || typeof val !== 'object') { + return false; + } + + // Must have type and props to be a valid React element + if (!val.type || !val.props) { + return false; + } + + // Check if this is an Enzyme ShallowWrapper with Emotion props + if (val.props.__EMOTION_TYPE_PLEASE_DO_NOT_USE__) { + return true; + } + + // Also check for components with a css prop (function, object, or string) + // These are Emotion-styled components that need css prop normalization + // BUT skip if css is already the processed string "unknown styles" to avoid infinite recursion + if (val.props.css && val.props.css !== 'unknown styles') { + return true; + } + + return false; + }, + serialize(val, config, indentation, depth, refs, printer) { + const props = { ...val.props }; + + // Get the original component type before we modify props + const emotionType = props.__EMOTION_TYPE_PLEASE_DO_NOT_USE__; + + // Simplify the css prop to match the old snapshot format + // Handle css as object, function, or any truthy value + if (props.css) { + props.css = 'unknown styles'; + } + + // Remove Emotion internals from props + delete props.__EMOTION_TYPE_PLEASE_DO_NOT_USE__; + + // Try to get the original component name from Emotion's internal type + let componentName = null; + if (emotionType) { + // If emotionType is a string (like 'div', 'span'), use it directly + if (typeof emotionType === 'string') { + componentName = emotionType; + } + // Emotion wraps components, try to get the display name + else if (emotionType.displayName) { + componentName = emotionType.displayName; + } else if (emotionType.name) { + componentName = emotionType.name; + } else if (typeof emotionType === 'function' && emotionType.render) { + componentName = emotionType.render.displayName || emotionType.render.name; + } + } + + // Return the cleaned up component structure + // Only replace the type if we successfully extracted a component name + return printer( + { + ...val, + type: componentName || val.type, // Preserve original type if we couldn't extract one + props, + }, + config, + indentation, + depth, + refs + ); + }, +}; diff --git a/src/platform/packages/shared/kbn-test/src/jest/transforms/babel/transformer_config.js b/src/platform/packages/shared/kbn-test/src/jest/transforms/babel/transformer_config.js index 8b275b37710f8..7582528cb8b99 100644 --- a/src/platform/packages/shared/kbn-test/src/jest/transforms/babel/transformer_config.js +++ b/src/platform/packages/shared/kbn-test/src/jest/transforms/babel/transformer_config.js @@ -27,6 +27,8 @@ module.exports = () => ({ [ require.resolve('@emotion/babel-preset-css-prop'), { + // Use Babel's compile-time labeling for better test performance + // This is preferred over Emotion's runtime labeling via stack traces because of performance autoLabel: 'always', labelFormat: '[local]', sourceMap: false, diff --git a/src/platform/packages/shared/kbn-unified-data-table/src/components/compare_documents/hooks/__snapshots__/use_comparison_css.test.ts.snap b/src/platform/packages/shared/kbn-unified-data-table/src/components/compare_documents/hooks/__snapshots__/use_comparison_css.test.ts.snap index 1153201b1d838..b8364d6f0902e 100644 --- a/src/platform/packages/shared/kbn-unified-data-table/src/components/compare_documents/hooks/__snapshots__/use_comparison_css.test.ts.snap +++ b/src/platform/packages/shared/kbn-unified-data-table/src/components/compare_documents/hooks/__snapshots__/use_comparison_css.test.ts.snap @@ -2,90 +2,72 @@ exports[`useComparisonCss should render with basic diff mode and diff decorations 1`] = ` Object { - "map": undefined, "name": "d1lkc2-useComparisonCss-useComparisonCss", "next": undefined, "styles": ".unifiedDataTable__cellValue{white-space:pre-wrap;}.unifiedDataTable__comparisonFieldName{font-weight:500;}.unifiedDataTable__comparisonBaseDocCell{background-color:#F6F9FC;}.unifiedDataTable__comparisonMatchCell{.unifiedDataTable__cellValue{&,& *{color:#09724D!important;}}}.unifiedDataTable__comparisonDiffCell{.unifiedDataTable__cellValue{&,& *{color:#A71627!important;}}};label:useComparisonCss;; .unifiedDataTable__comparisonSegment{position:relative;}.unifiedDataTable__comparisonAddedSegment{background-color:#E9FFF7;color:#09724D;}.unifiedDataTable__comparisonRemovedSegment{background-color:#FFF3F1;color:#A71627;} ;;label:useComparisonCss;", - "toString": [Function], } `; exports[`useComparisonCss should render with basic diff mode and no diff decorations 1`] = ` Object { - "map": undefined, "name": "d1lkc2-useComparisonCss-useComparisonCss", "next": undefined, "styles": ".unifiedDataTable__cellValue{white-space:pre-wrap;}.unifiedDataTable__comparisonFieldName{font-weight:500;}.unifiedDataTable__comparisonBaseDocCell{background-color:#F6F9FC;}.unifiedDataTable__comparisonMatchCell{.unifiedDataTable__cellValue{&,& *{color:#09724D!important;}}}.unifiedDataTable__comparisonDiffCell{.unifiedDataTable__cellValue{&,& *{color:#A71627!important;}}};label:useComparisonCss;; .unifiedDataTable__comparisonSegment{position:relative;}.unifiedDataTable__comparisonAddedSegment{background-color:#E9FFF7;color:#09724D;}.unifiedDataTable__comparisonRemovedSegment{background-color:#FFF3F1;color:#A71627;} ;;label:useComparisonCss;", - "toString": [Function], } `; exports[`useComparisonCss should render with chars diff mode and diff decorations 1`] = ` Object { - "map": undefined, "name": "1jb0lvv-useComparisonCss-useComparisonCss", "next": undefined, "styles": ".unifiedDataTable__cellValue{white-space:pre-wrap;}.unifiedDataTable__comparisonFieldName{font-weight:500;}.unifiedDataTable__comparisonBaseDocCell{background-color:#F6F9FC;} .unifiedDataTable__comparisonSegment{position:relative;}.unifiedDataTable__comparisonAddedSegment{background-color:#E9FFF7;color:#09724D;}.unifiedDataTable__comparisonRemovedSegment{background-color:#FFF3F1;color:#A71627;}.unifiedDataTable__comparisonAddedSegment{text-decoration:underline;}.unifiedDataTable__comparisonRemovedSegment{text-decoration:line-through;};label:useComparisonCss;; ;;label:useComparisonCss;", - "toString": [Function], } `; exports[`useComparisonCss should render with chars diff mode and no diff decorations 1`] = ` Object { - "map": undefined, "name": "1hwemuj-useComparisonCss", "next": undefined, "styles": ".unifiedDataTable__cellValue{white-space:pre-wrap;}.unifiedDataTable__comparisonFieldName{font-weight:500;}.unifiedDataTable__comparisonBaseDocCell{background-color:#F6F9FC;} .unifiedDataTable__comparisonSegment{position:relative;}.unifiedDataTable__comparisonAddedSegment{background-color:#E9FFF7;color:#09724D;}.unifiedDataTable__comparisonRemovedSegment{background-color:#FFF3F1;color:#A71627;} ;;label:useComparisonCss;", - "toString": [Function], } `; exports[`useComparisonCss should render with lines diff mode and diff decorations 1`] = ` Object { - "map": undefined, "name": "ng9d64-indicatorCss-indicatorCss-useComparisonCss-useComparisonCss-useComparisonCss", "next": undefined, "styles": ".unifiedDataTable__cellValue{white-space:pre-wrap;}.unifiedDataTable__comparisonFieldName{font-weight:500;}.unifiedDataTable__comparisonBaseDocCell{background-color:#F6F9FC;} .unifiedDataTable__comparisonSegment{position:relative;}.unifiedDataTable__comparisonAddedSegment{background-color:#E9FFF7;color:#09724D;}.unifiedDataTable__comparisonRemovedSegment{background-color:#FFF3F1;color:#A71627;} .unifiedDataTable__comparisonSegment{padding-left:calc(4px / 2);}.unifiedDataTable__comparisonAddedSegment:before{content:'+';position:absolute;width:8px;height:100%;margin-left:calc(-8px - calc(4px / 2));text-align:center;line-height:1;font-weight:450;;label:indicatorCss;; background-color:#008A5E;color:#ECF1F9;}.unifiedDataTable__comparisonRemovedSegment:before{content:'-';position:absolute;width:8px;height:100%;margin-left:calc(-8px - calc(4px / 2));text-align:center;line-height:1;font-weight:450;;label:indicatorCss;; background-color:#C61E25;color:#ECF1F9;};label:useComparisonCss;;;;label:useComparisonCss;;;;label:useComparisonCss;", - "toString": [Function], } `; exports[`useComparisonCss should render with lines diff mode and no diff decorations 1`] = ` Object { - "map": undefined, "name": "clcah7-useComparisonCss-useComparisonCss", "next": undefined, "styles": ".unifiedDataTable__cellValue{white-space:pre-wrap;}.unifiedDataTable__comparisonFieldName{font-weight:500;}.unifiedDataTable__comparisonBaseDocCell{background-color:#F6F9FC;} .unifiedDataTable__comparisonSegment{position:relative;}.unifiedDataTable__comparisonAddedSegment{background-color:#E9FFF7;color:#09724D;}.unifiedDataTable__comparisonRemovedSegment{background-color:#FFF3F1;color:#A71627;} .unifiedDataTable__comparisonSegment{padding-left:calc(4px / 2);};;label:useComparisonCss;;;;label:useComparisonCss;", - "toString": [Function], } `; exports[`useComparisonCss should render with no diff mode and no diff decorations 1`] = ` Object { - "map": undefined, "name": "1hwemuj-useComparisonCss", "next": undefined, "styles": ".unifiedDataTable__cellValue{white-space:pre-wrap;}.unifiedDataTable__comparisonFieldName{font-weight:500;}.unifiedDataTable__comparisonBaseDocCell{background-color:#F6F9FC;} .unifiedDataTable__comparisonSegment{position:relative;}.unifiedDataTable__comparisonAddedSegment{background-color:#E9FFF7;color:#09724D;}.unifiedDataTable__comparisonRemovedSegment{background-color:#FFF3F1;color:#A71627;} ;;label:useComparisonCss;", - "toString": [Function], } `; exports[`useComparisonCss should render with words diff mode and diff decorations 1`] = ` Object { - "map": undefined, "name": "1jb0lvv-useComparisonCss-useComparisonCss", "next": undefined, "styles": ".unifiedDataTable__cellValue{white-space:pre-wrap;}.unifiedDataTable__comparisonFieldName{font-weight:500;}.unifiedDataTable__comparisonBaseDocCell{background-color:#F6F9FC;} .unifiedDataTable__comparisonSegment{position:relative;}.unifiedDataTable__comparisonAddedSegment{background-color:#E9FFF7;color:#09724D;}.unifiedDataTable__comparisonRemovedSegment{background-color:#FFF3F1;color:#A71627;}.unifiedDataTable__comparisonAddedSegment{text-decoration:underline;}.unifiedDataTable__comparisonRemovedSegment{text-decoration:line-through;};label:useComparisonCss;; ;;label:useComparisonCss;", - "toString": [Function], } `; exports[`useComparisonCss should render with words diff mode and no diff decorations 1`] = ` Object { - "map": undefined, "name": "1hwemuj-useComparisonCss", "next": undefined, "styles": ".unifiedDataTable__cellValue{white-space:pre-wrap;}.unifiedDataTable__comparisonFieldName{font-weight:500;}.unifiedDataTable__comparisonBaseDocCell{background-color:#F6F9FC;} .unifiedDataTable__comparisonSegment{position:relative;}.unifiedDataTable__comparisonAddedSegment{background-color:#E9FFF7;color:#09724D;}.unifiedDataTable__comparisonRemovedSegment{background-color:#FFF3F1;color:#A71627;} ;;label:useComparisonCss;", - "toString": [Function], } `; diff --git a/src/platform/packages/shared/shared-ux/button_toolbar/src/buttons/add_from_library/__snapshots__/add_from_library.test.tsx.snap b/src/platform/packages/shared/shared-ux/button_toolbar/src/buttons/add_from_library/__snapshots__/add_from_library.test.tsx.snap index af5bffc680657..cab51a812092a 100644 --- a/src/platform/packages/shared/shared-ux/button_toolbar/src/buttons/add_from_library/__snapshots__/add_from_library.test.tsx.snap +++ b/src/platform/packages/shared/shared-ux/button_toolbar/src/buttons/add_from_library/__snapshots__/add_from_library.test.tsx.snap @@ -2,7 +2,7 @@ exports[` is rendered 1`] = `