Skip to content

Commit 3071ce5

Browse files
Add React component tests.
1 parent a530e45 commit 3071ce5

2 files changed

Lines changed: 190 additions & 0 deletions

File tree

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
import React from 'react';
10+
import { render } from '../../../test/rtl';
11+
12+
import { EuiFlyoutMain } from './flyout_main';
13+
import { EuiFlyoutManager } from './provider';
14+
import { LEVEL_MAIN, PROPERTY_LEVEL } from './const';
15+
16+
// Mock managed flyout so we can observe props passed through
17+
jest.mock('./flyout_managed', () => ({
18+
EuiManagedFlyout: ({ children, pushMinBreakpoint, level, ...props }: any) => (
19+
<div
20+
data-test-subj="main-flyout"
21+
data-managed-flyout
22+
data-managed-flyout-level={level}
23+
{...props}
24+
>
25+
{children}
26+
</div>
27+
),
28+
}));
29+
30+
// Keep layout/ID hooks deterministic
31+
jest.mock('./hooks', () => ({
32+
useFlyoutManagerReducer: () => ({
33+
state: { sessions: [], flyouts: [], layoutMode: 'side-by-side' },
34+
dispatch: jest.fn(),
35+
addFlyout: jest.fn(),
36+
closeFlyout: jest.fn(),
37+
setActiveFlyout: jest.fn(),
38+
setFlyoutWidth: jest.fn(),
39+
}),
40+
useFlyoutManager: () => ({
41+
state: { sessions: [], flyouts: [], layoutMode: 'side-by-side' },
42+
addFlyout: jest.fn(),
43+
closeFlyout: jest.fn(),
44+
setFlyoutWidth: jest.fn(),
45+
}),
46+
useHasChildFlyout: () => false,
47+
useFlyoutId: (id?: string) => id ?? 'generated-id',
48+
}));
49+
50+
describe('EuiFlyoutMain', () => {
51+
const renderInProvider = (ui: React.ReactElement) =>
52+
render(<EuiFlyoutManager>{ui}</EuiFlyoutManager>);
53+
54+
// intentionally skipping shouldRenderCustomStyles for this wrapper
55+
56+
it('renders and passes level=main to managed flyout', () => {
57+
const { getByTestSubject } = renderInProvider(
58+
<EuiFlyoutMain onClose={() => {}} />
59+
);
60+
expect(getByTestSubject('main-flyout')).toHaveAttribute(
61+
PROPERTY_LEVEL,
62+
LEVEL_MAIN
63+
);
64+
});
65+
66+
// CSS pass-through covered elsewhere; avoid hook re-mocking complexity here
67+
});
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
/* eslint-disable @typescript-eslint/no-var-requires */
10+
11+
import React from 'react';
12+
import { act } from '@testing-library/react';
13+
import userEvent from '@testing-library/user-event';
14+
import { render } from '../../../test/rtl';
15+
import { requiredProps } from '../../../test/required_props';
16+
17+
import { EuiManagedFlyout } from './flyout_managed';
18+
import { EuiFlyoutManager } from './provider';
19+
import {
20+
LEVEL_CHILD,
21+
LEVEL_MAIN,
22+
PROPERTY_FLYOUT,
23+
PROPERTY_LEVEL,
24+
} from './const';
25+
26+
// Mock base flyout to a simple div to avoid complex internals
27+
jest.mock('../flyout.component', () => {
28+
const React = require('react');
29+
return {
30+
EuiFlyoutComponent: React.forwardRef(function MockFlyout(
31+
props: any,
32+
ref: any
33+
) {
34+
return React.createElement('div', {
35+
ref,
36+
...props,
37+
'data-test-subj': 'managed-flyout',
38+
onClick: () => props.onClose && props.onClose({} as any),
39+
});
40+
}),
41+
};
42+
});
43+
44+
// Mock hooks that would otherwise depend on ResizeObserver or animation timing
45+
jest.mock('./hooks', () => ({
46+
useFlyoutManagerReducer: () => ({
47+
state: { sessions: [], flyouts: [], layoutMode: 'side-by-side' },
48+
dispatch: jest.fn(),
49+
addFlyout: jest.fn(),
50+
closeFlyout: jest.fn(),
51+
setActiveFlyout: jest.fn(),
52+
setFlyoutWidth: jest.fn(),
53+
}),
54+
useFlyoutManager: () => ({
55+
state: { sessions: [], flyouts: [], layoutMode: 'side-by-side' },
56+
addFlyout: jest.fn(),
57+
closeFlyout: jest.fn(),
58+
setFlyoutWidth: jest.fn(),
59+
}),
60+
useIsFlyoutActive: () => true,
61+
useHasChildFlyout: () => false,
62+
useParentFlyoutSize: () => 'm',
63+
useFlyoutLayoutMode: () => 'side-by-side',
64+
useFlyoutId: (id?: string) => id ?? 'generated-id',
65+
}));
66+
67+
// Mock validation helpers to be deterministic
68+
jest.mock('./validation', () => ({
69+
validateManagedFlyoutSize: () => undefined,
70+
validateSizeCombination: () => undefined,
71+
createValidationErrorMessage: (e: any) => String(e),
72+
isNamedSize: () => true,
73+
}));
74+
75+
// Mock resize observer hook to return a fixed width
76+
jest.mock('../../observer/resize_observer', () => ({
77+
useResizeObserver: () => ({ width: 480 }),
78+
}));
79+
80+
describe('EuiManagedFlyout', () => {
81+
const renderInProvider = (ui: React.ReactElement) =>
82+
render(<EuiFlyoutManager>{ui}</EuiFlyoutManager>);
83+
84+
it('renders and sets managed data attributes', () => {
85+
const { getByTestSubject } = renderInProvider(
86+
<EuiManagedFlyout
87+
{...requiredProps}
88+
id="my-flyout"
89+
level={LEVEL_MAIN}
90+
onClose={() => {}}
91+
/>
92+
);
93+
94+
const el = getByTestSubject('managed-flyout');
95+
expect(el).toHaveAttribute(PROPERTY_FLYOUT);
96+
expect(el).toHaveAttribute(PROPERTY_LEVEL, LEVEL_MAIN);
97+
});
98+
99+
it('calls onClose prop when onClose is invoked', () => {
100+
const onClose = jest.fn();
101+
102+
const { getByTestSubject } = renderInProvider(
103+
<EuiManagedFlyout id="close-me" level={LEVEL_MAIN} onClose={onClose} />
104+
);
105+
106+
act(() => {
107+
userEvent.click(getByTestSubject('managed-flyout'));
108+
});
109+
110+
expect(onClose).toHaveBeenCalledTimes(1);
111+
});
112+
113+
it('registers child flyout and sets data-level child', () => {
114+
const { getByTestSubject } = renderInProvider(
115+
<EuiManagedFlyout level={LEVEL_CHILD} onClose={() => {}} />
116+
);
117+
118+
expect(getByTestSubject('managed-flyout')).toHaveAttribute(
119+
PROPERTY_LEVEL,
120+
LEVEL_CHILD
121+
);
122+
});
123+
});

0 commit comments

Comments
 (0)