Skip to content

Commit 981789e

Browse files
fix: address PR review feedback for RTL migration
1 parent 85f3e50 commit 981789e

11 files changed

+216
-117
lines changed

tests/renderer/components/commands-spec.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,19 @@ import { AppState } from '../../../src/renderer/state';
1010
import { overrideRendererPlatform, resetRendererPlatform } from '../../utils';
1111

1212
vi.mock('../../../src/renderer/components/commands-runner', () => ({
13-
Runner: () => <div data-testid="runner" />,
13+
Runner: 'runner',
1414
}));
1515

1616
vi.mock('../../../src/renderer/components/commands-version-chooser', () => ({
17-
VersionChooser: () => <div data-testid="version-chooser" />,
17+
VersionChooser: 'version-chooser',
1818
}));
1919

2020
vi.mock('../../../src/renderer/components/commands-address-bar', () => ({
21-
AddressBar: () => <div data-testid="address-bar" />,
21+
AddressBar: 'address-bar',
2222
}));
2323

2424
vi.mock('../../../src/renderer/components/commands-action-button', () => ({
25-
GistActionButton: () => <div data-testid="action-button" />,
25+
GistActionButton: 'action-button',
2626
}));
2727

2828
describe('Commands component', () => {

tests/renderer/components/dialog-add-version-spec.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as React from 'react';
22

3-
import { act, render, screen } from '@testing-library/react';
3+
import { act, fireEvent, render, screen } from '@testing-library/react';
44
import { beforeEach, describe, expect, it, vi } from 'vitest';
55

66
import { renderClassComponentWithInstanceRef } from '../../../rtl-spec/test-utils/renderClassComponentWithInstanceRef';
@@ -73,18 +73,21 @@ describe('AddVersionDialog component', () => {
7373

7474
// The FileInput has id="custom-electron-version" with an onClick that
7575
// calls selectLocalVersion and preventDefault
76-
const fileInput = document.querySelector(
77-
'#custom-electron-version input[type="file"]',
78-
) as HTMLInputElement;
76+
const fileInput = screen.getByLabelText(
77+
'Select the folder containing Electron.app...',
78+
{ selector: 'input' },
79+
);
7980
expect(fileInput).toBeInTheDocument();
8081

8182
const preventDefault = vi.fn();
82-
fileInput.dispatchEvent(
83+
fireEvent(
84+
fileInput,
8385
Object.assign(new MouseEvent('click', { bubbles: true }), {
8486
preventDefault,
8587
}),
8688
);
8789

90+
expect(preventDefault).toHaveBeenCalled();
8891
expect(window.ElectronFiddle.selectLocalVersion).toHaveBeenCalled();
8992
});
9093

tests/renderer/components/dialog-bisect-spec.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,7 @@ describe.each([8, 15])('BisectDialog component', (numVersions) => {
180180
await instance.onSubmit();
181181
expect(Bisector).not.toHaveBeenCalled();
182182

183-
// Restore valid state for clean teardown
184-
(instance as any).state = origState;
183+
instance.state = origState;
185184
});
186185
});
187186

@@ -233,8 +232,7 @@ describe.each([8, 15])('BisectDialog component', (numVersions) => {
233232
await instance.onAuto();
234233
expect(Bisector).not.toHaveBeenCalled();
235234

236-
// Restore valid state for clean teardown
237-
(instance as any).state = origState;
235+
instance.state = origState;
238236
});
239237
});
240238

tests/renderer/components/dialog-generic-spec.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,26 +33,32 @@ describe('GenericDialog component', () => {
3333
renderDialogWithType(GenericDialogType.warning);
3434
expect(screen.getByText('Test label')).toBeInTheDocument();
3535
expect(screen.getByText('Okay')).toBeInTheDocument();
36+
expect(
37+
document.querySelector('[icon="warning-sign"]'),
38+
).toBeInTheDocument();
3639
});
3740

