【问题标题】:How to simulate a drag and drop action in puppeteer?如何在 puppeteer 中模拟拖放动作?
【发布时间】:2018-09-21 04:26:55
【问题描述】:

我的应用程序中有 React-DnD(拖放)。我想对它进行 E2E 测试。

我想要模拟的是拖动特定元素并拖放到特定位置。我该怎么做?

我拥有的是:

//test.js
const mouse = page.mouse;
await mouse.down();
await mouse.move(126, 19);
await page.waitFor(400);

使用此代码,选择完成,但拖动不起作用。我应该如何实现这个?

【问题讨论】:

标签: reactjs testing e2e-testing puppeteer


【解决方案1】:

以下方法将允许您在 Puppeteer 中模拟拖放操作:

const example = await page.$('#example');
const bounding_box = await example.boundingBox();

await page.mouse.move(bounding_box.x + bounding_box.width / 2, bounding_box.y + bounding_box.height / 2);
await page.mouse.down();
await page.mouse.move(126, 19);
await page.mouse.up();

【讨论】:

    【解决方案2】:

    没有一个 Puppeteer 特定的解决方案对我有用,所以我最终将本机 javascript 写入一个文件并将其导入 Puppeteer(在我的例子中是 Jest)。

    拖放.js

    async function dragAndDrop(source, target) {
      await page.evaluate((source, target) => {
        source = document.querySelector('#'+source);
    
        event = document.createEvent("CustomEvent");
        event.initCustomEvent("mousedown", true, true, null);
        event.clientX = source.getBoundingClientRect().top;
        event.clientY = source.getBoundingClientRect().left;
        source.dispatchEvent(event);
    
        event = document.createEvent("CustomEvent");
        event.initCustomEvent("dragstart", true, true, null);
        event.clientX = source.getBoundingClientRect().top;
        event.clientY = source.getBoundingClientRect().left;
        source.dispatchEvent(event);
    
        event = document.createEvent("CustomEvent");
        event.initCustomEvent("drag", true, true, null);
        event.clientX = source.getBoundingClientRect().top;
        event.clientY = source.getBoundingClientRect().left;
        source.dispatchEvent(event);
    
    
        target = document.querySelector('#'+target);
    
        event = document.createEvent("CustomEvent");
        event.initCustomEvent("dragover", true, true, null);
        event.clientX = target.getBoundingClientRect().top;
        event.clientY = target.getBoundingClientRect().left;
        target.dispatchEvent(event);
    
        event = document.createEvent("CustomEvent");
        event.initCustomEvent("drop", true, true, null);
        event.clientX = target.getBoundingClientRect().top;
        event.clientY = target.getBoundingClientRect().left;
        target.dispatchEvent(event);
    
        event = document.createEvent("CustomEvent");
        event.initCustomEvent("dragend", true, true, null);
        event.clientX = target.getBoundingClientRect().top;
        event.clientY = target.getBoundingClientRect().left;
        target.dispatchEvent(event);
      }, source, target);
    }
    

    test.js

    const dragAndDrop = require('./drag-and-drop')
    
    describe('when dragging and dropping todo', () => {
    
      it('should change order on DOM', async () => {
        const firstTodo = await page.evaluate(() => document.querySelectorAll('.input-container .input')[0].id);
        const secondTodo = await page.evaluate(() => document.querySelectorAll('.input-container .input')[1].id);
    
        dragAndDrop(firstTodo, secondTodo);
    
        const newFirstTodo = await page.evaluate(() => document.querySelectorAll('.input-container .input')[0].id);
        const newSecondTodo = await page.evaluate(() => document.querySelectorAll('.input-container .input')[1].id);
    
        expect(newFirstTodo).toEqual(secondTodo)
        expect(newSecondTodo).toEqual(firstTodo)
      });
    });
    

    比内置的 Puppeteer 功能稍微多一些工作,但希望对于需要更多控制拖放的其他人来说,这是一个足够简单的复制和粘贴解决方案。

    【讨论】:

    • clientX 和 clientY 与 getBoundingClientRect().top 交换并离开,但一旦我解决了这个问题,这对我有用,谢谢!!
    • 完美运行,唯一缺少的是事件上的 dataTransfer 对象
    【解决方案3】:

    这是我在 puppeteer 中用于拖放的 sn-p:

    //This assumes only one element will be found for selectors you provide, otherwise there's ambiguity on which element was selected.
    //In my code I'm throwing on more than 1 element found
    
    async dragAndDrop(page, originSelector, destinationSelector) {
      await page.waitForSelector(originSelector)
      await page.waitForSelector(destinationSelector)
      const origin = await page.$(originSelector)
      const destination = await page.$(destinationSelector)
      const ob = await origin.boundingBox()
      const db = await destination.boundingBox()
        
      console.log(`Dragging from ${ob.x + ob.width / 2}, ${ob.y + ob.height / 2}`)
      await page.mouse.move(ob.x + ob.width / 2, ob.y + ob.height / 2)
      await page.mouse.down()
      console.log(`Dropping at   ${db.x + db.width / 2}, ${db.y + db.height / 2}`)
      await page.mouse.move(db.x + db.width / 2, db.y + db.height / 2)
      await page.mouse.up()
    }
    

    请注意,在 puppeteer 中对拖放的支持仍然是 not fully 实现的。

    【讨论】:

      【解决方案4】:

      如果这些示例对您不起作用,则可能是另一个时间问题。我玩了一段时间,直到这对我有用。 请注意鼠标命令之间的 50 毫秒等待和增加的步数,这会产生更多的移动/拖动事件并且似乎有所作为。

              // drag node
              let elm = await (await page.waitForSelector("#mynode", { visible: true }));
              let bounding_box = await elm.boundingBox();
              let x = bounding_box.x + bounding_box.width / 2;
              let y = bounding_box.y + bounding_box.height / 2;
              await page.mouse.move(x, y);
              await page.mouse.down();
              await page.waitForTimeout(50);
              await page.mouse.move(x + 100, y, { steps: 10 });
              await page.waitForTimeout(50);
              await page.mouse.up();
              await page.waitForTimeout(50);
      
              await page.screenshot({ path: 'after-drag.png' });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-09-26
        • 2015-06-05
        • 2010-11-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多