Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 4 additions & 57 deletions e2e/next-app/app/editorProbe.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,60 +2,7 @@

import { useState } from 'react';

import MonacoEditor, { DiffEditor, loader, useMonaco, type Monaco } from '@willbooster/monaco-react';

type LoaderConfig = Parameters<typeof loader.config>[0];

const model = {
uri: { path: '/e2e.ts' },
dispose: () => {},
getFullModelRange: () => ({}),
};

const codeEditor = {
dispose: () => {},
executeEdits: () => {},
getModel: () => model,
getOption: () => false,
getValue: () => 'const answer = 42;',
onDidChangeModelContent: () => ({ dispose: () => {} }),
pushUndoStop: () => {},
restoreViewState: () => {},
revealLine: () => {},
saveViewState: () => ({}),
setModel: () => {},
updateOptions: () => {},
};

const diffEditor = {
dispose: () => {},
getModel: () => ({ original: model, modified: model }),
getModifiedEditor: () => codeEditor,
getOriginalEditor: () => codeEditor,
setModel: () => {},
updateOptions: () => {},
};

const monaco = {
editor: {
create: () => codeEditor,
createDiffEditor: () => diffEditor,
createModel: () => model,
EditorOption: {
readOnly: 'readOnly',
},
getModel: () => {},
getModelMarkers: () => [],
onDidChangeMarkers: () => ({ dispose: () => {} }),
setModelLanguage: () => {},
setTheme: () => {},
},
Uri: {
parse: (path: string) => ({ path }),
},
} as unknown as Monaco;

loader.config({ monaco: monaco as LoaderConfig['monaco'] });
import MonacoEditor, { DiffEditor, useMonaco } from '@willbooster/monaco-react';

export default function EditorProbe() {
const [editorStatus, setEditorStatus] = useState('editor-pending');
Expand All @@ -64,15 +11,15 @@ export default function EditorProbe() {

return (
<>
<p data-testid="hook-status">{loadedMonaco === monaco ? 'hook-ok' : 'hook-pending'}</p>
<p data-testid="hook-status">{loadedMonaco?.editor ? 'hook-ok' : 'hook-pending'}</p>
<div data-testid="editor-status">{editorStatus}</div>
<MonacoEditor
height={120}
defaultValue="const answer = 42;"
defaultLanguage="typescript"
onMount={(editor, mountedMonaco) => {
void editor;
setEditorStatus(mountedMonaco === monaco ? 'editor-ok' : 'editor-mismatch');
setEditorStatus(mountedMonaco.editor ? 'editor-ok' : 'editor-mismatch');
}}
/>
<div data-testid="diff-status">{diffStatus}</div>
Expand All @@ -83,7 +30,7 @@ export default function EditorProbe() {
language="typescript"
onMount={(editor, mountedMonaco) => {
void editor;
setDiffStatus(mountedMonaco === monaco ? 'diff-ok' : 'diff-mismatch');
setDiffStatus(mountedMonaco.editor ? 'diff-ok' : 'diff-mismatch');
}}
/>
</>
Expand Down
1 change: 1 addition & 0 deletions e2e/next-app/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference types="next/navigation-types/compat/navigation" />
import "./.next/types/routes.d.ts";

// NOTE: This file should not be edited
Expand Down
27 changes: 27 additions & 0 deletions e2e/next-app/next.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,30 @@ test('loads monaco-react through the Next.js app router', async ({ page }) => {
await expect(page.getByTestId('diff-status')).toHaveText('diff-ok');
expect(errors).toEqual([]);
});

test('keeps Monaco stylesheet after Next.js Head changes', async ({ page }) => {
const errors: string[] = [];
page.on('console', (message) => {
if (message.type() === 'error') {
errors.push(message.text());
}
});
page.on('pageerror', (error) => errors.push(error.message));

await page.goto('/issue272');

await expect(page.getByTestId('editor-status')).toHaveText('editor-ok');
await expect(page.getByTestId('stylesheet-count')).toHaveText('1');

const remountButton = page.getByRole('button', { name: 'Remount editor' });
await remountButton.click();
await expect(page.getByTestId('head-revision')).toHaveText('1');
await expect(page.getByTestId('editor-status')).toHaveText('editor-ok');
await expect(page.getByTestId('stylesheet-count')).toHaveText('1');

await remountButton.click();
await expect(page.getByTestId('head-revision')).toHaveText('2');
await expect(page.getByTestId('editor-status')).toHaveText('editor-ok');
await expect(page.getByTestId('stylesheet-count')).toHaveText('1');
expect(errors).toEqual([]);
});
55 changes: 55 additions & 0 deletions e2e/next-app/pages/issue272.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import Head from 'next/head';
import { useEffect, useState } from 'react';

import MonacoEditor from '@willbooster/monaco-react';

export default function Issue272Page() {
const [headRevision, setHeadRevision] = useState(0);
const [isEditorVisible, setIsEditorVisible] = useState(true);
const [editorStatus, setEditorStatus] = useState('editor-pending');
const [stylesheetCount, setStylesheetCount] = useState(0);
const faviconHref = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Ctext%3E${headRevision}%3C/text%3E%3C/svg%3E`;

useEffect(() => {
setStylesheetCount(countMonacoStylesheets());
}, [headRevision, isEditorVisible]);

function remountEditorWithHeadChange() {
setEditorStatus('editor-pending');
setIsEditorVisible(false);
setHeadRevision((currentRevision) => currentRevision + 1);
requestAnimationFrame(() => setIsEditorVisible(true));
}

return (
<>
<Head>
<title>Issue 272</title>
<link key="favicon" rel="icon" href={faviconHref} />
</Head>
<main>
<button type="button" onClick={remountEditorWithHeadChange}>
Remount editor
</button>
<p data-testid="head-revision">{headRevision}</p>
<p data-testid="stylesheet-count">{stylesheetCount}</p>
<p data-testid="editor-status">{editorStatus}</p>
{isEditorVisible && (
<MonacoEditor
height={120}
defaultValue="const answer = 42;"
defaultLanguage="typescript"
onMount={(_, monaco) => {
setStylesheetCount(countMonacoStylesheets());
setEditorStatus(monaco.editor ? 'editor-ok' : 'editor-mismatch');
}}
/>
)}
</main>
</>
);
}

function countMonacoStylesheets() {
return document.querySelectorAll('link[rel="stylesheet"][href*="/vs/editor/editor.main.css"]').length;
}
Loading