3841
it('confirmation', () => {
3942
renderDialogWithType(GenericDialogType.confirm);
4043
expect(screen.getByText('Test label')).toBeInTheDocument();
4144
expect(screen.getByText('Okay')).toBeInTheDocument();
45+
expect(document.querySelector('[icon="help"]')).toBeInTheDocument();
4246
});
4347

4448
it('success', () => {
4549
renderDialogWithType(GenericDialogType.success);
4650
expect(screen.getByText('Test label')).toBeInTheDocument();
4751
expect(screen.getByText('Okay')).toBeInTheDocument();
52+
expect(document.querySelector('[icon="info-sign"]')).toBeInTheDocument();
4853
});
4954

5055
it('with an input prompt', () => {
5156
store.genericDialogOptions.wantsInput = true;
5257
renderDialogWithType(GenericDialogType.confirm);
53-
expect(screen.getByText('Test label')).toBeInTheDocument();
58+
const label = screen.getByText('Test label');
59+
expect(label).toBeInTheDocument();
5460
// The InputGroup renders an input element with id="input"
55-
expect(document.getElementById('input')).toBeInTheDocument();
61+
expect(label.parentNode?.querySelector('input')).toBeInTheDocument();
5662
});
5763

5864
it('with an input prompt and placeholder', () => {
@@ -85,7 +91,7 @@ describe('GenericDialog component', () => {
8591
store.genericDialogOptions.wantsInput = true;
8692
render(<GenericDialog appState={store} />);
8793

88-
const input = document.getElementById('input') as HTMLInputElement;
94+
const input = document.getElementById('input')!;
8995
expect(input).toBeInTheDocument();
9096

9197
// Focus the input and press Enter

tests/renderer/components/dialog-token-spec.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,9 @@ describe('TokenDialog component', () => {
131131
});
132132

133133
act(() => {
134-
instance.handleChange({ target: { value: 'hi' } } as any);
134+
instance.handleChange({
135+
target: { value: 'hi' },
136+
} as React.ChangeEvent<HTMLInputElement>);
135137
});
136138

137139
expect(instance.state.tokenInput).toBe('hi');

tests/renderer/components/output-spec.tsx

Lines changed: 92 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,42 @@
1-
import * as React from 'react';
2-
3-
import { render } from '@testing-library/react';
41
import type * as MonacoType from 'monaco-editor';
5-
import { MosaicContext } from 'react-mosaic-component';
2+
import type { MosaicContext } from 'react-mosaic-component';
63
import { beforeEach, describe, expect, it, vi } from 'vitest';
74

5+
import { renderClassComponentWithInstanceRef } from '../../../rtl-spec/test-utils/renderClassComponentWithInstanceRef';
86
import { Output } from '../../../src/renderer/components/output';
7+
import { WrapperEditorId } from '../../../src/renderer/components/output-editors-wrapper';
98
import { AppState } from '../../../src/renderer/state';
109
import { MonacoMock } from '../../mocks/mocks';
1110

12-
const mockMosaicActions = {
13-
expand: vi.fn(),
14-
remove: vi.fn(),
15-
hide: vi.fn(),
16-
replaceWith: vi.fn(),
17-
updateTree: vi.fn(),
18-
getRoot: vi.fn(),
19-
};
20-
21-
const mockContextValue = {
22-
mosaicActions: mockMosaicActions,
23-
mosaicId: 'output',
24-
} as any;
25-
26-
function renderOutput(store: AppState, monaco: typeof MonacoType) {
27-
const ref = React.createRef<any>();
28-
const renderResult = render(
29-
<MosaicContext.Provider value={mockContextValue}>
30-
<Output appState={store} monaco={monaco} monacoOptions={{}} ref={ref} />
31-
</MosaicContext.Provider>,
11+
const mockContext = vi.hoisted(
12+
() =>
13+
({
14+
mosaicActions: {
15+
expand: vi.fn(),
16+
remove: vi.fn(),
17+
hide: vi.fn(),
18+
replaceWith: vi.fn(),
19+
updateTree: vi.fn(),
20+
getRoot: vi.fn(),
21+
},
22+
mosaicId: 'output',
23+
}) as unknown as MosaicContext<WrapperEditorId>,
24+
);
25+
26+
// Provide a default value for MosaicContext so that the component's
27+
// `static contextType = MosaicContext` picks up `mockContext` without
28+
// needing a Provider in the render tree.
29+
vi.mock('react-mosaic-component', async () => {
30+
const React = await import('react');
31+
const actual = await vi.importActual<typeof import('react-mosaic-component')>(
32+
'react-mosaic-component',
3233
);
33-
return { instance: ref.current!, renderResult };
34-
}
34+
35+
return {
36+
...actual,
37+
MosaicContext: React.createContext(mockContext),
38+
};
39+
});
3540

3641
describe('Output component', () => {
3742
let store: AppState;
@@ -40,26 +45,40 @@ describe('Output component', () => {
4045
beforeEach(() => {
4146
monaco = window.monaco;
4247
({ state: store } = window.app);
43-
vi.clearAllMocks();
48+
vi.mocked(mockContext.mosaicActions.replaceWith).mockClear();
49+
vi.mocked(mockContext.mosaicActions.getRoot).mockReset();
4450
});
4551

4652
it('renders the output container', () => {
47-
const { renderResult } = renderOutput(store, monaco);
53+
const { renderResult } = renderClassComponentWithInstanceRef(Output, {
54+
appState: store,
55+
monaco,
56+
monacoOptions: {},
57+
});
4858
const outputDiv = renderResult.container.querySelector('.output');
4959
expect(outputDiv).toBeInTheDocument();
5060
expect(outputDiv).toHaveStyle('display: inline-block');
5161
});
5262

5363
it('correctly sets the language', () => {
54-
const { instance } = renderOutput(store, monaco);
64+
const { instance } = renderClassComponentWithInstanceRef(Output, {
65+
appState: store,
66+
monaco,
67+
monacoOptions: {},
68+
});
5569
expect(instance.language).toBe('consoleOutputLanguage');
5670
});
5771

5872
describe('initMonaco()', () => {
5973
it('attempts to create an editor', async () => {
60-
const { instance } = renderOutput(store, monaco);
61-
62-
instance.outputRef.current = 'ref' as any;
74+
const { instance } = renderClassComponentWithInstanceRef(Output, {
75+
appState: store,
76+
monaco,
77+
monacoOptions: {},
78+
});
79+
80+
// outputRef is private — cast needed to test initMonaco directly
81+
(instance as any).outputRef.current = 'ref';
6382
await instance.initMonaco();
6483

6584
expect(monaco.editor.create).toHaveBeenCalled();
@@ -68,9 +87,14 @@ describe('Output component', () => {
6887
});
6988

7089
it('componentWillUnmount() attempts to dispose the editor', async () => {
71-
const { instance } = renderOutput(store, monaco);
90+
const { instance } = renderClassComponentWithInstanceRef(Output, {
91+
appState: store,
92+
monaco,
93+
monacoOptions: {},
94+
});
7295

73-
instance.outputRef.current = 'ref' as any;
96+
// outputRef is private
97+
(instance as any).outputRef.current = 'ref';
7498
await instance.initMonaco();
7599
instance.componentWillUnmount();
76100

@@ -80,22 +104,25 @@ describe('Output component', () => {
80104
});
81105

82106
it('hides the console with react-mosaic-component', async () => {
83-
const { instance } = renderOutput(store, monaco);
84-
85107
// direction is required to be recognized as a valid root node
86-
mockMosaicActions.getRoot.mockReturnValue({
108+
vi.mocked(mockContext.mosaicActions.getRoot).mockReturnValue({
87109
splitPercentage: 25,
88110
direction: 'row',
111+
} as ReturnType<typeof mockContext.mosaicActions.getRoot>);
112+
113+
const { instance } = renderClassComponentWithInstanceRef(Output, {
114+
appState: store,
115+
monaco,
116+
monacoOptions: {},
89117
});
90118

91-
instance.outputRef.current = 'ref' as any;
119+
// outputRef is private
120+
(instance as any).outputRef.current = 'ref';
92121
await instance.initMonaco();
93-
94-
// Trigger toggleConsole explicitly
95122
instance.toggleConsole();
96123

97-
expect(mockMosaicActions.replaceWith).toHaveBeenCalled();
98-
expect(mockMosaicActions.replaceWith).toHaveBeenCalledWith(
124+
expect(mockContext.mosaicActions.replaceWith).toHaveBeenCalled();
125+
expect(mockContext.mosaicActions.replaceWith).toHaveBeenCalledWith(
99126
[],
100127
expect.objectContaining({ splitPercentage: 25 }),
101128
);
@@ -114,12 +141,16 @@ describe('Output component', () => {
114141
},
115142
];
116143

117-
const { instance } = renderOutput(store, monaco);
144+
const { instance } = renderClassComponentWithInstanceRef(Output, {
145+
appState: store,
146+
monaco,
147+
monacoOptions: {},
148+
});
118149

119-
instance.outputRef.current = 'ref' as any;
150+
// outputRef and updateModel are private
151+
(instance as any).outputRef.current = 'ref';
120152
await instance.initMonaco();
121-
// updateModel is private — cast needed to test it directly
122-
(instance as any).updateModel();
153+
await (instance as any).updateModel();
123154

124155
expect(monaco.editor.createModel).toHaveBeenCalled();
125156
expect(instance.editor?.revealLine).toHaveBeenCalled();
@@ -133,15 +164,19 @@ describe('Output component', () => {
133164
},
134165
];
135166

136-
const { instance } = renderOutput(store, monaco);
167+
const { instance } = renderClassComponentWithInstanceRef(Output, {
168+
appState: store,
169+
monaco,
170+
monacoOptions: {},
171+
});
137172
// updateModel is private — cast needed to spy on it
138173
const spy = vi.spyOn(instance as any, 'updateModel');
139174

140-
instance.outputRef.current = 'ref' as any;
175+
// outputRef is private
176+
(instance as any).outputRef.current = 'ref';
141177
await instance.initMonaco();
142178

143-
// updateModel is private
144-
(instance as any).updateModel();
179+
await (instance as any).updateModel();
145180

146181
// new output
147182
store.output = [
@@ -159,13 +194,17 @@ describe('Output component', () => {
159194
});
160195

161196
it('handles componentDidUpdate', async () => {
162-
const { instance } = renderOutput(store, monaco);
197+
const { instance } = renderClassComponentWithInstanceRef(Output, {
198+
appState: store,
199+
monaco,
200+
monacoOptions: {},
201+
});
163202
const spy = vi.spyOn(instance, 'toggleConsole');
164203

165-
instance.outputRef.current = 'ref' as any;
204+
// outputRef and updateModel are private
205+
(instance as any).outputRef.current = 'ref';
166206
await instance.initMonaco();
167207

168-
// updateModel is private
169208
await (instance as any).updateModel();
170209
expect(spy).toHaveBeenCalled();
171210
});

tests/renderer/components/settings-electron-spec.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -292,10 +292,9 @@ describe('ElectronSettings component', () => {
292292
);
293293
store.hideChannels.mockImplementation((ids: ElectronReleaseChannel[]) =>
294294
runInAction(() => {
295-
for (const id of ids) {
296-
const idx = store.channelsToShow.indexOf(id);
297-
if (idx !== -1) store.channelsToShow.splice(idx, 1);
298-
}
295+
store.channelsToShow = store.channelsToShow.filter(
296+
(id: ElectronReleaseChannel) => !ids.includes(id),
297+
);
299298
}),
300299
);
301300

@@ -340,7 +339,7 @@ describe('ElectronSettings component', () => {
340339

341340
const disabledVersions = container.querySelectorAll('.disabled-version');
342341
expect(disabledVersions).toHaveLength(1);
343-
expect(disabledVersions[0]).toHaveClass('bp3-disabled');
342+
expect(disabledVersions[0]).toHaveAttribute('disabled');
344343
});
345344
});
346345
});

0 commit comments

Comments
 (0)