๐Ÿ“ Sign Up | ๐Ÿ” Log In

โ† Root | โ†‘ Up

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ ๐Ÿ“„ shadcn/directory/udecode/plate/(guides)/unit-testing.cn โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘

title: ๅ•ๅ…ƒๆต‹่ฏ• Plate description: ๅญฆไน ๅฆ‚ไฝ•ๅฏน Plate ็ผ–่พ‘ๅ™จๅŠๆ’ไปถ่ฟ›่กŒๅ•ๅ…ƒๆต‹่ฏ•ใ€‚

ๆœฌๆŒ‡ๅ—ๆฆ‚่ฟฐไบ†ไฝฟ็”จ @platejs/test-utils ๅฏน Plate ๆ’ไปถๅ’Œ็ป„ไปถ่ฟ›่กŒๅ•ๅ…ƒๆต‹่ฏ•็š„ๆœ€ไฝณๅฎž่ทตใ€‚

ๅฎ‰่ฃ…

npm install @platejs/test-utils

ๆต‹่ฏ•่ฎพ็ฝฎ

ๅœจๆต‹่ฏ•ๆ–‡ไปถ้กถ้ƒจๆทปๅŠ  JSX ็ผ–่ฏ‘ๆŒ‡็คบ๏ผš

/** @jsx jsx */

import { jsx } from '@platejs/test-utils';

jsx; // ้ฟๅ… ESLint ๆŠฅ้”™

่ฟ™ๅ…่ฎธไฝ ไฝฟ็”จ JSX ่ฏญๆณ•ๆฅๅˆ›ๅปบ็ผ–่พ‘ๅ™จๅ€ผใ€‚

ๅˆ›ๅปบๆต‹่ฏ•็”จไพ‹

็ผ–่พ‘ๅ™จ็Šถๆ€่กจ็คบ

ไฝฟ็”จ JSX ่กจ็คบ็ผ–่พ‘ๅ™จ็Šถๆ€๏ผš

const input = (
  <editor>
    <hp>
      Hello<cursor /> world
    </hp>
  </editor>
) as any as PlateEditor;

่Š‚็‚นๅ…ƒ็ด ๅฆ‚ <hp />ใ€<hul />ใ€<hli /> ่กจ็คบไธๅŒ็ฑปๅž‹็š„่Š‚็‚นใ€‚

็‰นๆฎŠๅ…ƒ็ด ๅฆ‚ <cursor />ใ€<anchor /> ๅ’Œ <focus /> ่กจ็คบ้€‰ๆ‹ฉ็Šถๆ€ใ€‚

ๆต‹่ฏ•่ฝฌๆขๆ“ไฝœ

  1. ๅˆ›ๅปบ่พ“ๅ…ฅ็Šถๆ€
  2. ๅฎšไน‰้ข„ๆœŸ่พ“ๅ‡บ็Šถๆ€
  3. ไฝฟ็”จ createPlateEditor ่ฎพ็ฝฎ็ผ–่พ‘ๅ™จ
  4. ็›ดๆŽฅๅบ”็”จ่ฝฌๆขๆ“ไฝœ
  5. ๆ–ญ่จ€็ผ–่พ‘ๅ™จ็š„ๆ–ฐ็Šถๆ€

ๆต‹่ฏ•ๅŠ ็ฒ—ๆ ผๅผๅŒ–็š„็คบไพ‹๏ผš

it('ๅบ”ๅบ”็”จๅŠ ็ฒ—ๆ ผๅผๅŒ–', () => {
  const input = (
    <editor>
      <hp>
        Hello <anchor />
        world
        <focus />
      </hp>
    </editor>
  ) as any as PlateEditor;

  const output = (
    <editor>
      <hp>
        Hello <htext bold>world</htext>
      </hp>
    </editor>
  ) as any as PlateEditor;

  const editor = createPlateEditor({
    plugins: [BoldPlugin],
    value: input.children,
    selection: input.selection,
  });

  // ็›ดๆŽฅๅบ”็”จ่ฝฌๆข
  editor.tf.toggleMark('bold');

  expect(editor.children).toEqual(output.children);
});

ๆต‹่ฏ•้€‰ๆ‹ฉๆ“ไฝœ

ๆต‹่ฏ•ๆ“ไฝœๅฆ‚ไฝ•ๅฝฑๅ“็ผ–่พ‘ๅ™จ็š„้€‰ๆ‹ฉ๏ผš

it('ๅบ”ๅœจ้€€ๆ ผๆ—ถๆŠ˜ๅ ้€‰ๆ‹ฉ', () => {
  const input = (
    <editor>
      <hp>
        He<anchor />llo wor<focus />ld
      </hp>
    </editor>
  ) as any as PlateEditor;

  const output = (
    <editor>
      <hp>
        He<cursor />ld
      </hp>
    </editor>
  ) as any as PlateEditor;

  const editor = createPlateEditor({
    value: input.children,
    selection: input.selection,
  });

  editor.tf.deleteBackward();

  expect(editor.children).toEqual(output.children);
  expect(editor.selection).toEqual(output.selection);
});

ๆต‹่ฏ•้”ฎ็›˜ไบ‹ไปถ

ๅฝ“้œ€่ฆ็›ดๆŽฅๆต‹่ฏ•้”ฎ็›˜ๅค„็†็จ‹ๅบๆ—ถ๏ผš

