浏览器测试
浏览器测试在 Chrome、Firefox 或 Safari 等真实浏览器中执行。我们使用 Playwright(一个浏览器自动化工具)来以编程方式与网页交互。
Playwright 既是一个测试框架,也是一个暴露 JavaScript API 以与浏览器交互的库。我们 不使用 Playwright 的测试框架,因为我们已经在使用 Japa,而在单个项目中使用多个测试框架只会导致混乱和配置臃肿。
相反,我们将使用 Japa 的 Browser Client 插件,它与 Playwright 集成良好,并提供出色的测试体验。
安装配置
第一步是从 npm 包注册表安装以下软件包。
npm i -D playwright @japa/browser-client
注册浏览器套件
让我们先在 adonisrc.ts 文件中为浏览器测试创建一个新的测试套件。浏览器套件的测试文件将存放在 tests/browser 目录中。
{
tests: {
suites: [
{
files: [
'tests/browser/**/*.spec(.ts|.js)'
],
name: 'browser',
timeout: 300000
}
]
}
}
配置插件
在开始编写测试之前,你必须在 tests/bootstrap.ts 文件中注册 browserClient 插件。
import { browserClient } from '@japa/browser-client'
export const plugins: Config['plugins'] = [
assert(),
apiClient(),
browserClient({
runInSuites: ['browser']
}),
pluginAdonisJS(app)
]
基础示例
让我们创建一个示例测试,它会打开 AdonisJS 应用的主页并验证页面内容。visit 辅助函数会打开一个新页面并访问某个 URL。其返回值是 page 对象。
另见:断言方法列表
node ace make:test pages/home --suite=browser
# DONE: create tests/browser/pages/home.spec.ts
import { test } from '@japa/runner'
test.group('Home page', () => {
test('see welcome message', async ({ visit }) => {
const page = await visit('/')
await page.assertTextContains('body', 'It works!')
})
})
最后,让我们使用 test 命令运行上面的测试。你可以使用 --watch 标志创建文件监视器,并在每次文件更改时重新运行测试。
node ace test browser
读取/写入 cookie
在真实浏览器中测试时,cookie 会在整个浏览器上下文(browser context)的生命周期内保持存在。
Japa 为每个测试创建一个全新的浏览器上下文。因此,一个测试中的 cookie 不会泄漏到其他测试中。不过,单个测试中的多次页面访问将共享 cookie,因为它们使用的是同一个 browserContext。
test.group('Home page', () => {
test('see welcome message', async ({ visit, browserContext }) => {
await browserContext.setCookie('username', 'virk')
// The "username" cookie will be sent during the request
const homePage = await visit('/')
// The "username" cookie will also be sent during this request
const aboutPage = await visit('/about')
})
})
类似地,服务器设置的 cookie 可以使用 browserContext.getCookie 方法访问。
import router from '@adonisjs/core/services/router'
router.get('/', async ({ response }) => {
response.cookie('cartTotal', '100')
return 'It works!'
})
test.group('Home page', () => {
test('see welcome message', async ({ visit, browserContext }) => {
const page = await visit('/')
console.log(await browserContext.getCookie('cartTotal'))
})
})
你可以使用以下方法来读取/写入加密 cookie 和明文 cookie。
// Write
await browserContext.setEncryptedCookie('username', 'virk')
await browserContext.setPlainCookie('username', 'virk')
// Read
await browserContext.getEncryptedCookie('cartTotal')
await browserContext.getPlainCookie('cartTotal')
填充会话存储
如果你使用 @adonisjs/session 包在应用中读写会话数据,那么在编写测试时你可能还想使用 sessionBrowserClient 插件来填充会话存储。
安装配置
第一步是在 tests/bootstrap.ts 文件中注册该插件。
import { sessionBrowserClient } from '@adonisjs/session/plugins/browser_client'
export const plugins: Config['plugins'] = [
assert(),
pluginAdonisJS(app),
sessionBrowserClient(app)
]
然后,更新 .env.test 文件(如果不存在则创建一个),并将 SESSON_DRIVER 设置为 memory。
SESSION_DRIVER=memory
写入会话数据
你可以使用 browserContext.setSession 方法为当前浏览器上下文定义会话数据。
使用同一浏览器上下文的所有页面访问都将能够访问相同的会话数据。不过,当浏览器或上下文关闭时,会话数据将被移除。
test('checkout with cart items', async ({ browserContext, visit }) => {
await browserContext.setSession({
cartItems: [
{
id: 1,
name: 'South Indian Filter Press Coffee'
},
{
id: 2,
name: 'Cold Brew Bags',
}
]
})
const page = await visit('/checkout')
})
与 setSession 方法类似,你可以使用 browser.setFlashMessages 方法来定义闪存消息。
/**
* Define flash messages
*/
await browserContext.setFlashMessages({
success: 'Post created successfully',
})
const page = await visit('/posts/1')
/**
* Assert the post page shows the flash message
* inside ".alert-success" div.
*/
await page.assertExists(page.locator(
'div.alert-success',
{ hasText: 'Post created successfully' }
))
读取会话数据
你可以使用 browserContext.getSession 和 browser.getFlashMessages 方法读取会话存储中的数据。这些方法将返回与特定浏览器上下文实例关联的会话 ID 的所有数据。
const session = await browserContext.getSession()
const flashMessages = await browserContext.getFlashMessages()
认证用户
如果你使用 @adonisjs/auth 包在应用中认证用户,那么在向应用发起 HTTP 请求时,你可以使用 authBrowserClient Japa 插件来认证用户。
第一步是在 tests/bootstrap.ts 文件中注册该插件。
import { authBrowserClient } from '@adonisjs/auth/plugins/browser_client'
export const plugins: Config['plugins'] = [
assert(),
pluginAdonisJS(app),
authBrowserClient(app)
]
如果你使用基于会话的身份认证,请务必同时设置好 session 插件。参见填充会话存储 - 安装配置。
这样就可以了。现在,你可以使用 loginAs 方法登录用户。该方法接受用户对象作为唯一参数,并将该用户标记为在当前浏览器上下文中已登录。
使用同一浏览器上下文的所有页面访问都将能够访问已登录的用户。不过,当浏览器或上下文关闭时,用户会话将被销毁。
import User from '#models/user'
test('get payments list', async ({ browserContext, visit }) => {
const user = await User.create(payload)
await browserContext.loginAs(user)
const page = await visit('/dashboard')
})
loginAs 方法使用 config/auth.ts 文件中配置的默认守卫进行身份认证。不过,你可以使用 withGuard 方法指定自定义守卫。例如:
const user = await User.create(payload)
await browserContext
.withGuard('admin')
.loginAs(user)
route 辅助函数
你可以使用 TestContext 中的 route 辅助函数为某个路由创建 URL。使用 route 辅助函数可确保每当你更新路由时,无需回过头去修复测试中所有的 URL。
route 辅助函数接受与全局模板方法 route 相同的一组参数。
test('see list of users', async ({ visit, route }) => {
const page = await visit(
route('users.list')
)
})