|
@@ -1,5 +1,6 @@
|
|
|
import { TIMEOUTS } from '../../utils/timeouts';
|
|
import { TIMEOUTS } from '../../utils/timeouts';
|
|
|
import { test, expect } from '../../utils/test-setup';
|
|
import { test, expect } from '../../utils/test-setup';
|
|
|
|
|
+import type { APIRequestContext } from '@playwright/test';
|
|
|
import { readFileSync } from 'fs';
|
|
import { readFileSync } from 'fs';
|
|
|
import { join, dirname } from 'path';
|
|
import { join, dirname } from 'path';
|
|
|
import { fileURLToPath } from 'url';
|
|
import { fileURLToPath } from 'url';
|
|
@@ -8,7 +9,7 @@ const __filename = fileURLToPath(import.meta.url);
|
|
|
const __dirname = dirname(__filename);
|
|
const __dirname = dirname(__filename);
|
|
|
const testUsers = JSON.parse(readFileSync(join(__dirname, '../../fixtures/test-users.json'), 'utf-8'));
|
|
const testUsers = JSON.parse(readFileSync(join(__dirname, '../../fixtures/test-users.json'), 'utf-8'));
|
|
|
|
|
|
|
|
-async function getAuthToken(request: Parameters<typeof test>[0]['request']): Promise<string | null> {
|
|
|
|
|
|
|
+async function getAuthToken(request: APIRequestContext): Promise<string | null> {
|
|
|
const loginResponse = await request.post('http://localhost:8080/api/v1/auth/login', {
|
|
const loginResponse = await request.post('http://localhost:8080/api/v1/auth/login', {
|
|
|
data: {
|
|
data: {
|
|
|
username: testUsers.admin.username,
|
|
username: testUsers.admin.username,
|
|
@@ -26,7 +27,7 @@ async function getAuthToken(request: Parameters<typeof test>[0]['request']): Pro
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
async function createDisabledPersonViaAPI(
|
|
async function createDisabledPersonViaAPI(
|
|
|
- request: Parameters<typeof test>[0]['request'],
|
|
|
|
|
|
|
+ request: APIRequestContext,
|
|
|
personData: {
|
|
personData: {
|
|
|
name: string;
|
|
name: string;
|
|
|
gender: string;
|
|
gender: string;
|
|
@@ -68,7 +69,7 @@ async function createDisabledPersonViaAPI(
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
async function createPlatformViaAPI(
|
|
async function createPlatformViaAPI(
|
|
|
- request: Parameters<typeof test>[0]['request']
|
|
|
|
|
|
|
+ request: APIRequestContext
|
|
|
): Promise<{ id: number; name: string } | null> {
|
|
): Promise<{ id: number; name: string } | null> {
|
|
|
try {
|
|
try {
|
|
|
const token = await getAuthToken(request);
|
|
const token = await getAuthToken(request);
|
|
@@ -106,7 +107,7 @@ async function createPlatformViaAPI(
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
async function createCompanyViaAPI(
|
|
async function createCompanyViaAPI(
|
|
|
- request: Parameters<typeof test>[0]['request'],
|
|
|
|
|
|
|
+ request: APIRequestContext,
|
|
|
platformId: number
|
|
platformId: number
|
|
|
): Promise<{ id: number; name: string } | null> {
|
|
): Promise<{ id: number; name: string } | null> {
|
|
|
try {
|
|
try {
|
|
@@ -170,7 +171,7 @@ async function createCompanyViaAPI(
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
async function createOrderViaAPI(
|
|
async function createOrderViaAPI(
|
|
|
- request: Parameters<typeof test>[0]['request'],
|
|
|
|
|
|
|
+ request: APIRequestContext,
|
|
|
orderData: {
|
|
orderData: {
|
|
|
orderName: string;
|
|
orderName: string;
|
|
|
platformId: number;
|
|
platformId: number;
|
|
@@ -206,7 +207,7 @@ async function createOrderViaAPI(
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
async function bindPersonToOrderViaAPI(
|
|
async function bindPersonToOrderViaAPI(
|
|
|
- request: Parameters<typeof test>[0]['request'],
|
|
|
|
|
|
|
+ request: APIRequestContext,
|
|
|
orderId: number,
|
|
orderId: number,
|
|
|
personId: number,
|
|
personId: number,
|
|
|
joinDate: string
|
|
joinDate: string
|
|
@@ -253,7 +254,7 @@ async function bindPersonToOrderViaAPI(
|
|
|
function generateUniqueTestData() {
|
|
function generateUniqueTestData() {
|
|
|
const timestamp = Date.now();
|
|
const timestamp = Date.now();
|
|
|
const counter = Math.floor(Math.random() * 10000);
|
|
const counter = Math.floor(Math.random() * 10000);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
return {
|
|
return {
|
|
|
orderName: '日期测试订单_' + String(timestamp),
|
|
orderName: '日期测试订单_' + String(timestamp),
|
|
|
personName: '日期测试残疾人_' + String(timestamp),
|
|
personName: '日期测试残疾人_' + String(timestamp),
|
|
@@ -266,19 +267,20 @@ function generateUniqueTestData() {
|
|
|
phone: '138' + String(counter).padStart(8, '0'),
|
|
phone: '138' + String(counter).padStart(8, '0'),
|
|
|
province: '北京市',
|
|
province: '北京市',
|
|
|
city: '北京市',
|
|
city: '北京市',
|
|
|
- joinDate: '2026-01-01',
|
|
|
|
|
|
|
+ joinDate: '2026-01-15',
|
|
|
|
|
+ newJoinDate: '2026-01-10',
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-test.describe.serial('订单管理 - 人员入职/离职日期编辑功能 (Story 15.7)', () => {
|
|
|
|
|
|
|
+test.describe.serial('订单管理 - 人员入职/离职日期行内编辑功能 (Story 15.5)', () => {
|
|
|
test.beforeEach(async ({ adminLoginPage }) => {
|
|
test.beforeEach(async ({ adminLoginPage }) => {
|
|
|
await adminLoginPage.goto();
|
|
await adminLoginPage.goto();
|
|
|
await adminLoginPage.login(testUsers.admin.username, testUsers.admin.password);
|
|
await adminLoginPage.login(testUsers.admin.username, testUsers.admin.password);
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- test('AC1: 订单人员详情页中入职日期和离职日期可点击编辑', async ({ page, request }) => {
|
|
|
|
|
- console.debug('========== Story 15.7 AC1: 入职/离职日期可编辑 ==========');
|
|
|
|
|
-
|
|
|
|
|
|
|
+ test('AC1: 订单人员详情页中入职日期和离职日期可点击编辑(行内编辑模式)', async ({ page, request }) => {
|
|
|
|
|
+ console.debug('========== Story 15.5 AC1: 入职/离职日期行内编辑 ==========');
|
|
|
|
|
+
|
|
|
const testData = generateUniqueTestData();
|
|
const testData = generateUniqueTestData();
|
|
|
console.debug('测试数据已生成:', testData.personName);
|
|
console.debug('测试数据已生成:', testData.personName);
|
|
|
|
|
|
|
@@ -292,7 +294,7 @@ test.describe.serial('订单管理 - 人员入职/离职日期编辑功能 (Stor
|
|
|
orderName: testData.orderName,
|
|
orderName: testData.orderName,
|
|
|
platformId: platform!.id,
|
|
platformId: platform!.id,
|
|
|
companyId: company!.id,
|
|
companyId: company!.id,
|
|
|
- expectedStartDate: testData.joinDate
|
|
|
|
|
|
|
+ expectedStartDate: '2026-01-01'
|
|
|
});
|
|
});
|
|
|
expect(order).not.toBeNull();
|
|
expect(order).not.toBeNull();
|
|
|
|
|
|
|
@@ -330,7 +332,7 @@ test.describe.serial('订单管理 - 人员入职/离职日期编辑功能 (Stor
|
|
|
const detailButton = page.getByRole('menuitem', { name: /查看详情/ });
|
|
const detailButton = page.getByRole('menuitem', { name: /查看详情/ });
|
|
|
await detailButton.click();
|
|
await detailButton.click();
|
|
|
|
|
|
|
|
- await page.waitForSelector('[data-testid="order-detail-dialog"]', { state: 'visible', timeout: TIMEOUTS.DIALOG_OPEN });
|
|
|
|
|
|
|
+ await page.waitForSelector('[data-testid="order-detail-dialog"]', { state: 'visible', timeout: TIMEOUTS.DIALOG });
|
|
|
|
|
|
|
|
const joinDateButton = page.locator('[data-testid="edit-join-date-' + String(person!.id) + '"]');
|
|
const joinDateButton = page.locator('[data-testid="edit-join-date-' + String(person!.id) + '"]');
|
|
|
await expect(joinDateButton).toBeVisible();
|
|
await expect(joinDateButton).toBeVisible();
|
|
@@ -340,25 +342,69 @@ test.describe.serial('订单管理 - 人员入职/离职日期编辑功能 (Stor
|
|
|
await expect(leaveDateButton).toBeVisible();
|
|
await expect(leaveDateButton).toBeVisible();
|
|
|
console.debug('离职日期按钮可见');
|
|
console.debug('离职日期按钮可见');
|
|
|
|
|
|
|
|
|
|
+ // 点击入职日期按钮,应该弹出日历选择器
|
|
|
await joinDateButton.click();
|
|
await joinDateButton.click();
|
|
|
|
|
+
|
|
|
|
|
+ // 等待日历选择器出现
|
|
|
|
|
+ const calendar = page.locator('[data-slot="calendar"]');
|
|
|
|
|
+ await expect(calendar).toBeVisible({ timeout: TIMEOUTS.DIALOG });
|
|
|
|
|
+ console.debug('日历选择器已打开');
|
|
|
|
|
+
|
|
|
|
|
+ // 验证初始日期被选中
|
|
|
|
|
+ // 验证初始日期被选中 - 查找包含"15"文本的按钮
|
|
|
|
|
+ const selectedDate = calendar.locator('button').filter({ hasText: '15' });
|
|
|
|
|
+ await expect(selectedDate.first()).toBeVisible();
|
|
|
|
|
+ console.debug('初始日期(15日)被正确选中');
|
|
|
|
|
+ console.debug('初始日期(15日)被正确选中');
|
|
|
|
|
+
|
|
|
|
|
+ // 点击新日期(10日)
|
|
|
|
|
+ const newDateButton = calendar.locator('button').filter({ hasText: '10' }).first();
|
|
|
|
|
+ // 增加等待时间确保动画完成
|
|
|
|
|
+ await page.waitForTimeout(TIMEOUTS.SHORT);
|
|
|
|
|
+
|
|
|
|
|
+ // 监听网络请求
|
|
|
|
|
+ let apiCalled = false;
|
|
|
|
|
+ let apiResponse = null;
|
|
|
|
|
+ page.on('response', async (response) => {
|
|
|
|
|
+ if (response.url().includes('/persons/dates')) {
|
|
|
|
|
+ apiCalled = true;
|
|
|
|
|
+ apiResponse = await response.text();
|
|
|
|
|
+ console.debug('API 调用已捕获:', response.status(), apiResponse);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 点击新日期
|
|
|
|
|
+ await newDateButton.click({ force: true });
|
|
|
|
|
+ await page.waitForTimeout(TIMEOUTS.MEDIUM);
|
|
|
|
|
|
|
|
- await expect(page.locator('[data-testid="person-date-edit-dialog"]')).toBeVisible();
|
|
|
|
|
- console.debug('日期编辑对话框已打开');
|
|
|
|
|
|
|
+ console.debug('API 是否被调用:', apiCalled);
|
|
|
|
|
+ if (apiCalled) {
|
|
|
|
|
+ console.debug('API 响应:', apiResponse);
|
|
|
|
|
+ }
|
|
|
|
|
+ const toast = page.locator('[data-sonner-toast]');
|
|
|
|
|
+ await expect(toast).toBeVisible();
|
|
|
|
|
+ await expect(toast).toContainText('入职日期更新成功');
|
|
|
|
|
+ console.debug('显示入职日期更新成功 toast');
|
|
|
|
|
|
|
|
- const dialogContent = page.locator('[data-testid="person-date-edit-dialog"] .text-sm.text-muted-foreground');
|
|
|
|
|
- await expect(dialogContent).toContainText(testData.personName);
|
|
|
|
|
- console.debug('对话框显示正确的人员名称');
|
|
|
|
|
|
|
+ // 验证日期已更新
|
|
|
|
|
+ await expect(joinDateButton).toContainText(testData.newJoinDate);
|
|
|
|
|
+ console.debug('入职日期已更新为:', testData.newJoinDate);
|
|
|
|
|
|
|
|
- await page.locator('[data-testid="cancel-button"]').click();
|
|
|
|
|
- await expect(page.locator('[data-testid="person-date-edit-dialog"]')).not.toBeVisible();
|
|
|
|
|
- console.debug('对话框已关闭');
|
|
|
|
|
|
|
+ // 验证日历选择器已关闭
|
|
|
|
|
+ await expect(calendar).not.toBeVisible();
|
|
|
|
|
+ console.debug('日历选择器已自动关闭');
|
|
|
|
|
|
|
|
|
|
+ // 测试离职日期编辑
|
|
|
await leaveDateButton.click();
|
|
await leaveDateButton.click();
|
|
|
-
|
|
|
|
|
- await expect(page.locator('[data-testid="person-date-edit-dialog"]')).toBeVisible();
|
|
|
|
|
- console.debug('通过离职日期按钮打开了对话框');
|
|
|
|
|
|
|
|
|
|
- await page.locator('[data-testid="cancel-button"]').click();
|
|
|
|
|
|
|
+ // 等待日历选择器出现
|
|
|
|
|
+ await expect(calendar).toBeVisible({ timeout: TIMEOUTS.DIALOG });
|
|
|
|
|
+ console.debug('离职日期日历选择器已打开');
|
|
|
|
|
+
|
|
|
|
|
+ // 按 ESC 键关闭日历
|
|
|
|
|
+ await page.keyboard.press('Escape');
|
|
|
|
|
+ await expect(calendar).not.toBeVisible();
|
|
|
|
|
+ console.debug('按 ESC 键关闭了日历选择器');
|
|
|
|
|
|
|
|
console.debug('========== AC1 测试完成 ==========');
|
|
console.debug('========== AC1 测试完成 ==========');
|
|
|
});
|
|
});
|