codemirror / dev

Development repository for the CodeMirror editor project
https://codemirror.net/
Other
5.94k stars 376 forks source link

Codemirror is failing in the unit tests. Undefiend exception on (this.observer.delayedAndroidKey #1430

Closed ievgennaida closed 2 months ago

ievgennaida commented 2 months ago

Describe the issue

I am trying to run codemirrow from the headless mode using vitest.

versions:

    "@codemirror/lang-sql": "6.7.1",
    "codemirror": "6.0.1",

Somehow this.win.requestAnimationFrame is starting measurments before observer is actually initialized or set.

redraw scheduler is started:

    requestMeasure(request) {
        if (this.measureScheduled < 0)
            this.measureScheduled = this.win.requestAnimationFrame(() => this.measure());

Next code is failing while observer is not initialized yet:

      if (this.observer.delayedAndroidKey) {
            this.measureScheduled = -1;
            this.requestMeasure();
            return;
        }

Stack trace:

 at runAnimationFrameCallbacks (node_moduow.js:664:13)
    at Timeout._onTimeout (node_modules\jsdo0:11)
    at listOnTimeout (node:internal/timers:573:17)
    at processTimers (node:internal/timers:514:7) TypeError: Cannot read p
'delayedAndroidKey')
    at EditorView.measure (/node_modujs:7630:27)
    at file:////node_modules/@codemirror/view
    at invokeTheCallbackFunction (node_modulted\Function.js:19:26)
    at runAnimationFrameCallbacks (node_moduow.js:662:13)
    at Timeout._onTimeout (node_modules\jsdo0:11)

Expected result:

    if(!this.observer)
    {
          return;
    }

      if (this.observer.delayedAndroidKey) {
            this.measureScheduled = -1;
            this.requestMeasure();
            return;
        }

Don't crash application when non critical operation cannot be performed.

Browser and platform

Edge, windows

Reproduction link

See code above.

ievgennaida commented 2 months ago

Can be also an issue that you need to first cancelAnimationFrame and only then destroy observer.

Cancel animation frame first?

        this.observer.destroy();
        if (this.measureScheduled > -1)
            this.win.cancelAnimationFrame(this.measureScheduled);
        this.destroyed = true;
ievgennaida commented 2 months ago

Another exception

TypeError: this.printQuery.addListener is not a function
 ? DOMObserver.addWindowListeners node_modules/@codemirror/view/dist/index.js:7039:33       
 ? new DOMObserver node_modules/@codemirror/view/dist/index.js:6711:14
 ? new EditorView node_modules/@codemirror/view/dist/index.js:7414:25
TypeError: this.printQuery.removeListener is not a function 

Both functions are deprecated.

marijnh commented 2 months ago

Somehow this.win.requestAnimationFrame is starting measurments before observer is actually initialized or set.

The EditorView constructor synchronously initializes this.observer, and animation frames run asynchronously, so this isn't really possible unless the requestAnimationFrame in your test environment is weird.

TypeError: this.printQuery.removeListener is not a function

Here too, if you're running this in a pseudo-browser that doesn't support the standards (in this case MediaQueryList.removeEventListener or removeListener), that's not something I'm going to adjust the library for.