Как правильно смоделировать DOM, чтобы я мог протестировать приложение Vue с Jest, использующим Xterm.js? - PullRequest
2 голосов
/ 04 июня 2019

У меня есть компонент Vue, который отображает терминал Xterm.js.

Terminal.vue

<template>
  <div id="terminal"></div>
</template>

<script>
import Vue from 'vue';
import { Terminal } from 'xterm/lib/public/Terminal';
import { ITerminalOptions, ITheme } from 'xterm';

export default Vue.extend({
  data() {
    return {};
  },
  mounted() {
    Terminal.applyAddon(fit);
    this.term = new Terminal(opts);
    this.term.open(document.getElementById('terminal'));    
  },
</script>

Я хочу протестировать этот компонент.

Terminal.test.js

import Terminal from 'components/Terminal'
import { mount } from '@vue/test-utils';

describe('test', ()=>{
  const wrapper = mount(App);
});

Когда я запускаю jest для этого тестового файла, я получаю эту ошибку:

TypeError: Cannot set property 'globalCompositeOperation' of null

      45 |     this.term = new Terminal(opts);
    > 46 |     this.term.open(document.getElementById('terminal'));

Копаясь в трассировке стека, я вижу, что это как-то связано с ColorManager Xterm.

  at new ColorManager (node_modules/xterm/src/renderer/ColorManager.ts:94:39)
  at new Renderer (node_modules/xterm/src/renderer/Renderer.ts:41:25)

Если я посмотрю на их код, я вижу довольно запутанную вещь:

xterm.js / ColorManager.ts

  constructor(document: Document, public allowTransparency: boolean) {
    const canvas = document.createElement('canvas');
    canvas.width = 1;
    canvas.height = 1;
    const ctx = canvas.getContext('2d');
    // I would expect to see the "could not get rendering context"
    // error, as "ctx" shows up as "null" later, guessing from the
    // error that Jest caught
    if (!ctx) {
      throw new Error('Could not get rendering context');
    }
    this._ctx = ctx;
    // Somehow this._ctx is null here, but passed a boolean check earlier?
    this._ctx.globalCompositeOperation = 'copy';
    this._litmusColor = this._ctx.createLinearGradient(0, 0, 1, 1);
    this.colors = {
      foreground: DEFAULT_FOREGROUND,
      background: DEFAULT_BACKGROUND,
      cursor: DEFAULT_CURSOR,
      cursorAccent: DEFAULT_CURSOR_ACCENT,
      selection: DEFAULT_SELECTION,
      ansi: DEFAULT_ANSI_COLORS.slice()
    };
  }

Я не совсем понимаю, как canvas.getContext, по-видимому, возвратил что-то, прошедшее булеву проверку (на if(!ctx)), но позже вызвало ошибку cannot set globalCompositeOperation of null для этой же переменной.

Я очень озадачен тем, как я могу успешно выполнить макет-рендеринг и, следовательно, протестировать этот компонент - в собственных файлах тестирования xterm они, похоже, создают поддельный DOM с использованием jsdom:

xterm.js / ColorManager.test.ts

  beforeEach(() => {
    dom = new jsdom.JSDOM('');
    window = dom.window;
    document = window.document;
    (<any>window).HTMLCanvasElement.prototype.getContext = () => ({
      createLinearGradient(): any {
        return null;
      },

      fillRect(): void { },

      getImageData(): any {
        return {data: [0, 0, 0, 0xFF]};
      }
    });
    cm = new ColorManager(document, false);
});

Но я считаю, что под капотом vue-test-utils также создает поддельный DOM с использованием jsdom.Кроме того, в документации указано, что функция mount одновременно подключает и визуализирует компонент vue.

Создает оболочку, содержащую смонтированный и визуализированный компонент Vue.

https://vue -test-utils.vuejs.org / api / # mount

Как я могу успешно смоделировать DOM таким образом, чтобы я мог протестировать компонент Vue, который реализует Xterm.js, с использованием Jest?

1 Ответ

0 голосов
/ 04 июня 2019

Для этого есть несколько причин.

Прежде всего, Jest js использует jsdom под капотом, как я и подозревал.

Jsdom не поддерживает API-интерфейс DOM для холста из коробки. Прежде всего, вам нужно jest-canvas-mock .

npm install --save-dev jest-canvas-mock

Затем вам нужно добавить его в часть setupFiles вашего jest config. Мой был в package.json, поэтому я добавил это так:

package.json

{
  "jest": {
    "setupFiles": ["jest-canvas-mock"]
  }
}

Затем я получил ошибки о методе insertAdjacentElement метода DOM. В частности, ошибка была:

[Vue warn]: Error in mounted hook: "TypeError: _this._terminal.element.insertAdjacentElement is not a function"

Это потому, что версия jsdom, используемая jest, на сегодняшний день 11.12.0:

npm ls jsdom

└─┬ jest@24.8.0
  └─┬ jest-cli@24.8.0
    └─┬ jest-config@24.8.0
      └─┬ jest-environment-jsdom@24.8.0
        └── jsdom@11.12.0 

С помощью stackoverflow я обнаружил, что в версии 11.12.0 jsdom не реализовал insertAdjacentElement. Однако более поздняя версия jsdom была внедрена insertAdjacentElement еще в июле 2018 года.

Попытки убедить команду шутников использовать более свежую версию jsdom потерпели неудачу. Они не хотят отказываться от совместимости с node6 до последней секунды (они утверждали, что это было в апреле) или, наоборот, больше не хотят реализовывать jsdom, и рекомендуют людям раскошелиться на свои собственные версии репо, если они хотят особенность.

К счастью, вы можете вручную установить, какую версию jsdom jest использует.

Сначала установите пакет jest-environment-jsdom-четырнадцать .

npm install --save jest-environment-jsdom-fourteen

Затем вам нужно изменить свойство testEnvironment вашей конфигурации jest. Итак, теперь мой шутливый конфиг выглядит так:

package.json

  "jest": {
    "testEnvironment": "jest-environment-jsdom-fourteen",
    "setupFiles": ["jest-canvas-mock"]
  }

Теперь я могу запускать тесты без ошибок.

...