Skip to content

Commit 9449eec

Browse files
committed
test: migrate Editors tests to RTL
1 parent 1f38b72 commit 9449eec

File tree

5 files changed

+77
-1010
lines changed

5 files changed

+77
-1010
lines changed

rtl-spec/components/editors.spec.tsx

+45-41
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
import * as React from 'react';
2-
3-
import { mount, shallow } from 'enzyme';
4-
import { MosaicWindowProps } from 'react-mosaic-component';
1+
import { MosaicNode } from 'react-mosaic-component';
52

63
import { EditorId, EditorValues, MAIN_JS } from '../../src/interfaces';
74
import { App } from '../../src/renderer/app';
@@ -10,26 +7,24 @@ import { Editor, EditorMosaic } from '../../src/renderer/editor-mosaic';
107
import { AppState } from '../../src/renderer/state';
118
import {
129
MonacoEditorMock,
13-
MonacoMock,
1410
StateMock,
1511
createEditorValues,
1612
} from '../../tests/mocks/mocks';
1713
import { emitEvent } from '../../tests/utils';
14+
import { renderClassComponentWithInstanceRef } from '../test-utils/renderClassComponentWithInstanceRef';
1815

1916
jest.mock('../../src/renderer/components/editor', () => ({
2017
Editor: () => 'Editor',
2118
}));
2219

