现在位置: 首页 > Playwright 教程 > 正文

Playwright JavaScript 执行

本章介绍如何在 Playwright 中执行 JavaScript 代码,包括页面上下文执行、参数传递和初始化脚本注入。


page.evaluate() 页面上下文执行

page.evaluate() 在页面的 JavaScript 环境中执行代码,可以访问 DOM 和页面全局变量。

实例

test('获取页面数据', async ({ page }) => {
  await page.goto('https://www.runoob.com/');

  // 获取页面标题(在页面上下文中执行)
  const title = await page.evaluate(() => {
    return document.title;
  });
  console.log('页面标题:', title);

  // 获取页面中所有链接数量
  const linkCount = await page.evaluate(() => {
    return document.querySelectorAll('a').length;
  });
  console.log('链接数量:', linkCount);

  // 获取页面滚动位置
  const scrollY = await page.evaluate(() => {
    return window.scrollY;
  });
});

向 evaluate 传递参数

page.evaluate() 的第二个参数会传递给页面内的函数。

实例

test('传递参数到页面', async ({ page }) => {
  await page.goto('https://www.runoob.com/');

  // 传递单个参数
  const result1 = await page.evaluate((name) => {
    return `Hello, ${name}!`;
  }, 'RUNOOB');

  // 传递对象参数
  const userInfo = { name: 'runoob', role: 'admin' };
  const result2 = await page.evaluate((user) => {
    return `${user.name} 的角色是 ${user.role}`;
  }, userInfo);

  // 传递多个参数(使用解构)
  const result3 = await page.evaluate(
    ({ x, y }) => {
      return x + y;
    },
    { x: 10, y: 20 }
  );
  console.log('10 + 20 =', result3); // 30
});

传递的参数会被 JSON 序列化后发送到页面上下文,因此不能传递函数、DOM 元素等无法序列化的对象。

传回的值同样会被序列化。


locator.evaluate() 元素上下文执行

locator.evaluate() 在匹配的元素上下文中执行代码,参数中包含该元素的 DOM 节点引用。

实例

test('获取元素的 DOM 属性', async ({ page }) => {
  await page.goto('https://www.runoob.com/');

  // 获取特定元素的 textContent
  const text = await page
    .getByRole('heading', { name: 'RUNOOB' })
    .evaluate(node => node.textContent);

  // 获取元素的样式属性
  const color = await page
    .getByRole('button', { name: '搜索' })
    .evaluate(node => getComputedStyle(node).backgroundColor);
});

locator.evaluateAll() 遍历所有匹配元素

evaluateAll() 对所有匹配元素执行相同的代码,返回数组。

实例

test('获取所有列表项的文本', async ({ page }) => {
  await page.goto('https://www.runoob.com/');

  // 获取所有菜单项的文本
  const menuItems = await page
    .getByRole('navigation')
    .locator('a')
    .evaluateAll(links => links.map(link => link.textContent));

  console.log('菜单项:', menuItems);
  // ['首页', '教程', '工具', ...]
});

page.addInitScript() 注入初始脚本

addInitScript() 在页面加载之前注入 JavaScript 代码,可以在页面脚本执行前修改浏览器环境。

实例

test('注入初始脚本', async ({ page }) => {
  // 在页面加载前修改 navigator 属性
  await page.addInitScript(() => {
    // 覆盖 WebDriver 检测
    Object.defineProperty(navigator, 'webdriver', {
      get: () => false,
    });

    // Mock window 上的全局变量
    window.RUNOOB_CONFIG = {
      env: 'test',
      version: '1.0.0',
    };
  });

  await page.goto('https://www.runoob.com/');

  // 验证注入的变量生效
  const config = await page.evaluate(() => window.RUNOOB_CONFIG);
  console.log(config); // { env: 'test', version: '1.0.0' }
});

addInitScript() 常见用途:

用途说明
Mock 浏览器 API覆盖 navigator.webdrivernavigator.language
注入自定义配置设置测试环境变量、Mock 数据源等
禁用功能关闭 Service Worker、禁用日志等
Polyfill添加页面依赖但测试环境缺少的功能

ElementHandle 的用途与局限

ElementHandle 是 DOM 元素的直接引用,在 Playwright 早期版本中广泛使用。

现在大多数场景应使用 Locator 替代 ElementHandle。

实例

// ElementHandle 方式(旧式,不推荐)
const handle = await page.$('.my-element');
await handle.click();

// Locator 方式(新式,推荐)
await page.locator('.my-element').click();

ElementHandle 仅在需要获取 boundingBox() 或进行复杂 DOM 操作时使用。