| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411 |
- import { TIMEOUTS } from '../../utils/timeouts';
- import { test, expect } from '../../utils/test-setup';
- import type { APIRequestContext } from '@playwright/test';
- import { readFileSync } from 'fs';
- import { join, dirname } from 'path';
- import { fileURLToPath } from 'url';
- const __filename = fileURLToPath(import.meta.url);
- const __dirname = dirname(__filename);
- const testUsers = JSON.parse(readFileSync(join(__dirname, '../../fixtures/test-users.json'), 'utf-8'));
- async function getAuthToken(request: APIRequestContext): Promise<string | null> {
- const loginResponse = await request.post('http://localhost:8080/api/v1/auth/login', {
- data: {
- username: testUsers.admin.username,
- password: testUsers.admin.password
- }
- });
- if (!loginResponse.ok()) {
- console.debug('API 登录失败:', await loginResponse.text());
- return null;
- }
- const loginData = await loginResponse.json();
- return loginData.data?.token || loginData.token || null;
- }
- async function createDisabledPersonViaAPI(
- request: APIRequestContext,
- personData: {
- name: string;
- gender: string;
- idCard: string;
- disabilityId: string;
- disabilityType: string;
- disabilityLevel: string;
- idAddress: string;
- phone: string;
- province: string;
- city: string;
- }
- ): Promise<{ id: number; name: string } | null> {
- try {
- const token = await getAuthToken(request);
- if (!token) return null;
- const createResponse = await request.post('http://localhost:8080/api/v1/disability/createDisabledPerson', {
- headers: {
- 'Authorization': 'Bearer ' + String(token),
- 'Content-Type': 'application/json'
- },
- data: personData
- });
- if (!createResponse.ok()) {
- const errorText = await createResponse.text();
- console.debug('API 创建残疾人失败:', createResponse.status(), errorText);
- return null;
- }
- const result = await createResponse.json();
- console.debug('API 创建残疾人成功:', result.name);
- return { id: result.id, name: result.name };
- } catch (error) {
- console.debug('API 调用出错:', error);
- return null;
- }
- }
- async function createPlatformViaAPI(
- request: APIRequestContext
- ): Promise<{ id: number; name: string } | null> {
- try {
- const token = await getAuthToken(request);
- if (!token) return null;
- const timestamp = Date.now();
- const platformData = {
- platformName: '测试平台_' + String(timestamp),
- contactPerson: '测试联系人',
- contactPhone: '13800138000',
- contactEmail: 'test@example.com'
- };
- const createResponse = await request.post('http://localhost:8080/api/v1/platform/createPlatform', {
- headers: {
- 'Authorization': 'Bearer ' + String(token),
- 'Content-Type': 'application/json'
- },
- data: platformData
- });
- if (!createResponse.ok()) {
- const errorText = await createResponse.text();
- console.debug('API 创建平台失败:', createResponse.status(), errorText);
- return null;
- }
- const result = await createResponse.json();
- console.debug('API 创建平台成功:', result.id, result.platformName);
- return { id: result.id, name: result.platformName };
- } catch (error) {
- console.debug('创建平台 API 调用出错:', error);
- return null;
- }
- }
- async function createCompanyViaAPI(
- request: APIRequestContext,
- platformId: number
- ): Promise<{ id: number; name: string } | null> {
- try {
- const token = await getAuthToken(request);
- if (!token) return null;
- const timestamp = Date.now();
- const companyName = '测试公司_' + String(timestamp);
- const companyData = {
- companyName: companyName,
- platformId: platformId,
- contactPerson: '测试联系人',
- contactPhone: '13900139000',
- contactEmail: 'company@example.com'
- };
- const createResponse = await request.post('http://localhost:8080/api/v1/company/createCompany', {
- headers: {
- 'Authorization': 'Bearer ' + String(token),
- 'Content-Type': 'application/json'
- },
- data: companyData
- });
- if (!createResponse.ok()) {
- const errorText = await createResponse.text();
- console.debug('API 创建公司失败:', createResponse.status(), errorText);
- return null;
- }
- const createResult = await createResponse.json();
- if (!createResult.success) {
- console.debug('API 创建公司返回 success=false');
- return null;
- }
- const listResponse = await request.get('http://localhost:8080/api/v1/company/getCompaniesByPlatform/' + String(platformId), {
- headers: {
- 'Authorization': 'Bearer ' + String(token)
- }
- });
- if (!listResponse.ok()) {
- console.debug('API 获取公司列表失败');
- return null;
- }
- const companies = await listResponse.json();
- const createdCompany = companies.find((c: { companyName: string }) => c.companyName === companyName);
- if (createdCompany) {
- console.debug('API 创建公司成功:', createdCompany.id, createdCompany.companyName);
- return { id: createdCompany.id, name: createdCompany.companyName };
- }
- console.debug('未找到创建的公司');
- return null;
- } catch (error) {
- console.debug('创建公司 API 调用出错:', error);
- return null;
- }
- }
- async function createOrderViaAPI(
- request: APIRequestContext,
- orderData: {
- orderName: string;
- platformId: number;
- companyId: number;
- expectedStartDate: string;
- }
- ): Promise<{ id: number; name: string } | null> {
- try {
- const token = await getAuthToken(request);
- if (!token) return null;
- const createResponse = await request.post('http://localhost:8080/api/v1/order/create', {
- headers: {
- 'Authorization': 'Bearer ' + String(token),
- 'Content-Type': 'application/json'
- },
- data: orderData
- });
- if (!createResponse.ok()) {
- const errorText = await createResponse.text();
- console.debug('API 创建订单失败:', createResponse.status(), errorText);
- return null;
- }
- const result = await createResponse.json();
- console.debug('API 创建订单成功:', result.id, result.orderName);
- return { id: result.id, name: result.orderName };
- } catch (error) {
- console.debug('创建订单 API 调用出错:', error);
- return null;
- }
- }
- async function bindPersonToOrderViaAPI(
- request: APIRequestContext,
- orderId: number,
- personId: number,
- joinDate: string
- ): Promise<boolean> {
- try {
- const token = await getAuthToken(request);
- if (!token) return false;
- const url = 'http://localhost:8080/api/v1/order/' + String(orderId) + '/persons/batch';
- const createResponse = await request.post(url, {
- headers: {
- 'Authorization': 'Bearer ' + String(token),
- 'Content-Type': 'application/json'
- },
- data: {
- persons: [
- {
- personId: personId,
- joinDate: joinDate,
- salaryDetail: 5000
- }
- ]
- }
- });
- if (!createResponse.ok()) {
- const errorText = await createResponse.text();
- console.debug('API 绑定人员失败:', createResponse.status(), errorText);
- return false;
- }
- const result = await createResponse.json();
- if (result.success) {
- console.debug('API 绑定人员成功:', personId);
- return true;
- }
- return false;
- } catch (error) {
- console.debug('绑定人员 API 调用出错:', error);
- return false;
- }
- }
- function generateUniqueTestData() {
- const timestamp = Date.now();
- const counter = Math.floor(Math.random() * 10000);
- return {
- orderName: '日期测试订单_' + String(timestamp),
- personName: '日期测试残疾人_' + String(timestamp),
- gender: '男',
- idCard: '110101' + String(timestamp).slice(-8) + String(counter).slice(-4),
- disabilityId: '残疾证' + String(timestamp).slice(-6) + String(counter),
- disabilityType: '视力残疾',
- disabilityLevel: '一级',
- idAddress: '北京市东城区测试地址' + String(timestamp),
- phone: '138' + String(counter).padStart(8, '0'),
- province: '北京市',
- city: '北京市',
- joinDate: '2026-01-15',
- newJoinDate: '2026-01-10',
- };
- }
- test.describe.serial('订单管理 - 人员入职/离职日期行内编辑功能 (Story 15.5)', () => {
- test.beforeEach(async ({ adminLoginPage }) => {
- await adminLoginPage.goto();
- await adminLoginPage.login(testUsers.admin.username, testUsers.admin.password);
- });
- test('AC1: 订单人员详情页中入职日期和离职日期可点击编辑(行内编辑模式)', async ({ page, request }) => {
- console.debug('========== Story 15.5 AC1: 入职/离职日期行内编辑 ==========');
- const testData = generateUniqueTestData();
- console.debug('测试数据已生成:', testData.personName);
- const platform = await createPlatformViaAPI(request);
- expect(platform).not.toBeNull();
- const company = await createCompanyViaAPI(request, platform!.id);
- expect(company).not.toBeNull();
- const order = await createOrderViaAPI(request, {
- orderName: testData.orderName,
- platformId: platform!.id,
- companyId: company!.id,
- expectedStartDate: '2026-01-01'
- });
- expect(order).not.toBeNull();
- const person = await createDisabledPersonViaAPI(request, {
- name: testData.personName,
- gender: testData.gender,
- idCard: testData.idCard,
- disabilityId: testData.disabilityId,
- disabilityType: testData.disabilityType,
- disabilityLevel: testData.disabilityLevel,
- idAddress: testData.idAddress,
- phone: testData.phone,
- province: testData.province,
- city: testData.city,
- });
- expect(person).not.toBeNull();
- const bound = await bindPersonToOrderViaAPI(request, order!.id, person!.id, testData.joinDate);
- expect(bound).toBe(true);
- await page.goto('/admin/orders');
- await page.waitForLoadState('networkidle');
- await page.fill('input[placeholder*="搜索"]', testData.orderName);
- await page.waitForTimeout(TIMEOUTS.MEDIUM);
- const orderRow = page.locator('tbody tr').filter({ hasText: testData.orderName });
- await orderRow.waitFor({ state: 'visible', timeout: TIMEOUTS.TABLE_LOAD });
- // 点击"打开菜单"按钮
- const menuTrigger = orderRow.getByRole('button', { name: /打开菜单/ });
- await menuTrigger.click();
- await page.waitForTimeout(TIMEOUTS.VERY_SHORT);
- // 点击"查看详情"菜单项
- const detailButton = page.getByRole('menuitem', { name: /查看详情/ });
- await detailButton.click();
- 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) + '"]');
- await expect(joinDateButton).toBeVisible();
- console.debug('入职日期按钮可见');
- const leaveDateButton = page.locator('[data-testid="edit-leave-date-' + String(person!.id) + '"]');
- await expect(leaveDateButton).toBeVisible();
- console.debug('离职日期按钮可见');
- // 点击入职日期按钮,应该弹出日历选择器
- 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);
-
- 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');
- // 验证日期已更新
- await expect(joinDateButton).toContainText(testData.newJoinDate);
- console.debug('入职日期已更新为:', testData.newJoinDate);
- // 验证日历选择器已关闭
- await expect(calendar).not.toBeVisible();
- console.debug('日历选择器已自动关闭');
- // 测试离职日期编辑
- await leaveDateButton.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 测试完成 ==========');
- });
- });
|