How to write tests for events in code mirror?

I’m trying to write unit tests for my editor in code mirror.

I’m trying to write a unit test, that mimics a user action, like maybe Ctrl+V or RightMouseClick->Paste, and then the test would verify certain action.

However, I’m having a problem, because I don’t know how to dispatch a custom event, so that the CodeMirror would catch it.

import {EditorState} from "@codemirror/state";
import {EditorView} from "@codemirror/view";

test('fire', () => {
  const parent = document.createElement('div');
  const state = EditorState.create({
    doc: 'welcome',
    extensions: [
      EditorView.domEventHandlers({
        keydown(event) {
          console.log("doesn't get called");
        },
      })
    ]
  });
  new EditorView({parent, state});

  parent.addEventListener('keydown', event => {
    console.log("gets called");
  });

  parent.dispatchEvent(new CustomEvent('keydown')); // I'm pretty sure this is wrong
});

I just want a unit test, that can spoof an event, dispatch it (or in other ways spoof user action of pasting something), and then verify its result in the editor state.

Using a ‘browser driver’ in the style of Selenium should work. There is no way that I know of for client code to generate events that behave exactly like the browser’s native events – you can dispatch DOM events, but your paste events won’t have clipboard access, your keyboard events won’t cause the browsers default behavior, and so on.

1 Like

Using a ‘browser driver’ in the style of Selenium should work.

Won’t that cause my tests to be turbo slow? :confused:

There is no way that I know of for client code to generate events that behave exactly like the browser’s native events – you can dispatch DOM events, but your paste events won’t have clipboard access, your keyboard events won’t cause the browsers default behavior, and so on.

That’s fine, I want to run it in node.js, and I will create dummy ClipboardEvent instances, for the sake of unit tests. I don’t want to test the browser behaviour anyway, just CodeMirror extensions.

Do you think this is fine, or will it break the library?

const view = new EditorView({parent, state});
view.contentDOM.dispatchEvent(new CustomEvent('keydown'));

As far as CodeMirror is concerned, dispatchEvent should work (though an empty custom event named ‘keydown’ won’t have any useful KeyboardEvent properties). But to get typed text, CodeMirror relies on the browser’s text input behavior, and simulated events won’t provide that.

1 Like

But to get typed text, CodeMirror relies on the browser’s text input behavior, and simulated events won’t provide that.

So maybe if I have

view.contentDOM.innerHTML; // hello

and I run

view.contentDOM.innerHTML += 'p';

Will this "p" change in the innerHTML simulate browser input? Or maybe I should fire "input" event?

Doing += on innerHTML will cause the entire content of the element to refresh. Also appending text after the line divs doesn’t seem like a very reasonable way to simulate typing. So try something a bit more focused, like adding text nodes in the right place or updating the nodeValue of existing text nodes.

Okay, I’ll do that.

And how would I fake selection changes?

Set the DOM selection.