Repository: electron/fiddle
Pull request #679 (2021-04-30 18:02:05)

refactor: add EditorMosaic class
Part 4 of breaking #664 into smaller, human-reviewable pieces.

This one is a very incremental change: replace `window.ElectronFiddle.editors` with `appState.editorMosaic`, which is a new class which just holds a `Map<EditorId, Monaco.editor.IStandaloneCodeEditor`. That's all! global -> non-global + Record -> Map. The important thing for future parts is that now there is a logical place to start consolidating mosaic code.

Structurally this is a _really_ simple PR. The diff is because snapshots feel every ripple in the mocks, and we've added a new class to the mocks. So don't be afraid of the diff size; this isn't 2K LOC being added :smile_cat: 

Biggest 10 file changes:

```
17	2	tests/mocks/state.ts
18	5	tests/utils/editor-backup-spec.ts
21	26	src/renderer/app.tsx
24	41	tests/renderer/app-spec.tsx
25	36	tests/utils/editor-value-spec.ts
27	23	tests/utils/focused-editor-spec.ts
100	0	tests/renderer/components/__snapshots__/commands-version-chooser-spec.tsx.snap
200	0	tests/renderer/components/__snapshots__/editors-spec.tsx.snap
500	0	tests/renderer/components/__snapshots__/commands-spec.tsx.snap
1000	0	tests/renderer/components/__snapshots__/dialog-bisect-spec.tsx.snap
```

