Skip to content

Commit 8deaaac

Browse files
committed
Merge branch 'gagik/context-menu-compass-ui' of github.com:mongodb-js/compass into gagik/collection-tab
2 parents 97dd158 + 4f05381 commit 8deaaac

File tree

7 files changed

+154
-170
lines changed

7 files changed

+154
-170
lines changed

configs/testing-library-compass/src/index.tsx

Lines changed: 36 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,7 @@ import {
4545
ReadOnlyPreferenceAccess,
4646
} from 'compass-preferences-model/provider';
4747
import { TelemetryProvider } from '@mongodb-js/compass-telemetry/provider';
48-
import {
49-
CompassComponentsProvider,
50-
ContextMenuProvider,
51-
} from '@mongodb-js/compass-components';
48+
import { CompassComponentsProvider } from '@mongodb-js/compass-components';
5249
import {
5350
TestEnvCurrentConnectionContext,
5451
ConnectionInfoProvider,
@@ -352,43 +349,41 @@ function createWrapper(
352349
<PreferencesProvider value={wrapperState.preferences}>
353350
<LoggerProvider value={logger}>
354351
<TelemetryProvider options={telemetryOptions}>
355-
<ContextMenuProvider>
356-
<ConnectionStorageProvider
357-
value={wrapperState.connectionStorage}
358-
>
359-
<ConnectFnProvider connect={wrapperState.connect}>
360-
<CompassConnections
361-
appName={options.appName ?? 'TEST'}
362-
onFailToLoadConnections={
363-
options.onFailToLoadConnections ??
364-
(() => {
365-
// noop
366-
})
367-
}
368-
onExtraConnectionDataRequest={
369-
options.onExtraConnectionDataRequest ??
370-
(() => {
371-
return Promise.resolve([{}, null] as [any, null]);
372-
})
373-
}
374-
onAutoconnectInfoRequest={
375-
options.onAutoconnectInfoRequest
376-
}
377-
preloadStorageConnectionInfos={connections}
378-
>
379-
<StoreGetter>
380-
<TestEnvCurrentConnectionContext.Provider
381-
value={TEST_ENV_CURRENT_CONNECTION}
382-
>
383-
<TestingLibraryWrapper {...props}>
384-
{children}
385-
</TestingLibraryWrapper>
386-
</TestEnvCurrentConnectionContext.Provider>
387-
</StoreGetter>
388-
</CompassConnections>
389-
</ConnectFnProvider>
390-
</ConnectionStorageProvider>
391-
</ContextMenuProvider>
352+
<ConnectionStorageProvider
353+
value={wrapperState.connectionStorage}
354+
>
355+
<ConnectFnProvider connect={wrapperState.connect}>
356+
<CompassConnections
357+
appName={options.appName ?? 'TEST'}
358+
onFailToLoadConnections={
359+
options.onFailToLoadConnections ??
360+
(() => {
361+
// noop
362+
})
363+
}
364+
onExtraConnectionDataRequest={
365+
options.onExtraConnectionDataRequest ??
366+
(() => {
367+
return Promise.resolve([{}, null] as [any, null]);
368+
})
369+
}
370+
onAutoconnectInfoRequest={
371+
options.onAutoconnectInfoRequest
372+
}
373+
preloadStorageConnectionInfos={connections}
374+
>
375+
<StoreGetter>
376+
<TestEnvCurrentConnectionContext.Provider
377+
value={TEST_ENV_CURRENT_CONNECTION}
378+
>
379+
<TestingLibraryWrapper {...props}>
380+
{children}
381+
</TestingLibraryWrapper>
382+
</TestEnvCurrentConnectionContext.Provider>
383+
</StoreGetter>
384+
</CompassConnections>
385+
</ConnectFnProvider>
386+
</ConnectionStorageProvider>
392387
</TelemetryProvider>
393388
</LoggerProvider>
394389
</PreferencesProvider>

packages/compass-components/src/components/compass-components-provider.tsx

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { GuideCueProvider } from './guide-cue/guide-cue';
66
import { SignalHooksProvider } from './signal-popover';
77
import { RequiredURLSearchParamsProvider } from './links/link';
88
import { StackedComponentProvider } from '../hooks/use-stacked-component';
9+
import { ContextMenuProvider } from './context-menu';
910

1011
type GuideCueProviderProps = React.ComponentProps<typeof GuideCueProvider>;
1112

@@ -135,15 +136,17 @@ export const CompassComponentsProvider = ({
135136
>
136137
<SignalHooksProvider {...signalHooksProviderProps}>
137138
<ConfirmationModalArea>
138-
<ToastArea>
139-
{typeof children === 'function'
140-
? children({
141-
darkMode,
142-
portalContainerRef: setPortalContainer,
143-
scrollContainerRef: setScrollContainer,
144-
})
145-
: children}
146-
</ToastArea>
139+
<ContextMenuProvider>
140+
<ToastArea>
141+
{typeof children === 'function'
142+
? children({
143+
darkMode,
144+
portalContainerRef: setPortalContainer,
145+
scrollContainerRef: setScrollContainer,
146+
})
147+
: children}
148+
</ToastArea>
149+
</ContextMenuProvider>
147150
</ConfirmationModalArea>
148151
</SignalHooksProvider>
149152
</GuideCueProvider>

packages/compass-components/src/components/content-with-fallback.spec.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,10 @@ describe('ContentWithFallback', function () {
5858
{ container }
5959
);
6060

61-
expect(container).to.be.empty;
61+
expect(container.children.length).to.equal(1);
62+
expect(container.children[0].getAttribute('data-testid')).to.equal(
63+
'context-menu'
64+
);
6265
});
6366

6467
it('should render fallback when the timeout passes', async function () {

packages/compass-components/src/components/context-menu.spec.tsx

Lines changed: 99 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -28,40 +28,88 @@ describe('useContextMenuItems', function () {
2828
);
2929
};
3030

31-
describe('when used outside provider', function () {
32-
it('throws an error', function () {
33-
const items = [
34-
{
35-
label: 'Test Item',
36-
onAction: () => {},
37-
},
38-
];
39-
40-
expect(() => {
41-
render(<TestComponent items={items} />);
42-
}).to.throw('useContextMenu called outside of the provider');
43-
});
44-
});
45-
46-
describe('with a valid provider', function () {
47-
it('renders without error', function () {
48-
const items = [
49-
{
50-
label: 'Test Item',
51-
onAction: () => {},
52-
},
53-
];
54-
31+
it('errors if the component is double wrapped', function () {
32+
const items = [
33+
{
34+
label: 'Test Item',
35+
onAction: () => {},
36+
},
37+
];
38+
39+
expect(() => {
5540
render(
5641
<ContextMenuProvider wrapper={ContextMenu}>
5742
<TestComponent items={items} />
5843
</ContextMenuProvider>
5944
);
45+
}).to.throw(
46+
'Duplicated ContextMenuProvider found. Please remove the nested provider.'
47+
);
48+
});
6049

61-
expect(screen.getByTestId(menuTestTriggerId)).to.exist;
62-
});
50+
it('renders without error', function () {
51+
const items = [
52+
{
53+
label: 'Test Item',
54+
onAction: () => {},
55+
},
56+
];
57+
58+
render(<TestComponent items={items} />);
59+
60+
expect(screen.getByTestId(menuTestTriggerId)).to.exist;
61+
});
62+
63+
it('shows context menu with items on right click', function () {
64+
const items = [
65+
{
66+
label: 'Test Item 1',
67+
onAction: () => {},
68+
},
69+
{
70+
label: 'Test Item 2',
71+
onAction: () => {},
72+
},
73+
];
74+
75+
render(<TestComponent items={items} />);
76+
77+
const trigger = screen.getByTestId(menuTestTriggerId);
78+
userEvent.click(trigger, { button: 2 });
79+
80+
// The menu items should be rendered
81+
expect(screen.getByTestId('menu-group-0-item-0')).to.exist;
82+
expect(screen.getByTestId('menu-group-0-item-1')).to.exist;
83+
});
84+
85+
it('triggers the correct action when menu item is clicked', function () {
86+
const onAction = sinon.spy();
87+
const items = [
88+
{
89+
label: 'Test Item 1',
90+
onAction: () => onAction(1),
91+
},
92+
{
93+
label: 'Test Item 2',
94+
onAction: () => onAction(2),
95+
},
96+
];
97+
98+
render(<TestComponent items={items} />);
99+
100+
const trigger = screen.getByTestId(menuTestTriggerId);
101+
userEvent.click(trigger, { button: 2 });
63102

64-
it('shows context menu with items on right click', function () {
103+
const menuItem = screen.getByTestId('menu-group-0-item-1');
104+
userEvent.click(menuItem);
105+
106+
expect(onAction).to.have.been.calledOnceWithExactly(2);
107+
});
108+
109+
describe('with nested components', function () {
110+
const childTriggerId = 'child-trigger';
111+
112+
beforeEach(function () {
65113
const items = [
66114
{
67115
label: 'Test Item 1',
@@ -73,101 +121,41 @@ describe('useContextMenuItems', function () {
73121
},
74122
];
75123

76-
render(
77-
<ContextMenuProvider wrapper={ContextMenu}>
78-
<TestComponent items={items} />
79-
</ContextMenuProvider>
80-
);
81-
82-
const trigger = screen.getByTestId(menuTestTriggerId);
83-
userEvent.click(trigger, { button: 2 });
84-
85-
// The menu items should be rendered
86-
expect(screen.getByTestId('menu-group-0-item-0')).to.exist;
87-
expect(screen.getByTestId('menu-group-0-item-1')).to.exist;
88-
});
89-
90-
it('triggers the correct action when menu item is clicked', function () {
91-
const onAction = sinon.spy();
92-
const items = [
124+
const childItems = [
93125
{
94-
label: 'Test Item 1',
95-
onAction: () => onAction(1),
96-
},
97-
{
98-
label: 'Test Item 2',
99-
onAction: () => onAction(2),
126+
label: 'Child Item 1',
127+
onAction: () => {},
100128
},
101129
];
102130

103131
render(
104-
<ContextMenuProvider wrapper={ContextMenu}>
105-
<TestComponent items={items} />
106-
</ContextMenuProvider>
132+
<TestComponent items={items}>
133+
<TestComponent items={childItems} data-testid={childTriggerId} />
134+
</TestComponent>
107135
);
136+
});
108137

109-
const trigger = screen.getByTestId(menuTestTriggerId);
138+
it('renders menu items with separators', function () {
139+
const trigger = screen.getByTestId(childTriggerId);
110140
userEvent.click(trigger, { button: 2 });
111141

112-
const menuItem = screen.getByTestId('menu-group-0-item-1');
113-
userEvent.click(menuItem);
142+
// Should find the menu item and the separator
143+
expect(screen.getByTestId('menu-group-0').children.length).to.equal(2);
144+
expect(
145+
screen.getByTestId('menu-group-0').children.item(0)?.textContent
146+
).to.equal('Child Item 1');
114147

115-
expect(onAction).to.have.been.calledOnceWithExactly(2);
116-
});
148+
expect(screen.getByTestId('menu-group-0-separator')).to.exist;
149+
150+
expect(screen.getByTestId('menu-group-1').children.length).to.equal(2);
151+
expect(
152+
screen.getByTestId('menu-group-1').children.item(0)?.textContent
153+
).to.equal('Test Item 1');
154+
expect(
155+
screen.getByTestId('menu-group-1').children.item(1)?.textContent
156+
).to.equal('Test Item 2');
117157

118-
describe('with nested components', function () {
119-
const childTriggerId = 'child-trigger';
120-
121-
beforeEach(function () {
122-
const items = [
123-
{
124-
label: 'Test Item 1',
125-
onAction: () => {},
126-
},
127-
{
128-
label: 'Test Item 2',
129-
onAction: () => {},
130-
},
131-
];
132-
133-
const childItems = [
134-
{
135-
label: 'Child Item 1',
136-
onAction: () => {},
137-
},
138-
];
139-
140-
render(
141-
<ContextMenuProvider wrapper={ContextMenu}>
142-
<TestComponent items={items}>
143-
<TestComponent items={childItems} data-testid={childTriggerId} />
144-
</TestComponent>
145-
</ContextMenuProvider>
146-
);
147-
});
148-
149-
it('renders menu items with separators', function () {
150-
const trigger = screen.getByTestId(childTriggerId);
151-
userEvent.click(trigger, { button: 2 });
152-
153-
// Should find the menu item and the separator
154-
expect(screen.getByTestId('menu-group-0').children.length).to.equal(2);
155-
expect(
156-
screen.getByTestId('menu-group-0').children.item(0)?.textContent
157-
).to.equal('Child Item 1');
158-
159-
expect(screen.getByTestId('menu-group-0-separator')).to.exist;
160-
161-
expect(screen.getByTestId('menu-group-1').children.length).to.equal(2);
162-
expect(
163-
screen.getByTestId('menu-group-1').children.item(0)?.textContent
164-
).to.equal('Test Item 1');
165-
expect(
166-
screen.getByTestId('menu-group-1').children.item(1)?.textContent
167-
).to.equal('Test Item 2');
168-
169-
expect(screen.queryByTestId('menu-group-1-separator')).not.to.exist;
170-
});
158+
expect(screen.queryByTestId('menu-group-1-separator')).not.to.exist;
171159
});
172160
});
173161
});

packages/compass-components/src/components/context-menu.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export function ContextMenu({ menu }: ContextMenuWrapperProps) {
3232

3333
return (
3434
<div
35+
data-testid="context-menu"
3536
style={{
3637
position: 'absolute',
3738
pointerEvents: 'all',

packages/compass-components/src/index.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,7 @@ export { ModalHeader } from './components/modals/modal-header';
9393
export { FormModal } from './components/modals/form-modal';
9494
export { InfoModal } from './components/modals/info-modal';
9595

96-
export {
97-
ContextMenuProvider,
98-
useContextMenuItems,
99-
} from './components/context-menu';
96+
export { useContextMenuItems } from './components/context-menu';
10097

10198
export type {
10299
FileInputBackend,

0 commit comments

Comments
 (0)