-
-
Notifications
You must be signed in to change notification settings - Fork 269
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
How to test Editor #88
Comments
I didn't find a universal way to do it. Depends on the test and testing tool, there can be different problems. First, by default it tries to load sources by injecting a script into the body, it can cause problems, plus it will try to set up workers and etc. So, unfortunately we haven't a normal way to do it yet. |
Thanks for this component! I am using rollup so not having to have a compile step was huge. I am trying to test a component using Jest and either react testing library or enzyme. I am having issues with both. Do you have any tips @suren-atoyan? |
Hi @davidicus. I am sorry for the inconvenience regarding testing. Currently, I have no tips. As the initialization process is supposed to load some scripts from CDN, there is a problem with Jest (and other testing tools). I'll try to find the best way to test it and will come back to you. |
Hi everyone! @suren-atoyan thank you for your great work on this project 👍 Recently we started using |
Hey @przlada, thank you for sharing this 🙂 It's really promising |
Hi Everyone, I mocked out a "fake" Editor using Jest. I used this example as a guide. My implementation of the Editor component is pretty simple, therefore my mock is also pretty simple. The main behavior I needed to test was the onChange function I wrote for my Editor. I realize mocking a component is not ideal, but I was finally able to test how other elements on my page are affected by the onChange. As seen on the react-testing-library FAQ:
import * from "@testing-library/react";
import Tabs from ".";
jest.mock("@monaco-editor/react", () => {
const FakeEditor = jest.fn(props => {
return (
<textarea
data-auto={props.wrapperClassName}
onChange={e => props.onChange(e.target.value)}
value={props.value}
></textarea>
);
});
return FakeEditor;
});
it("can save blob", async () => {
render(<Tabs />);
let saveChangesButton = screen.getByTestId("save-changes");
expect(saveChangesButton).toBeDisabled();
let editor = screen.getByTestId("monaco-editor");
let newValue = JSON.stringify([{ key: false }]);
act(() => {
fireEvent.change(editor, {
target: { value: newValue },
});
});
expect(saveChangesButton).toBeEnabled();
act(() => {
fireEvent.click(saveChangesButton);
});
await waitFor(() => {
expect(screen.getByTestId("success-notification")).toBeInTheDocument();
});
}); Looking forward to a more robust solution in the future... |
Any updates on that?? Would be great to test using RTL the real component instead of a mock. |
Hey everyone 👋 could you please try to use monaco-editor as an npm package during the testing? It's available in |
Not sure if using a 70mb lib just for testing is a good approach. |
@fboechats It shouldn't be |
@suren-atoyan Npm says it's around that: https://www.npmjs.com/package/monaco-editor |
@fboechats the number you've seen on the npm website includes everything in the repo - README, images, etc. The real size of the source is incomparably less than that. In fact, it is just 81.4kB minified and 13.7 KB min+gziped. Check it here. |
@suren-atoyan Having this issue as well. I'm not sure I understand what you mean by using the npm package during the testing? Am I to mock out the import in Jest or actually change my component (thin wrapper for |
@vicky-carbon please check this for more information. Let me know if it helps. By default you do not use |
Can anyone post a working example of this in a codepen? It seems the response from @suren-atoyan results in a number of follow-on questions, and I haven't been able to find any way to implement the advice or the reference given in any test of my own. When I attempt to implement any of the the solutions I've been able to find, either:
as in:
as in...
I've done just about everything I've seen suggested. Installed the 'monaco-editor-webpack-plugin' followed a number of threads on stack overflow to change settings in webpack.config.js, the jest settings, etc. I'm just trying to run a simple test with React Testing Library and Jest that gets past that initially rendered "Loading...". Does anyone have a working example which they can share on codepen or some other way they can share similar @kevinpowell1's super helpful post? Much appreciated. And btw, thank you @suren-atoyan for this great project and all your help. |
@suren-atoyan I am facing the same problem. Is there any working example with a test setup for @monaco-editor/react? It is highly appreciated. |
@Nishchit14 Unfortunately, I do not have a working example, but it's supposed to be working with this setup. It's the second option of @nikiforos-dev comment.
I am wondering what issues he faced here |
I tried the first option and I was also getting the error something like I am using this solution for now #88 (comment) but this is not perfect for our usecase. |
I am facing a similar issue, using import * as monaco from 'monaco-editor';
import Editor, {loader} from "@monaco-editor/react";
loader.config({monaco}); I get this error when running the test suite:
|
Hi Everyone, I spent some time trying to figure it out, and finally, I can make it work, at least to pass the 'Loading...' state and a little bit more in If you just want to see the final solution, check this codesandbox. Long story short, you need Loading the scriptsAs @suren-atoyan explained that the Monaco tries to load sources by injecting a script into the HTML, by default it will load those scripts from CDN as configured here. However, where they are loaded from isn't a problem, the problem is how can we load them. You can paste the following
Executing the scripts
Executing external (untrusted) scripts is very dangerous so At this point, we can load and execute scripts for initiating the Monaco (even from CDN, of course). MockingIf you try to initiate the Monaco in an environment like The list of errors that I fixed in the example is the following:
The special one is import { TextDecoder } from 'util';
...
beforeAll(() => {
// Resolve "TypeError: document.queryCommandSupported is not a function"
global.document.queryCommandSupported = () => true;
// Resolve "TypeError: window.matchMedia is not a function"
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation(query => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(),
removeListener: jest.fn(),
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
})),
});
// Resolve "ReferenceError: ResizeObserver is not defined"
Object.defineProperty(window, 'ResizeObserver', {
value: class ResizeObserver {
observe() {}
unobserve() {}
disconnect() {}
},
});
// Resolve "ReferenceError: TextDecoder is not defined"
Object.defineProperty(window, 'TextDecoder', { value: TextDecoder });
})
...
it("Test monaco editor",async () => {
render(<Monaco/>)
const editor = await screen.findByRole('textbox')
expect(editor).toBeInTheDocument()
}) When you run your test now, you can pass the 'Loading...' state. Congratulation, if this is you goal, you can stop here. I want a little bit more so I tried to type something into the Monaco and it started to complain again ( import { performance } from 'perf_hooks';
...
beforeAll(() => {
...
// Resolve "TypeError: performance.mark is not a function" and other properties of performance
Object.defineProperty(window, 'performance', { value: performance });
})
...
it("Test monaco editor",async () => {
render(<Monaco/>)
const editor = await screen.findByRole('textbox')
expect(editor).toBeInTheDocument()
const user = userEvnet.setup()
await user.type(editor, 'console.log("Hello");');
await expect(screen.findByDisplayValue('console.log("Hello");')).resolves.toBeInTheDocument()
}) Using your local files instead of CDNThis is the easy part. We can change the source where the Monaco will load the scripts using import { loader } from '@monaco-editor/react';
import path from 'path';
...
function ensureFirstBackSlash(str) {
return str.length > 0 && !str.startsWith('/') ? '/' + str : str;
}
function uriFromPath(_path) {
const pathName = path.resolve(_path).replace(/\\/g, '/');
return encodeURI('file://' + ensureFirstBackSlash(pathName));
}
const appPath = path.join(__dirname, '../');
beforeAll(() => {
loader.config({ paths: { vs: uriFromPath(path.resolve(appPath, 'node_modules/monaco-editor/min/vs')) }})
...
});
... Notes
"peerDependencies": {
"monaco-editor": ">= 0.25.0 < 1",
...
},
|
@pasinJ your codesandbox link doesn't seem to have the code anymore. Can you please share an updated sandbox link or a link to a repo? |
@macintushar Please check this repo. I hope it could help. Testing Monaco in a JSDOM environment is pretty complicated and has limited features because we need to mock many things. This method may be suitable only for testing whether it can display something correctly. For more realistic testing, I recommend using a real browser with a framework like Cypress. |
Thanks for the help @pasinJ! 🙌 |
I'm trying to test components using ControlledEditor, but I'm using react testing library and I only can see "Loading..." but never gets the editor working in the tests.
Is there a way to get given value / autocomplete items in the tests ?
The text was updated successfully, but these errors were encountered: