fix(e2e): 修复测试失败问题
数据库修复: - 添加测试用户 'user'(密码:admin123) 测试代码优化: - 添加页面加载等待逻辑(waitForLoadState) - 添加元素可见性等待(waitFor visible) - 修复用户密码错误(user123 -> admin123) - 改进错误处理和稳定性
This commit is contained in:
@@ -5,6 +5,9 @@ spring:
|
||||
password: novalon123
|
||||
flyway:
|
||||
enabled: true
|
||||
locations: classpath:db/migration
|
||||
baseline-on-migrate: true
|
||||
validate-on-migrate: true
|
||||
|
||||
rate:
|
||||
limit:
|
||||
|
||||
+12
-4
@@ -3,18 +3,26 @@
|
||||
-- 描述: 插入必要的初始数据
|
||||
|
||||
-- 插入初始角色
|
||||
INSERT INTO roles (role_name, role_key, role_sort, status, create_by, update_by)
|
||||
INSERT INTO sys_role (role_name, role_key, role_sort, status, create_by, update_by)
|
||||
VALUES ('超级管理员', 'admin', 1, 1, 'system', 'system')
|
||||
ON CONFLICT (role_key) DO NOTHING;
|
||||
|
||||
-- 插入初始管理员用户
|
||||
-- BCrypt哈希值对应明文密码: admin123
|
||||
INSERT INTO users (id, username, password, email, phone, status, create_by, update_by)
|
||||
INSERT INTO sys_user (id, username, password, email, phone, status, create_by, update_by)
|
||||
VALUES (1, 'admin', '$2b$12$SFefXlGRFMA0fvxIufpWPuIAl0OPLgRDoCZPThCvjpiJGPYS8yNYy', 'admin@novalon.com', '13800138000', 1, 'system', 'system')
|
||||
ON CONFLICT (username) DO UPDATE SET
|
||||
password = EXCLUDED.password,
|
||||
status = EXCLUDED.status;
|
||||
|
||||
-- 插入测试用户(用于E2E测试)
|
||||
-- BCrypt哈希值对应明文密码: admin123
|
||||
INSERT INTO sys_user (id, username, password, email, phone, status, create_by, update_by)
|
||||
VALUES (2, 'user', '$2b$12$SFefXlGRFMA0fvxIufpWPuIAl0OPLgRDoCZPThCvjpiJGPYS8yNYy', 'user@novalon.com', '13800138001', 1, 'system', 'system')
|
||||
ON CONFLICT (username) DO UPDATE SET
|
||||
password = EXCLUDED.password,
|
||||
status = EXCLUDED.status;
|
||||
|
||||
-- 插入初始字典类型
|
||||
INSERT INTO sys_dict_type (dict_name, dict_type, status, remark, create_by, update_by)
|
||||
VALUES
|
||||
@@ -52,8 +60,8 @@ VALUES
|
||||
ON CONFLICT (config_key) DO NOTHING;
|
||||
|
||||
-- 重置序列值
|
||||
SELECT setval('users_id_seq', (SELECT COALESCE(MAX(id), 1) FROM users));
|
||||
SELECT setval('roles_id_seq', (SELECT COALESCE(MAX(id), 1) FROM roles));
|
||||
SELECT setval('sys_user_id_seq', (SELECT COALESCE(MAX(id), 1) FROM sys_user));
|
||||
SELECT setval('sys_role_id_seq', (SELECT COALESCE(MAX(id), 1) FROM sys_role));
|
||||
SELECT setval('sys_dict_type_id_seq', (SELECT COALESCE(MAX(id), 1) FROM sys_dict_type));
|
||||
SELECT setval('sys_dict_data_id_seq', (SELECT COALESCE(MAX(id), 1) FROM sys_dict_data));
|
||||
SELECT setval('sys_config_id_seq', (SELECT COALESCE(MAX(id), 1) FROM sys_config));
|
||||
+1
-1
@@ -27,7 +27,7 @@ CREATE TABLE IF NOT EXISTS sys_role_permission (
|
||||
update_by VARCHAR(50),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (role_id) REFERENCES sys_role(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (permission_id) REFERENCES sys_permission(id) ON DELETE CASCADE,
|
||||
UNIQUE (role_id, permission_id)
|
||||
);
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
-- 描述: 为表创建必要的索引以提升查询性能
|
||||
|
||||
-- 用户表索引
|
||||
CREATE INDEX IF NOT EXISTS idx_users_username ON users(username);
|
||||
CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
|
||||
CREATE INDEX IF NOT EXISTS idx_users_status ON users(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_users_deleted_at ON users(deleted_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_users_username ON sys_user(username);
|
||||
CREATE INDEX IF NOT EXISTS idx_users_email ON sys_user(email);
|
||||
CREATE INDEX IF NOT EXISTS idx_users_status ON sys_user(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_users_deleted_at ON sys_user(deleted_at);
|
||||
|
||||
-- 角色表索引
|
||||
CREATE INDEX IF NOT EXISTS idx_roles_role_key ON roles(role_key);
|
||||
CREATE INDEX IF NOT EXISTS idx_roles_status ON roles(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_roles_deleted_at ON roles(deleted_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_roles_role_key ON sys_role(role_key);
|
||||
CREATE INDEX IF NOT EXISTS idx_roles_status ON sys_role(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_roles_deleted_at ON sys_role(deleted_at);
|
||||
|
||||
-- 菜单表索引
|
||||
CREATE INDEX IF NOT EXISTS idx_sys_menu_parent_id ON sys_menu(parent_id);
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
-- Novalon管理系统权限授予脚本
|
||||
-- 版本: V9
|
||||
-- 描述: 为novalon用户授予所有表的访问权限
|
||||
|
||||
-- 授予所有表的SELECT, INSERT, UPDATE, DELETE权限
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO novalon;
|
||||
|
||||
-- 授予所有序列的使用权限
|
||||
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO novalon;
|
||||
|
||||
-- 设置默认权限,使未来创建的表自动授予novalon用户权限
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO novalon;
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT USAGE, SELECT ON SEQUENCES TO novalon;
|
||||
@@ -14,13 +14,26 @@ test.describe('管理员完整工作流', () => {
|
||||
await expect(page).toHaveTitle(/登录/);
|
||||
});
|
||||
|
||||
await test.step('等待页面加载完成', async () => {
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page.locator('input[placeholder*="用户名"]')).toBeVisible({ timeout: 10000 });
|
||||
});
|
||||
|
||||
await test.step('输入管理员凭证', async () => {
|
||||
await page.locator('input[placeholder*="用户名"]').fill('admin');
|
||||
await page.locator('input[placeholder*="密码"]').fill('admin123');
|
||||
const usernameInput = page.locator('input[placeholder*="用户名"]');
|
||||
const passwordInput = page.locator('input[placeholder*="密码"]');
|
||||
|
||||
await usernameInput.waitFor({ state: 'visible' });
|
||||
await usernameInput.fill('admin');
|
||||
|
||||
await passwordInput.waitFor({ state: 'visible' });
|
||||
await passwordInput.fill('admin123');
|
||||
});
|
||||
|
||||
await test.step('点击登录按钮', async () => {
|
||||
await page.locator('button:has-text("登录")').click();
|
||||
const loginButton = page.locator('button:has-text("登录")');
|
||||
await loginButton.waitFor({ state: 'visible' });
|
||||
await loginButton.click();
|
||||
});
|
||||
|
||||
await test.step('验证登录成功', async () => {
|
||||
|
||||
@@ -4,9 +4,21 @@ test.describe('用户权限边界验证', () => {
|
||||
test('管理员可以访问所有管理功能', async ({ page }) => {
|
||||
await test.step('管理员登录', async () => {
|
||||
await page.goto('/login');
|
||||
await page.locator('input[placeholder*="用户名"]').fill('admin');
|
||||
await page.locator('input[placeholder*="密码"]').fill('admin123');
|
||||
await page.locator('button:has-text("登录")').click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const usernameInput = page.locator('input[placeholder*="用户名"]');
|
||||
const passwordInput = page.locator('input[placeholder*="密码"]');
|
||||
const loginButton = page.locator('button:has-text("登录")');
|
||||
|
||||
await usernameInput.waitFor({ state: 'visible' });
|
||||
await usernameInput.fill('admin');
|
||||
|
||||
await passwordInput.waitFor({ state: 'visible' });
|
||||
await passwordInput.fill('admin123');
|
||||
|
||||
await loginButton.waitFor({ state: 'visible' });
|
||||
await loginButton.click();
|
||||
|
||||
await page.waitForURL('**/dashboard', { timeout: 30000 });
|
||||
});
|
||||
|
||||
@@ -34,9 +46,21 @@ test.describe('用户权限边界验证', () => {
|
||||
test('普通用户只能访问个人信息', async ({ page }) => {
|
||||
await test.step('普通用户登录', async () => {
|
||||
await page.goto('/login');
|
||||
await page.locator('input[placeholder*="用户名"]').fill('user');
|
||||
await page.locator('input[placeholder*="密码"]').fill('user123');
|
||||
await page.locator('button:has-text("登录")').click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const usernameInput = page.locator('input[placeholder*="用户名"]');
|
||||
const passwordInput = page.locator('input[placeholder*="密码"]');
|
||||
const loginButton = page.locator('button:has-text("登录")');
|
||||
|
||||
await usernameInput.waitFor({ state: 'visible' });
|
||||
await usernameInput.fill('user');
|
||||
|
||||
await passwordInput.waitFor({ state: 'visible' });
|
||||
await passwordInput.fill('admin123');
|
||||
|
||||
await loginButton.waitFor({ state: 'visible' });
|
||||
await loginButton.click();
|
||||
|
||||
await page.waitForURL('**/dashboard', { timeout: 30000 });
|
||||
});
|
||||
|
||||
@@ -65,9 +89,21 @@ test.describe('用户权限边界验证', () => {
|
||||
test('权限不足时显示提示信息', async ({ page }) => {
|
||||
await test.step('普通用户登录', async () => {
|
||||
await page.goto('/login');
|
||||
await page.locator('input[placeholder*="用户名"]').fill('user');
|
||||
await page.locator('input[placeholder*="密码"]').fill('user123');
|
||||
await page.locator('button:has-text("登录")').click();
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const usernameInput = page.locator('input[placeholder*="用户名"]');
|
||||
const passwordInput = page.locator('input[placeholder*="密码"]');
|
||||
const loginButton = page.locator('button:has-text("登录")');
|
||||
|
||||
await usernameInput.waitFor({ state: 'visible' });
|
||||
await usernameInput.fill('user');
|
||||
|
||||
await passwordInput.waitFor({ state: 'visible' });
|
||||
await passwordInput.fill('admin123');
|
||||
|
||||
await loginButton.waitFor({ state: 'visible' });
|
||||
await loginButton.click();
|
||||
|
||||
await page.waitForURL('**/dashboard', { timeout: 30000 });
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user