Puppeteer - 测试不执行任何操作

Puppeteer - the tests do not perform any action

因此,我将 Puppeteer 与 Jest 结合使用。添加后

    const browser = await puppeteer.launch({ headless: false });
    const page = await browser.newPage();

我的测试没有执行任何操作。无论我使用的是无头模式还是我们称之为 "normal" 模式都没有关系。有人可以帮帮我吗?

homepage.test.js

const puppeteer = require('puppeteer');
const HomePage = require('./page_objects/HomePage');

const homePage = new HomePage();
describe('Homepage', () => {
  beforeAll(async () => {
    const browser = await puppeteer.launch({ headless: false });
    const page = await browser.newPage();
    await page.goto(homePage.path);
    await page.waitForSelector(homePage.loginPanel);
  });
  it('Log into your account', async () => {
    await homePage.fillLoginForm();
    await expect(page).toMatchElement(homePage.productList);
    await page.screenshot({ path: 'example.png' });
  });

HomePage.js

module.exports = class HomePage {
  constructor() {
    this.path = 'https://www.saucedemo.com/index.html';
    this.loginPanel = '#login_button_container';
    this.productList = 'div[class="inventory_container"]';
    this.loginForm = {
      fields: {
        usernameInput: 'input[id="user-name"]',
        passwordInput: 'input[id="password"]',
        logInButton: 'input[class="btn_action"]',
      },
    };
  }

  async fillLoginForm() {
    await page.type(this.loginForm.fields.usernameInput, 'standard_user');
    await page.type(this.loginForm.fields.passwordInput, 'secret_sauce');
    await page.click(this.loginForm.fields.logInButton);
  }
};

答案有两部分,一部分是正常的jest,另一部分是jest-puppeteer。如果需要,您可以跳到 jest-puppeteer

问题(jest):

beforeAll 块中的 browserpageit 块无关。它也与HomePage class中的page没有任何关系。

你没有提到你是否使用 jest-puppeteer

解决方案:

为描述块创建块范围变量,并将页面对象传递给模块。

优化主页class

考虑以下 HomePage class.

// HomePage.js
class HomePage {
  constructor(page) {
    this.page = page;
  }

  async getScreenshot() {
    await this.page.screenshot({ path: "example.png" });
  }

  async getTitle(page) {
    return page.title();
  }
}

如您所见,有两种方法可以访问class内的页面。要么在构造函数内部传递,要么直接与方法一起使用。

方法 getScreenshot 有一个 this.page,而 getTitle 可以访问一个 page

优化测试

由于 this issue,您不能在玩笑测试中使用 this,但您可以在块顶部声明一个变量,然后稍后访问它。

describe("Example", () => {
  // define them up here inside the parent block
  let browser;
  let page;
  let homepage;

  beforeAll(async () => {
    // it has access to the browser, page and homepage
    browser = await puppeteer.launch({ headless: true });
    page = await browser.newPage();
    homepage = new HomePage(page); // <-- pass the page to HomePage here

    await page.goto("http://example.com");
    await page.waitForSelector("h1");
    return true;
  });
});

现在所有其他块都可以访问该页面。根据我们之前的示例 HomePage class,我们可以根据我们如何定义方法来执行以下任一操作。

it("Gets the screenshot", async () => {
    await homepage.getScreenshot(); // <-- will use this.page
  });
it("Gets the title", async () => {
    await homepage.getTitle(page); // <-- will use the page we are passing on
});

最后我们清理了测试,

afterAll(async () => {
    await page.close();
    await browser.close();
    return true;
});

我们可能需要 运行 用 detectOpenHandles 开玩笑地测试 headfull 模式。

jest . --detectOpenHandles

结果:

问题(jest-puppeteer):

jest-puppeteer 已经为您提供了全局浏览器和页面对象。你不需要定义任何东西。

但是,如果您想使用 jest-puppeteerexpect-puppeteer,则必须使用自定义配置文件。

解决方案:

创建一个jest-config.json文件并放入内容,

{
  "preset": "jest-puppeteer",
  "setupFilesAfterEnv": ["expect-puppeteer"]
}

现在,摆脱浏览器和页面创建代码,以及 page.close 的任何 afterAll 挂钩。

这是一个有效的测试文件,

class HomePage {
  async getTitle() {
    return page.$("h1");
  }
}

describe("Example", () => {
  const homepage = new HomePage();
  beforeAll(async () => {
    // it has access to a global browser, page and scoped homepage

    await page.goto("http://example.com");
    await page.waitForSelector("h1");
  });
  it("Gets the screenshot", async () => {
    const element = await homepage.getTitle();
    await expect(element).toMatch("Example");
  });
});

让我们运行这个,

jest . --detectOpenHandles --config jest-config.json

结果: