傀儡师测试 - CdpElementHandle.click() 似乎不起作用

Puppeteer testing - CdpElementHandle.click() doesn't seem to work

提问人:karalkal 提问时间:10/21/2023 最后编辑:karalkal 更新时间:10/24/2023 访问量:37

问:

Previous test finds the button but cannot click on it我正试图对 Puppeteer 的工作原理有一些基本的了解,并且正在苦苦挣扎。 我正在测试的应用程序可以在这里找到。 单击登录按钮后,应用程序应重定向到 Spotify 并获得 AOuth 授权以搜索 API 并在登录用户帐户中创建和保存播放列表。 但是,我不认为我的测试会点击该按钮,尽管它“找到”了它 - 它似乎在模式下没有做任何事情,当然也不会重定向到任何地方。当然,测试也失败了。 如果我设法以一种或另一种方式解决这个问题,我是否能够在“测试模式”中获得令牌(对不起,愚蠢的表达,希望它足够清楚)?我无法想象能够做到这一点,因为 Puppeteer 必须“登录”到 Spotify,但必须有办法。 顺便说一句,任何人都可以解释一下表达方式的实际作用。如果我用有意义的东西替换参数,即 10000,我就会收到超时错误。字符串值实际上有什么作用? 谢谢。headless: falseawait page.waitForTimeout(HEADING_SELECTOR);

const puppeteer = require('puppeteer');
const { expect } = require('chai');
const _ = require('lodash');
const globalVariables = _.pick(global, ['browser', 'expect']);


// puppeteer options
const opts = {
    headless: false,
    slowMo: 100,
    timeout: 10000
};

// expose variables
before(async function () {
    global.expect = expect;
    global.browser = await puppeteer.launch(opts);
});

// close browser and reset global variables
after(function () {
    browser.close();

    global.browser = globalVariables.browser;
    global.expect = globalVariables.expect;
});


describe('sample test', function () {

    // By default, Mocha tests have a 2 second timeout (which means that the test needs to be completed in 2 seconds).
    // You can increase it (in milliseconds) as follows:

    this.timeout(8000); // this test can take up to 5 seconds

    let page;

    before(async function () {
        page = await browser.newPage();
        await page.goto('http://localhost:3000');
    });

    after(async function () {
        await page.close();
    })


    // TESTS
    it('should work', async function () {
        console.log(await browser.version());
        expect(true).to.be.true;
    });

    it('should have the correct page title', async function () {
        expect(await page.title()).to.eql('Spotify Playlist Creator');
    });

    it('should have correct heading', async function () {
        const HEADING_SELECTOR = 'h1';
        let heading;

        page.waitForSelector(HEADING_SELECTOR)

        /*
        page.$eval takes two arguments - selector and pageFunction. 
        It runs a document.querySelector in the browser environment and passes the result to the pageFunction. 
        Finally, it resolves with the value returned by pageFunction. 
        In this case, we are just returning the text for h1 tag.
        */
        heading = await page.$eval(HEADING_SELECTOR, heading => heading.innerText);

        expect(heading).to.eql('Spotify Playlist Creator');
    });

    it('should not display ErrorModal', async function () {
        const ERROR_MODAL_SELECTOR = '.ErrorModal';

        page.waitForSelector(ERROR_MODAL_SELECTOR)

        // The method runs document.querySelectorAll within the page. If no elements match the selector, the return value resolves to []
        expect(await page.$$(ERROR_MODAL_SELECTOR)).to.be.deep.equal([])
    });

    it('should be displaying login button', async function () {
        const LOGIN_BUTTON_SELECTOR = 'button';
        let loginBtn;

        page.waitForSelector(LOGIN_BUTTON_SELECTOR);

        loginBtn = await page.$(LOGIN_BUTTON_SELECTOR)
        const btnText = await page.evaluate(loginBtn => loginBtn.textContent, loginBtn);

        expect(btnText).to.equal("Login to Spotify");
    });

    // DOES NOT WORK!!!
    it('should click login button', async function () {
        const LOGIN_BUTTON_SELECTOR = 'button';
        let loginBtn;

        page.waitForSelector(LOGIN_BUTTON_SELECTOR);

        loginBtn = await page.$(LOGIN_BUTTON_SELECTOR)

        await loginBtn.click();
        console.log(loginBtn, "button has been clicked")

        expect(page.url()).to.include("https://accounts.spotify.com/en/login?");
    });
})
JavaScript 自动测试 mocha.js 木偶师

评论

1赞 ggorlen 10/21/2023
你需要.几乎所有的 Puppeteer API 调用都会返回 promise,如果您不等待它们,则会出现争用条件和错误。 应该失败。waitForTimeout 接受一个数字作为其参数,而不是字符串。也就是说,超时一开始就不好用。你可能想在这里使用。可能还有其他问题,但如果没有一个最小的可重复示例,除了快速的现场抽查之外,很难提供太多的东西。await loginBtn.click();await page.waitForTimeout(HEADING_SELECTOR);waitForSelector
1赞 ggorlen 10/23/2023
请将您的代码更新为文本,而不是屏幕截图。我仍然看到您的代码中缺少 s。每个返回 promise 的 Puppeteer 调用都需要进行编辑。缺少一个是非启动器。awaitawaitawait
0赞 karalkal 10/23/2023
你好。感谢您的帮助。当然,page.waitForTimeout([string-value]) 没有意义。我被一个旧教程误导了,我通过上传实际失败测试的图片更新了我原来的问题。之前的测试(找到按钮)通过,我单击按钮并期望被重定向到 spotify 的登录页面失败。

答:

0赞 karalkal 10/24/2023 #1

我首先用赛普拉斯达到了预期的效果:

cy.on("url:changed", (newUrl) => {
            expect(newUrl).to.contain([whatever-it-should-contain])

如果我没记错的话,Page.waitForNavigation() 方法在 Puppeteer 中也做同样的事情。 我不是一只快乐的兔子,因为我浪费了几个小时来弄清楚这一点 - 我从没想过一个名为“waitForNavigation”的方法会等待页面导航到新的 URL......当然,这完全是我的错。 正确的测试如下:

it.only('should click login button', async function () {
        const LOGIN_BUTTON_SELECTOR = 'button';
        let loginBtn;
        page.waitForSelector(LOGIN_BUTTON_SELECTOR);
        loginBtn = await page.$(LOGIN_BUTTON_SELECTOR)

        await loginBtn.click();

        await page.waitForNavigation();
        expect(page.url()).to.include("https://accounts.spotify.com/en/login?");
    });