149 lines
5.1 KiB
JavaScript
149 lines
5.1 KiB
JavaScript
const { test, expect } = require('@playwright/test');
|
||
const bcrypt = require('bcryptjs');
|
||
const testData = require('./fixtures/test-data');
|
||
const { cleanDatabase, seedExistingUser, disconnect, prisma } = require('./fixtures/database');
|
||
|
||
// 非创作者用户(用于角色库测试)
|
||
const NON_CREATOR = {
|
||
account: 'e2e_noncreator',
|
||
password: 'Test123456',
|
||
};
|
||
|
||
test.describe('角色库与角色详情', () => {
|
||
let existingUser;
|
||
let testRole;
|
||
|
||
test.beforeAll(async () => {
|
||
await cleanDatabase();
|
||
await seedExistingUser();
|
||
existingUser = await prisma.user.findUnique({
|
||
where: { account: testData.users.existing.account },
|
||
});
|
||
|
||
// 创建非创作者用户(open-characters 对非创作者进入 role-library)
|
||
await prisma.user.create({
|
||
data: {
|
||
account: NON_CREATOR.account,
|
||
password: bcrypt.hashSync(NON_CREATOR.password, 10),
|
||
isCreator: false,
|
||
libraryName: 'E2E测试库',
|
||
},
|
||
});
|
||
|
||
// 创建一个测试角色(status=running 才会在角色库展示)
|
||
testRole = await prisma.role.create({
|
||
data: {
|
||
creatorId: existingUser.id,
|
||
displayName: '测试角色A',
|
||
gender: 'female',
|
||
age: '24',
|
||
relationship: '女友',
|
||
personality: '温柔可爱,善解人意',
|
||
background: '来自海边的小镇女孩',
|
||
speechStyle: '轻柔细腻',
|
||
greeting: '你好呀~',
|
||
desc: '温柔可爱的女友角色',
|
||
price: 29.9,
|
||
status: 'running',
|
||
avatar: 'https://example.com/avatar.png',
|
||
},
|
||
});
|
||
});
|
||
|
||
test.afterAll(async () => {
|
||
await cleanDatabase();
|
||
await disconnect();
|
||
});
|
||
|
||
// 以非创作者身份登录,登录后自动进入角色库
|
||
async function loginAsNonCreator(page) {
|
||
await page.goto('/');
|
||
await page.locator('[data-action="open-characters"]').first().click();
|
||
await expect(page.locator('#auth')).toBeVisible();
|
||
// 确保登录 tab 激活
|
||
await page.locator('.auth-tabs [data-tab="login"]').click();
|
||
await page.locator('[data-form="login"]').waitFor();
|
||
await page.fill('[data-form="login"] [name="account"]', NON_CREATOR.account);
|
||
await page.fill('[data-form="login"] [name="password"]', NON_CREATOR.password);
|
||
await page.locator('[data-form="login"] button[type="submit"]').click();
|
||
await expect(page.locator('#role-library')).toBeVisible({ timeout: 5000 });
|
||
}
|
||
|
||
test('角色库显示已上架角色', async ({ page }) => {
|
||
await loginAsNonCreator(page);
|
||
|
||
// 应显示测试角色
|
||
await expect(page.locator('#role-list .role-card')).toHaveCount(1, { timeout: 5000 });
|
||
await expect(page.locator('#role-list .role-card__name')).toHaveText('测试角色A');
|
||
});
|
||
|
||
test('空角色库显示空状态', async ({ page }) => {
|
||
// 清空角色
|
||
await prisma.role.deleteMany();
|
||
|
||
await loginAsNonCreator(page);
|
||
|
||
// 应显示空状态
|
||
await expect(page.locator('#library-empty')).toBeVisible({ timeout: 5000 });
|
||
});
|
||
|
||
test('点击角色卡片进入详情页', async ({ page }) => {
|
||
// 重新创建角色
|
||
testRole = await prisma.role.create({
|
||
data: {
|
||
creatorId: existingUser.id,
|
||
displayName: '详情测试角色',
|
||
gender: 'male',
|
||
personality: '阳光开朗',
|
||
background: '运动少年',
|
||
speechStyle: '热情直接',
|
||
greeting: '嘿!你好!',
|
||
desc: '阳光开朗的男孩',
|
||
price: 19.9,
|
||
status: 'running',
|
||
},
|
||
});
|
||
|
||
await loginAsNonCreator(page);
|
||
|
||
// 点击角色卡片
|
||
await page.locator('#role-list .role-card').first().click();
|
||
await expect(page.locator('#role-detail')).toBeVisible();
|
||
|
||
// 验证详情内容
|
||
await expect(page.locator('#detail-name')).toHaveText('详情测试角色');
|
||
await expect(page.locator('#detail-role-name')).toHaveText('详情测试角色');
|
||
await expect(page.locator('#detail-price')).toContainText('19.9');
|
||
});
|
||
|
||
test('角色详情页返回按钮', async ({ page }) => {
|
||
await loginAsNonCreator(page);
|
||
|
||
await page.locator('#role-list .role-card').first().click();
|
||
await expect(page.locator('#role-detail')).toBeVisible();
|
||
|
||
// 点击返回(role-detail 使用 back-to-library)
|
||
await page.locator('[data-action="back-to-library"]').click();
|
||
await expect(page.locator('#role-library')).toBeVisible();
|
||
});
|
||
|
||
test('角色详情付款流程', async ({ page }) => {
|
||
await loginAsNonCreator(page);
|
||
|
||
await page.locator('#role-list .role-card').first().click();
|
||
await expect(page.locator('#role-detail')).toBeVisible();
|
||
|
||
// 付款前:pre-pay 按钮区可见,paid 区隐藏
|
||
await expect(page.locator('#detail-actions-pre')).toBeVisible();
|
||
await expect(page.locator('#detail-paid')).toBeHidden();
|
||
|
||
// 点击付款按钮(data-action="pay",非 pay-role)
|
||
await page.locator('[data-action="pay"]').click();
|
||
|
||
// 应显示已付款区域(含二维码 / 头像下载)
|
||
await expect(page.locator('#detail-paid')).toBeVisible({ timeout: 5000 });
|
||
await expect(page.locator('#detail-actions-pre')).toBeHidden();
|
||
await expect(page.locator('[data-action="download-avatar"]')).toBeVisible();
|
||
});
|
||
});
|