auth.js
6.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
/*
* @Date: 2026-01-28 22:00:00
* @Description: E2E 测试认证辅助工具
*/
import { test as base } from '@playwright/test'
// 测试账号配置
export const TEST_ACCOUNT = {
phone: '13761653761',
code: '888888', // 测试环境固定验证码
password: '', // 如果有密码登录
}
/**
* 扩展 test 对象,添加 authenticated fixture
*/
export const test = base.extend({
// 已认证的页面(自动登录)
authenticatedPage: async ({ page }, use) => {
// 执行登录
await login(page)
// 使用已认证的页面
await use(page)
},
})
/**
* 登录操作
* @param {Page} page - Playwright page 对象
* @param {Object} account - 账号信息(可选,默认使用测试账号)
*/
export async function login(page, account = TEST_ACCOUNT) {
console.log('🔐 开始登录流程...')
// 1. 访问登录页
await page.goto('/#/login')
console.log('✓ 已访问登录页')
// 2. 等待登录表单加载
await page.waitForSelector('input[name="mobile"]', { timeout: 10000 })
console.log('✓ 登录表单已加载')
// 3. 输入手机号
const phoneInput = page.locator('input[name="mobile"]')
await phoneInput.fill(account.phone)
console.log(`✓ 已输入手机号: ${account.phone}`)
// 触发 blur 事件以验证手机号
await phoneInput.blur()
await page.waitForTimeout(500) // 等待验证完成
// 4. 点击"获取验证码"按钮(触发短信接口)
const sendCodeButton = page.locator('button:has-text("获取验证码")')
// 确保按钮可点击(等待按钮启用)
await sendCodeButton.waitFor({ state: 'visible', timeout: 5000 })
console.log('✓ 发送验证码按钮已找到')
// 等待按钮启用(手机号验证通过后启用)
await page.waitForTimeout(1000)
// Poll until button is enabled
let retries = 0
while ((await sendCodeButton.isDisabled()) && retries < 10) {
await page.waitForTimeout(500)
retries++
}
// 点击发送验证码
await sendCodeButton.click()
console.log('✓ 已点击发送验证码按钮,等待接口响应...')
// 5. 等待发送短信接口响应
// 等待按钮进入倒计时状态(通常是禁用或文本变为倒计时)
await page.waitForTimeout(2000)
// 验证按钮状态变化(表示接口已响应)
const isDisabled = await sendCodeButton.isDisabled()
const buttonText = await sendCodeButton.textContent()
console.log(
`✓ 短信接口已响应,按钮状态: ${isDisabled ? '已禁用' : '可用'}, 文本: "${buttonText}"`
)
// 6. 等待一小段时间再输入验证码(模拟真实用户操作)
await page.waitForTimeout(500)
// 7. 输入验证码
const codeInput = page.locator('#verificationCode')
await codeInput.waitFor({ state: 'visible', timeout: 5000 })
await codeInput.fill(account.code)
console.log(`✓ 已输入验证码: ${account.code}`)
// 8. 点击登录按钮
const loginButton = page.locator('button[type="submit"]')
await loginButton.waitFor({ state: 'visible', timeout: 5000 })
await loginButton.click()
console.log('✓ 已点击登录按钮,等待登录响应...')
// 9. 等待登录成功(跳转到首页或显示成功提示)
try {
// 方式1:等待 URL 变化
await page.waitForURL(/\/#\/(home|index)?/, { timeout: 15000 })
console.log('✓ 登录成功(URL 已变化)')
} catch (error) {
// 方式2:等待成功提示(toast)
try {
await page.waitForSelector('.van-toast--success', { timeout: 5000 })
console.log('✓ 登录成功(显示成功提示)')
} catch (toastError) {
// 方式3:检查是否已经在首页
const currentUrl = page.url()
if (
currentUrl.includes('/#/home') ||
currentUrl.includes('/#/index') ||
currentUrl.endsWith('#/')
) {
console.log('✓ 登录成功(已在首页)')
} else {
console.log(`⚠ 当前 URL: ${currentUrl}`)
console.log('⚠ 可能登录失败,请检查错误提示')
throw new Error('登录失败:未检测到登录成功的标志')
}
}
}
// 10. 等待 localStorage 被写入(getUserInfoAPI 是异步的)
await page.waitForTimeout(3000)
// 11. 等待页面加载完成
await page.waitForLoadState('networkidle', { timeout: 10000 })
console.log('✅ 登录流程完成!')
}
/**
* 快速登录(使用 localStorage 直接设置 token)
* 适用于需要跳过登录流程的场景
* @param {Page} page - Playwright page 对象
* @param {string} token - 用户 token(可选)
*/
export async function quickLogin(page, token = null) {
// 如果没有提供 token,先执行一次正常登录获取
if (!token) {
await login(page)
// 从 localStorage 获取 token
token = await page.evaluate(() => {
const currentUser = localStorage.getItem('currentUser')
if (currentUser) {
return JSON.parse(currentUser).token
}
return null
})
}
// 直接设置 localStorage(用于后续测试)
await page.evaluate(userToken => {
const mockUserInfo = {
token: userToken,
userId: 'test-user-123',
phone: '13761653761',
id: 817005,
name: '胡大',
mobile: '13761653761',
}
localStorage.setItem('currentUser', JSON.stringify(mockUserInfo))
}, token)
console.log('✅ 快速登录成功')
}
/**
* 登出操作
* @param {Page} page - Playwright page 对象
*/
export async function logout(page) {
try {
// 清空 localStorage(同时清除两个可能的key)
await page.evaluate(() => {
localStorage.removeItem('user_info')
localStorage.removeItem('currentUser')
})
// 或者点击退出按钮(如果有)
// await page.click('button:has-text("退出")')
// 刷新页面
await page.reload()
console.log('✅ 登出成功')
} catch (error) {
// 如果页面还没加载,先导航到一个页面再清理
console.log('⚠ 页面未初始化,跳过 localStorage 清理')
}
}
/**
* 检查登录状态
* @param {Page} page - Playwright page 对象
* @returns {Promise<boolean>} 是否已登录
*/
export async function isLoggedIn(page) {
const currentUser = await page.evaluate(() => localStorage.getItem('currentUser'))
return !!currentUser
}
/**
* 等待登录状态
* @param {Page} page - Playwright page 对象
* @param {boolean} loggedIn - 期望的登录状态
*/
export async function waitForLoginState(page, loggedIn = true) {
if (loggedIn) {
// 等待登录成功
await page.waitForURL(/\/#\/(home|index)?/, { timeout: 10000 })
} else {
// 等待退出到登录页
await page.waitForURL('/#/login', { timeout: 10000 })
}
}