it('ๅบ”่ฐƒ็”จ onKeyDown ๅค„็†็จ‹ๅบ', () => {
  const input = (
    <editor>
      <hp>
        Hello <anchor />world<focus />
      </hp>
    </editor>
  ) as any as PlateEditor;

  // ๅˆ›ๅปบๆจกๆ‹Ÿๅค„็†็จ‹ๅบไปฅ้ชŒ่ฏ่ฐƒ็”จ
  const onKeyDownMock = jest.fn();

  const editor = createPlateEditor({
    value: input.children,
    selection: input.selection,
    plugins: [
      {
        key: 'test',
        handlers: {
          onKeyDown: onKeyDownMock,
        },
      },
    ],
  });

  // ๅˆ›ๅปบ้”ฎ็›˜ไบ‹ไปถ
  const event = new KeyboardEvent('keydown', {
    key: 'Enter',
  }) as any;

  // ็›ดๆŽฅ่ฐƒ็”จๅค„็†็จ‹ๅบ
  editor.plugins.test.handlers.onKeyDown({
    ...getEditorPlugin(editor, { key: 'test' }),
    event,
  });

  // ้ชŒ่ฏๅค„็†็จ‹ๅบ่ขซ่ฐƒ็”จ
  expect(onKeyDownMock).toHaveBeenCalled();
});

ๆต‹่ฏ•ๅคๆ‚ๅœบๆ™ฏ

ๅฏนไบŽ่กจๆ ผ็ญ‰ๅคๆ‚ๆ’ไปถ๏ผŒ้€š่ฟ‡็›ดๆŽฅๅบ”็”จ่ฝฌๆขๆฅๆต‹่ฏ•ๅ„็งๅœบๆ™ฏ๏ผš

describe('่กจๆ ผๆ’ไปถ', () => {
  it('ๅบ”ๆ’ๅ…ฅ่กจๆ ผ', () => {
    const input = (
      <editor>
        <hp>
          Test<cursor />
        </hp>
      </editor>
    ) as any as PlateEditor;

    const output = (
      <editor>
        <hp>Test</hp>
        <htable>
          <htr>
            <htd>
              <hp>
                <cursor />
              </hp>
            </htd>
            <htd>
              <hp></hp>
            </htd>
          </htr>
          <htr>
            <htd>
              <hp></hp>
            </htd>
            <htd>
              <hp></hp>
            </htd>
          </htr>
        </htable>
      </editor>
    ) as any as PlateEditor;

    const editor = createPlateEditor({
      value: input.children,
      selection: input.selection,
      plugins: [TablePlugin],
    });

    // ็›ดๆŽฅ่ฐƒ็”จ่ฝฌๆข
    editor.tf.insertTable({ rows: 2, columns: 2 });

    expect(editor.children).toEqual(output.children);
    expect(editor.selection).toEqual(output.selection);
  });
});

ๆต‹่ฏ•ๅธฆ้€‰้กน็š„ๆ’ไปถ

ๆต‹่ฏ•ไธๅŒๆ’ไปถ้€‰้กนๅฆ‚ไฝ•ๅฝฑๅ“่กŒไธบ๏ผš

describe('ๅฝ“ๅฏ็”จๆ’ค้”€ๆ—ถ', () => {
  it('ๅบ”ๅœจๅˆ ้™คๆ—ถๆ’ค้”€ๆ–‡ๆœฌๆ ผๅผ', () => {
    const input = (
      <fragment>
        <hp>
          1/<cursor />
        </hp>
      </fragment>
    ) as any;

    const output = (
      <fragment>
        <hp>
          1/4<cursor />
        </hp>
      </fragment>
    ) as any;

    const editor = createPlateEditor({
      plugins: [
        AutoformatPlugin.configure({
          options: {
            enableUndoOnDelete: true,
            rules: [
              {
                format: 'ยผ',
                match: '1/4',
                mode: 'text',
              },
            ],
          },
        }),
      ],
      value: input,
    });

    // ่งฆๅ‘่‡ชๅŠจๆ ผๅผๅŒ–
    editor.tf.insertText('4');

    // ๆจกๆ‹Ÿ้€€ๆ ผ้”ฎ
    const event = new KeyboardEvent('keydown', {
      key: 'backspace',
    }) as any;

    // ่ฐƒ็”จๅค„็†็จ‹ๅบ
    editor.getPlugin({key: KEYS.autoformat}).handlers.onKeyDown({
      ...getEditorPlugin(editor, AutoformatPlugin),
      event,
    });

    // ๅฝ“ enableUndoOnDelete: true ๆ—ถ๏ผŒๆŒ‰้€€ๆ ผ้”ฎๅบ”ๆขๅคๅŽŸๅง‹ๆ–‡ๆœฌ
    expect(input.children).toEqual(output.children);
  });
});

ๆจกๆ‹ŸไธŽ็œŸๅฎž่ฝฌๆข

่™ฝ็„ถๆจกๆ‹Ÿๅฏ็”จไบŽ้š”็ฆป็‰นๅฎš่กŒไธบ๏ผŒไฝ† Plate ๆต‹่ฏ•้€šๅธธไผšๅœจ่ฝฌๆขๅŽ่ฏ„ไผฐๅฎž้™…็š„็ผ–่พ‘ๅ™จๅญ่Š‚็‚นๅ’Œ้€‰ๆ‹ฉใ€‚่ฟ™็งๆ–นๆณ•็กฎไฟๆ’ไปถ่ƒฝไธŽๆ•ดไธช็ผ–่พ‘ๅ™จ็Šถๆ€ๆญฃ็กฎๅๅŒๅทฅไฝœใ€‚

โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•‘
โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

โ† Root | โ†‘ Up