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

/**
 * 商品管理页面选择器
 */
const selectors = {
  // 导航
  productManagementMenu: 'text=商品管理',
  addProductButton: 'text=新增商品',
  
  // 表单
  productNameInput: '.nut-input__input > .uni-input-wrapper > .uni-input-input',
  categorySearchInput: '.uni-scroll-view-content > .z-paging-content > .nut-searchbar > .nut-searchbar__search-input > .nut-searchbar__input-inner > .nut-searchbar__input-form > span > .nut-searchbar__input-bar > .uni-input-wrapper > .uni-input-input',
  categoryOption: (categoryName: string) => `uni-view:has-text("${categoryName}")`,
  saveButton: 'text=保存',
  
  // 列表
  productInList: (productName: string) => `text=${productName}`,
};

/**
 * 商品管理页面类
 * 处理商品相关操作
 */
export class ProductPage extends BasePage {
  // 导航定位器
  readonly productManagementMenu: Locator;
  readonly addProductButton: Locator;
  
  // 表单定位器
  readonly productNameInput: Locator;
  readonly categorySearchInput: Locator;
  readonly saveButton: Locator;

  constructor(page: Page) {
    super(page);
    
    this.productManagementMenu = page.getByText('商品管理');
    this.addProductButton = page.getByText('新增商品');
    this.productNameInput = page.locator('.nut-input__input > .uni-input-wrapper > .uni-input-input').first();
    this.categorySearchInput = page.locator('.uni-scroll-view-content > .z-paging-content > .nut-searchbar > .nut-searchbar__search-input > .nut-searchbar__input-inner > .nut-searchbar__input-form > span > .nut-searchbar__input-bar > .uni-input-wrapper > .uni-input-input');
    this.saveButton = page.getByText('保存');
  }

  /**
   * 导航到首页
   */
  async gotoHome(): Promise<void> {
    await this.navigate('/');
  }

  /**
   * 打开商品管理菜单
   */
  async openProductManagement(): Promise<void> {
    await this.productManagementMenu.click();
  }

  /**
   * 点击新增商品按钮
   */
  async clickAddProduct(): Promise<void> {
    await this.addProductButton.click();
  }

  /**
   * 打开新增商品表单
   * 完整流程:导航首页 -> 商品管理 -> 新增商品
   */
  async openAddProductForm(): Promise<void> {
    await this.gotoHome();
    await this.openProductManagement();
    await this.clickAddProduct();
  }

  /**
   * 输入商品名称
   * @param productName 商品名称
   */
  async enterProductName(productName: string): Promise<void> {
    await this.productNameInput.click();
    await this.productNameInput.fill(productName);
  }

  /**
   * 选择商品分类
   * @param categoryName 分类名称
   */
  async selectCategory(categoryName: string): Promise<void> {
    // 点击分类选择器
    await this.page.locator('.nut-input__mask').first().click();

    // 搜索分类
    await this.categorySearchInput.click();
    await this.categorySearchInput.fill(categoryName);
    
    // 选择匹配的分类,精准匹配
    await this.page.locator('uni-view').filter({ hasText: new RegExp(`^${categoryName}$`) }).first().click();
    // 匹配包含分类名称的元素
    // 匹配以分类名称开头的元素(允许后面有其他字符)
    // await this.page.locator('uni-view').filter({ hasText: new RegExp(`^${categoryName}`) }).first().click();

  }

//   /**
//  * 选择分类
//  * @param categoryName 分类名称
//  */
// async selectCategory(categoryName: string): Promise<void> {

//  // 点击分类选择器
//   await this.page.locator('.nut-input__mask').first().click();
//     // 搜索分类
//   await this.categorySearchInput.click();
// //   await this.categorySearchInput.fill(categoryName);
//   // 取前两个字匹配,避免后缀影响
//   const categoryPrefix = categoryName.substring(0, 2);
//   await this.categorySearchInput.fill(categoryPrefix);
//   // 直接用文本匹配,排除容器
//   await this.page.getByText(new RegExp(`^${categoryPrefix}`), { exact: false })
//     .nth(1)  // 可能第一个是搜索框里的文字,用 nth(1) 选第二个
//     .click({ force: true });

 


// }


  /**
   * 点击保存按钮
   */
  async clickSave(): Promise<void> {
    await this.saveButton.click();
  }

  /**
   * 创建新商品(完整流程)
   * @param productName 商品名称
   * @param categoryName 分类名称
   */
  async createProduct(productName: string, categoryName: string): Promise<void> {
    await this.openAddProductForm();
    await this.enterProductName(productName);
    await this.selectCategory(categoryName);
    await this.clickSave();
  }

  /**
   * 验证商品是否可见
   * @param productName 商品名称
   */
  async expectProductVisible(productName: string): Promise<void> {
    await expect(this.page.getByText(productName)).toBeVisible();
  }

  /**
   * 验证商品创建成功
   * @param productName 商品名称
   */
  async verifyProductCreated(productName: string): Promise<void> {
    await this.expectProductVisible(productName);
  }

  /**
   * 在列表中查找商品
   * @param productName 商品名称
   */
  async findProductInList(productName: string): Promise<Locator> {
    return this.page.getByText(productName);
  }

  /**
   * 检查商品是否存在于列表
   * @param productName 商品名称
   */
  async isProductInList(productName: string): Promise<boolean> {
    try {
      const product = await this.findProductInList(productName);
      await product.waitFor({ state: 'visible', timeout: 5000 });
      return true;
    } catch {
      return false;
    }
  }

  /**
   * 等待商品列表加载
   */
  async waitForProductListLoad(): Promise<void> {
    await this.page.waitForLoadState('networkidle');
  }
}