如何在Playwright中基于Page Object Model实现Keycloak登录及认证状态复用
问题根因
login-page.js中login方法内重复定义的baseUrl拼写错误,缺少后缀.com,导致登录完成后跳转的目标域名和后续测试用例访问的业务域名不一致,认证状态自然无法匹配。- 登录按钮选择器错误,可正常运行的原生代码中登录按钮选择器为
[id="login-button"],但POM封装时写成了[id="fc-login-button"],实际上并未完成有效登录就提前保存了未授权的状态。 test.use({storageState: xxx})只能在测试文件的顶层或者test.describe块中生效,写在POM的类方法内不会产生任何效果。
修复后的代码
1. login-page.js
// login-page.js const { expect } = require('@playwright/test'); // 全局统一业务域名,不要在方法内重复定义 const baseUrl = 'https://myBaseUrl_xyz.com'; const auth_storage_path = 'storage_auth.json'; exports.LoginPage = class LoginPage { /** * @param {import('@playwright/test').Page} page */ constructor(page) { this.page = page; // 统一管理元素选择器,避免硬编码错误 this.usernameInput = this.page.locator('[id="username"]'); this.passwordInput = this.page.locator('[id="password"]'); // 修正登录按钮选择器,和原生有效代码保持一致 this.loginBtn = this.page.locator('[id="login-button"]'); } async login() { process.env.STORAGE = null; await this.page.goto(baseUrl); await this.usernameInput.fill('*****'); await this.passwordInput.fill('*****'); // 等待登录后成功跳回业务域名,再保存状态 await Promise.all([ this.page.waitForNavigation({ url: baseUrl }), this.loginBtn.click() ]); // 可选:等待网络空闲确保所有认证cookie都已写入 await this.page.waitForLoadState('networkidle'); // 登录完成后再保存上下文状态 const storage = await this.page.context().storageState({path: auth_storage_path}); process.env.STORAGE = JSON.stringify(storage); } }
2. 测试文件调用逻辑无需调整
原来的tests_with_auth_store_viaPage.spec.js逻辑已经正确,只需要保证登录用例执行顺序在测试套之前即可,Playwright默认按文件内代码顺序执行用例,无需额外配置。
优化建议
- 可以将登录逻辑放到Playwright的
globalSetup配置中,避免每个测试文件都执行一次登录用例,全局只需要登录一次即可复用状态。 - 敏感的账号密码不要硬编码在代码中,建议通过
.env环境变量配置读取。 - 修改完成后可打开生成的
storage_auth.json文件,检查cookies数组中是否存在Keycloak和业务域名下的认证cookie,确认状态存储正常。
内容的提问来源于stack exchange,提问作者Angel Lopez
相关产品推荐
相关产品推荐

