反応試験ライブラリによる反応DNDの試験


このポストはReact DnD Chessboard AppReact Testing Libraryをテストする方法を示します.

full code example is here.
https://github.com/laststance/react-testing-library-react-dnd-chessboard-example


コード例

  • ナイト.TSX
  • import React from 'react'
    import { ItemTypes knightImage} from './Game'
    import { useDrag, DragPreviewImage } from 'react-dnd'
    
    const Knight: React.FC = () => {
      const [{ isDragging }, drag, preview] = useDrag({
        item: { type: ItemTypes.KNIGHT },
        collect: (monitor) => ({
          isDragging: !!monitor.isDragging(),
        }),
      })
    
      return (
        <>
          <DragPreviewImage connect={preview} src={knightImage} />
          <div
            ref={drag}
            style={{
              display: 'block',
              opacity: isDragging ? 0.5 : 1,
              fontSize: '64px',
              fontWeight: 'bold',
              cursor: 'move',
            }}
          ></div>
        </>
      )
    }
    
    export default Knight
    
  • ボードスクエア.TSX
  • Drop area side
    import React from 'react'
    import Square from './Square'
    import Overlay from './Overlay'
    import { canMoveKnight, moveKnight, X, Y } from './Game'
    import { ItemTypes } from './Game'
    import { useDrop } from 'react-dnd'
    
    interface Props {
      x: X
      y: Y
      index: number
    }
    
    const BoardSquare: React.FC<Props> = ({ x, y, index, children }) => {
      const black = (x + y) % 2 === 1
      const [{ isOver, canDrop }, drop] = useDrop({
        accept: ItemTypes.KNIGHT,
        drop: () => moveKnight(x, y),
        canDrop: () => canMoveKnight(x, y),
        collect: (monitor) => ({
          isOver: !!monitor.isOver(),
          canDrop: !!monitor.canDrop(),
        }),
      })
    
      return (
        <div
          role="gridcell"
          ref={drop}
          data-testid={children ? 'KnightPosition: ' + index : index}
          style={{
            position: 'relative',
            width: '100%',
            height: '100%',
          }}
        >
          <Square black={black}>{children}</Square>
          {isOver && !canDrop && <Overlay color="red" data-testid="RedOverlay" />}
          {!isOver && canDrop && (
            <Overlay color="yellow" data-testid="YellowOverlay" />
          )}
          {isOver && canDrop && (
            <Overlay color="green" data-testid="GreenOverlay" />
          )}
        </div>
      )
    }
    
    export default BoardSquare
    
  • の統合.テスト.TSX
  • import React from 'react'
    import '../index.css'
    import { render, screen, fireEvent } from '@testing-library/react'
    import Board from '../Board'
    import { observe, KnightPosition, releaseObserver } from '../Game'
    
    function dragAndDrop(knight: HTMLElement, cell: HTMLElement) {
      fireEvent.dragStart(knight)
      fireEvent.dragEnter(cell)
      fireEvent.dragOver(cell)
      fireEvent.drop(cell)
    }
    
    function dragHold(knight: HTMLElement, cell: HTMLElement) {
      fireEvent.dragStart(knight)
      fireEvent.dragEnter(cell)
      fireEvent.dragOver(cell)
    }
    
    beforeEach(() => {
      /*
       * Every time Knight initial position: "57"
       * and Knight droppable positions are "40", "42", "51"
       * when you got all cells with screen.getAllByRole('gridcell')
       */
      observe((knightPosition: KnightPosition) =>
        render(<Board knightPosition={knightPosition} />)
      )
    })
    
    afterEach(() => {
      releaseObserver()
    })
    
    test('should exist Knight with certain visual on board', () => {
      const Knight = screen.getByText('')
    
      const display = window.getComputedStyle(Knight).getPropertyValue('display')
      const opacity = window.getComputedStyle(Knight).getPropertyValue('opacity')
      const fontSize = window.getComputedStyle(Knight).getPropertyValue('font-size')
      const fontWeight = window
        .getComputedStyle(Knight)
        .getPropertyValue('font-weight')
      const cursor = window.getComputedStyle(Knight).getPropertyValue('cursor')
    
      expect({
        display: display,
        opacity: opacity,
        fontSize: fontSize,
        fontWeight: fontWeight,
        cursor: cursor,
      }).toStrictEqual({
        display: 'block',
        opacity: '1',
        fontSize: '64px',
        fontWeight: 'bold',
        cursor: 'move',
      })
    })
    
    test('should board have 64 cells', () => {
      const boardSquares = screen.getAllByRole('gridcell')
      expect(boardSquares.length).toBe(64) // chessboard ragnge is 8 * 8
    })
    
    test("Knight initial position is 'index 57' of all cell array", () => {
      expect(screen.getByTestId('KnightPosition: 57')).toHaveTextContent('')
    })
    
    test('testing the moment of dragging hold', () => {
      const knight = screen.getByText('')
      const boardSquares = screen.getAllByRole('gridcell')
      const knightPosition = boardSquares[57]
    
      dragHold(knight, knightPosition)
    
      // Yellow cell is knight moving range
      const KnightDropableSquares = screen.getAllByTestId('YellowOverlay')
    
      // Initially knight can move to 3 position
      expect(KnightDropableSquares.length).toBe(3)
    
      // Yellow color css check
      KnightDropableSquares.forEach((square) => {
        expect(square).toHaveStyle('backgroundColor: yellow')
      })
    
      // Red cell is current knight position when hold dragging
      expect(screen.getByTestId('RedOverlay')).toHaveStyle('backgroundColor: red')
    })
    
    describe('Knight can drag and drop initial moving range', () => {
      // Knight initially has moving position 'index: 40 42 51' of 64 cell array
      test('gridcell[40]', () => {
        const knight = screen.getByText('')
        const yellowCell40 = screen.getAllByRole('gridcell')[40]
        dragAndDrop(knight, yellowCell40)
        expect(screen.getByTestId('KnightPosition: 40')).toHaveTextContent('')
      })
    
      test('gridcell[42]', () => {
        const knight = screen.getByText('')
        const yellowCell42 = screen.getAllByRole('gridcell')[42]
        dragAndDrop(knight, yellowCell42)
        expect(screen.getByTestId('KnightPosition: 42')).toHaveTextContent('')
      })
    
      test('gridcell[51]', () => {
        const knight = screen.getByText('')
        const yellowCell51 = screen.getAllByRole('gridcell')[51]
        dragAndDrop(knight, yellowCell51)
        expect(screen.getByTestId('KnightPosition: 51')).toHaveTextContent('')
      })
    })
    
    test('Knight can not drop not yellow cell', () => {
      const knight = screen.getByText('')
      const whiteCell = screen.getByTestId('0')
      const blackCell = screen.getByTestId('1')
      expect(whiteCell.firstChild).toHaveStyle('background-color: white;')
      expect(blackCell.firstChild).toHaveStyle('background-color: black;')
    
      dragAndDrop(knight, whiteCell)
    
      expect(screen.getByTestId('KnightPosition: 57')).toHaveTextContent('')
    
      dragAndDrop(knight, blackCell)
    
      expect(screen.getByTestId('KnightPosition: 57')).toHaveTextContent('')
    })
    

    問題


    DND抽象242479152に反応するが、標準的なWeb APIを使用してテストライブラリをテストし、ブラウザイベントをテストする(Standard Drag Web APIを参照)
    私はどのDNS APIが一緒にウェブAPI(ondragstartなど)を結びつけたかを知りません.
    したがって、これらのマッピングやChrome devtoolsデバッグによるチェックを推論する必要があるかもしれません.

    発火イベント ブラウザのイベント発火をデバッグしましょう


    とchrome devtoolsについて説明します.

    チェスボードの例アプリ オープンソースのタブ


    そして、右から右へのEvent Listener Breakpointsパンを見つける.

    デバッグするイベントをチェックします


    次の画像では、dragEndが選択される.
    これはセットアップ準備ブレークポイントの全画面dragEndイベントを意味します.

    ブラウザにデバッグターゲットアクションを行う


    次の画像ブラウザでは、ドラッグ項目を起動して停止し、トリガされたイベントリスナーを表示したときにブレークポイントによって停止します.


    したがって、あなたが反応DNDによってインプリメントするどんな行動も持っていて、反応テストライブラリでテストを書きたいとき.
    あなたは、どのイベントリスナーがそれと結びつくかを調査しなければなりません.

    結論


    私は、このポストが少しニッチな話題であると思います、私は関連した問題を持っている誰かにとって役に立つことができてうれしいです.
    そして、その重要な知識を通じて、基本的には、特定のライブラリではなく、Web技術の基本的なものだと思いました.
    記事を読んでくれてありがとう!
    また会いましょう!🤗