import { Locator, Page } from '@playwright/test'; /** * The Categories and Tags tabs, which share a shape: a table or tree, an * "Add X" button, and an antd Modal with a single Name field behind it. * * Categories are a tree because they nest arbitrarily deep; tags are flat. The * tree is what makes "Add child" meaningful, and it is mounted before a new * branch exists — so a child is only visible if expansion follows newly created * nodes rather than the state captured at first render, which is the thing the * spec here pins down. */ export class AdminTaxonomy { readonly addCategoryButton: Locator; readonly addTagButton: Locator; readonly name: Locator; readonly confirmButton: Locator; readonly tagAddedNotice: Locator; constructor(private readonly page: Page) { this.addCategoryButton = page.getByRole('button', { name: 'Add Category' }); this.addTagButton = page.getByRole('button', { name: 'Add Tag' }); this.name = page.getByLabel('Name'); this.confirmButton = page.getByRole('button', { name: 'OK' }); this.tagAddedNotice = page.getByText('Tag added'); } categoryNode(name: string): Locator { return this.page.getByRole('treeitem').filter({ hasText: name }); } async addCategory(name: string): Promise { await this.addCategoryButton.click(); await this.name.fill(name); await this.confirmButton.click(); } async addChildCategory(parentName: string, childName: string): Promise { await this.categoryNode(parentName).getByRole('button', { name: 'Add child' }).click(); await this.name.fill(childName); await this.confirmButton.click(); } async addTag(name: string): Promise { await this.addTagButton.click(); await this.name.fill(name); await this.confirmButton.click(); } }