coveralls: 
[![Coverage Status](https://coveralls.io/builds/39269470/badge)](https://coveralls.io/builds/39269470)

Coverage increased (+0.03%) to 95.975% when pulling **e8a5cf7cf5c507c446b2b3f82a12f7a260cffd4b on refactor/add-editor-mosaic** into **55ca77750807e268e556b2e1314c9f4c42b40327 on master**.


Patch:
diff --git a/src/ambient.d.ts b/src/ambient.d.ts
index ed3db63a..8952714e 100644
--- a/src/ambient.d.ts
+++ b/src/ambient.d.ts
@@ -1,8 +1,5 @@
-import * as MonacoType from 'monaco-editor';
-
 // Type-only-import
 import { App as AppType } from './renderer/app';
-import { EditorId } from './interfaces';
 
 declare global {
   interface Window {
@@ -10,10 +7,6 @@ declare global {
       appPaths: Record<string, string>;
       app: AppType;
       contentChangeListeners: Array<any>;
-      editors: Record<
-        EditorId,
-        MonacoType.editor.IStandaloneCodeEditor | null | undefined
-      >;
     };
   }
 }
diff --git a/src/renderer/app.tsx b/src/renderer/app.tsx
index dd8280bd..95b400e1 100644
--- a/src/renderer/app.tsx
+++ b/src/renderer/app.tsx
@@ -7,12 +7,11 @@ import * as MonacoType from 'monaco-editor';
 import { ipcRenderer } from 'electron';
 import {
   DefaultEditorId,
+  EditorId,
   EditorValues,
   GenericDialogType,
-  SetFiddleOptions,
-  EditorId,
   PACKAGE_NAME,
-  DEFAULT_EDITORS,
+  SetFiddleOptions,
 } from '../interfaces';
 import { WEBCONTENTS_READY_FOR_IPC_SIGNAL } from '../ipc-events';
 import { updateEditorLayout } from '../utils/editor-layout';
@@ -114,27 +113,23 @@ export class App {
     }
 
     // Set content for mosaics.
-    const allEditors = [...this.state.customMosaics, ...DEFAULT_EDITORS];
-    for (const name of allEditors) {
-      const editor = fiddle.editors[name];
-      if (typeof values[name] !== 'undefined') {
-        const backup = this.state.closedPanels[name];
-        if (backup) {
-          // The editor does not exist, attempt to set it on the backup.
-          // If there's a model, we'll do it on the model. Else, we'll
-          // set the value.
-
-          if (backup.model) {
-            backup.model.setValue(values[name]!);
-          } else {
-            backup.value = values[name]!;
-          }
-        } else if (editor?.setValue) {
-          // The editor exists, set the value directly
-          const newValue = values[name]!;
-          if (!editor.getValue || editor.getValue() !== newValue) {
-            editor.setValue(newValue);
-          }
+    const { closedPanels, editorMosaic } = this.state;
+    for (const [name, content] of Object.entries(values)) {
+      const backup = closedPanels[name];
+      if (backup) {
+        // The editor does not exist, attempt to set it on the backup.
+        // If there's a model, we'll do it on the model. Else, we'll
+        // set the value.
+        if (backup.model) {
+          backup.model.setValue(values[name]!);
+        } else {
+          backup.value = values[name]!;
+        }
+      } else {
+        const editor = editorMosaic.editors.get(name as EditorId);
+        // The editor exists, set the value directly
+        if (editor && editor.getValue() !== content) {
+          editor.setValue(content as string);
         }
       }
     }
@@ -155,8 +150,8 @@ export class App {
     }
 
     const values: EditorValues = {};
-    for (const editor in fiddle?.editors) {
-      values[editor] = getEditorValue(editor as EditorId);
+    for (const name of this.state.editorMosaic.editors.keys()) {
+      values[name] = getEditorValue(name);
     }
 
     if (options && options.include !== false) {
diff --git a/src/renderer/components/editor.tsx b/src/renderer/components/editor.tsx
index 61146f2c..a1dafd9b 100644
--- a/src/renderer/components/editor.tsx
+++ b/src/renderer/components/editor.tsx
@@ -55,13 +55,13 @@ export class Editor extends React.Component<EditorProps> {
    * @param {MonacoType.editor.IStandaloneCodeEditor} editor
    */
   public async editorDidMount(editor: MonacoType.editor.IStandaloneCodeEditor) {
-    const { editorDidMount } = this.props;
+    const { appState, editorDidMount, id } = this.props;
 
     // Set the content on the editor.
     await this.setContent();
 
     // Set the editor as an available object.
-    window.ElectronFiddle.editors[this.props.id] = editor;
+    appState.editorMosaic.editors.set(id, editor);
 
     // And notify others
     if (editorDidMount) {
diff --git a/src/renderer/components/editors.tsx b/src/renderer/components/editors.tsx
index f2a6422c..9a7ddb31 100644
--- a/src/renderer/components/editors.tsx
+++ b/src/renderer/components/editors.tsx
@@ -151,10 +151,6 @@ export class Editors extends React.Component<EditorsProps, EditorsState> {
   }
 
   public toggleEditorOption(path: string): boolean {
-    if (!window.ElectronFiddle.editors) {
-      return false;
-    }
-
     try {
       const { monacoOptions } = this.state;
       const newOptions = { ...monacoOptions };
@@ -162,14 +158,10 @@ export class Editors extends React.Component<EditorsProps, EditorsState> {
 
       setAtPath(path, newOptions, toggleMonaco(currentSetting));
 
-      Object.keys(window.ElectronFiddle.editors).forEach((key) => {
-        const editor: MonacoType.editor.IStandaloneCodeEditor | null =
-          window.ElectronFiddle.editors[key];
-
-        if (editor) {
-          editor.updateOptions(newOptions);
-        }
-      });
+      const { editorMosaic } = window.ElectronFiddle.app.state;
+      for (const editor of editorMosaic.editors.values()) {
+        editor.updateOptions(newOptions);
+      }
 
       this.setState({ monacoOptions: newOptions });
 
diff --git a/src/renderer/editor-mosaic.ts b/src/renderer/editor-mosaic.ts
new file mode 100644
index 00000000..30efa2f9
--- /dev/null
+++ b/src/renderer/editor-mosaic.ts
@@ -0,0 +1,10 @@
+import * as MonacoType from 'monaco-editor';
+import { observable } from 'mobx';
+
+import { EditorId } from '../interfaces';
+
+export type Editor = MonacoType.editor.IStandaloneCodeEditor;
+
+export class EditorMosaic {
+  @observable public readonly editors: Map<EditorId, Editor> = new Map();
+}
diff --git a/src/renderer/state.ts b/src/renderer/state.ts
index 8db7950d..2338e1e5 100644
--- a/src/renderer/state.ts
+++ b/src/renderer/state.ts
@@ -1,4 +1,5 @@
 import * as fs from 'fs-extra';
+import * as MonacoType from 'monaco-editor';
 import semver from 'semver';
 import { action, autorun, computed, observable, when } from 'mobx';
 import { MosaicNode } from 'react-mosaic-component';
@@ -30,6 +31,7 @@ import { getName } from '../utils/get-name';
 import { normalizeVersion } from '../utils/normalize-version';
 import { removeBinary, setupBinary } from './binary';
 import { Bisector } from './bisect';
+import { EditorMosaic } from './editor-mosaic';
 import { DEFAULT_CLOSED_PANELS, DEFAULT_MOSAIC_ARRANGEMENT } from './constants';
 import { getTemplate, isContentUnchanged } from './content';
 import {
@@ -52,6 +54,8 @@ import {
   saveLocalVersions,
 } from './versions';
 
+export type Editor = MonacoType.editor.IStandaloneCodeEditor;
+
 /**
  * The application's state. Exported as a singleton below.
  *
@@ -126,6 +130,7 @@ export class AppState {
     wantsInput: false,
     placeholder: '',
   };
+  @observable public readonly editorMosaic = new EditorMosaic();
   @observable public customMosaics: EditorId[] = [];
   @observable public genericDialogLastResult: boolean | null = null;
   @observable public genericDialogLastInput: string | null = null;
@@ -275,11 +280,9 @@ export class AppState {
         window.onbeforeunload = null;
 
         // set up editor listeners to verify if unsaved
-        const ids = DEFAULT_EDITORS.filter(
-          (id) => id in window.ElectronFiddle.editors,
-        );
-        await waitForEditorsToMount(ids);
-        for (const editor of Object.values(window.ElectronFiddle.editors)) {
+        const { editors } = this.editorMosaic;
+        await waitForEditorsToMount([...editors.keys()]);
+        for (const editor of editors.values()) {
           const disposable = (editor as any).onDidChangeModelContent(() => {
             this.isUnsaved = true;
             disposable.dispose();
@@ -682,14 +685,14 @@ export class AppState {
   }
 
   @action public async setVisibleMosaics(visible: Array<EditorId>) {
-    const { editors } = window.ElectronFiddle;
-    const currentlyVisible = getVisibleMosaics(this.mosaicArrangement);
+    const { editorMosaic, mosaicArrangement } = this;
+    const currentlyVisible = getVisibleMosaics(mosaicArrangement);
 
     for (const id of DEFAULT_EDITORS) {
       if (!visible.includes(id) && currentlyVisible.includes(id)) {
         this.closedPanels[id] = getEditorBackup(id);
         // if we have backup, remove active editor
-        delete editors[id];
+        editorMosaic.editors.delete(id);
       }
     }
 
@@ -726,7 +729,7 @@ export class AppState {
    */
   @action public removeCustomMosaic(id: EditorId) {
     this.hideAndBackupMosaic(id);
-    delete window.ElectronFiddle.editors[id];
+    this.editorMosaic.editors.delete(id);
     this.customMosaics = this.customMosaics.filter((mosaic) => mosaic !== id);
   }
 
diff --git a/src/utils/editor-layout.ts b/src/utils/editor-layout.ts
index 0cc08245..3aa1027f 100644
--- a/src/utils/editor-layout.ts
+++ b/src/utils/editor-layout.ts
@@ -3,11 +3,8 @@
  * a debounced version below.
  */
 function _updateEditorLayout() {
-  Object.keys(window.ElectronFiddle.editors).forEach((key) => {
-    if (window.ElectronFiddle.editors[key]) {
-      window.ElectronFiddle.editors[key].layout();
-    }
-  });
+  const { editorMosaic } = window.ElectronFiddle.app.state;
+  editorMosaic.editors.forEach((editor) => editor.layout());
 }
 
 let handle: number;
diff --git a/src/utils/editor-model.ts b/src/utils/editor-model.ts
index f5b79fcc..bf5c0861 100644
--- a/src/utils/editor-model.ts
+++ b/src/utils/editor-model.ts
@@ -9,14 +9,11 @@ import { EditorId } from '../interfaces';
  * @returns {editor.ITextModel | null}
  */
 export function getEditorModel(id: EditorId): editor.ITextModel | null {
-  const { ElectronFiddle: fiddle } = window;
+  if (window.ElectronFiddle?.app?.state) {
+    const { editorMosaic } = window.ElectronFiddle.app.state;
 
-  if (!fiddle?.editors) {
-    return null;
-  }
-
-  if (fiddle.editors[id] && fiddle.editors[id]!.getModel) {
-    return fiddle.editors[id]!.getModel();
+    const editor = editorMosaic.editors.get(id);
+    if (editor) return editor.getModel();
   }
 
   return null;
diff --git a/src/utils/editor-mounted.ts b/src/utils/editor-mounted.ts
index 4ce4a314..e9f195f4 100644
--- a/src/utils/editor-mounted.ts
+++ b/src/utils/editor-mounted.ts
@@ -6,9 +6,9 @@ import { waitFor } from './wait-for';
  * Waits for editors to mount on a list of Mosaic IDs
  * @param editors
  */
-export function waitForEditorsToMount(editors: Array<EditorId>) {
-  const allMounted = () =>
-    editors.every((id) => !!window.ElectronFiddle.editors[id]);
+export function waitForEditorsToMount(files: EditorId[]) {
+  const { editorMosaic } = window.ElectronFiddle.app.state;
+  const allMounted = () => files.every((id) => editorMosaic.editors.has(id));
   const opts = { timeout: 3000, interval: 100 };
   return waitFor(allMounted, opts).catch((error) => {
     throw `Can't mount editors onto mosaics. ${error.toString()}`;
diff --git a/src/utils/editor-value.ts b/src/utils/editor-value.ts
index 40b96704..7f2e9d40 100644
--- a/src/utils/editor-value.ts
+++ b/src/utils/editor-value.ts
@@ -1,5 +1,4 @@
 import { EditorId } from '../interfaces';
-import { EditorBackup } from './editor-backup';
 
 /**
  * Return the value for a given editor
@@ -8,19 +7,14 @@ import { EditorBackup } from './editor-backup';
  * @returns {string}
  */
 export function getEditorValue(id: EditorId): string {
-  const { ElectronFiddle: fiddle } = window;
+  if (window.ElectronFiddle?.app?.state) {
+    const { closedPanels, editorMosaic } = window.ElectronFiddle.app.state;
 
-  if (!fiddle?.editors) {
-    return '';
-  }
-
-  const editor = fiddle.editors[id];
-  const backup = fiddle.app?.state?.closedPanels[id] as EditorBackup;
+    const editor = editorMosaic.editors.get(id);
+    if (editor) return editor.getValue();
 
-  if (editor?.getValue) {
-    return fiddle.editors[id]!.getValue();
-  } else if (backup?.value) {
-    return backup.value;
+    const backup = closedPanels[id];
+    if (backup?.value) return backup.value;
   }
 
   return '';
diff --git a/src/utils/editor-viewstate.ts b/src/utils/editor-viewstate.ts
index dca8e0d3..846a73d5 100644
--- a/src/utils/editor-viewstate.ts
+++ b/src/utils/editor-viewstate.ts
@@ -12,15 +12,9 @@ import { EditorId } from '../interfaces';
 export function getEditorViewState(
   id: EditorId,
 ): editor.ICodeEditorViewState | null {
-  const { ElectronFiddle: fiddle } = window;
-
-  if (!fiddle?.editors) {
-    return null;
-  }
-
-  if (fiddle.editors[id] && fiddle.editors[id]!.saveViewState) {
-    return fiddle.editors[id]!.saveViewState();
-  }
-
-  return null;
+  return (
+    window.ElectronFiddle?.app?.state.editorMosaic.editors
+      .get(id)
+      ?.saveViewState() || null
+  );
 }
diff --git a/src/utils/focused-editor.ts b/src/utils/focused-editor.ts
index 8eac92d1..ea65b1f2 100644
--- a/src/utils/focused-editor.ts
+++ b/src/utils/focused-editor.ts
@@ -1,16 +1,18 @@
-import * as MonacoType from 'monaco-editor';
+import { Editor } from '../renderer/state';
 
 /**
  * Returns the currently focused editor.
  *
  * @returns {(MonacoType.editor.IStandaloneCodeEditor | null)}
  */
-export function getFocusedEditor(): MonacoType.editor.IStandaloneCodeEditor | null {
-  const focusedKey = Object.keys(window.ElectronFiddle.editors).find((key) => {
-    const editor: MonacoType.editor.IStandaloneCodeEditor =
-      window.ElectronFiddle.editors[key];
-    return editor && editor.hasTextFocus && editor.hasTextFocus();
-  });
+export function getFocusedEditor(): Editor | null {
+  const { editorMosaic } = window.ElectronFiddle.app.state;
 
-  return focusedKey ? window.ElectronFiddle.editors[focusedKey] : null;
+  for (const editor of editorMosaic.editors.values()) {
+    if (editor.hasTextFocus()) {
+      return editor;
+    }
+  }
+
+  return null;
 }


Test patch:
diff --git a/tests/mocks/editor-mosaic.ts b/tests/mocks/editor-mosaic.ts
new file mode 100644
index 00000000..d7249921
--- /dev/null
+++ b/tests/mocks/editor-mosaic.ts
@@ -0,0 +1,10 @@
+import { MonacoEditorMock } from './monaco-editor';
+import { observable } from 'mobx';
+
+import { EditorId } from '../../src/interfaces';
+
+export type Editor = MonacoEditorMock;
+
+export class EditorMosaicMock {
+  @observable public readonly editors: Map<EditorId, Editor> = new Map();
+}
diff --git a/tests/mocks/editors.ts b/tests/mocks/editors.ts
deleted file mode 100644
index a130eb15..00000000
--- a/tests/mocks/editors.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { DefaultEditorId } from '../../src/interfaces';
-
-export class EditorMock {
-  public layout = jest.fn();
-  public hasTextFocus = jest.fn();
-  public getModel = jest.fn().mockReturnValue({ testModel: true });
-  public restoreViewState = jest.fn();
-  public saveViewState = jest.fn().mockReturnValue({ testViewState: true });
-  public setValue = jest.fn();
-  public getValue = jest.fn().mockReturnValue('editor-value');
-  public onDidChangeModelContent = jest.fn().mockReturnValue({
-    dispose: jest.fn(),
-  });
-  public updateOptions = jest.fn();
-
-  constructor(public readonly name: string) {}
-}
-
-export class EditorsMock {
-  public [DefaultEditorId.main] = new EditorMock(DefaultEditorId.main);
-  public [DefaultEditorId.renderer] = new EditorMock(DefaultEditorId.renderer);
-  public [DefaultEditorId.html] = new EditorMock(DefaultEditorId.html);
-  public [DefaultEditorId.preload] = new EditorMock(DefaultEditorId.preload);
-}
diff --git a/tests/mocks/electron-fiddle.ts b/tests/mocks/electron-fiddle.ts
index a23733ed..4fd4debb 100644
--- a/tests/mocks/electron-fiddle.ts
+++ b/tests/mocks/electron-fiddle.ts
@@ -1,9 +1,7 @@
 import { AppMock } from './app';
-import { EditorsMock } from './editors';
 
 export class ElectronFiddleMock {
   public app = new AppMock();
-  public editors = new EditorsMock();
   public appPaths = {
     userData: '/fake/path',
     home: `~`,
diff --git a/tests/mocks/mocks.ts b/tests/mocks/mocks.ts
index a260304d..2227127e 100644
--- a/tests/mocks/mocks.ts
+++ b/tests/mocks/mocks.ts
@@ -3,7 +3,7 @@ import { AppMock } from './app';
 import { BisectorMock } from './bisector';
 import { BrowserWindowMock } from './browser-window';
 import { ChildProcessMock } from './child-process';
-import { EditorsMock } from './editors';
+import { EditorMosaicMock } from './editor-mosaic';
 import { ElectronFiddleMock } from './electron-fiddle';
 import { FileManagerMock } from './file-manager';
 import { MonacoEditorMock } from './monaco-editor';
@@ -26,7 +26,7 @@ export {
   BisectorMock,
   BrowserWindowMock,
   ChildProcessMock,
-  EditorsMock,
+  EditorMosaicMock,
   ElectronFiddleMock,
   FileManagerMock,
   IPCMainMock,
diff --git a/tests/mocks/monaco-editor.ts b/tests/mocks/monaco-editor.ts
index 47b027f2..fda32ef1 100644
--- a/tests/mocks/monaco-editor.ts
+++ b/tests/mocks/monaco-editor.ts
@@ -1,9 +1,9 @@
 export class MonacoEditorMock {
-  private action = {
+  public action = {
     isSupported: jest.fn(),
     run: jest.fn(),
   };
-  private model = {
+  public model = {
     getFullModelRange: jest.fn(),
   };
   public value = '';
diff --git a/tests/mocks/state.ts b/tests/mocks/state.ts
index 7f880774..35d12c55 100644
--- a/tests/mocks/state.ts
+++ b/tests/mocks/state.ts
@@ -3,6 +3,7 @@ import { MosaicNode } from 'react-mosaic-component';
 
 import {
   BlockableAccelerator,
+  DefaultEditorId,
   EditorId,
   ElectronReleaseChannel,
   GenericDialogOptions,
@@ -12,6 +13,8 @@ import {
 import { EditorBackup } from '../../src/utils/editor-backup';
 
 import { BisectorMock } from './bisector';
+import { EditorMosaicMock } from './editor-mosaic';
+import { MonacoEditorMock } from './monaco-editor';
 import { VersionsMock } from './electron-versions';
 
 export class StateMock {
@@ -21,7 +24,6 @@ export class StateMock {
   @observable public closedPanels: Partial<
     Record<EditorId, EditorBackup | true>
   > = {};
-  @observable public customMosaics: EditorId[] = [];
   @observable public environmentVariables: string[] = [];
   @observable public executionFlags: string[] = [];
   @observable public genericDialogLastInput: string | null = null;
@@ -47,7 +49,6 @@ export class StateMock {
   @observable public isTourShowing = false;
   @observable public isUsingSystemTheme = true;
   @observable public isWarningDialogShowing = false;
-  @observable public mosaicArrangement: MosaicNode<EditorId> | null = null;
   @observable public output = [];
   @observable public showUndownloadedVersions = false;
   @observable public theme: string | null;
@@ -56,6 +57,11 @@ export class StateMock {
   @observable public versions: Record<string, RunnableVersion>;
   @observable public versionsToShow: RunnableVersion[] = [];
 
+  // editor mosaic
+  @observable public customMosaics: EditorId[] = [];
+  @observable public editorMosaic = new EditorMosaicMock();
+  @observable public mosaicArrangement: MosaicNode<EditorId> | null = null;
+
   public Bisector = new BisectorMock();
   public addAcceleratorToBlock = jest.fn();
   public addLocalVersion = jest.fn();
@@ -97,6 +103,15 @@ export class StateMock {
     this.versions = obj;
     this.currentElectronVersion = arr[arr.length - 1];
     this.version = this.currentElectronVersion.version;
+
+    for (const filename of [
+      DefaultEditorId.main,
+      DefaultEditorId.renderer,
+      DefaultEditorId.html,
+      DefaultEditorId.preload,
+    ]) {
+      this.editorMosaic.editors.set(filename, new MonacoEditorMock());
+    }
   }
 
   public initVersions(
diff --git a/tests/renderer/app-spec.tsx b/tests/renderer/app-spec.tsx
index 7f3892ee..d5c267fa 100644
--- a/tests/renderer/app-spec.tsx
+++ b/tests/renderer/app-spec.tsx
@@ -1,7 +1,11 @@
 import { App } from '../../src/renderer/app';
 import { EditorBackup } from '../../src/utils/editor-backup';
 import { waitFor } from '../../src/utils/wait-for';
-import { DefaultEditorId, PACKAGE_NAME } from '../../src/interfaces';
+import {
+  DefaultEditorId,
+  EditorValues,
+  PACKAGE_NAME,
+} from '../../src/interfaces';
 import { defaultDark, defaultLight } from '../../src/renderer/themes-defaults';
 
 jest.mock('../../src/renderer/components/header', () => ({
@@ -17,6 +21,7 @@ jest.mock('../../src/renderer/components/output-editors-wrapper', () => ({
 describe('App component', () => {
   let app: App;
   let ElectronFiddle: any;
+  let editorMosaic: any;
 
   beforeAll(() => {
     document.body.innerHTML = '<div id="app" />';
@@ -24,6 +29,7 @@ describe('App component', () => {
 
   beforeEach(() => {
     ({ ElectronFiddle } = window as any);
+    ({ editorMosaic } = ElectronFiddle.app.state);
 
     // make a real App and inject it into the mocks
     app = new App();
@@ -68,29 +74,18 @@ describe('App component', () => {
 
   describe('getEditorValues()', () => {
     it('gets values', async () => {
+      const value = 'editor-value';
+      for (const editor of editorMosaic.editors.values()) {
+        editor.getValue.mockReturnValue(value);
+      }
       const b = await app.getEditorValues({});
-      expect(b[DefaultEditorId.html]).toBe('editor-value');
-      expect(b[DefaultEditorId.main]).toBe('editor-value');
-      expect(b[DefaultEditorId.renderer]).toBe('editor-value');
+      expect(b[DefaultEditorId.html]).toBe(value);
+      expect(b[DefaultEditorId.main]).toBe(value);
+      expect(b[DefaultEditorId.renderer]).toBe(value);
       expect(b[PACKAGE_NAME]).toBeTruthy();
       expect(JSON.parse(b[PACKAGE_NAME]!)).toBeTruthy();
     });
 
-    it('handles missing editors', async () => {
-      ElectronFiddle.editors[DefaultEditorId.html] = null;
-      ElectronFiddle.editors[DefaultEditorId.main] = null;
-      ElectronFiddle.editors[DefaultEditorId.renderer] = null;
-
-      const app = new App();
-      const result = await app.getEditorValues({});
-
-      expect(result[DefaultEditorId.html]).toBe('');
-      expect(result[DefaultEditorId.main]).toBe('');
-      expect(result[DefaultEditorId.renderer]).toBe('');
-      expect(result[PACKAGE_NAME]).toBeTruthy();
-      expect(JSON.parse(result[PACKAGE_NAME]!)).toBeTruthy();
-    });
-
     it('throws if the Fiddle object is not present', async () => {
       const app = new App();
 
@@ -312,29 +307,21 @@ describe('App component', () => {
 
   describe('setEditorValues()', () => {
     it('attempts to set values', () => {
-      app.setEditorValues({
+      const editorValues: EditorValues = {
         [DefaultEditorId.html]: 'html-value',
         [DefaultEditorId.main]: 'main-value',
         [DefaultEditorId.renderer]: 'renderer-value',
-      });
+      } as const;
+      app.setEditorValues(editorValues);
 
-      expect(
-        (window as any).ElectronFiddle.editors[DefaultEditorId.html].setValue,
-      ).toHaveBeenCalledWith('html-value');
-      expect(
-        (window as any).ElectronFiddle.editors[DefaultEditorId.main].setValue,
-      ).toHaveBeenCalledWith('main-value');
-      expect(
-        (window as any).ElectronFiddle.editors[DefaultEditorId.renderer]
-          .setValue,
-      ).toHaveBeenCalledWith('renderer-value');
+      for (const [filename, value] of Object.entries(editorValues)) {
+        const editor = editorMosaic.editors.get(filename);
+        expect(editor.setValue).toHaveBeenCalledWith(value);
+      }
     });
 
     it('attempts to set values for closed editors', () => {
-      const { editors } = ElectronFiddle;
-
-      const oldMainEditor = editors[DefaultEditorId.main];
-      delete editors[DefaultEditorId.main];
+      editorMosaic.editors.delete(DefaultEditorId.main);
 
       (app.state.closedPanels as any)[DefaultEditorId.main] = {
         model: { setValue: jest.fn() },
@@ -360,8 +347,6 @@ describe('App component', () => {
       expect(app.state.closedPanels[DefaultEditorId.css]).toEqual({
         value: 'css-value',
       });
-
-      editors[DefaultEditorId.main] = oldMainEditor;
     });
 
     it('throws if the Fiddle object is not present', async () => {
@@ -386,10 +371,8 @@ describe('App component', () => {
         [DefaultEditorId.main]: 'main-value',
       });
 
-      expect(
-        (window as any).ElectronFiddle.editors[DefaultEditorId.renderer]
-          .setValue,
-      ).not.toHaveBeenCalled();
+      const editor = editorMosaic.editors.get(DefaultEditorId.renderer);
+      expect(editor.setValue).not.toHaveBeenCalled();
     });
   });
 
diff --git a/tests/renderer/components/__snapshots__/commands-spec.tsx.snap b/tests/renderer/components/__snapshots__/commands-spec.tsx.snap
index cd1bff7f..8b1f59ce 100644
--- a/tests/renderer/components/__snapshots__/commands-spec.tsx.snap
+++ b/tests/renderer/components/__snapshots__/commands-spec.tsx.snap
@@ -32,6 +32,106 @@ exports[`Commands component renders 1`] = `
             "customMosaics": Array [],
             "disableTour": [MockFunction],
             "downloadVersion": [MockFunction],
+            "editorMosaic": EditorMosaicMock {
+              "editors": Object {
+                "index.html": MonacoEditorMock {
+                  "action": Object {
+                    "isSupported": [MockFunction],
+                    "run": [MockFunction],
+                  },
+                  "dispose": [MockFunction],
+                  "getAction": [MockFunction],
+                  "getModel": [MockFunction],
+                  "getValue": [MockFunction],
+                  "hasTextFocus": [MockFunction],
+                  "layout": [MockFunction],
+                  "model": Object {
+                    "getFullModelRange": [MockFunction],
+                  },
+                  "onDidChangeModelContent": [MockFunction],
+                  "onDidFocusEditorText": [MockFunction],
+                  "restoreViewState": [MockFunction],
+                  "saveViewState": [MockFunction],
+                  "setModel": [MockFunction],
+                  "setSelection": [MockFunction],
+                  "setValue": [MockFunction],
+                  "updateOptions": [MockFunction],
+                  "value": "",
+                },
+                "main.js": MonacoEditorMock {
+                  "action": Object {
+                    "isSupported": [MockFunction],
+                    "run": [MockFunction],
+                  },
+                  "dispose": [MockFunction],
+                  "getAction": [MockFunction],
+                  "getModel": [MockFunction],
+                  "getValue": [MockFunction],
+                  "hasTextFocus": [MockFunction],
+                  "layout": [MockFunction],
+                  "model": Object {
+                    "getFullModelRange": [MockFunction],
+                  },
+                  "onDidChangeModelContent": [MockFunction],
+                  "onDidFocusEditorText": [MockFunction],
+                  "restoreViewState": [MockFunction],
+                  "saveViewState": [MockFunction],
+                  "setModel": [MockFunction],
+                  "setSelection": [MockFunction],
+                  "setValue": [MockFunction],
+                  "updateOptions": [MockFunction],
+                  "value": "",
+                },
+                "preload.js": MonacoEditorMock {
+                  "action": Object {
+                    "isSupported": [MockFunction],
+                    "run": [MockFunction],
+                  },
+                  "dispose": [MockFunction],
+                  "getAction": [MockFunction],
+                  "getModel": [MockFunction],
+                  "getValue": [MockFunction],
+                  "hasTextFocus": [MockFunction],
+                  "layout": [MockFunction],
+                  "model": Object {
+                    "getFullModelRange": [MockFunction],
+                  },
+                  "onDidChangeModelContent": [MockFunction],
+                  "onDidFocusEditorText": [MockFunction],
+                  "restoreViewState": [MockFunction],
+                  "saveViewState": [MockFunction],
+                  "setModel": [MockFunction],
+                  "setSelection": [MockFunction],
+                  "setValue": [MockFunction],
+                  "updateOptions": [MockFunction],
+                  "value": "",
+                },
+                "renderer.js": MonacoEditorMock {
+                  "action": Object {
+                    "isSupported": [MockFunction],
+                    "run": [MockFunction],
+                  },
+                  "dispose": [MockFunction],
+                  "getAction": [MockFunction],
+                  "getModel": [MockFunction],
+                  "getValue": [MockFunction],
+                  "hasTextFocus": [MockFunction],
+                  "layout": [MockFunction],
+                  "model": Object {
+                    "getFullModelRange": [MockFunction],
+                  },
+                  "onDidChangeModelContent": [MockFunction],
+                  "onDidFocusEditorText": [MockFunction],
+                  "restoreViewState": [MockFunction],
+                  "saveViewState": [MockFunction],
+                  "setModel": [MockFunction],
+                  "setSelection": [MockFunction],
+                  "setValue": [MockFunction],
+                  "updateOptions": [MockFunction],
+                  "value": "",
+                },
+              },
+            },
             "environmentVariables": Array [],
             "executionFlags": Array [],
             "genericDialogLastInput": null,
@@ -140,6 +240,106 @@ exports[`Commands component renders 1`] = `
             "customMosaics": Array [],
             "disableTour": [MockFunction],
             "downloadVersion": [MockFunction],
+            "editorMosaic": EditorMosaicMock {
+              "editors": Object {
+                "index.html": MonacoEditorMock {
+                  "action": Object {
+                    "isSupported": [MockFunction],
+                    "run": [MockFunction],
+                  },
+                  "dispose": [MockFunction],
+                  "getAction": [MockFunction],
+                  "getModel": [MockFunction],
+                  "getValue": [MockFunction],
+                  "hasTextFocus": [MockFunction],
+                  "layout": [MockFunction],
+                  "model": Object {
+                    "getFullModelRange": [MockFunction],
+                  },
+                  "onDidChangeModelContent": [MockFunction],
+                  "onDidFocusEditorText": [MockFunction],
+                  "restoreViewState": [MockFunction],
+                  "saveViewState": [MockFunction],
+                  "setModel": [MockFunction],
+                  "setSelection": [MockFunction],
+                  "setValue": [MockFunction],
+                  "updateOptions": [MockFunction],
+                  "value": "",
+                },
+                "main.js": MonacoEditorMock {
+                  "action": Object {
+                    "isSupported": [MockFunction],
+                    "run": [MockFunction],
+                  },
+                  "dispose": [MockFunction],
+                  "getAction": [MockFunction],
+                  "getModel": [MockFunction],
+                  "getValue": [MockFunction],
+                  "hasTextFocus": [MockFunction],
+                  "layout": [MockFunction],
+                  "model": Object {
+                    "getFullModelRange": [MockFunction],
+                  },
+                  "onDidChangeModelContent": [MockFunction],
+                  "onDidFocusEditorText": [MockFunction],
+                  "restoreViewState": [MockFunction],
+                  "saveViewState": [MockFunction],
+                  "setModel": [MockFunction],
+                  "setSelection": [MockFunction],
+                  "setValue": [MockFunction],
+                  "updateOptions": [MockFunction],
+                  "value": "",
+                },
+                "preload.js": MonacoEditorMock {
+                  "action": Object {
+                    "isSupported": [MockFunction],
+                    "run": [MockFunction],
+                  },
+                  "dispose": [MockFunction],
+                  "getAction": [MockFunction],
+                  "getModel": [MockFunction],
+                  "getValue": [MockFunction],
+                  "hasTextFocus": [MockFunction],
+                  "layout": [MockFunction],
+                  "model": Object {
+                    "getFullModelRange": [MockFunction],
+                  },
+                  "onDidChangeModelContent": [MockFunction],
+                  "onDidFocusEditorText": [MockFunction],
+                  "restoreViewState": [MockFunction],
+                  "saveViewState": [MockFunction],
+                  "setModel": [MockFunction],
+                  "setSelection": [MockFunction],
+                  "setValue": [MockFunction],
+                  "updateOptions": [MockFunction],
+                  "value": "",
+                },
+                "renderer.js": MonacoEditorMock {
+                  "action": Object {
+                    "isSupported": [MockFunction],
+                    "run": [MockFunction],
+                  },
+                  "dispose": [MockFunction],
+                  "getAction": [MockFunction],
+                  "getModel": [MockFunction],
+                  "getValue": [MockFunction],
+                  "hasTextFocus": [MockFunction],
+                  "layout": [MockFunction],
+                  "model": Object {
+                    "getFullModelRange": [MockFunction],
+                  },
+                  "onDidChangeModelContent": [MockFunction],
+                  "onDidFocusEditorText": [MockFunction],
+                  "restoreViewState": [MockFunction],
+                  "saveViewState": [MockFunction],
+                  "setModel": [MockFunction],
+                  "setSelection": [MockFunction],
+                  "setValue": [MockFunction],
+                  "updateOptions": [MockFunction],
+                  "value": "",
+                },
+              },
+            },
             "environmentVariables": Array [],
             "executionFlags": Array [],
             "genericDialogLastInput": null,
@@ -258,6 +458,106 @@ exports[`Commands component renders 1`] = `
             "customMosaics": Array [],
             "disableTour": [MockFunction],
             "downloadVersion": [MockFunction],
+            "editorMosaic": EditorMosaicMock {
+              "editors": Object {
+                "index.html": MonacoEditorMock {
+                  "action": Object {
+                    "isSupported": [MockFunction],
+                    "run": [MockFunction],
+                  },
+                  "dispose": [MockFunction],
+                  "getAction": [MockFunction],
+                  "getModel": [MockFunction],
+                  "getValue": [MockFunction],
+                  "hasTextFocus": [MockFunction],
+                  "layout": [MockFunction],
+                  "model": Object {
+                    "getFullModelRange": [MockFunction],
+                  },
+                  "onDidChangeModelContent": [MockFunction],
+                  "onDidFocusEditorText": [MockFunction],
+                  "restoreViewState": [MockFunction],
+                  "saveViewState": [MockFunction],
+                  "setModel": [MockFunction],
+                  "setSelection": [MockFunction],
+                  "setValue": [MockFunction],
+                  "updateOptions": [MockFunction],
+                  "value": "",
+                },
+                "main.js": MonacoEditorMock {
+                  "action": Object {
+                    "isSupported": [MockFunction],
+                    "run": [MockFunction],
+                  },
+                  "dispose": [MockFunction],
+                  "getAction": [MockFunction],
+                  "getModel": [MockFunction],
+                  "getValue": [MockFunction],
+                  "hasTextFocus": [MockFunction],
+                  "layout": [MockFunction],
+                  "model": Object {
+                    "getFullModelRange": [MockFunction],
+                  },
+                  "onDidChangeModelContent": [MockFunction],
+                  "onDidFocusEditorText": [MockFunction],
+                  "restoreViewState": [MockFunction],
+                  "saveViewState": [MockFunction],
+                  "setModel": [MockFunction],
+                  "setSelection": [MockFunction],
+                  "setValue": [MockFunction],
+                  "updateOptions": [MockFunction],
+                  "value": "",
+                },
+                "preload.js": MonacoEditorMock {
+                  "action": Object {
+                    "isSupported": [MockFunction],
+                    "run": [MockFunction],
+                  },
+                  "dispose": [MockFunction],
+                  "getAction": [MockFunction],
+                  "getModel": [MockFunction],
+                  "getValue": [MockFunction],
+                  "hasTextFocus": [MockFunction],
+                  "layout": [MockFunction],
+                  "model": Object {
+                    "getFullModelRange": [MockFunction],
+                  },
+                  "onDidChangeModelContent": [MockFunction],
+                  "onDidFocusEditorText": [MockFunction],
+                  "restoreViewState": [MockFunction],
+                  "saveViewState": [MockFunction],
+                  "setModel": [MockFunction],
+                  "setSelection": [MockFunction],
+                  "setValue": [MockFunction],
+                  "updateOptions": [MockFunction],
+                  "value": "",
+                },
+                "renderer.js": MonacoEditorMock {
+                  "action": Object {
+                    "isSupported": [MockFunction],
+                    "run": [MockFunction],
+                  },
+                  "dispose": [MockFunction],
+                  "getAction": [MockFunction],
+                  "getModel": [MockFunction],
+                  "getValue": [MockFunction],
+                  "hasTextFocus": [MockFunction],
+                  "layout": [MockFunction],
+                  "model": Object {
+                    "getFullModelRange": [MockFunction],
+                  },
+                  "onDidChangeModelContent": [MockFunction],
+                  "onDidFocusEditorText": [MockFunction],
+                  "restoreViewState": [MockFunction],
+                  "saveViewState": [MockFunction],
+                  "setModel": [MockFunction],
+                  "setSelection": [MockFunction],
+                  "setValue": [MockFunction],
+                  "updateOptions": [MockFunction],
+                  "value": "",
+                },
+              },
+            },
             "environmentVariables": Array [],
             "executionFlags": Array [],
             "genericDialogLastInput": null,
@@ -369,6 +669,106 @@ exports[`Commands component renders 1`] = `
           "customMosaics": Array [],
           "disableTour": [MockFunction],
           "downloadVersion": [MockFunction],
+          "editorMosaic": EditorMosaicMock {
+            "editors": Object {
+              "index.html": MonacoEditorMock {
+                "action": Object {
+                  "isSupported": [MockFunction],
+                  "run": [MockFunction],
+                },
+                "dispose": [MockFunction],
+                "getAction": [MockFunction],
+                "getModel": [MockFunction],
+                "getValue": [MockFunction],
+                "hasTextFocus": [MockFunction],
+                "layout": [MockFunction],
+                "model": Object {
+                  "getFullModelRange": [MockFunction],
+                },
+                "onDidChangeModelContent": [MockFunction],
+                "onDidFocusEditorText": [MockFunction],
+                "restoreViewState": [MockFunction],
+                "saveViewState": [MockFunction],
+                "setModel": [MockFunction],
+                "setSelection": [MockFunction],
+                "setValue": [MockFunction],
+                "updateOptions": [MockFunction],
+                "value": "",
+              },
+              "main.js": MonacoEditorMock {
+                "action": Object {
+                  "isSupported": [MockFunction],
+                  "run": [MockFunction],
+                },
+                "dispose": [MockFunction],
+                "getAction": [MockFunction],
+                "getModel": [MockFunction],
+                "getValue": [MockFunction],
+                "hasTextFocus": [MockFunction],
+                "layout": [MockFunction],
+                "model": Object {
+                  "getFullModelRange": [MockFunction],
+                },
+                "onDidChangeModelContent": [MockFunction],
+                "onDidFocusEditorText": [MockFunction],
+                "restoreViewState": [MockFunction],
+                "saveViewState": [MockFunction],
+                "setModel": [MockFunction],
+                "setSelection": [MockFunction],
+                "setValue": [MockFunction],
+                "updateOptions": [MockFunction],
+                "value": "",
+              },
+              "preload.js": MonacoEditorMock {
+                "action": Object {
+                  "isSupported": [MockFunction],
+                  "run": [MockFunction],
+                },
+                "dispose": [MockFunction],
+                "getAction": [MockFunction],
+                "getModel": [MockFunction],
+                "getValue": [MockFunction],
+                "hasTextFocus": [MockFunction],
+                "layout": [MockFunction],
+                "model": Object {
+                  "getFullModelRange": [MockFunction],
+                },
+                "onDidChangeModelContent": [MockFunction],
+                "onDidFocusEditorText": [MockFunction],
+                "restoreViewState": [MockFunction],
+                "saveViewState": [MockFunction],
+                "setModel": [MockFunction],
+                "setSelection": [MockFunction],
+                "setValue": [MockFunction],
+                "updateOptions": [MockFunction],
+                "value": "",
+              },
+              "renderer.js": MonacoEditorMock {
+                "action": Object {
+                  "isSupported": [MockFunction],
+                  "run": [MockFunction],
+                },
+                "dispose": [MockFunction],
+                "getAction": [MockFunction],
+                "getModel": [MockFunction],
+                "getValue": [MockFunction],
+                "hasTextFocus": [MockFunction],
+                "layout": [MockFunction],
+                "model": Object {
+                  "getFullModelRange": [MockFunction],
+                },
+                "onDidChangeModelContent": [MockFunction],
+                "onDidFocusEditorText": [MockFunction],
+                "restoreViewState": [MockFunction],
+                "saveViewState": [MockFunction],
+                "setModel": [MockFunction],
+                "setSelection": [MockFunction],
+                "setValue": [MockFunction],
+                "updateOptions": [MockFunction],
+                "value": "",
+              },
+            },
+          },
           "environmentVariables": Array [],
           "executionFlags": Array [],
           "genericDialogLastInput": null,
@@ -477,6 +877,106 @@ exports[`Commands component renders 1`] = `
           "customMosaics": Array [],
           "disableTour": [MockFunction],
           "downloadVersion": [MockFunction],
+          "editorMosaic": EditorMosaicMock {
+            "editors": Object {
+              "index.html": MonacoEditorMock {
+                "action": Object {
+                  "isSupported": [MockFunction],
+                  "run": [MockFunction],
+                },
+                "dispose": [MockFunction],
+                "getAction": [MockFunction],
+                "getModel": [MockFunction],
+                "getValue": [MockFunction],
+                "hasTextFocus": [MockFunction],
+                "layout": [MockFunction],
+                "model": Object {
+                  "getFullModelRange": [MockFunction],
+                },
+                "onDidChangeModelContent": [MockFunction],
+                "onDidFocusEditorText": [MockFunction],
+                "restoreViewState": [MockFunction],
+                "saveViewState": [MockFunction],
+                "setModel": [MockFunction],
+                "setSelection": [MockFunction],
+                "setValue": [MockFunction],
+                "updateOptions": [MockFunction],
+                "value": "",
+              },
+              "main.js": MonacoEditorMock {
+                "action": Object {
+                  "isSupported": [MockFunction],
+                  "run": [MockFunction],
+                },
+                "dispose": [MockFunction],
+                "getAction": [MockFunction],
+                "getModel": [MockFunction],
+                "getValue": [MockFunction],
+                "hasTextFocus": [MockFunction],
+                "layout": [MockFunction],
+                "model": Object {
+                  "getFullModelRange": [MockFunction],
+                },
+                "onDidChangeModelContent": [MockFunction],
+                "onDidFocusEditorText": [MockFunction],
+                "restoreViewState": [MockFunction],
+                "saveViewState": [MockFunction],
+                "setModel": [MockFunction],
+                "setSelection": [MockFunction],
+                "setValue": [MockFunction],
+                "updateOptions": [MockFunction],
+                "value": "",
+              },
+              "preload.js": MonacoEditorMock {
+                "action": Object {
+                  "isSupported": [MockFunction],
+                  "run": [MockFunction],
+                },
+                "dispose": [MockFunction],
+                "getAction": [MockFunction],
+                "getModel": [MockFunction],
+                "getValue": [MockFunction],
+                "hasTextFocus": [MockFunction],
+                "layout": [MockFunction],
+                "model": Object {
+                  "getFullModelRange": [MockFunction],
+                },
+                "onDidChangeModelContent": [MockFunction],
+                "onDidFocusEditorText": [MockFunction],
+                "restoreViewState": [MockFunction],
+                "saveViewState": [MockFunction],
+                "setModel": [MockFunction],
+                "setSelection": [MockFunction],
+                "setValue": [MockFunction],
+                "updateOptions": [MockFunction],
+                "value": "",
+              },
+              "renderer.js": MonacoEditorMock {
+                "action": Object {
+                  "isSupported": [MockFunction],
+                  "run": [MockFunction],
+                },
+                "dispose": [MockFunction],
+                "getAction": [MockFunction],
+                "getModel": [MockFunction],
+                "getValue": [MockFunction],
+                "hasTextFocus": [MockFunction],
+                "layout": [MockFunction],
+                "model": Object {
+                  "getFullModelRange": [MockFunction],
+                },
+                "onDidChangeModelContent": [MockFunction],
+                "onDidFocusEditorText": [MockFunction],
+                "restoreViewState": [MockFunction],
+                "saveViewState": [MockFunction],
+                "setModel": [MockFunction],
+                "setSelection": [MockFunction],
+                "setValue": [MockFunction],
+                "updateOptions": [MockFunction],
+                "value": "",
+              },
+            },
+          },
           "environmentVariables": Array [],
           "executionFlags": Array [],
           "genericDialogLastInput": null,
diff --git a/tests/renderer/components/__snapshots__/commands-version-chooser-spec.tsx.snap b/tests/renderer/components/__snapshots__/commands-version-chooser-spec.tsx.snap
index ef639b6f..e7b01625 100644
--- a/tests/renderer/components/__snapshots__/commands-version-chooser-spec.tsx.snap
+++ b/tests/renderer/components/__snapshots__/commands-version-chooser-spec.tsx.snap
@@ -28,6 +28,106 @@ exports[`VersionSelect component renders 1`] = `
         "customMosaics": Array [],
         "disableTour": [MockFunction],
         "downloadVersion": [MockFunction],
+        "editorMosaic": EditorMosaicMock {
+          "editors": Object {
+            "index.html": MonacoEditorMock {
+              "action": Object {
+                "isSupported": [MockFunction],
+                "run": [MockFunction],
+              },
+              "dispose": [MockFunction],
+              "getAction": [MockFunction],
+              "getModel": [MockFunction],
+              "getValue": [MockFunction],
+              "hasTextFocus": [MockFunction],
+              "layout": [MockFunction],
+              "model": Object {
+                "getFullModelRange": [MockFunction],
+              },
+              "onDidChangeModelContent": [MockFunction],
+              "onDidFocusEditorText": [MockFunction],
+              "restoreViewState": [MockFunction],
+              "saveViewState": [MockFunction],
+              "setModel": [MockFunction],
+              "setSelection": [MockFunction],
+              "setValue": [MockFunction],
+              "updateOptions": [MockFunction],
+              "value": "",
+            },
+            "main.js": MonacoEditorMock {
+              "action": Object {
+                "isSupported": [MockFunction],
+                "run": [MockFunction],
+              },
+              "dispose": [MockFunction],
+              "getAction": [MockFunction],
+              "getModel": [MockFunction],
+              "getValue": [MockFunction],
+              "hasTextFocus": [MockFunction],
+              "layout": [MockFunction],
+              "model": Object {
+                "getFullModelRange": [MockFunction],
+              },
+              "onDidChangeModelContent": [MockFunction],
+              "onDidFocusEditorText": [MockFunction],
+              "restoreViewState": [MockFunction],
+              "saveViewState": [MockFunction],
+              "setModel": [MockFunction],
+              "setSelection": [MockFunction],
+              "setValue": [MockFunction],
+              "updateOptions": [MockFunction],
+              "value": "",
+            },
+            "preload.js": MonacoEditorMock {
+              "action": Object {
+                "isSupported": [MockFunction],
+                "run": [MockFunction],
+              },
+              "dispose": [MockFunction],
+              "getAction": [MockFunction],
+              "getModel": [MockFunction],
+              "getValue": [MockFunction],
+              "hasTextFocus": [MockFunction],
+              "layout": [MockFunction],
+              "model": Object {
+                "getFullModelRange": [MockFunction],
+              },
+              "onDidChangeModelContent": [MockFunction],
+              "onDidFocusEditorText": [MockFunction],
+              "restoreViewState": [MockFunction],
+              "saveViewState": [MockFunction],
+              "setModel": [MockFunction],
+              "setSelection": [MockFunction],
+              "setValue": [MockFunction],
+              "updateOptions": [MockFunction],
+              "value": "",
+            },
+            "renderer.js": MonacoEditorMock {
+              "action": Object {
+                "isSupported": [MockFunction],
+                "run": [MockFunction],
+              },
+              "dispose": [MockFunction],
+              "getAction": [MockFunction],
+              "getModel": [MockFunction],
+              "getValue": [MockFunction],
+              "hasTextFocus": [MockFunction],
+              "layout": [MockFunction],
+              "model": Object {
+                "getFullModelRange": [MockFunction],
+              },
+              "onDidChangeModelContent": [MockFunction],
+              "onDidFocusEditorText": [MockFunction],
+              "restoreViewState": [MockFunction],
+              "saveViewState": [MockFunction],
+              "setModel": [MockFunction],
+              "setSelection": [MockFunction],
+              "setValue": [MockFunction],
+              "updateOptions": [MockFunction],
+              "value": "",
+            },
+          },
+        },
         "environmentVariables": Array [],
         "executionFlags": Array [],
         "genericDialogLastInput": null,
diff --git a/tests/renderer/components/__snapshots__/dialog-bisect-spec.tsx.snap b/tests/renderer/components/__snapshots__/dialog-bisect-spec.tsx.snap
index 9d438227..72ca1311 100644
--- a/tests/renderer/components/__snapshots__/dialog-bisect-spec.tsx.snap
+++ b/tests/renderer/components/__snapshots__/dialog-bisect-spec.tsx.snap
@@ -71,6 +71,106 @@ exports[`BisectDialog component renders 1`] = `
               "customMosaics": Array [],
               "disableTour": [MockFunction],
               "downloadVersion": [MockFunction],
+              "editorMosaic": EditorMosaicMock {
+                "editors": Object {
+                  "index.html": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "main.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "preload.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "renderer.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                },
+              },
               "environmentVariables": Array [],
               "executionFlags": Array [],
               "genericDialogLastInput": null,
@@ -273,6 +373,106 @@ exports[`BisectDialog component renders 1`] = `
               "customMosaics": Array [],
               "disableTour": [MockFunction],
               "downloadVersion": [MockFunction],
+              "editorMosaic": EditorMosaicMock {
+                "editors": Object {
+                  "index.html": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "main.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "preload.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "renderer.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                },
+              },
               "environmentVariables": Array [],
               "executionFlags": Array [],
               "genericDialogLastInput": null,
@@ -548,6 +748,106 @@ exports[`BisectDialog component renders 2`] = `
               "customMosaics": Array [],
               "disableTour": [MockFunction],
               "downloadVersion": [MockFunction],
+              "editorMosaic": EditorMosaicMock {
+                "editors": Object {
+                  "index.html": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "main.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "preload.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "renderer.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                },
+              },
               "environmentVariables": Array [],
               "executionFlags": Array [],
               "genericDialogLastInput": null,
@@ -743,6 +1043,106 @@ exports[`BisectDialog component renders 2`] = `
               "customMosaics": Array [],
               "disableTour": [MockFunction],
               "downloadVersion": [MockFunction],
+              "editorMosaic": EditorMosaicMock {
+                "editors": Object {
+                  "index.html": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "main.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "preload.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "renderer.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                },
+              },
               "environmentVariables": Array [],
               "executionFlags": Array [],
               "genericDialogLastInput": null,
@@ -1011,6 +1411,106 @@ exports[`BisectDialog component renders 3`] = `
               "customMosaics": Array [],
               "disableTour": [MockFunction],
               "downloadVersion": [MockFunction],
+              "editorMosaic": EditorMosaicMock {
+                "editors": Object {
+                  "index.html": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "main.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "preload.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "renderer.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                },
+              },
               "environmentVariables": Array [],
               "executionFlags": Array [],
               "genericDialogLastInput": null,
@@ -1213,6 +1713,106 @@ exports[`BisectDialog component renders 3`] = `
               "customMosaics": Array [],
               "disableTour": [MockFunction],
               "downloadVersion": [MockFunction],
+              "editorMosaic": EditorMosaicMock {
+                "editors": Object {
+                  "index.html": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "main.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "preload.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "renderer.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                },
+              },
               "environmentVariables": Array [],
               "executionFlags": Array [],
               "genericDialogLastInput": null,
@@ -1481,6 +2081,106 @@ exports[`BisectDialog component renders 4`] = `
               "customMosaics": Array [],
               "disableTour": [MockFunction],
               "downloadVersion": [MockFunction],
+              "editorMosaic": EditorMosaicMock {
+                "editors": Object {
+                  "index.html": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "main.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "preload.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "renderer.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                },
+              },
               "environmentVariables": Array [],
               "executionFlags": Array [],
               "genericDialogLastInput": null,
@@ -1683,6 +2383,106 @@ exports[`BisectDialog component renders 4`] = `
               "customMosaics": Array [],
               "disableTour": [MockFunction],
               "downloadVersion": [MockFunction],
+              "editorMosaic": EditorMosaicMock {
+                "editors": Object {
+                  "index.html": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "main.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "preload.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "renderer.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                },
+              },
               "environmentVariables": Array [],
               "executionFlags": Array [],
               "genericDialogLastInput": null,
@@ -1959,6 +2759,106 @@ exports[`BisectDialog component renders 5`] = `
               "customMosaics": Array [],
               "disableTour": [MockFunction],
               "downloadVersion": [MockFunction],
+              "editorMosaic": EditorMosaicMock {
+                "editors": Object {
+                  "index.html": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "main.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "preload.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "renderer.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                },
+              },
               "environmentVariables": Array [],
               "executionFlags": Array [],
               "genericDialogLastInput": null,
@@ -2161,6 +3061,106 @@ exports[`BisectDialog component renders 5`] = `
               "customMosaics": Array [],
               "disableTour": [MockFunction],
               "downloadVersion": [MockFunction],
+              "editorMosaic": EditorMosaicMock {
+                "editors": Object {
+                  "index.html": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "main.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "preload.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                  "renderer.js": MonacoEditorMock {
+                    "action": Object {
+                      "isSupported": [MockFunction],
+                      "run": [MockFunction],
+                    },
+                    "dispose": [MockFunction],
+                    "getAction": [MockFunction],
+                    "getModel": [MockFunction],
+                    "getValue": [MockFunction],
+                    "hasTextFocus": [MockFunction],
+                    "layout": [MockFunction],
+                    "model": Object {
+                      "getFullModelRange": [MockFunction],
+                    },
+                    "onDidChangeModelContent": [MockFunction],
+                    "onDidFocusEditorText": [MockFunction],
+                    "restoreViewState": [MockFunction],
+                    "saveViewState": [MockFunction],
+                    "setModel": [MockFunction],
+                    "setSelection": [MockFunction],
+                    "setValue": [MockFunction],
+                    "updateOptions": [MockFunction],
+                    "value": "",
+                  },
+                },
+              },
               "environmentVariables": Array [],
               "executionFlags": Array [],
               "genericDialogLastInput": null,
diff --git a/tests/renderer/components/__snapshots__/editors-spec.tsx.snap b/tests/renderer/components/__snapshots__/editors-spec.tsx.snap
index b57a1447..6c3ef8f8 100644
--- a/tests/renderer/components/__snapshots__/editors-spec.tsx.snap
+++ b/tests/renderer/components/__snapshots__/editors-spec.tsx.snap
@@ -935,6 +935,106 @@ exports[`Editors component renders a toolbar 1`] = `
             "customMosaics": Array [],
             "disableTour": [MockFunction],
             "downloadVersion": [MockFunction],
+            "editorMosaic": EditorMosaicMock {
+              "editors": Object {
+                "index.html": MonacoEditorMock {
+                  "action": Object {
+                    "isSupported": [MockFunction],
+                    "run": [MockFunction],
+                  },
+                  "dispose": [MockFunction],
+                  "getAction": [MockFunction],
+                  "getModel": [MockFunction],
+                  "getValue": [MockFunction],
+                  "hasTextFocus": [MockFunction],
+                  "layout": [MockFunction],
+                  "model": Object {
+                    "getFullModelRange": [MockFunction],
+                  },
+                  "onDidChangeModelContent": [MockFunction],
+                  "onDidFocusEditorText": [MockFunction],
+                  "restoreViewState": [MockFunction],
+                  "saveViewState": [MockFunction],
+                  "setModel": [MockFunction],
+                  "setSelection": [MockFunction],
+                  "setValue": [MockFunction],
+                  "updateOptions": [MockFunction],
+                  "value": "",
+                },
+                "main.js": MonacoEditorMock {
+                  "action": Object {
+                    "isSupported": [MockFunction],
+                    "run": [MockFunction],
+                  },
+                  "dispose": [MockFunction],
+                  "getAction": [MockFunction],
+                  "getModel": [MockFunction],
+                  "getValue": [MockFunction],
+                  "hasTextFocus": [MockFunction],
+                  "layout": [MockFunction],
+                  "model": Object {
+                    "getFullModelRange": [MockFunction],
+                  },
+                  "onDidChangeModelContent": [MockFunction],
+                  "onDidFocusEditorText": [MockFunction],
+                  "restoreViewState": [MockFunction],
+                  "saveViewState": [MockFunction],
+                  "setModel": [MockFunction],
+                  "setSelection": [MockFunction],
+                  "setValue": [MockFunction],
+                  "updateOptions": [MockFunction],
+                  "value": "",
+                },
+                "preload.js": MonacoEditorMock {
+                  "action": Object {
+                    "isSupported": [MockFunction],
+                    "run": [MockFunction],
+                  },
+                  "dispose": [MockFunction],
+                  "getAction": [MockFunction],
+                  "getModel": [MockFunction],
+                  "getValue": [MockFunction],
+                  "hasTextFocus": [MockFunction],
+                  "layout": [MockFunction],
+                  "model": Object {
+                    "getFullModelRange": [MockFunction],
+                  },
+                  "onDidChangeModelContent": [MockFunction],
+                  "onDidFocusEditorText": [MockFunction],
+                  "restoreViewState": [MockFunction],
+                  "saveViewState": [MockFunction],
+                  "setModel": [MockFunction],
+                  "setSelection": [MockFunction],
+                  "setValue": [MockFunction],
+                  "updateOptions": [MockFunction],
+                  "value": "",
+                },
+                "renderer.js": MonacoEditorMock {
+                  "action": Object {
+                    "isSupported": [MockFunction],
+                    "run": [MockFunction],
+                  },
+                  "dispose": [MockFunction],
+                  "getAction": [MockFunction],
+                  "getModel": [MockFunction],
+                  "getValue": [MockFunction],
+                  "hasTextFocus": [MockFunction],
+                  "layout": [MockFunction],
+                  "model": Object {
+                    "getFullModelRange": [MockFunction],
+                  },
+                  "onDidChangeModelContent": [MockFunction],
+                  "onDidFocusEditorText": [MockFunction],
+                  "restoreViewState": [MockFunction],
+                  "saveViewState": [MockFunction],
+                  "setModel": [MockFunction],
+                  "setSelection": [MockFunction],
+                  "setValue": [MockFunction],
+                  "updateOptions": [MockFunction],
+                  "value": "",
+                },
+              },
+            },
             "environmentVariables": Array [],
             "executionFlags": Array [],
             "genericDialogLastInput": null,
@@ -1060,6 +1160,106 @@ exports[`Editors component renders a toolbar 1`] = `
             "customMosaics": Array [],
             "disableTour": [MockFunction],
             "downloadVersion": [MockFunction],
+            "editorMosaic": EditorMosaicMock {
+              "editors": Object {
+                "index.html": MonacoEditorMock {
+                  "action": Object {
+                    "isSupported": [MockFunction],
+                    "run": [MockFunction],
+                  },
+                  "dispose": [MockFunction],
+                  "getAction": [MockFunction],
+                  "getModel": [MockFunction],
+                  "getValue": [MockFunction],
+                  "hasTextFocus": [MockFunction],
+                  "layout": [MockFunction],
+                  "model": Object {
+                    "getFullModelRange": [MockFunction],
+                  },
+                  "onDidChangeModelContent": [MockFunction],
+                  "onDidFocusEditorText": [MockFunction],
+                  "restoreViewState": [MockFunction],
+                  "saveViewState": [MockFunction],
+                  "setModel": [MockFunction],
+                  "setSelection": [MockFunction],
+                  "setValue": [MockFunction],
+                  "updateOptions": [MockFunction],
+                  "value": "",
+                },
+                "main.js": MonacoEditorMock {
+                  "action": Object {
+                    "isSupported": [MockFunction],
+                    "run": [MockFunction],
+                  },
+                  "dispose": [MockFunction],
+                  "getAction": [MockFunction],
+                  "getModel": [MockFunction],
+                  "getValue": [MockFunction],
+                  "hasTextFocus": [MockFunction],
+                  "layout": [MockFunction],
+                  "model": Object {
+                    "getFullModelRange": [MockFunction],
+                  },
+                  "onDidChangeModelContent": [MockFunction],
+                  "onDidFocusEditorText": [MockFunction],
+                  "restoreViewState": [MockFunction],
+                  "saveViewState": [MockFunction],
+                  "setModel": [MockFunction],
+                  "setSelection": [MockFunction],
+                  "setValue": [MockFunction],
+                  "updateOptions": [MockFunction],
+                  "value": "",
+                },
+                "preload.js": MonacoEditorMock {
+                  "action": Object {
+                    "isSupported": [MockFunction],
+                    "run": [MockFunction],
+                  },
+                  "dispose": [MockFunction],
+                  "getAction": [MockFunction],
+                  "getModel": [MockFunction],
+                  "getValue": [MockFunction],
+                  "hasTextFocus": [MockFunction],
+                  "layout": [MockFunction],
+                  "model": Object {
+                    "getFullModelRange": [MockFunction],
+                  },
+                  "onDidChangeModelContent": [MockFunction],
+                  "onDidFocusEditorText": [MockFunction],
+                  "restoreViewState": [MockFunction],
+                  "saveViewState": [MockFunction],
+                  "setModel": [MockFunction],
+                  "setSelection": [MockFunction],
+                  "setValue": [MockFunction],
+                  "updateOptions": [MockFunction],
+                  "value": "",
+                },
+                "renderer.js": MonacoEditorMock {
+                  "action": Object {
+                    "isSupported": [MockFunction],
+                    "run": [MockFunction],
+                  },
+                  "dispose": [MockFunction],
+                  "getAction": [MockFunction],
+                  "getModel": [MockFunction],
+                  "getValue": [MockFunction],
+                  "hasTextFocus": [MockFunction],
+                  "layout": [MockFunction],
+                  "model": Object {
+                    "getFullModelRange": [MockFunction],
+                  },
+                  "onDidChangeModelContent": [MockFunction],
+                  "onDidFocusEditorText": [MockFunction],
+                  "restoreViewState": [MockFunction],
+                  "saveViewState": [MockFunction],
+                  "setModel": [MockFunction],
+                  "setSelection": [MockFunction],
+                  "setValue": [MockFunction],
+                  "updateOptions": [MockFunction],
+                  "value": "",
+                },
+              },
+            },
             "environmentVariables": Array [],
             "executionFlags": Array [],
             "genericDialogLastInput": null,
diff --git a/tests/renderer/components/editors-spec.tsx b/tests/renderer/components/editors-spec.tsx
index 0eec4eac..1b650564 100644
--- a/tests/renderer/components/editors-spec.tsx
+++ b/tests/renderer/components/editors-spec.tsx
@@ -10,7 +10,11 @@ import { getFocusedEditor } from '../../../src/utils/focused-editor';
 import { ipcRendererManager } from '../../../src/renderer/ipc';
 import { updateEditorLayout } from '../../../src/utils/editor-layout';
 
-import { MonacoEditorMock, StateMock } from '../../mocks/mocks';
+import {
+  EditorMosaicMock,
+  MonacoEditorMock,
+  StateMock,
+} from '../../mocks/mocks';
 
 jest.mock('monaco-loader', () =>
   jest.fn(async () => {
@@ -34,10 +38,12 @@ describe('Editors component', () => {
   let ElectronFiddle: any;
   let monaco: any;
   let store: StateMock;
+  let editorMosaic: EditorMosaicMock;
 
   beforeEach(() => {
     ({ ElectronFiddle } = window as any);
     ({ monaco, state: store } = ElectronFiddle.app);
+    ({ editorMosaic } = store);
     store.mosaicArrangement = createMosaicArrangement(DEFAULT_EDITORS);
   });
 
@@ -64,20 +70,11 @@ describe('Editors component', () => {
   });
 
   describe('toggleEditorOption()', () => {
-    it('handles a missing ElectronFiddle global', () => {
-      const oldEditors = ElectronFiddle.editors;
-      ElectronFiddle.editors = undefined as any;
-
-      const wrapper = shallow(<Editors appState={store as any} />);
-      const instance: Editors = wrapper.instance() as any;
-
-      expect(instance.toggleEditorOption('wordWrap')).toBe(false);
-      ElectronFiddle.editors = oldEditors;
-    });
+    const filename = DefaultEditorId.html;
 
     it('handles an error', () => {
-      (ElectronFiddle.editors[DefaultEditorId.html]!
-        .updateOptions as jest.Mock).mockImplementationOnce(() => {
+      const editor = editorMosaic.editors.get(filename);
+      editor!.updateOptions.mockImplementationOnce(() => {
         throw new Error('Bwap bwap');
       });
 
@@ -92,9 +89,8 @@ describe('Editors component', () => {
       const instance: Editors = wrapper.instance() as any;
 
       expect(instance.toggleEditorOption('wordWrap')).toBe(true);
-      expect(
-        ElectronFiddle.editors[DefaultEditorId.html]!.updateOptions,
-      ).toHaveBeenCalledWith({
+      const editor = editorMosaic.editors.get(filename);
+      expect(editor!.updateOptions).toHaveBeenCalledWith({
         minimap: { enabled: false },
         wordWrap: 'off',
       });
@@ -279,10 +275,9 @@ describe('Editors component', () => {
 
       ipcRendererManager.emit(IpcEvents.MONACO_TOGGLE_OPTION, null, 'wordWrap');
 
-      const { editors: eds } = ElectronFiddle;
-      expect(eds[DefaultEditorId.html]!.updateOptions).toHaveBeenCalled();
-      expect(eds[DefaultEditorId.renderer]!.updateOptions).toHaveBeenCalled();
-      expect(eds[DefaultEditorId.main]!.updateOptions).toHaveBeenCalled();
+      for (const editor of editorMosaic.editors.values()) {
+        expect(editor.updateOptions).toHaveBeenCalled();
+      }
     });
   });
 
diff --git a/tests/renderer/state-spec.ts b/tests/renderer/state-spec.ts
index b0136363..7fb86a4e 100644
--- a/tests/renderer/state-spec.ts
+++ b/tests/renderer/state-spec.ts
@@ -1,5 +1,3 @@
-import * as MonacoType from 'monaco-editor';
-
 import {
   BlockableAccelerator,
   DEFAULT_EDITORS,
@@ -33,7 +31,7 @@ import {
 import { createMosaicArrangement } from '../../src/utils/editors-mosaic-arrangement';
 import { waitFor } from '../../src/utils/wait-for';
 import { getName } from '../../src/utils/get-name';
-import { VersionsMock } from '../mocks/electron-versions';
+import { MonacoEditorMock, VersionsMock } from '../mocks/mocks';
 import { overridePlatform, resetPlatform } from '../utils';
 
 jest.mock('../../src/renderer/content', () => ({
@@ -148,11 +146,15 @@ describe('AppState', () => {
     });
 
     it('sets the onDidChangeModelContent handler if saved', async (done) => {
+      const { editorMosaic } = appState;
+      const editor = new MonacoEditorMock();
+      const fn = editor.onDidChangeModelContent;
+      const filename = DefaultEditorId.renderer;
+      editorMosaic.editors.set(filename, editor as any);
+
       // confirm that setting appState.isUnsaved to false
       // causes a new change-model-content callback to be installed
       appState.isUnsaved = false;
-      const fn = window.ElectronFiddle.editors!['renderer.js']!
-        .onDidChangeModelContent;
       await waitFor(() => (fn as jest.Mock).mock.calls.length > 0);
       expect(window.onbeforeunload).toBe(null);
       expect(fn as jest.Mock).toHaveBeenCalledTimes(1);
@@ -624,9 +626,8 @@ describe('AppState', () => {
       await appState.setVisibleMosaics([DefaultEditorId.main]);
 
       // we just need to mock something truthy here
-      window.ElectronFiddle.editors[
-        DefaultEditorId.main
-      ] = {} as MonacoType.editor.IStandaloneCodeEditor;
+      const { editorMosaic } = (window as any).ElectronFiddle.app.state;
+      editorMosaic.editors.set(DefaultEditorId.main, {});
 
       expect(appState.mosaicArrangement).toEqual(DefaultEditorId.main);
       expect(appState.closedPanels[DefaultEditorId.renderer]).toBeTruthy();
diff --git a/tests/utils/editor-backup-spec.ts b/tests/utils/editor-backup-spec.ts
index 9e9c0179..cec9c0dd 100644
--- a/tests/utils/editor-backup-spec.ts
+++ b/tests/utils/editor-backup-spec.ts
@@ -1,12 +1,25 @@
 import { DefaultEditorId } from '../../src/interfaces';
 import { getEditorBackup } from '../../src/utils/editor-backup';
+import { EditorMosaicMock } from '../mocks/mocks';
 
 describe('getEditorBackup()', () => {
+  let editorMosaic: EditorMosaicMock;
+
+  beforeEach(() => {
+    ({ editorMosaic } = (window as any).ElectronFiddle.app.state);
+  });
+
   it('returns the value for an editor', () => {
-    expect(getEditorBackup(DefaultEditorId.html)).toEqual({
-      value: 'editor-value',
-      model: { testModel: true },
-      viewState: { testViewState: true },
-    });
+    const filename = DefaultEditorId.html;
+    const editor = editorMosaic.editors.get(filename);
+    const model = { testModel: true };
+    const viewState = { testViewState: true };
+    const value = 'editor-value';
+
+    (editor as any).model = model;
+    editor!.saveViewState.mockReturnValue(viewState);
+    editor!.value = value;
+
+    expect(getEditorBackup(filename)).toEqual({ model, value, viewState });
   });
 });
diff --git a/tests/utils/editor-layout-spec.ts b/tests/utils/editor-layout-spec.ts
index 82a8ec9c..d73b61db 100644
--- a/tests/utils/editor-layout-spec.ts
+++ b/tests/utils/editor-layout-spec.ts
@@ -1,10 +1,11 @@
-import { DefaultEditorId } from '../../src/interfaces';
 import { updateEditorLayout } from '../../src/utils/editor-layout';
-import { ElectronFiddleMock } from '../mocks/electron-fiddle';
+import { EditorMosaicMock } from '../mocks/mocks';
 
 describe('editor-layout', () => {
+  let editorMosaic: EditorMosaicMock;
+
   beforeEach(() => {
-    window.ElectronFiddle = new ElectronFiddleMock() as any;
+    ({ editorMosaic } = (window as any).ElectronFiddle.app.state);
   });
 
   it('updateEditorLayout calls layout() just once', (done) => {
@@ -14,19 +15,9 @@ describe('editor-layout', () => {
     updateEditorLayout();
 
     setTimeout(() => {
-      const editors = window.ElectronFiddle.editors;
-
-      expect(
-        (editors[DefaultEditorId.main]!.layout as jest.Mock<any>).mock.calls,
-      ).toHaveLength(1);
-      expect(
-        (editors[DefaultEditorId.html]!.layout as jest.Mock<any>).mock.calls,
-      ).toHaveLength(1);
-      expect(
-        (editors[DefaultEditorId.renderer]!.layout as jest.Mock<any>).mock
-          .calls,
-      ).toHaveLength(1);
-
+      for (const editor of editorMosaic.editors.values()) {
+        expect(editor.layout).toHaveBeenCalledTimes(1);
+      }
       done();
     }, 100);
   });
diff --git a/tests/utils/editor-model-spec.ts b/tests/utils/editor-model-spec.ts
index db0835ea..a45b40de 100644
--- a/tests/utils/editor-model-spec.ts
+++ b/tests/utils/editor-model-spec.ts
@@ -1,27 +1,30 @@
 import { DefaultEditorId } from '../../src/interfaces';
 import { getEditorModel } from '../../src/utils/editor-model';
+import { EditorMosaicMock } from '../mocks/editor-mosaic';
 
 describe('getEditorModel()', () => {
-  it('returns the value for an editor', () => {
-    expect(getEditorModel(DefaultEditorId.html)).toEqual({ testModel: true });
+  const filename = DefaultEditorId.html;
+  let editorMosaic: EditorMosaicMock;
+
+  beforeEach(() => {
+    ({ editorMosaic } = (window as any).ElectronFiddle.app.state);
   });
 
-  it('returns null if the editor does not exist', () => {
-    const { ElectronFiddle: fiddle } = window as any;
-    const oldEditor = fiddle.editors[DefaultEditorId.html];
-    delete fiddle.editors[DefaultEditorId.html];
+  it('returns the value for an editor', () => {
+    const model = { testModel: true };
+    const editor = editorMosaic.editors.get(filename);
+    editor!.getModel.mockReturnValue(model);
 
-    expect(getEditorModel(DefaultEditorId.html)).toEqual(null);
+    expect(getEditorModel(filename)).toBe(model);
+  });
 
-    fiddle.editors[DefaultEditorId.html] = oldEditor;
+  it('returns null if the editor does not exist', () => {
+    editorMosaic.editors.delete(filename);
+    expect(getEditorModel(filename)).toBeNull();
   });
 
   it('returns null if window.Fiddle is not ready', () => {
-    const { ElectronFiddle: fiddle } = window as any;
     (window as any).ElectronFiddle = undefined;
-
-    expect(getEditorModel(DefaultEditorId.html)).toEqual(null);
-
-    window.ElectronFiddle = fiddle;
+    expect(getEditorModel(filename)).toBeNull();
   });
 });
diff --git a/tests/utils/editor-mounted-spec.ts b/tests/utils/editor-mounted-spec.ts
index fdb7c967..80bdc9a0 100644
--- a/tests/utils/editor-mounted-spec.ts
+++ b/tests/utils/editor-mounted-spec.ts
@@ -4,18 +4,18 @@ import { DefaultEditorId } from '../../src/interfaces';
 
 describe('waitforEditorsToMount', () => {
   it('resolves when editors match list', async () => {
+    const { editorMosaic } = (window as any).ElectronFiddle.app.state;
+
     // these editors should be mounted by default.
-    const { ElectronFiddle: fiddle } = window as any;
-    const ids = [
+    const files = [
       DefaultEditorId.html,
       DefaultEditorId.main,
       DefaultEditorId.preload,
       DefaultEditorId.renderer,
     ];
-    await waitForEditorsToMount(ids);
+    await waitForEditorsToMount(files);
 
-    const editors = Object.getOwnPropertyNames(fiddle.editors);
-    expect(editors.sort()).toEqual(ids.sort());
+    files.every((file) => expect(editorMosaic.editors.has(file)).toBe(true));
   });
 
   it('rejects if editors fail to match list', async () => {
diff --git a/tests/utils/editor-value-spec.ts b/tests/utils/editor-value-spec.ts
index a4ad7c9f..f04aeb33 100644
--- a/tests/utils/editor-value-spec.ts
+++ b/tests/utils/editor-value-spec.ts
@@ -1,50 +1,39 @@
-import { DefaultEditorId, EditorId } from '../../src/interfaces';
+import { DefaultEditorId } from '../../src/interfaces';
 import { getEditorValue } from '../../src/utils/editor-value';
-import { StateMock } from '../mocks/state';
+import { AppMock, EditorMosaicMock, StateMock } from '../mocks/mocks';
 
 describe('getEditorValue()', () => {
+  const filename = DefaultEditorId.html;
+  const value = 'editor-value';
+  let app: AppMock;
+  let state: StateMock;
+  let editorMosaic: EditorMosaicMock;
+
+  beforeEach(() => {
+    ({ app } = (window as any).ElectronFiddle);
+    ({ state } = app);
+    ({ editorMosaic } = state);
+
+    for (const editor of editorMosaic.editors.values()) {
+      editor.getValue.mockReturnValue(value);
+    }
+  });
+
   it('returns the value for an editor if it exists', () => {
-    expect(getEditorValue(DefaultEditorId.html)).toBe('editor-value');
+    expect(getEditorValue(filename)).toBe(value);
   });
 
   it('returns the value for the editor backup if it exists', () => {
     // set up mock state that has the editor deleted and a backup
-    const oldEditor = window.ElectronFiddle.editors[DefaultEditorId.html];
-    window.ElectronFiddle.editors[DefaultEditorId.html] = null;
-
-    window.ElectronFiddle.app.state = new StateMock() as any;
-    const mockState = window.ElectronFiddle.app.state;
+    editorMosaic.editors.delete(filename);
+    const value = 'editor-backup-value';
+    state.closedPanels = { [filename]: { value } };
 
-    mockState.closedPanels = {
-      [DefaultEditorId.html as EditorId]: {
-        value: 'editor-backup-value',
-      },
-    };
-
-    // assert
-    expect(getEditorValue(DefaultEditorId.html)).toBe('editor-backup-value');
-
-    // revert to initial state
-    window.ElectronFiddle.app.state = new StateMock() as any;
-    window.ElectronFiddle.editors[DefaultEditorId.html] = oldEditor;
-  });
-
-  it('returns an empty string if window.Fiddle is not ready', () => {
-    const oldFiddle = window.ElectronFiddle;
-    (window as any).ElectronFiddle = undefined;
-
-    expect(getEditorValue(DefaultEditorId.html)).toBe('');
-
-    window.ElectronFiddle = oldFiddle;
+    expect(getEditorValue(filename)).toBe(value);
   });
 
   it('returns an empty string if the editor does not exist', () => {
-    const { ElectronFiddle: fiddle } = window as any;
-    const oldEditor = fiddle.editors[DefaultEditorId.html];
-    delete fiddle.editors[DefaultEditorId.html];
-
-    expect(getEditorValue(DefaultEditorId.html)).toBe('');
-
-    fiddle.editors[DefaultEditorId.html] = oldEditor;
+    editorMosaic.editors.delete(filename);
+    expect(getEditorValue(filename)).toBe('');
   });
 });
diff --git a/tests/utils/editor-viewstate-spec.ts b/tests/utils/editor-viewstate-spec.ts
index f53ba722..61944909 100644
--- a/tests/utils/editor-viewstate-spec.ts
+++ b/tests/utils/editor-viewstate-spec.ts
@@ -1,29 +1,30 @@
 import { DefaultEditorId } from '../../src/interfaces';
 import { getEditorViewState } from '../../src/utils/editor-viewstate';
+import { EditorMosaicMock } from '../mocks/mocks';
 
 describe('getEditorViewState()', () => {
+  const filename = DefaultEditorId.html;
+  let editorMosaic: EditorMosaicMock;
+
+  beforeEach(() => {
+    ({ editorMosaic } = (window as any).ElectronFiddle.app.state);
+  });
+
   it('returns the value for an editor', () => {
-    expect(getEditorViewState(DefaultEditorId.html)).toEqual({
-      testViewState: true,
-    });
+    const viewState = { testViewState: true };
+    editorMosaic.editors
+      .get(filename)!
+      .saveViewState.mockReturnValue(viewState);
+    expect(getEditorViewState(filename)).toBe(viewState);
   });
 
   it('returns null if the editor does not exist', () => {
-    const { ElectronFiddle: fiddle } = window as any;
-    const oldEditor = fiddle.editors[DefaultEditorId.html];
-    delete fiddle.editors[DefaultEditorId.html];
-
-    expect(getEditorViewState(DefaultEditorId.html)).toEqual(null);
-
-    fiddle.editors[DefaultEditorId.html] = oldEditor;
+    editorMosaic.editors.delete(filename);
+    expect(getEditorViewState(filename)).toEqual(null);
   });
 
   it('throws if window.Fiddle is not ready', () => {
-    const { ElectronFiddle: fiddle } = window as any;
     (window as any).ElectronFiddle = undefined;
-
-    expect(getEditorViewState(DefaultEditorId.html)).toBeNull();
-
-    window.ElectronFiddle = fiddle;
+    expect(getEditorViewState(filename)).toBeNull();
   });
 });
diff --git a/tests/utils/focused-editor-spec.ts b/tests/utils/focused-editor-spec.ts
index d37c13ff..d22f2376 100644
--- a/tests/utils/focused-editor-spec.ts
+++ b/tests/utils/focused-editor-spec.ts
@@ -1,47 +1,51 @@
-import { DefaultEditorId } from '../../src/interfaces';
+import { DefaultEditorId, EditorId } from '../../src/interfaces';
 import { getFocusedEditor } from '../../src/utils/focused-editor';
-import { EditorMock } from '../mocks/editors';
-import { ElectronFiddleMock } from '../mocks/electron-fiddle';
+import { EditorMosaicMock, MonacoEditorMock } from '../mocks/mocks';
 
 describe('focused-editor', () => {
+  let editorMosaic: EditorMosaicMock;
+
   beforeEach(() => {
-    window.ElectronFiddle = new ElectronFiddleMock() as any;
+    ({ editorMosaic } = (window as any).ElectronFiddle.app.state);
   });
 
+  function setFocus(editor?: MonacoEditorMock) {
+    for (const e of editorMosaic.editors.values()) {
+      e.hasTextFocus.mockReturnValue(e === editor);
+    }
+  }
+
+  function expectCanFocus(name: EditorId) {
+    const editor = editorMosaic.editors.get(name);
+    setFocus(editor);
+    expect(getFocusedEditor()).toBe(editor);
+  }
+
   it('getFocusedEditor() returns the focused editor when it is main.js', () => {
-    (window.ElectronFiddle.editors[DefaultEditorId.main]!
-      .hasTextFocus as jest.Mock<any>).mockReturnValue(true);
-    expect((getFocusedEditor() as any).name).toBe(DefaultEditorId.main);
+    expectCanFocus(DefaultEditorId.main);
   });
 
   it('getFocusedEditor() returns the focused editor when it is preload.js', () => {
-    (window.ElectronFiddle.editors[DefaultEditorId.preload]!
-      .hasTextFocus as jest.Mock<any>).mockReturnValue(true);
-    expect((getFocusedEditor() as any).name).toBe(DefaultEditorId.preload);
+    expectCanFocus(DefaultEditorId.preload);
   });
 
   it('getFocusedEditor() returns the focused editor when it is index.html', () => {
-    (window.ElectronFiddle.editors[DefaultEditorId.html]!
-      .hasTextFocus as jest.Mock<any>).mockReturnValue(true);
-    expect((getFocusedEditor() as any).name).toBe(DefaultEditorId.html);
+    expectCanFocus(DefaultEditorId.html);
   });
 
   it('getFocusedEditor() returns the focused editor when it is renderer.js', () => {
-    (window.ElectronFiddle.editors[DefaultEditorId.renderer]!
-      .hasTextFocus as jest.Mock<any>).mockReturnValue(true);
-    expect((getFocusedEditor() as any).name).toBe(DefaultEditorId.renderer);
+    expectCanFocus(DefaultEditorId.renderer);
   });
 
   it('getFocusedEditor() returns the focused editor when it is custom', () => {
-    const file = new EditorMock('file.js');
-    window.ElectronFiddle.editors['file.js'] = file;
-
-    (window.ElectronFiddle.editors['file.js']!
-      .hasTextFocus as jest.Mock<any>).mockReturnValue(true);
-    expect((getFocusedEditor() as any).name).toBe('file.js');
+    const file = 'file.js';
+    const editor = new MonacoEditorMock();
+    editorMosaic.editors.set(file, editor);
+    expectCanFocus(file);
   });
 
   it('getFocusedEditor() returns null if the editor does not exist', () => {
-    expect(getFocusedEditor() as any).toBe(null);
+    setFocus(undefined);
+    expect(getFocusedEditor()).toBe(null);
   });
 });