Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(CodeEditor): use new monaco package #9842

Merged
merged 5 commits into from
Jan 5, 2024
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
6 changes: 3 additions & 3 deletions packages/react-code-editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@
"@patternfly/react-icons": "^5.2.0-prerelease.8",
"@patternfly/react-styles": "^5.2.0-prerelease.5",
"react-dropzone": "14.2.3",
"tslib": "^2.5.0"
"tslib": "^2.5.0",
"@monaco-editor/react": "^4.6.0"
},
"peerDependencies": {
"react": "^17 || ^18",
"react-dom": "^17 || ^18",
"react-monaco-editor": "^0.51.0"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe changing the Peer dependency here is breaking. We would want to introduce this as next.

"react-dom": "^17 || ^18"
},
"devDependencies": {
"rimraf": "^2.6.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
TooltipPosition,
EmptyStateHeader
} from '@patternfly/react-core';
import MonacoEditor, { ChangeHandler, EditorDidMount } from 'react-monaco-editor';
import Editor, { Monaco } from '@monaco-editor/react';
import { editor } from 'monaco-editor/esm/vs/editor/editor.api';
import CopyIcon from '@patternfly/react-icons/dist/esm/icons/copy-icon';
import UploadIcon from '@patternfly/react-icons/dist/esm/icons/upload-icon';
Expand All @@ -28,6 +28,9 @@ import Dropzone, { FileRejection } from 'react-dropzone';
import { CodeEditorContext } from './CodeEditorUtils';
import { CodeEditorControl } from './CodeEditorControl';

export type ChangeHandler = (value: string, event: editor.IModelContentChangedEvent) => void;
export type EditorDidMount = (editor: editor.IStandaloneCodeEditor, monaco: Monaco) => void;

export interface Shortcut {
description: string;
keys: string[];
Expand Down Expand Up @@ -631,15 +634,15 @@ class CodeEditor extends React.Component<CodeEditorProps, CodeEditorState> {

const editor = (
<div className={css(styles.codeEditorCode)} ref={this.wrapperRef} tabIndex={0} dir="ltr">
<MonacoEditor
<Editor
height={height}
width={width}
language={language}
value={value}
options={options}
overrideServices={overrideServices}
onChange={this.onChange}
editorDidMount={this.editorDidMount}
onMount={this.editorDidMount}
theme={isDarkTheme ? 'vs-dark' : 'vs-light'}
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,46 +1,79 @@
import React from 'react';
import { render } from '@testing-library/react';
import { render, screen, act } from '@testing-library/react';
import { CodeEditor, Language } from '../CodeEditor';
import styles from '@patternfly/react-styles/css/components/CodeEditor/code-editor';
import fileUploadStyles from '@patternfly/react-styles/css/components/FileUpload/file-upload';

Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation((query) => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // Deprecated
removeListener: jest.fn(), // Deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn()
}))
});

describe('CodeEditor', () => {
beforeAll(() => {
window.HTMLCanvasElement.prototype.getContext = () => ({}) as any;
});
jest.mock('@monaco-editor/react', () => jest.fn(() => <div data-testid="mock-editor"></div>));

test('matches snapshot without props', () => {
const { asFragment } = render(<CodeEditor />);
expect(asFragment()).toMatchSnapshot();
});
test('Matches snapshot without props', () => {
const { asFragment } = render(<CodeEditor code="test" />);
expect(asFragment()).toMatchSnapshot();
});

test('Matches snapshot with control buttons enabled', () => {
const { asFragment } = render(<CodeEditor isUploadEnabled isDownloadEnabled isCopyEnabled code="test" />);
expect(asFragment()).toMatchSnapshot();
});

test(`Renders with default classes ${styles.codeEditor}, ${styles.codeEditorMain}, ${styles.codeEditorCode}`, () => {
render(<CodeEditor />);
expect(screen.getByTestId('mock-editor').parentElement).toHaveClass(styles.codeEditorCode);
expect(screen.getByTestId('mock-editor').parentElement?.parentElement).toHaveClass(styles.codeEditorMain);
expect(screen.getByTestId('mock-editor').parentElement?.parentElement?.parentElement).toHaveClass(styles.codeEditor);
});

test('Renders custom class when className is passed', () => {
render(<CodeEditor className="custom" />);
expect(screen.getByTestId('mock-editor').parentElement?.parentElement?.parentElement).toHaveClass('custom');
});

test(`Renders with ${styles.modifiers.readOnly} when isReadOnly = true`, () => {
render(<CodeEditor isReadOnly />);
expect(screen.getByTestId('mock-editor').parentElement?.parentElement?.parentElement).toHaveClass(
styles.modifiers.readOnly
);
});

test(`Renders with ${fileUploadStyles.fileUpload} when isUploadEnabled = true`, () => {
render(<CodeEditor isUploadEnabled code="test" />);
expect(screen.getByTestId('mock-editor').parentElement?.parentElement?.parentElement).toHaveClass(
fileUploadStyles.fileUpload
);
});

test(`Renders with empty state when code = undefined`, () => {
render(<CodeEditor emptyState={<div>empty</div>} />);
expect(screen.getByText('empty')).toBeInTheDocument();
});

test(`Renders with empty state when isUploadEnabled = true and code = undefined`, () => {
render(<CodeEditor emptyState={<div>empty</div>} isUploadEnabled />);
expect(screen.getByText('empty')).toBeInTheDocument();
});

test(`Renders with language label when isLanguageLabelVisible`, () => {
render(<CodeEditor isLanguageLabelVisible language={Language.java} />);
expect(screen.getByText('JAVA')).toBeInTheDocument();
});

test(`Renders with custom controls when customControls is passed`, () => {
render(<CodeEditor customControls={<div>control</div>} />);
expect(screen.getByText('control')).toBeInTheDocument();
});

test(`Renders with custom header content when headerMainContent is passed`, () => {
render(<CodeEditor headerMainContent="header content" />);
expect(screen.getByText('header content')).toBeInTheDocument();
});

test('matches snapshot with all props', () => {
const { asFragment } = render(
<CodeEditor
isReadOnly
isDarkTheme
isLineNumbersVisible={false}
isUploadEnabled
isLanguageLabelVisible
isDownloadEnabled
isCopyEnabled
height="400px"
code={'test'}
language={Language.javascript}
/>
);
expect(asFragment()).toMatchSnapshot();
test(`Renders with shortcuts when shortcutsPopoverButtonText is passed`, () => {
render(
<CodeEditor shortcutsPopoverButtonText="shortcuts-button" shortcutsPopoverProps={{ bodyContent: 'shortcuts' }} />
);
expect(screen.getByText('shortcuts-button')).toBeInTheDocument();
act(() => {
screen.getByText('shortcuts-button').click();
});
expect(screen.getByText('shortcuts')).toBeInTheDocument();
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import { CodeEditorControl } from '../CodeEditorControl';

test('Matches snapshot', () => {
const { asFragment } = render(<CodeEditorControl icon={<div>icon</div>} onClick={jest.fn()} />);
expect(asFragment()).toMatchSnapshot();
});

test('Renders with custom class when className is passed', () => {
render(<CodeEditorControl className="custom" icon={<div>icon</div>} onClick={jest.fn()} />);
expect(screen.getByText('icon').parentElement).toHaveClass('custom');
});

test('Renders with accessible name when aria-label is passed', () => {
render(<CodeEditorControl aria-label="aria-test" icon={<div>icon</div>} onClick={jest.fn()} />);
expect(screen.getByLabelText('aria-test'));
});
Loading
Loading