从零开发短视频电商 端到端测试Playwright实战CSDN搜索

背景

假设我是csdn的测试人员,我想测试如下流程:

1.用户进入站点https://www.csdn.net

2.在搜索框输入"lakernote"

3.点击搜索按钮

4.切换为用户tab

5.断言列表中是否包含lakernote

相关源码在https://gitee.com/lakernote/easy-auto-uitest

Playwright 内置了自动等待功能,它会在执行操作之前等待元素可操作。

Playwright 提供了assertThat重载来编写断言。

浏览器上下文 Playwright 为每个测试创建一个浏览器上下文。浏览器上下文相当于一个全新的浏览器配置文件。这提供了零开销的完整测试隔离。创建新的浏览器上下文只需几毫秒。

登录一次 保存上下文的身份验证状态并在所有测试中重用它。这绕过了每个测试中的重复登录操作,但提供了独立测试的完全隔离。

脚本录制

当您在浏览器中执行操作时,Playwright 的录制器能够为您生成测试代码。录制器将查看您的页面并找出最佳定位器,确定角色、文本和测试 ID 定位器的优先级。如果生成器找到与定位器匹配的多个元素,它将改进定位器,使其具有唯一标识目标元素的弹性。

运行下面代码以启动录制器

import com.microsoft.playwright.*;

public class Example {
  public static void main(String[] args) {
    try (Playwright playwright = Playwright.create()) {
      BrowserType chromium = playwright.chromium();
      // Make sure to run headed.
      Browser browser = chromium.launch(new BrowserType.LaunchOptions().setHeadless(false));
      // Setup context however you like.
      BrowserContext context = browser.newContext(/* pass any options */);
      context.route("**/*", route -> route.resume());
      // Pause the page, and start recording manually.
      Page page = context.newPage();
      page.pause();
    }
  }
}

录制器各按钮功能介绍

配置

窗口大小

设置浏览器页面的视口大小。

browser.newContext(new Browser.NewContextOptions()
                    .setViewportSize(1280, 720)
                    .setUserAgent("laker"));

UserAgent

browser.newContext(new Browser.NewContextOptions()
  					.setUserAgent("My user agent"));

设置全局默认超时时间

BrowserContext context = browser.newContext();
// 设置全局等待时间,默认是30s
context.setDefaultTimeout(5000); // 5秒

将更改所有接受超时选项的方法的默认最大时间。
注意:Page.setDefaultNavigationTimeout()、Page.setDefaultTimeout() 和 BrowserContext.setDefaultNavigationTimeout() 优先于 BrowserContext.setDefaultTimeout()。

保留登录身份信息

我们在录制脚本时配置storageState,用于保存浏览器中cookielocalStorage的信息到指定文件。

这对于单独记录身份验证步骤并在稍后记录更多测试时重复使用非常有用。

import com.microsoft.playwright.*;
import java.nio.file.Paths;

public class Example {
    public static void main(String[] args) {
        try (Playwright playwright = Playwright.create()) {
            BrowserType chromium = playwright.chromium();
            // Make sure to run headed.
            Browser browser = chromium.launch(new BrowserType.LaunchOptions().setHeadless(false));
            // Setup context however you like.
            BrowserContext context = browser.newContext(new Browser.NewContextOptions()
                    .setViewportSize(1280, 720)
                    .setUserAgent("laker"));
            context.route("**/*", Route::resume);
            // Pause the page, and start recording manually.
            Page page = context.newPage();
            page.pause();
            // 把登录状态,即浏览器的cookie和localstorage存储到文件中。
            context.storageState(new BrowserContext.StorageStateOptions().setPath(Paths.get("auth.json")));
        }
    }
}

执行身份验证并关闭浏览器后(关闭一定要在Playwright Inspector点击关闭),auth.json将包含您可以在测试中重用的存储状态。

确保auth.json仅在本地使用,因为它包含敏感信息。将其添加到.gitignore

加载登录身份信息

加载上面的auth.json`所有cookielocalStorage将被恢复,使大多数 Web 应用程序进入经过身份验证的状态,而无需再次登录。这意味着您可以继续从登录状态生成测试。

import com.microsoft.playwright.*;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        try (Playwright playwright = Playwright.create()) {
            Browser browser = playwright.chromium().launch(new BrowserType.LaunchOptions()
                    .setHeadless(false));
            BrowserContext context = browser.newContext(new Browser.NewContextOptions()
                    .setViewportSize(1280, 720)
                    // 加载cookie和localstorage, 模拟登录态
                    .setStorageStatePath(Paths.get("auth.json")));
            Page page = context.newPage();
            page.navigate("https://gitee.com/lakernote/easy-admin");
            // 将停止执行脚本
            TimeUnit.SECONDS.sleep(20);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

你可以观察下是否已经处于登录态了。

测试框架建议

Playwright 和 Browser 实例可以在测试之间重用,以获得更好的性能。

我们建议在新的 BrowserContext 中运行每个测试用例,这样浏览器状态将在测试之间隔离。

JUnit中,您可以在**@BeforeAll方法中初始化PlaywrightBrowser并在@AfterAll**中销毁它们。

在下面的示例中,三种测试方法都使用相同的Browser。每个测试都使用自己的BrowserContextPage

import com.microsoft.playwright.Browser;
import com.microsoft.playwright.BrowserContext;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.Playwright;
import org.junit.jupiter.api.*;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class TestExample {
  // Shared between all tests in this class.
  static Playwright playwright;
  static Browser browser;

  // New instance for each test method.
  BrowserContext context;
  Page page;

  @BeforeAll
  static void launchBrowser() {
    playwright = Playwright.create();
    browser = playwright.chromium().launch();
  }

  @AfterAll
  static void closeBrowser() {
    playwright.close();
  }

  @BeforeEach
  void createContextAndPage() {
    context = browser.newContext();
    page = context.newPage();
  }

  @AfterEach
  void closeContext() {
    context.close();
  }

  @Test
  void shouldClickButton() {
    page.navigate("data:text/html,<script>var result;</script><button οnclick='result=\"Clicked\"'>Go</button>");
    page.locator("button").click();
    assertEquals("Clicked", page.evaluate("result"));
  }

  @Test
  void shouldCheckTheBox() {
    page.setContent("<input id='checkbox' type='checkbox'></input>");
    page.locator("input").check();
    assertTrue((Boolean) page.evaluate("() => window['checkbox'].checked"));
  }

  @Test
  void shouldSearchWiki() {
    page.navigate("https://www.wikipedia.org/");
    page.locator("input[name=\"search\"]").click();
    page.locator("input[name=\"search\"]").fill("playwright");
    page.locator("input[name=\"search\"]").press("Enter");
    assertEquals("https://en.wikipedia.org/wiki/Playwright", page.url());
  }
}

默认情况下,JUnit 将在单个线程上按顺序运行所有测试。

从 JUnit 5.3 开始,您可以更改此行为以并行运行测试以加快执行速度(请参阅此页)。由于在没有额外同步的情况下从多个线程使用相同的 Playwright 对象是不安全的,因此我们建议您为每个线程创建 Playwright 实例并专门在该线程上使用它。