accountPage.ts 6.6 KB
import { Page, Locator, expect } from '@playwright/test';
import { BasePage } from './basePage';

/**
 * 账目管理页面选择器
 */
const selectors = {
  // 导航
  moreMenu: 'text=更多 >',
  accountMenu: 'text=账目管理',
  
  // 操作按钮
  addButton: 'text=新增',
  saveButton: 'text=保存',
  
  // 表单字段
  accountNameInput: 'uni-input:has-text("科目名称") input',
  remarkTextarea: 'uni-scroll-view textarea',
  
  // 收支类型单选
  incomeRadio: '.nut-radio-group > uni-view:nth-child(1) > .nut-icon',
  expenseRadio: '.nut-radio-group > uni-view:nth-child(2) > .nut-icon',
};

/**
 * 账目管理页面类
 * 处理账目管理相关操作
 */
export class AccountPage extends BasePage {
  // 导航定位器
  readonly moreMenu: Locator;
  readonly accountMenu: Locator;
  
  // 操作按钮
  readonly addButton: Locator;
  readonly saveButton: Locator;
  readonly editButton: Locator;
  
  // 表单字段
  readonly accountNameInput: Locator;
  readonly remarkTextarea: Locator;
  
  // 收支类型
  readonly incomeRadio: Locator;
  readonly expenseRadio: Locator;

  constructor(page: Page) {
    super(page);
    
    this.moreMenu = page.getByText('更多 >');
    this.accountMenu = page.getByText('账目管理').first();
    this.addButton = page.getByText('新增', { exact: true });
    this.saveButton = page.locator('uni-button.execute-btn').filter({ hasText: '保存' });
    this.editButton = page.locator('uni-button').filter({ hasText: '修改' });
    this.accountNameInput = page.locator('uni-input').filter({ hasText: '科目名称' }).getByRole('textbox');
    this.remarkTextarea = page.locator('uni-scroll-view textarea');
    this.incomeRadio = page.locator('.nut-radio-group > uni-view:nth-child(1) > .nut-icon');
    this.expenseRadio = page.locator('.nut-radio-group > uni-view:nth-child(2) > .nut-icon');
  }

  /**
   * 进入账目管理页面
   */
  async openAccountManagement(): Promise<void> {
    await this.navigate('/');
    await this.moreMenu.click();
    await this.page.waitForTimeout(500);
    await this.accountMenu.click();
    await this.page.waitForLoadState('networkidle', { timeout: 30000 });
  }

  /**
   * 点击新增按钮
   */
  async clickAddButton(): Promise<void> {
    await this.addButton.click();
    await this.page.waitForTimeout(500);
  }

  /**
   * 填写账目名称
   * @param name 账目名称
   */
  async fillAccountName(name: string): Promise<void> {
    await this.accountNameInput.click();
    await this.accountNameInput.fill(name);
  }

  /**
   * 选择收支类型
   * @param type '收入' 或 '支出'
   */
  async selectIncomeType(type: '收入' | '支出'): Promise<void> {
    if (type === '支出') {
      await this.expenseRadio.click();
    }
    // 收入是默认选项,无需选择
  }

  /**
   * 填写备注
   * @param remark 备注内容
   */
  async fillRemark(remark: string): Promise<void> {
    await this.remarkTextarea.click();
    await this.remarkTextarea.fill(remark);
  }

  /**
   * 保存账目
   */
  async saveAccount(): Promise<void> {
    await this.saveButton.click();
    await this.page.waitForTimeout(1000);
  }

  /**
   * 搜索账目
   * @param name 账目名称
   */
  async searchAccount(name: string): Promise<void> {
    await this.page.locator('uni-input').filter({ hasText: '账目名称' }).getByRole('textbox').click();
    await this.page.locator('uni-input').filter({ hasText: '账目名称' }).getByRole('textbox').fill(name);
    await this.page.waitForTimeout(1000);
  }

  /**
   * 验证账目是否存在
   * @param name 账目名称
   * @returns 是否存在
   */
  async verifyAccountExists(name: string): Promise<boolean> {
    const isVisible = await this.page.getByText(name, { exact: true }).isVisible().catch(() => false);
    return isVisible;
  }

  /**
   * 删除账目
   * @param name 账目名称
   */
  async deleteAccount(name: string): Promise<void> {
    // 搜索账目
    await this.searchAccount(name);
    await this.page.waitForTimeout(500);
    // 点击删除按钮
    await this.page.getByText('删除').click();
    await this.page.waitForTimeout(500);
    // 确认删除
    await this.page.getByText('确定').click();
    await this.page.waitForTimeout(1000);
  }

  /**
   * 验证账目删除成功
   * @param name 账目名称
   * @returns 是否删除成功
   */
  async verifyAccountDeleted(name: string): Promise<boolean> {
    await this.searchAccount(name);
    await this.page.waitForTimeout(500);
    const isVisible = await this.page.getByText(name, { exact: true }).isVisible().catch(() => false);
    return !isVisible;
  }

  /**
   * 点击修改按钮
   */
  async clickEditButton(): Promise<void> {
    await this.editButton.click();
    await this.page.waitForTimeout(500);
  }

  /**
   * 修改账目完整流程
   * @param originalName 原账目名称
   * @param newName 新账目名称
   * @param incomeType 收支类型(收入/支出)
   * @param remark 备注
   */
  async updateAccount(originalName: string, newName: string, incomeType?: '收入' | '支出', remark?: string): Promise<void> {
    // 搜索原账目
    await this.searchAccount(originalName);
    await this.page.waitForTimeout(500);
    // 点击修改按钮
    await this.clickEditButton();
    // 修改账目名称
    await this.accountNameInput.click();
    await this.accountNameInput.fill(newName);
    // 修改收支类型
    if (incomeType === '支出') {
      await this.expenseRadio.click();
    }
    // 修改备注
    if (remark) {
      await this.remarkTextarea.click();
      await this.remarkTextarea.fill(remark);
    }
    // 保存
    await this.saveAccount();
  }

  /**
   * 清除搜索框
   */
  async clearSearchBox(): Promise<void> {
    await this.page.locator('.nut-icon.nutui-iconfont.nut-icon-circle-close').click();
    await this.page.waitForTimeout(500);
  }

  /**
   * 新增账目完整流程
   * @param accountName 账目名称
   * @param incomeType 收支类型(默认'收入')
   * @param remark 备注
   */
  async createAccount(accountName: string, incomeType: '收入' | '支出' = '收入', remark?: string): Promise<void> {
    await this.openAccountManagement();
    await this.clickAddButton();
    await this.fillAccountName(accountName);
    await this.selectIncomeType(incomeType);
    if (remark) {
      await this.fillRemark(remark);
    }
    await this.saveAccount();
  }

  /**
   * 验证账目创建成功
   * @param accountName 账目名称
   * @returns 是否创建成功
   */
  async verifyAccountCreated(accountName: string): Promise<boolean> {
    await this.searchAccount(accountName);
    return await this.verifyAccountExists(accountName);
  }
}