Playwright 第6章:页面操作基础

页面操作是 Playwright 自动化的核心。本章详细介绍页面导航、元素交互方法以及 Playwright 自动等待机制,帮助您编写可靠的自动化脚本。

页面导航与跳转

goto() 方法详解

import { chromium } from 'playwright';

const browser = await chromium.launch();
const page = await browser.newPage();

// 基本导航
await page.goto('https://example.com');

// 完整配置
await page.goto('https://example.com', {
  url: 'https://example.com',
  waitUntil: 'networkidle',
  timeout: 30000,
  referer: 'https://google.com',
});

// 相对路径(需要配置 baseURL)
// playwright.config.ts 中 use: { baseURL: 'http://localhost:3000' }
await page.goto('/login');
await page.goto('/products?id=123');

await browser.close();

页面导航相关方法

const page = await browser.newPage();

// 前进/后退
await page.goBack();
await page.goForward();

// 重新加载
await page.reload();
await page.reload({ waitUntil: 'networkidle' });

// 获取当前 URL
const currentUrl = page.url();
console.log('当前URL:', currentUrl);

// 等待导航完成
await page.waitForURL('**/dashboard');
await page.waitForURL(url => url.includes('success'));

元素交互方法

点击操作

// 基本点击
await page.click('button.submit');

// 使用定位器
await page.locator('#login-btn').click();

// 点击选项
await page.click('.menu-item', {
  button: 'right',        // 右键点击
  clickCount: 2,          // 双击
  delay: 100,             // 按下与释放的延迟
  position: { x: 10, y: 20 }, // 相对元素偏移
  modifiers: ['Shift'],   // 组合键
  force: true,            // 强制点击(绕过可操作性检查)
  timeout: 5000,          // 超时时间
});

// 双击
await page.dblclick('.item');

// 右键点击
await page.click('.item', { button: 'right' });

// Shift+点击
await page.click('.item', { modifiers: ['Shift'] });

文本输入

// fill() 方法:清空原内容后输入
await page.fill('#username', 'admin');
await page.fill('#username', '');  // 清空输入

// type() 方法:逐字符输入(模拟真实打字)
await page.type('#search', 'Playwright', { delay: 50 });

// 清除内容
await page.locator('#username').clear();

// 设置文件输入
await page.setInputFiles('#avatar', 'photo.jpg');

// 聚焦元素
await page.focus('#username');

// 获取值
const value = await page.inputValue('#username');

选择操作

// 单选框/复选框
await page.check('#agree');    // 勾选
await page.uncheck('#agree');  // 取消勾选
const isChecked = await page.isChecked('#agree');

// 下拉选择框
await page.selectOption('#country', 'china');           // 按 value 选择
await page.selectOption('#country', { label: '中国' });  // 按文本选择
await page.selectOption('#country', { index: 2 });       // 按索引选择
await page.selectOption('#colors', ['red', 'blue']);     // 多选

// 获取选择状态
const selectedValue = await page.$eval('#country', el => el.value);
const selectedOptions = await page.locator('#country').inputValue();

获取元素状态

const button = page.locator('.submit-btn');

// 可见性
await expect(button).toBeVisible();
const isVisible = await button.isVisible();

// 启用状态
await expect(button).toBeEnabled();
const isEnabled = await button.isEnabled();

// 存在状态
await expect(button).toBeAttached();
const isAttached = await button.isAttached();

// 已勾选
const isChecked = await button.isChecked();

// 已禁用
const isDisabled = await button.isDisabled();

// 只读
const isEditable = await button.isEditable();

等待策略

自动等待

Playwright 在执行操作前会自动等待元素满足条件:

// 点击前自动等待:
// 1. 元素附加到 DOM
// 2. 元素可见
// 3. 元素稳定(无动画、过渡)
// 4. 元素接收事件(不被遮挡)
// 5. 元素启用
await page.click('.submit-btn');

显式等待

// 等待元素可见
await page.waitForSelector('.loading-done', { state: 'visible' });

// 等待元素消失
await page.waitForSelector('.spinner', { state: 'hidden' });

// 等待特定时间(不推荐)
await page.waitForTimeout(2000);

// 等待网络空闲
await page.waitForLoadState('networkidle');

// 等待自定义条件
await page.waitForFunction(() => {
  return document.querySelectorAll('.item').length >= 10;
}, { timeout: 10000 });

页面信息获取

const page = await browser.newPage();
await page.goto('https://example.com');

// 页面标题
const title = await page.title();

// 页面内容
const content = await page.content();

// 页面文本
const bodyText = await page.locator('body').innerText();

// 页面 URL
const url = page.url();

// 获取特定元素的文本
const headerText = await page.locator('h1').textContent();

// 获取属性
const className = await page.locator('.main').getAttribute('class');
const href = await page.locator('a').getAttribute('href');

// HTML 内容
const html = await page.locator('#main').innerHTML();

console.log({
  title,
  url,
  headerText,
});

页面交互综合示例

import { chromium } from 'playwright';

async function loginFlow() {
  const browser = await chromium.launch({ headless: false });
  const page = await browser.newPage();

  try {
    // 导航到登录页
    await page.goto('https://example.com/login', {
      waitUntil: 'networkidle',
    });

    // 等待表单加载
    await page.waitForSelector('#login-form', { state: 'visible' });

    // 填写用户名和密码
    await page.fill('#username', 'testuser');
    await page.fill('#password', 'TestPass123!');

    // 勾选"记住我"
    await page.check('#remember-me');

    // 提交表单
    await page.click('button[type="submit"]');

    // 等待跳转到首页
    await page.waitForURL('**/dashboard', { timeout: 10000 });

    // 验证登录成功
    const welcomeText = await page.locator('.welcome-message').textContent();
    console.log('登录成功:', welcomeText);

    return true;
  } catch (error) {
    console.error('登录失败:', error);
    await page.screenshot({ path: 'login-error.png' });
    return false;
  } finally {
    await browser.close();
  }
}

loginFlow();

总结

页面操作是 Playwright 自动化的基础。理解自动等待机制是编写稳定测试的关键,推荐优先使用定位器方法(page.locator())而非直接的选择器方法。fill() 是输入文本的首选方法,click() 支持丰富的选项参数满足各种点击场景。在实际项目中,建议将页面操作封装为 Page Object 以提高代码复用性。