n8n/packages/testing/playwright/pages/components/NodeCreator.ts
n8n-cat-bot[bot] bf02ed5990
chore: Route node-creator category collapse assertions through (#32820)
Co-authored-by: n8n-cat-bot[bot] <n8n-cat-bot[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 09:48:56 +00:00

120 lines
3.1 KiB
TypeScript

import type { Locator, Page } from '@playwright/test';
import { expect } from '@playwright/test';
/**
* Node Creator component for adding nodes to workflows.
* Used within CanvasPage as `n8n.canvas.nodeCreator.*`
*
* @example
* // Access via canvas page
* await n8n.canvas.nodeCreator.open();
* await n8n.canvas.nodeCreator.searchFor('Gmail');
* await n8n.canvas.nodeCreator.selectItem('Gmail');
*/
export class NodeCreator {
constructor(private page: Page) {}
// Core locators
getRoot(): Locator {
return this.page.getByTestId('node-creator');
}
getSearchBar(): Locator {
return this.page.getByTestId('node-creator-search-bar');
}
getNodeItems(): Locator {
return this.page.getByTestId('item-iterator-item');
}
getCategoryItems(): Locator {
return this.page.getByTestId('node-creator-category-item');
}
getActiveSubcategory(): Locator {
return this.page.getByTestId('nodes-list-header').first();
}
getNoResults(): Locator {
return this.page.getByTestId('node-creator-no-results');
}
getNoTriggersCallout(): Locator {
return this.page.getByTestId('actions-panel-no-triggers-callout');
}
getActivationCallout(): Locator {
return this.page.getByTestId('actions-panel-activation-callout');
}
getTriggerText(): Locator {
return this.page.getByText('What triggers this workflow?');
}
getNextText(): Locator {
return this.page.getByText('What happens next?');
}
// Item getters
getItem(text: string, options: { exact?: boolean } = {}): Locator {
if (options.exact) {
return this.getNodeItems().filter({ has: this.page.getByText(text, { exact: true }) });
}
return this.getNodeItems().filter({ hasText: text }).first();
}
getCategoryItem(text: string): Locator {
return this.getCategoryItems().filter({ hasText: text });
}
getCategoryContainer(text: string): Locator {
return this.getCategoryItem(text).locator('..');
}
async expectCategoryCollapsed(text: string, collapsed: boolean): Promise<void> {
await expect(this.getCategoryContainer(text)).toHaveAttribute(
'data-category-collapsed',
String(collapsed),
);
}
// Actions
async open(): Promise<void> {
await this.page.getByTestId('node-creator-plus-button').click();
await expect(this.getRoot()).toBeVisible();
}
async close(): Promise<void> {
await this.page.keyboard.press('Escape');
}
async searchFor(text: string): Promise<void> {
await this.getSearchBar().fill(text);
}
async clearSearch(): Promise<void> {
await this.getSearchBar().clear();
}
async selectItem(text: string): Promise<void> {
await this.getItem(text).click();
}
async selectCategoryItem(text: string): Promise<void> {
await this.getCategoryItem(text).click();
}
async navigateToSubcategory(category: string, options: { exact?: boolean } = {}): Promise<void> {
await this.getItem(category, options).click();
await expect(this.getActiveSubcategory()).toContainText(category);
}
async goBackFromSubcategory(): Promise<void> {
await this.getActiveSubcategory().locator('button').click();
}
async clickInsertOneLink(): Promise<void> {
await this.page.getByText('Insert one').click();
}
}