浏览器测试
浏览器测试在真实浏览器(如 Chrome、Firefox 或 Safari)中执行。我们使用 Playwright(一个浏览器自动化工具)以编程方式与网页交互。
Playwright 既是一个测试框架,也是一个暴露 JavaScript API 与浏览器交互的库。我们不使用 Playwright 测试框架,因为我们已经在使用 Japa,在单个项目中使用多个测试框架只会导致混乱和配置臃肿。
相反,我们将使用 Japa 的浏览器客户端插件,它与 Playwright 很好地集成并提供出色的测试体验。
设置
第一步是从 npm 包注册表安装以下包。
:::codegroup
// title: npm
npm i -D playwright @japa/browser-client:::
注册浏览器套件
让我们首先在 adonisrc.ts 文件中为浏览器测试创建一个新的测试套件。浏览器套件的测试文件将存储在 tests/browser 目录中。
{
tests: {
suites: [
// highlight-start
{
files: [
'tests/browser/**/*.spec(.ts|.js)'
],
name: 'browser',
timeout: 300000
}
// highlight-end
]
}
}配置插件
在开始编写测试之前,您必须在 tests/bootstrap.ts 文件中注册 browserClient 插件。
import { browserClient } from '@japa/browser-client'
export const plugins: Config['plugins'] = [
assert(),
apiClient(),
// highlight-start
browserClient({
runInSuites: ['browser']
}),
// highlight-end
pluginAdonisJS(app)
]基本示例
让我们创建一个示例测试,它将打开 AdonisJS 应用程序的主页并验证页面内容。visit 助手打开一个新页面并访问 URL。返回值是页面对象。
另请参阅:断言方法列表
node ace make:test pages/home --suite=browser
# DONE: create tests/browser/pages/home.spec.ts// title: tests/browser/pages/home.spec.ts
import { test } from '@japa/runner'
test.group('Home page', () => {
test('查看欢迎消息', async ({ visit }) => {
const page = await visit('/')
await page.assertTextContains('body', 'It works!')
})
})最后,让我们使用 test 命令运行上述测试。您可以使用 --watch 标志创建文件监视器,并在每次文件更改时重新运行测试。
node ace test browser
读取/写入 cookie
在真实浏览器中测试时,cookie 在浏览器上下文的整个生命周期中保持持久。
Japa 为每个测试创建一个新的浏览器上下文。因此,一个测试的 cookie 不会泄漏到其他测试。但是,单个测试中的多个页面访问将共享 cookie,因为它们使用相同的 browserContext。
test.group('Home page', () => {
test('查看欢迎消息', async ({ visit, browserContext }) => {
// highlight-start
await browserContext.setCookie('username', 'virk')
// highlight-end
// "username" cookie 将在请求期间发送
const homePage = await visit('/')
// "username" cookie 也将在此请求期间发送
const aboutPage = await visit('/about')
})
})类似地,服务器设置的 cookie 可以使用 browserContext.getCookie 方法访问。
import router from '@adonisjs/core/services/router'
router.get('/', async ({ response }) => {
// highlight-start
response.cookie('cartTotal', '100')
// highlight-end
return 'It works!'
})test.group('Home page', () => {
test('查看欢迎消息', async ({ visit, browserContext }) => {
const page = await visit('/')
// highlight-start
console.log(await browserContext.getCookie('cartTotal'))
// highlight-end
})
})您可以使用以下方法读取/写入加密和纯文本 cookie。
// 写入
await browserContext.setEncryptedCookie('username', 'virk')
await browserContext.setPlainCookie('username', 'virk')
// 读取
await browserContext.getEncryptedCookie('cartTotal')
await browserContext.getPlainCookie('cartTotal')填充会话存储
如果您使用 @adonisjs/session 包在应用程序中读取/写入会话数据,您可能还需要使用 sessionBrowserClient 插件在编写测试时填充会话存储。
设置
第一步是在 tests/bootstrap.ts 文件中注册插件。
// insert-start
import { sessionBrowserClient } from '@adonisjs/session/plugins/browser_client'
// insert-end
export const plugins: Config['plugins'] = [
assert(),
pluginAdonisJS(app),
// insert-start
sessionBrowserClient(app)
// insert-end
]然后,更新 .env.test 文件(如果缺少则创建一个)并将 SESSON_DRIVER 设置为 memory。
// title: .env.test
SESSION_DRIVER=memory写入会话数据
您可以使用 browserContext.setSession 方法为当前浏览器上下文定义会话数据。
使用相同浏览器上下文的所有页面访问都将访问相同的会话数据。但是,当浏览器或上下文关闭时,会话数据将被删除。
test('使用购物车商品结账', async ({ browserContext, visit }) => {
// highlight-start
await browserContext.setSession({
cartItems: [
{
id: 1,
name: '南印度滤压咖啡'
},
{
id: 2,
name: '冷萃咖啡袋',
}
]
})
// highlight-end
const page = await visit('/checkout')
})与 setSession 方法类似,您可以使用 browser.setFlashMessages 方法定义闪存消息。
/**
* 定义闪存消息
*/
await browserContext.setFlashMessages({
success: '帖子创建成功',
})
const page = await visit('/posts/1')
/**
* 断言帖子页面在 ".alert-success" div 中显示闪存消息。
*/
await page.assertExists(page.locator(
'div.alert-success',
{ hasText: '帖子创建成功' }
))读取会话数据
您可以使用 browserContext.getSession 和 browser.getFlashMessages 方法读取会话存储中的数据。这些方法将返回与特定浏览器上下文实例关联的会话 ID 的所有数据。
const session = await browserContext.getSession()
const flashMessages = await browserContext.getFlashMessages()认证用户
如果您使用 @adonisjs/auth 包在应用程序中认证用户,您可以使用 authBrowserClient Japa 插件在向应用程序发出 HTTP 请求时认证用户。
第一步是在 tests/bootstrap.ts 文件中注册插件。
// title: tests/bootstrap.ts
// insert-start
import { authBrowserClient } from '@adonisjs/auth/plugins/browser_client'
// insert-end
export const plugins: Config['plugins'] = [
assert(),
pluginAdonisJS(app),
// insert-start
authBrowserClient(app)
// insert-end
]如果您使用基于会话的认证,请确保也设置会话插件。参见填充会话存储 - 设置。
就是这样。现在,您可以使用 loginAs 方法登录用户。该方法接受用户对象作为唯一参数,并将用户标记为当前浏览器上下文中的已登录状态。
使用相同浏览器上下文的所有页面访问都将访问已登录用户。但是,当浏览器或上下文关闭时,用户会话将被销毁。
import User from '#models/user'
test('获取付款列表', async ({ browserContext, visit }) => {
// highlight-start
const user = await User.create(payload)
await browserContext.loginAs(user)
// highlight-end
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('查看用户列表', async ({ visit, route }) => {
const page = await visit(
// highlight-start
route('users.list')
// highlight-end
)
})