You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Monaco Editor单元测试仅渲染第一行问题求助

针对Monaco Editor在Vitest环境下的单元测试方案

问题定位

你遇到的Monaco仅渲染第一行、无法交互的问题,本质是Vitest的jsdom环境对Monaco的DOM模拟不完整——Monaco依赖大量浏览器原生API(如requestAnimationFrame、完整的DOM事件系统),而jsdom默认模拟有限,vitest-canvas-mock只覆盖了canvas相关能力,没补全Monaco需要的其他核心API。

基础配置修复

先完善Vitest的环境配置,确保Monaco能正常初始化:

  1. 在vitest.config.ts中添加环境模拟配置:
import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    environment: 'jsdom',
    setupFiles: ['./vitest.setup.ts'],
    testTimeout: 10000, // 给Monaco异步初始化留足时间
    fakeTimers: {
      enableGlobally: true,
      timers: ['setTimeout', 'setInterval', 'requestAnimationFrame'],
    },
  },
});
  1. 在vitest.setup.ts中补全Monaco依赖的缺失API:
import 'vitest-canvas-mock';

// 模拟ResizeObserver(Monaco布局依赖)
window.ResizeObserver = class ResizeObserver {
  constructor(callback: () => void) {
    callback();
  }
  observe() {}
  unobserve() {}
  disconnect() {}
};

// 模拟文本选择API(Monaco编辑交互依赖)
Object.defineProperty(window, 'getSelection', {
  value: () => ({
    anchorNode: document.body,
    anchorOffset: 0,
    focusNode: document.body,
    focusOffset: 0,
    isCollapsed: true,
    rangeCount: 0,
    getRangeAt: () => ({
      setStart: () => {},
      setEnd: () => {},
      collapse: () => {},
      getBoundingClientRect: () => ({ top: 0, left: 0, width: 0, height: 0 }),
      cloneRange: () => ({})
    }),
    removeAllRanges: () => {},
    addRange: () => {}
  })
});

编写规范的Monaco单元测试

1. 基础渲染验证(单元测试)

优先通过mock Monaco实例的方式,验证编辑器初始化逻辑:

import { render } from '@testing-library/vue'; // Vue项目示例,React可替换为react-testing-library
import MyMonacoEditor from './MyMonacoEditor.vue';
import { vi } from 'vitest';

// Mock Monaco核心模块
vi.mock('monaco-editor', () => ({
  editor: {
    create: vi.fn((el, options) => ({
      getValue: () => options.value,
      setValue: vi.fn(),
      onDidChangeModelContent: vi.fn(),
      dispose: vi.fn(),
    })),
  },
}));

test('Monaco编辑器初始化时传入完整的多行内容', () => {
  const testContent = `function hello() {
  console.log('world');
  return true;
}`;
  render(MyMonacoEditor, { props: { value: testContent } });
  
  // 验证编辑器创建时接收了完整的初始内容
  expect(vi.mocked(import('monaco-editor').editor.create)).toHaveBeenCalledWith(
    expect.any(HTMLElement),
    expect.objectContaining({ value: testContent })
  );
});

2. 交互功能测试(单元测试)

验证内容变更、事件触发等核心交互逻辑:

import { render } from '@testing-library/vue';
import MyMonacoEditor from './MyMonacoEditor.vue';
import { vi } from 'vitest';

test('Monaco编辑器内容变更时能触发组件的change事件', async () => {
  let onChangeCallback: () => void;
  const mockEditor = {
    getValue: vi.fn(() => '初始内容'),
    setValue: vi.fn(),
    onDidChangeModelContent: vi.fn((cb) => {
      onChangeCallback = cb;
      return { dispose: vi.fn() };
    }),
    dispose: vi.fn(),
  };
  vi.mock('monaco-editor', () => ({
    editor: { create: vi.fn(() => mockEditor) },
  }));

  const { emitted } = render(MyMonacoEditor, { props: { value: '初始内容' } });
  
  // 模拟编辑器内部的内容变更事件
  onChangeCallback?.();
  mockEditor.getValue.mockReturnValue('修改后的多行内容');
  
  // 验证组件向外抛出了正确的变更事件
  expect(emitted().change).toHaveLength(1);
  expect(emitted().change[0][0]).toBe('修改后的多行内容');
});

3. 真实交互验证(E2E测试)

如果需要验证真实DOM下的输入、渲染效果,可配合Playwright做E2E测试:

import { test, expect } from '@playwright/test';

test('Monaco编辑器可正常输入并渲染多行文本', async ({ page }) => {
  await page.goto('/editor-page'); // 打开你的编辑器页面路由
  const editorInput = page.locator('.monaco-editor textarea');
  
  // 输入多行代码
  await editorInput.fill(`function calculateSum(a, b) {
  const total = a + b;
  return total;
}`);
  
  // 验证编辑器内容正确
  const inputValue = await editorInput.inputValue();
  expect(inputValue).toContain('const total = a + b;');
  expect(inputValue).toContain('return total;');
});

核心注意事项

  • 单元测试优先mock Monaco实例,避免真实DOM环境的复杂度;
  • 复杂交互、样式渲染类场景,用E2E测试更可靠;
  • 拆分测试粒度:每个测试只验证一个功能点,比如初始化渲染、内容变更、语法校验触发等。

内容的提问来源于stack exchange,提问作者Vamshi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 17:45:27