2320
describe('Editors component', () => {
2421
let app: App;
25-
let monaco: MonacoMock;
2622
let store: AppState;
2723
let editorMosaic: EditorMosaic;
2824
let editorValues: EditorValues;
2925

3026
beforeEach(() => {
3127
({ app } = window);
32-
monaco = window.monaco as unknown as MonacoMock;
3328
({ state: store } = window.app);
3429
editorValues = createEditorValues();
3530
editorMosaic = new EditorMosaic();
@@ -38,15 +33,20 @@ describe('Editors component', () => {
3833
(store as unknown as StateMock).editorMosaic = editorMosaic;
3934
});
4035

36+
function renderEditors() {
37+
return renderClassComponentWithInstanceRef(Editors, {
38+
appState: store,
39+
});
40+
}
41+
4142
it('renders', () => {
42-
const wrapper = mount(<Editors appState={store} />);
43-
wrapper.setState({ monaco });
44-
expect(wrapper).toMatchSnapshot();
43+
const { renderResult } = renderEditors();
44+
45+
expect(renderResult.getByTestId('editors')).toBeInTheDocument();
4546
});
4647

4748
it('does not execute command if not supported', () => {
48-
const wrapper = shallow(<Editors appState={store} />);
49-
const instance: any = wrapper.instance();
49+
const { instance } = renderEditors();
5050

5151
const editor = new MonacoEditorMock();
5252
const action = editor.getAction();
@@ -70,15 +70,13 @@ describe('Editors component', () => {
7070
throw new Error('Bwap bwap');
7171
});
7272

73-
const wrapper = shallow(<Editors appState={store} />);
74-
const instance: any = wrapper.instance();
73+
const { instance } = renderEditors();
7574

7675
expect(instance.toggleEditorOption('wordWrap')).toBe(false);
7776
});
7877

7978
it('updates a setting', () => {
80-
const wrapper = shallow(<Editors appState={store} />);
81-
const instance: any = wrapper.instance();
79+
const { instance } = renderEditors();
8280

8381
const editor = new MonacoEditorMock();
8482
editorMosaic.addEditor(filename, editor as unknown as Editor);
@@ -90,29 +88,35 @@ describe('Editors component', () => {
9088
});
9189
});
9290

93-
it('renders a toolbar', () => {
94-
const wrapper = shallow(<Editors appState={store} />);
95-
const instance: any = wrapper.instance();
96-
const toolbar = instance.renderToolbar(
97-
{ title: MAIN_JS } as MosaicWindowProps<EditorId>,
98-
MAIN_JS,
99-
);
100-
101-
expect(toolbar).toMatchSnapshot();
91+
it('renders toolbars', () => {
92+
const { renderResult } = renderEditors();
93+
94+
const [
95+
mainToolbar,
96+
rendererToolbar,
97+
htmlToolbar,
98+
preloadToolbar,
99+
stylesheetToolbar,
100+
] = renderResult.getAllByTestId('editors-toolbar');
101+
102+
expect(mainToolbar).toHaveTextContent('Main Process (main.js)');
103+
expect(rendererToolbar).toHaveTextContent('Renderer Process (renderer.js)');
104+
expect(htmlToolbar).toHaveTextContent('HTML (index.html)');
105+
expect(preloadToolbar).toHaveTextContent('Preload (preload.js)');
106+
expect(stylesheetToolbar).toHaveTextContent('Stylesheet (styles.css)');
102107
});
103108

104109
it('onChange() updates the mosaic arrangement in the appState', () => {
105-
const wrapper = shallow(<Editors appState={store} />);
106-
const instance: any = wrapper.instance();
110+
const { instance } = renderEditors();
107111

108-
const arrangement = { testArrangement: true };
109-
instance.onChange(arrangement as any);
112+
const arrangement: MosaicNode<EditorId> = 'testArrangement.js';
113+
instance.onChange(arrangement);
110114
expect(editorMosaic.mosaic).toStrictEqual(arrangement);
111115
});
112116

113117
describe('events', () => {
114118
it('handles a "execute-monaco-command" event', () => {
115-
shallow(<Editors appState={store} />);
119+
renderEditors();
116120

117121
const editor = new MonacoEditorMock();
118122
const action = editor.getAction();
@@ -129,7 +133,7 @@ describe('Editors component', () => {
129133
const fakeValues = { [MAIN_JS]: 'hi' } as const;
130134

131135
it('handles a "new-fiddle" event', async () => {
132-
shallow(<Editors appState={store} />);
136+
renderEditors();
133137

134138
let resolve: (value?: unknown) => void;
135139
const replacePromise = new Promise((r) => {
@@ -162,7 +166,7 @@ describe('Editors component', () => {
162166

163167
describe('"select-all-in-editor" handler', () => {
164168
it('selects all in the focused editor', async () => {
165-
shallow(<Editors appState={store} />);
169+
renderEditors();
166170

167171
const range = 'range';
168172
const editor = new MonacoEditorMock();
@@ -177,7 +181,7 @@ describe('Editors component', () => {
177181
});
178182

179183
it('does not change selection if the selected editor has no model', async () => {
180-
shallow(<Editors appState={store} />);
184+
renderEditors();
181185

182186
const editor = new MonacoEditorMock();
183187
delete (editor as any).model;
@@ -191,14 +195,14 @@ describe('Editors component', () => {
191195
});
192196

193197
it('does not crash if there is no selected editor', () => {
194-
shallow(<Editors appState={store} />);
198+
renderEditors();
195199
editorMosaic.focusedEditor = jest.fn().mockReturnValue(null);
196200
emitEvent('select-all-in-editor');
197201
});
198202
});
199203

200204
it('handles a "new-test" event', async () => {
201-
shallow(<Editors appState={store} />);
205+
renderEditors();
202206

203207
// setup
204208
const getTestTemplateSpy = jest
@@ -229,7 +233,7 @@ describe('Editors component', () => {
229233
});
230234

231235
it('handles a "select-all-in-editor" event', async () => {
232-
shallow(<Editors appState={store} />);
236+
renderEditors();
233237

234238
const range = 'range';
235239
const editor = new MonacoEditorMock();
@@ -247,16 +251,16 @@ describe('Editors component', () => {
247251
const editor = new MonacoEditorMock();
248252
editorMosaic.addEditor(id, editor as unknown as Editor);
249253

250-
shallow(<Editors appState={store} />);
254+
renderEditors();
251255
emitEvent('toggle-monaco-option', 'wordWrap');
252256
expect(editor.updateOptions).toHaveBeenCalled();
253257
});
254258
});
255259

256260
describe('setFocused()', () => {
257261
it('sets the "focused" property', () => {
258-
const wrapper = shallow(<Editors appState={store} />);
259-
const instance: any = wrapper.instance();
262+
const { instance } = renderEditors();
263+
260264
const spy = jest.spyOn(instance, 'setState');
261265

262266
const id = MAIN_JS;
@@ -265,8 +269,8 @@ describe('Editors component', () => {
265269
});
266270

267271
it('focus sidebar file', () => {
268-
const wrapper = shallow(<Editors appState={store} />);
269-
const instance: any = wrapper.instance();
272+
const { instance } = renderEditors();
273+
270274
const spy = jest.spyOn(instance, 'setState');
271275

272276
const id = MAIN_JS;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import React, { PropsWithChildren } from 'react';
2+
3+
type TestIdContainerProps = PropsWithChildren<{
4+
testId: string;
5+
}>;
6+
7+
/**
8+
* A wrapper for third-party components that don't allow us to pass arbitrary
9+
* DOM attributes like `data-testid`. It uses `display: contents` in the
10+
* wrapping `div` so it has no CSS side effects.
11+
*/
12+
export function TestIdContainer({ testId, children }: TestIdContainerProps) {
13+
return (
14+
<div data-testid={testId} style={{ display: 'contents' }}>
15+
{children}
16+
</div>
17+
);
18+
}

src/renderer/components/editors.tsx

+11-8
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
import { Editor } from './editor';
1414
import { renderNonIdealState } from './editors-non-ideal-state';
1515
import { MaximizeButton, RemoveButton } from './editors-toolbar-button';
16+
import { TestIdContainer } from './TestIdContainer';
1617
import { EditorId, SetFiddleOptions } from '../../interfaces';
1718
import { AppState } from '../state';
1819
import { getEditorTitle } from '../utils/editor-utils';
@@ -191,7 +192,7 @@ export const Editors = observer(
191192
const { appState } = this.props;
192193

193194
return (
194-
<div>
195+
<div data-testid="editors-toolbar">
195196
{/* Left */}
196197
<div>
197198
<h5>{title}</h5>
@@ -258,13 +259,15 @@ export const Editors = observer(
258259
const { editorMosaic } = this.props.appState;
259260

260261
return (
261-
<Mosaic<EditorId>
262-
className={`focused__${this.state.focused}`}
263-
onChange={this.onChange}
264-
value={editorMosaic.mosaic}
265-
zeroStateView={renderNonIdealState(editorMosaic)}
266-
renderTile={this.renderTile}
267-
/>
262+
<TestIdContainer testId="editors">
263+
<Mosaic<EditorId>
264+
className={`focused__${this.state.focused}`}
265+
onChange={this.onChange}
266+
value={editorMosaic.mosaic}
267+
zeroStateView={renderNonIdealState(editorMosaic)}
268+
renderTile={this.renderTile}
269+
/>
270+
</TestIdContainer>
268271
);
269272
}
270273

src/renderer/components/tour-welcome.tsx

+3-5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as React from 'react';
33
import { Button, Classes, Dialog } from '@blueprintjs/core';
44
import { observer } from 'mobx-react';
55

6+
import { TestIdContainer } from './TestIdContainer';
67
import { Tour, TourScriptStep, TourStepGetButtonParams } from './tour';
78
import { AppState } from '../state';
89

@@ -238,10 +239,7 @@ export const WelcomeTour = observer(
238239
if (!isTourStarted) {
239240
return (
240241
<Dialog key="welcome-tour-dialog" isOpen={true}>
241-
<div
242-
data-testid="welcome-tour-dialog"
243-
style={{ display: 'contents' }}
244-
>
242+
<TestIdContainer testId="welcome-tour-dialog">
245243
<div className={Classes.DIALOG_HEADER}>
246244
<h4 className={Classes.HEADING}>🙋‍ Hey There!</h4>
247245
</div>
@@ -260,7 +258,7 @@ export const WelcomeTour = observer(
260258
{this.buttons}
261259
</div>
262260
</div>
263-
</div>
261+
</TestIdContainer>
264262
</Dialog>
265263
);
266264
} else {

0 commit comments

Comments
 (0)