library-picturebook-activity/lesingle-creation-frontend/e2e/leai/creation-iframe.spec.ts

245 lines
7.5 KiB
TypeScript
Raw Normal View History

import { test, expect } from '../fixtures/auth.fixture'
import { fileURLToPath } from 'url'
import path from 'path'
/**
* P1: 创作页 iframe
*
* frontend/src/views/public/create/Index.vue
* - iframe
* -
* -
* - iframe allow
*/
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
/** Mock H5 页面的文件路径 */
const MOCK_H5_PATH = path.resolve(__dirname, '../utils/mock-h5.html')
test.describe('创作页 iframe 嵌入', () => {
test.describe('未登录状态', () => {
test('访问 /p/create — 重定向到登录页', async ({ page }) => {
await page.goto('/p/create')
// 应该重定向到登录页或显示登录提示
await page.waitForTimeout(2000)
const url = page.url()
expect(url).toMatch(/\/(login|auth)/)
})
})
test.describe('已登录状态', () => {
test('显示加载中提示', async ({ loggedInPage }) => {
// 拦截 token API让它延迟
await loggedInPage.route('**/leai-auth/token', async (route) => {
await new Promise((r) => setTimeout(r, 3000))
await route.continue()
})
await loggedInPage.goto('/p/create')
// 应该显示加载状态
const loadingText = loggedInPage.locator('text=正在加载创作工坊')
await expect(loadingText).toBeVisible({ timeout: 5000 })
})
test('iframe 正确渲染', async ({ loggedInPage }) => {
// 拦截 token API 返回 mock 数据
await loggedInPage.route('**/leai-auth/token', async (route) => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
code: 200,
data: {
token: 'mock_session_token_xxx',
orgId: 'gdlib',
phone: '13800001111',
},
}),
})
})
// 拦截 iframe 加载,返回 mock H5 页面
await loggedInPage.route('**/*leai*/**', async (route) => {
await route.fulfill({
status: 200,
contentType: 'text/html',
path: MOCK_H5_PATH,
})
})
// 也拦截通配形式的 H5 URL
await loggedInPage.route('http://192.168.1.120:3001/**', async (route) => {
await route.fulfill({
status: 200,
contentType: 'text/html',
path: MOCK_H5_PATH,
})
})
await loggedInPage.goto('/p/create')
// 等待 iframe 出现
const iframe = loggedInPage.locator('iframe.creation-iframe, iframe[allow*="camera"]')
await expect(iframe).toBeVisible({ timeout: 10_000 })
// 验证 iframe src 包含必要参数
const src = await iframe.getAttribute('src')
expect(src).toBeTruthy()
expect(src).toContain('token=')
expect(src).toContain('orgId=')
expect(src).toContain('phone=')
expect(src).toContain('embed=1')
})
test('iframe 有 camera 和 microphone 权限', async ({ loggedInPage }) => {
await loggedInPage.route('**/leai-auth/token', async (route) => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
code: 200,
data: {
token: 'mock_token',
orgId: 'gdlib',
phone: '13800001111',
},
}),
})
})
await loggedInPage.route('http://192.168.1.120:3001/**', async (route) => {
await route.fulfill({
status: 200,
contentType: 'text/html',
path: MOCK_H5_PATH,
})
})
await loggedInPage.goto('/p/create')
const iframe = loggedInPage.locator('iframe').first()
await expect(iframe).toBeVisible({ timeout: 10_000 })
const allow = await iframe.getAttribute('allow')
expect(allow).toContain('camera')
expect(allow).toContain('microphone')
})
test('Token 获取失败 — 显示错误和重试按钮', async ({ loggedInPage }) => {
// 拦截 token API 返回 HTTP 500 错误
await loggedInPage.route('**/leai-auth/token', async (route) => {
await route.fulfill({
status: 500,
contentType: 'application/json',
body: JSON.stringify({
code: 500,
message: '获取创作Token失败: 连接超时',
}),
})
})
await loggedInPage.goto('/p/create')
// 应该显示错误信息(.load-error 在 v-if="loading" 容器内)
const errorText = loggedInPage.locator('.load-error')
await expect(errorText).toBeVisible({ timeout: 10_000 })
// 应该有重新加载按钮
const retryBtn = loggedInPage.locator('button:has-text("重新加载")')
await expect(retryBtn).toBeVisible()
})
test('重新加载按钮 — 可重新获取 Token', async ({ loggedInPage }) => {
let callCount = 0
await loggedInPage.route('**/leai-auth/token', async (route) => {
callCount++
if (callCount === 1) {
// 第一次失败HTTP 500
await route.fulfill({
status: 500,
contentType: 'application/json',
body: JSON.stringify({ code: 500, message: '网络错误' }),
})
} else {
// 第二次成功
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
code: 200,
data: {
token: 'retry_token_success',
orgId: 'gdlib',
phone: '13800001111',
},
}),
})
}
})
await loggedInPage.route('http://192.168.1.120:3001/**', async (route) => {
await route.fulfill({
status: 200,
contentType: 'text/html',
path: MOCK_H5_PATH,
})
})
await loggedInPage.goto('/p/create')
// 等待错误出现
const retryBtn = loggedInPage.locator('button:has-text("重新加载")')
await expect(retryBtn).toBeVisible({ timeout: 10_000 })
// 点击重试
await retryBtn.click()
// 第二次应成功iframe 应出现
const iframe = loggedInPage.locator('iframe')
await expect(iframe).toBeVisible({ timeout: 10_000 })
expect(callCount).toBe(2)
})
test('iframe 占满内容区域', async ({ loggedInPage }) => {
await loggedInPage.route('**/leai-auth/token', async (route) => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
code: 200,
data: {
token: 'mock_token',
orgId: 'gdlib',
phone: '13800001111',
},
}),
})
})
await loggedInPage.route('http://192.168.1.120:3001/**', async (route) => {
await route.fulfill({
status: 200,
contentType: 'text/html',
path: MOCK_H5_PATH,
})
})
await loggedInPage.goto('/p/create')
const iframe = loggedInPage.locator('iframe').first()
await expect(iframe).toBeVisible({ timeout: 10_000 })
// iframe 应该没有边框
const frameBorder = await iframe.getAttribute('frameborder')
expect(frameBorder).toBe('0')
// iframe 高度应接近视口高度(至少 400px
const box = await iframe.boundingBox()
expect(box).toBeTruthy()
expect(box!.height).toBeGreaterThan(400)
})
})
})