umbraco-playwright-testhelpers by umbraco/umbraco-cms-backoffice-skills
npx skills add https://github.com/umbraco/umbraco-cms-backoffice-skills --skill umbraco-playwright-testhelpers@umbraco/playwright-testhelpers 是 Umbraco 官方提供的包,它为针对 Umbraco 后台实例编写端到端(E2E)测试提供了 Playwright 夹具、API 助手和 UI 助手。
代码仓库 : https://github.com/umbraco/Umbraco.Playwright.Testhelpers
npm install @umbraco/playwright-testhelpers --save-dev
该包导出以下主要项目:
import {
test, // 带有夹具的扩展版 Playwright test
ApiHelpers, // 直接 API 助手类
UiHelpers, // 直接 UI 助手类
ConstantHelper, // 用于区域、操作、按钮的常量
AliasHelper, // 别名生成工具
JsonHelper // JSON 解析工具
} from '@umbraco/playwright-testhelpers';
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
test 导出项通过两个夹具扩展了 Playwright 的 test:
import { test } from '@umbraco/playwright-testhelpers';
test('我的测试', async ({ umbracoApi, umbracoUi }) => {
// umbracoApi - 用于快速测试设置/清理的 API 助手
// umbracoUi - 用于后台交互的 UI 助手
});
// testExtension.ts (内部)
const test = base.extend<{umbracoApi: ApiHelpers} & {umbracoUi: UiHelpers}>({
umbracoApi: async ({ page }, use) => {
const umbracoApi = new ApiHelpers(page);
await use(umbracoApi);
},
umbracoUi: async ({ page }, use) => {
const umbracoUi = new UiHelpers(page);
await use(umbracoUi);
}
});
ApiHelpers 类为每种实体类型提供了子助手:
| 属性 | 助手类 | 用途 |
|---|---|---|
content | ContentApiHelper | 内容/文档操作 |
documentTypes | DocumentTypeApiHelper | 文档类型操作 |
dataTypes | DatatypeApiHelper | 数据类型操作 |
media | MediaApiHelper | 媒体操作 |
mediaTypes | MediaTypeApiHelper | 媒体类型操作 |
templates | TemplatesApiHelper | 模板操作 |
languages | LanguagesApiHelper | 语言操作 |
users | UserApiHelper | 用户操作 |
userGroups | UserGroupApiHelper | 用户组操作 |
members | MemberApiHelper | 会员操作 |
memberTypes | MemberTypeApiHelper | 会员类型操作 |
memberGroups | MemberGroupApiHelper | 会员组操作 |
macros | MacroApiHelper | 宏操作 |
scripts | ScriptApiHelper | 脚本操作 |
stylesheets | StylesheetApiHelper | 样式表操作 |
partialViews | PartialViewApiHelper | 部分视图操作 |
relationTypes | RelationTypeApiHelper | 关系类型操作 |
packages | PackageApiHelper | 包操作 |
domain | DomainApiHelper | 域名操作 |
translation | TranslationApiHelper | 翻译操作 |
webhook | WebhookApiHelper | Webhook 操作 |
// 基础 HTTP 方法(可直接在 umbracoApi 上使用)
await umbracoApi.get(url, params?);
await umbracoApi.post(url, data?);
await umbracoApi.delete(url, data?);
// CSRF 令牌(自动处理)
await umbracoApi.getCsrfToken();
// 登录
await umbracoApi.login(skipCheckTours?: boolean);
// 确保清理(幂等操作 - 如果不存在也不会失败)
await umbracoApi.documentTypes.ensureNameNotExists('MyDocType');
// 创建默认文档类型
const docType = await umbracoApi.documentTypes.createDefaultDocumentType('MyDocType');
// 创建元素类型(用于区块)
const elementType = await umbracoApi.documentTypes.createDefaultElementType('MyElement', 'myElement');
// 创建带有区块网格编辑器的文档类型
const element = await umbracoApi.documentTypes.createDefaultDocumentWithBlockGridEditor(element?, dataType?);
// 保存文档类型(使用构建器)
const docType = new DocumentTypeBuilder()
.withName('MyDocType')
.withAlias('myDocType')
.build();
await umbracoApi.documentTypes.save(docType);
// 参考:ContentApiHelper.ts 模式
// 注意:实际方法取决于版本 - 请查看源代码
// 常见模式:
await umbracoApi.content.ensureNameNotExists('MyContent');
await umbracoApi.content.createDefaultContent(name, documentTypeId);
await umbracoApi.content.getByName('MyContent');
await umbracoApi.content.publish(contentId);
// 获取内置数据类型
const dataType = await umbracoApi.dataTypes.getByName('Textstring');
// 创建区块网格数据类型
const blockGrid = await umbracoApi.dataTypes.createDefaultBlockGrid('MyBlockGrid', elementType);
// 确保清理
await umbracoApi.dataTypes.ensureNameNotExists('MyDataType');
// 创建媒体文件夹
await umbracoApi.media.createDefaultMediaFolder('MyFolder');
// 创建带文件的图片
await umbracoApi.media.createImageWithFile(
'MyImage',
{ src: '/path/to/image.jpg' },
'image.jpg',
'/local/path/to/image.jpg',
'image/jpeg'
);
// 清理
await umbracoApi.media.ensureNameNotExists('MyImage');
await umbracoApi.media.clearRecycleBin();
// 导航到区域
await umbracoUi.goToSection(ConstantHelper.sections.content);
await umbracoUi.goToSection(ConstantHelper.sections.settings);
await umbracoUi.goToSection(ConstantHelper.sections.media);
// 导航到特定项目
await umbracoUi.navigateToContent('MyContent');
await umbracoUi.navigateToMedia('MyMedia');
await umbracoUi.navigateToDocumentType('MyDocType');
await umbracoUi.navigateToDataType('MyDataType');
await umbracoUi.navigateToTemplate('MyTemplate');
// 通过路径获取树节点
const item = await umbracoUi.getTreeItem('contentTypes', ['MyFolder', 'MyDocType']);
// 刷新树
await umbracoUi.refreshContentTree();
await umbracoUi.refreshMediaTree();
// 等待树加载
await umbracoUi.waitForTreeLoad('settings');
// 通过 data-element 属性点击
await umbracoUi.clickDataElementByElementName('tree-item-myItem');
// 通过文本点击
await umbracoUi.clickButtonByText('Save');
// 点击元素
await umbracoUi.clickElement(locator);
// 点击多个元素
await umbracoUi.clickMultiple(locator);
// 设置标题名称(等待别名生成)
await umbracoUi.setEditorHeaderName('My Document');
// 获取编辑器标题名称
await umbracoUi.getEditorHeaderName('My Document');
// 添加属性组和编辑器
await umbracoUi.goToAddEditor('Content', 'Title');
// 获取元素
const helpButton = await umbracoUi.getGlobalHelp();
const userButton = await umbracoUi.getGlobalUser();
const element = await umbracoUi.getDataElementByElementName('my-element');
const button = await umbracoUi.getButtonByText('Save');
const button = await umbracoUi.getButtonByLabelKey('buttons_save');
const contextAction = await umbracoUi.getContextMenuAction('action-create');
// 通知
const success = await umbracoUi.getSuccessNotification();
const error = await umbracoUi.getErrorNotification();
// 检查通知
await umbracoUi.isSuccessNotificationVisible();
await umbracoUi.isErrorNotificationVisible();
// 检查数据类型是否存在
await umbracoUi.doesDataTypeExist('MyDataType');
// 使用模板创建
await umbracoUi.createNewDocumentTypeWithTemplate();
// 更新权限
await umbracoUi.updateDocumentPermissionsToAllowCultureVariant();
// 创建内容
await umbracoUi.createContentWithDocumentType('MyDocType');
// 切换文化
await umbracoUi.switchCultureInContent('Danish');
// 上传文件
await umbracoUi.fileUploader('/path/to/file.jpg');
// 拖放元素
await umbracoUi.dragAndDrop(
fromLocator,
toLocator,
verticalOffset,
horizontalOffset,
steps?
);
import { ConstantHelper } from '@umbraco/playwright-testhelpers';
// 区域
ConstantHelper.sections.content // "content"
ConstantHelper.sections.media // "media"
ConstantHelper.sections.settings // "settings"
ConstantHelper.sections.users // "users"
ConstantHelper.sections.member // "member"
ConstantHelper.sections.packages // "packages"
ConstantHelper.sections.translation // "translation"
// 操作(data-element 值)
ConstantHelper.actions.create // "action-create"
ConstantHelper.actions.delete // "action-delete"
ConstantHelper.actions.copy // "action-copy"
ConstantHelper.actions.move // "action-move"
ConstantHelper.actions.sort // "action-sort"
ConstantHelper.actions.save // "saveNew"
ConstantHelper.actions.publish // "publishNew"
ConstantHelper.actions.documentType // "action-documentType"
ConstantHelper.actions.dataType // "action-data-type"
ConstantHelper.actions.remove // "actions_remove"
// 按钮(label-key 值)
ConstantHelper.buttons.save // "buttons_save"
ConstantHelper.buttons.saveAndPublish // "buttons_saveAndPublish"
ConstantHelper.buttons.delete // "general_delete"
ConstantHelper.buttons.ok // "general_ok"
ConstantHelper.buttons.close // "general_close"
ConstantHelper.buttons.insert // "general_insert"
ConstantHelper.buttons.download // "general_download"
ConstantHelper.buttons.submit // "general_submit"
ConstantHelper.buttons.rollback // "actions_rollback"
ConstantHelper.buttons.add // "general_add"
ConstantHelper.buttons.submitChanges // "buttons_submitChanges"
ConstantHelper.buttons.remove // "general_remove"
ConstantHelper.buttons.change // "general_change"
ConstantHelper.buttons.select // "buttons_select"
// 内容应用
ConstantHelper.contentApps.info // '[data-element="sub-view-umbInfo"]'
有关全面的 AliasHelper 文档,请参见 umbraco-test-builders。
import { JsonHelper } from '@umbraco/playwright-testhelpers';
// 解析响应体
const response = await umbracoApi.get(url);
const body = await JsonHelper.getBody(response);
有关完整的测试示例和模板,请参见 umbraco-e2e-testing。
/Users/philw/Projects/Umbraco.Playwright.Testhelpers/lib/helpers/ApiHelpers.ts - API 助手类lib/helpers/UiHelpers.ts - UI 助手类lib/helpers/testExtension.ts - 测试夹具扩展lib/helpers/ConstantHelper.ts - 常量lib/helpers/AliasHelper.ts - 别名工具每周安装量
72
代码仓库
GitHub 星标数
17
首次出现
2026年2月4日
安全审计
安装于
github-copilot52
codex22
opencode21
cursor21
gemini-cli19
amp19
@umbraco/playwright-testhelpers is the official Umbraco package that provides Playwright fixtures, API helpers, and UI helpers for writing E2E tests against an Umbraco backoffice instance.
Repository : https://github.com/umbraco/Umbraco.Playwright.Testhelpers
npm install @umbraco/playwright-testhelpers --save-dev
The package exports these main items:
import {
test, // Extended Playwright test with fixtures
ApiHelpers, // Direct API helper class
UiHelpers, // Direct UI helper class
ConstantHelper, // Constants for sections, actions, buttons
AliasHelper, // Alias generation utilities
JsonHelper // JSON parsing utilities
} from '@umbraco/playwright-testhelpers';
The test export extends Playwright's test with two fixtures:
import { test } from '@umbraco/playwright-testhelpers';
test('my test', async ({ umbracoApi, umbracoUi }) => {
// umbracoApi - API helpers for fast test setup/teardown
// umbracoUi - UI helpers for backoffice interaction
});
// testExtension.ts (internal)
const test = base.extend<{umbracoApi: ApiHelpers} & {umbracoUi: UiHelpers}>({
umbracoApi: async ({ page }, use) => {
const umbracoApi = new ApiHelpers(page);
await use(umbracoApi);
},
umbracoUi: async ({ page }, use) => {
const umbracoUi = new UiHelpers(page);
await use(umbracoUi);
}
});
The ApiHelpers class provides sub-helpers for each entity type:
| Property | Helper Class | Purpose |
|---|---|---|
content | ContentApiHelper | Content/document operations |
documentTypes | DocumentTypeApiHelper | Document type operations |
dataTypes | DatatypeApiHelper | Data type operations |
media | MediaApiHelper | Media operations |
mediaTypes | MediaTypeApiHelper |
// Base HTTP methods (available on umbracoApi directly)
await umbracoApi.get(url, params?);
await umbracoApi.post(url, data?);
await umbracoApi.delete(url, data?);
// CSRF token (automatically handled)
await umbracoApi.getCsrfToken();
// Login
await umbracoApi.login(skipCheckTours?: boolean);
// Ensure cleanup (idempotent - won't fail if not exists)
await umbracoApi.documentTypes.ensureNameNotExists('MyDocType');
// Create default document type
const docType = await umbracoApi.documentTypes.createDefaultDocumentType('MyDocType');
// Create element type (for blocks)
const elementType = await umbracoApi.documentTypes.createDefaultElementType('MyElement', 'myElement');
// Create document type with block grid
const element = await umbracoApi.documentTypes.createDefaultDocumentWithBlockGridEditor(element?, dataType?);
// Save document type (using builder)
const docType = new DocumentTypeBuilder()
.withName('MyDocType')
.withAlias('myDocType')
.build();
await umbracoApi.documentTypes.save(docType);
// Reference: ContentApiHelper.ts patterns
// Note: Actual methods depend on version - check source
// Common patterns:
await umbracoApi.content.ensureNameNotExists('MyContent');
await umbracoApi.content.createDefaultContent(name, documentTypeId);
await umbracoApi.content.getByName('MyContent');
await umbracoApi.content.publish(contentId);
// Get built-in data type
const dataType = await umbracoApi.dataTypes.getByName('Textstring');
// Create block grid data type
const blockGrid = await umbracoApi.dataTypes.createDefaultBlockGrid('MyBlockGrid', elementType);
// Ensure cleanup
await umbracoApi.dataTypes.ensureNameNotExists('MyDataType');
// Create media folder
await umbracoApi.media.createDefaultMediaFolder('MyFolder');
// Create image with file
await umbracoApi.media.createImageWithFile(
'MyImage',
{ src: '/path/to/image.jpg' },
'image.jpg',
'/local/path/to/image.jpg',
'image/jpeg'
);
// Cleanup
await umbracoApi.media.ensureNameNotExists('MyImage');
await umbracoApi.media.clearRecycleBin();
// Navigate to section
await umbracoUi.goToSection(ConstantHelper.sections.content);
await umbracoUi.goToSection(ConstantHelper.sections.settings);
await umbracoUi.goToSection(ConstantHelper.sections.media);
// Navigate to specific items
await umbracoUi.navigateToContent('MyContent');
await umbracoUi.navigateToMedia('MyMedia');
await umbracoUi.navigateToDocumentType('MyDocType');
await umbracoUi.navigateToDataType('MyDataType');
await umbracoUi.navigateToTemplate('MyTemplate');
// Get tree item by path
const item = await umbracoUi.getTreeItem('contentTypes', ['MyFolder', 'MyDocType']);
// Refresh trees
await umbracoUi.refreshContentTree();
await umbracoUi.refreshMediaTree();
// Wait for tree load
await umbracoUi.waitForTreeLoad('settings');
// Click by data-element attribute
await umbracoUi.clickDataElementByElementName('tree-item-myItem');
// Click by text
await umbracoUi.clickButtonByText('Save');
// Click element
await umbracoUi.clickElement(locator);
// Click multiple elements
await umbracoUi.clickMultiple(locator);
// Set header name (with alias generation wait)
await umbracoUi.setEditorHeaderName('My Document');
// Get editor header name
await umbracoUi.getEditorHeaderName('My Document');
// Add property group and editor
await umbracoUi.goToAddEditor('Content', 'Title');
// Get elements
const helpButton = await umbracoUi.getGlobalHelp();
const userButton = await umbracoUi.getGlobalUser();
const element = await umbracoUi.getDataElementByElementName('my-element');
const button = await umbracoUi.getButtonByText('Save');
const button = await umbracoUi.getButtonByLabelKey('buttons_save');
const contextAction = await umbracoUi.getContextMenuAction('action-create');
// Notifications
const success = await umbracoUi.getSuccessNotification();
const error = await umbracoUi.getErrorNotification();
// Check notifications
await umbracoUi.isSuccessNotificationVisible();
await umbracoUi.isErrorNotificationVisible();
// Check data type exists
await umbracoUi.doesDataTypeExist('MyDataType');
// Create with template
await umbracoUi.createNewDocumentTypeWithTemplate();
// Update permissions
await umbracoUi.updateDocumentPermissionsToAllowCultureVariant();
// Create content
await umbracoUi.createContentWithDocumentType('MyDocType');
// Switch culture
await umbracoUi.switchCultureInContent('Danish');
// Upload file
await umbracoUi.fileUploader('/path/to/file.jpg');
// Drag and drop elements
await umbracoUi.dragAndDrop(
fromLocator,
toLocator,
verticalOffset,
horizontalOffset,
steps?
);
import { ConstantHelper } from '@umbraco/playwright-testhelpers';
// Sections
ConstantHelper.sections.content // "content"
ConstantHelper.sections.media // "media"
ConstantHelper.sections.settings // "settings"
ConstantHelper.sections.users // "users"
ConstantHelper.sections.member // "member"
ConstantHelper.sections.packages // "packages"
ConstantHelper.sections.translation // "translation"
// Actions (data-element values)
ConstantHelper.actions.create // "action-create"
ConstantHelper.actions.delete // "action-delete"
ConstantHelper.actions.copy // "action-copy"
ConstantHelper.actions.move // "action-move"
ConstantHelper.actions.sort // "action-sort"
ConstantHelper.actions.save // "saveNew"
ConstantHelper.actions.publish // "publishNew"
ConstantHelper.actions.documentType // "action-documentType"
ConstantHelper.actions.dataType // "action-data-type"
ConstantHelper.actions.remove // "actions_remove"
// Buttons (label-key values)
ConstantHelper.buttons.save // "buttons_save"
ConstantHelper.buttons.saveAndPublish // "buttons_saveAndPublish"
ConstantHelper.buttons.delete // "general_delete"
ConstantHelper.buttons.ok // "general_ok"
ConstantHelper.buttons.close // "general_close"
ConstantHelper.buttons.insert // "general_insert"
ConstantHelper.buttons.download // "general_download"
ConstantHelper.buttons.submit // "general_submit"
ConstantHelper.buttons.rollback // "actions_rollback"
ConstantHelper.buttons.add // "general_add"
ConstantHelper.buttons.submitChanges // "buttons_submitChanges"
ConstantHelper.buttons.remove // "general_remove"
ConstantHelper.buttons.change // "general_change"
ConstantHelper.buttons.select // "buttons_select"
// Content Apps
ConstantHelper.contentApps.info // '[data-element="sub-view-umbInfo"]'
See umbraco-test-builders for comprehensive AliasHelper documentation.
import { JsonHelper } from '@umbraco/playwright-testhelpers';
// Parse response body
const response = await umbracoApi.get(url);
const body = await JsonHelper.getBody(response);
See umbraco-e2e-testing for full test examples and templates.
/Users/philw/Projects/Umbraco.Playwright.Testhelpers/lib/helpers/ApiHelpers.ts - API helper classlib/helpers/UiHelpers.ts - UI helper classlib/helpers/testExtension.ts - Test fixture extensionlib/helpers/ConstantHelper.ts - Constantslib/helpers/AliasHelper.ts - Alias utilitiesWeekly Installs
72
Repository
GitHub Stars
17
First Seen
Feb 4, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
github-copilot52
codex22
opencode21
cursor21
gemini-cli19
amp19
GitHub Actions 官方文档查询助手 - 精准解答 CI/CD 工作流问题
45,200 周安装
Rust元认知并行分析工具 - 三层并行认知分析解决编程问题
508 周安装
跨越鸿沟框架:颠覆性技术产品从早期采用者到主流市场的营销策略指南
550 周安装
Chrome DevTools 自动化脚本:Puppeteer 浏览器自动化与性能监控工具
523 周安装
Overlastic:支持React、Vue、Svelte的Promise模态框库,实现弹窗管理
524 周安装
Obsidian Agent Skill - 知识管理与笔记工具集成,提升AI助手工作效率
72 周安装
btca-cli:源码优先的AI研究工具,将Git、本地和npm资源转化为可搜索上下文
525 周安装
| Media type operations |
templates | TemplatesApiHelper | Template operations |
languages | LanguagesApiHelper | Language operations |
users | UserApiHelper | User operations |
userGroups | UserGroupApiHelper | User group operations |
members | MemberApiHelper | Member operations |
memberTypes | MemberTypeApiHelper | Member type operations |
memberGroups | MemberGroupApiHelper | Member group operations |
macros | MacroApiHelper | Macro operations |
scripts | ScriptApiHelper | Script operations |
stylesheets | StylesheetApiHelper | Stylesheet operations |
partialViews | PartialViewApiHelper | Partial view operations |
relationTypes | RelationTypeApiHelper | Relation type operations |
packages | PackageApiHelper | Package operations |
domain | DomainApiHelper | Domain operations |
translation | TranslationApiHelper | Translation operations |
webhook | WebhookApiHelper | Webhook operations |