@umbraco/playwright-testhelpers 17.0.17 → 17.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +139 -29
- package/dist/lib/helpers/ContentUiHelper.d.ts +6 -0
- package/dist/lib/helpers/ContentUiHelper.js +32 -0
- package/dist/lib/helpers/ContentUiHelper.js.map +1 -1
- package/dist/lib/helpers/DataTypeUiHelper.d.ts +1 -0
- package/dist/lib/helpers/DataTypeUiHelper.js +4 -0
- package/dist/lib/helpers/DataTypeUiHelper.js.map +1 -1
- package/dist/lib/helpers/DocumentTypeApiHelper.d.ts +4 -1
- package/dist/lib/helpers/DocumentTypeApiHelper.js +121 -1
- package/dist/lib/helpers/DocumentTypeApiHelper.js.map +1 -1
- package/dist/lib/helpers/TemplateApiHelper.d.ts +1 -0
- package/dist/lib/helpers/TemplateApiHelper.js +4 -0
- package/dist/lib/helpers/TemplateApiHelper.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -3
package/README.md
CHANGED
|
@@ -1,48 +1,158 @@
|
|
|
1
|
-
# Umbraco
|
|
2
|
-
|
|
1
|
+
# Umbraco Playwright Test Helpers
|
|
2
|
+
|
|
3
|
+
Test helpers for writing Playwright end-to-end tests for Umbraco CMS.
|
|
4
|
+
|
|
5
|
+
**Repository:** https://github.com/umbraco/umbraco-playwright-testhelpers
|
|
3
6
|
|
|
4
7
|
## Prerequisites
|
|
5
|
-
This project was made with Node V16, so the minimum requirement is node `16.17.1`
|
|
6
|
-
Having playwright installed, you can install playwright by running `npx playwright install`
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
- **Node.js:** Minimum version `16.17.1`
|
|
10
|
+
- **Playwright:** Install via `npx playwright install`
|
|
10
11
|
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @umbraco/playwright-testhelpers
|
|
11
16
|
```
|
|
12
|
-
import { ConstantHelper } from "@umbraco/playwright-testhelpers";
|
|
13
|
-
```
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
### Basic Test Setup
|
|
21
|
+
|
|
22
|
+
Import the `test` fixture from the package to get access to `umbracoApi` and `umbracoUi` helpers:
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { test } from "@umbraco/playwright-testhelpers";
|
|
26
|
+
|
|
27
|
+
test('my test', async ({ umbracoApi, umbracoUi }) => {
|
|
28
|
+
// Your test code here
|
|
29
|
+
});
|
|
16
30
|
```
|
|
17
|
-
|
|
31
|
+
|
|
32
|
+
### API Helpers
|
|
33
|
+
|
|
34
|
+
Use API helpers for test setup, teardown, and backend verification:
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { test } from "@umbraco/playwright-testhelpers";
|
|
38
|
+
|
|
39
|
+
test('create document type via API', async ({ umbracoApi }) => {
|
|
40
|
+
const name = 'TestDocType';
|
|
41
|
+
|
|
42
|
+
// Cleanup before test
|
|
43
|
+
await umbracoApi.documentType.ensureNameNotExists(name);
|
|
44
|
+
|
|
45
|
+
// Create via API
|
|
46
|
+
await umbracoApi.documentType.createDefaultDocumentType(name);
|
|
47
|
+
|
|
48
|
+
// Cleanup after test
|
|
49
|
+
await umbracoApi.documentType.ensureNameNotExists(name);
|
|
50
|
+
});
|
|
18
51
|
```
|
|
19
52
|
|
|
20
|
-
|
|
53
|
+
### UI Helpers
|
|
21
54
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
55
|
+
Use UI helpers for browser-based interactions:
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import { test } from "@umbraco/playwright-testhelpers";
|
|
59
|
+
|
|
60
|
+
test('create content via UI', async ({ umbracoUi }) => {
|
|
61
|
+
await umbracoUi.goToBackOffice();
|
|
62
|
+
await umbracoUi.content.clickActionsMenuAtRoot();
|
|
63
|
+
await umbracoUi.content.clickCreateButton();
|
|
64
|
+
});
|
|
25
65
|
```
|
|
26
|
-
|
|
66
|
+
|
|
67
|
+
### Combined API and UI Testing
|
|
68
|
+
|
|
69
|
+
A common pattern is using API helpers for setup/teardown and UI helpers for the actual test:
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import { test } from "@umbraco/playwright-testhelpers";
|
|
73
|
+
|
|
74
|
+
test('edit document type', async ({ umbracoApi, umbracoUi }) => {
|
|
75
|
+
const name = 'TestDocType';
|
|
76
|
+
|
|
77
|
+
// Setup via API
|
|
78
|
+
await umbracoApi.documentType.ensureNameNotExists(name);
|
|
79
|
+
await umbracoApi.documentType.createDefaultDocumentType(name);
|
|
80
|
+
|
|
81
|
+
// Test via UI
|
|
82
|
+
await umbracoUi.goToBackOffice();
|
|
83
|
+
await umbracoUi.documentType.goToDocumentType(name);
|
|
84
|
+
|
|
85
|
+
// Cleanup via API
|
|
86
|
+
await umbracoApi.documentType.ensureNameNotExists(name);
|
|
87
|
+
});
|
|
27
88
|
```
|
|
28
|
-
|
|
89
|
+
|
|
90
|
+
### Constants and Utilities
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import { ConstantHelper, AliasHelper, NotificationConstantHelper } from "@umbraco/playwright-testhelpers";
|
|
94
|
+
|
|
95
|
+
// Access UI sections
|
|
96
|
+
const settingsSection = ConstantHelper.sections.settings;
|
|
97
|
+
|
|
98
|
+
// Convert strings to aliases
|
|
99
|
+
const alias = AliasHelper.toAlias('My Document Type'); // 'myDocumentType'
|
|
100
|
+
|
|
101
|
+
// Access notification messages
|
|
102
|
+
const successMsg = NotificationConstantHelper.success.created;
|
|
29
103
|
```
|
|
104
|
+
|
|
105
|
+
## Available Helpers
|
|
106
|
+
|
|
107
|
+
### API Helpers (`umbracoApi.*`)
|
|
108
|
+
|
|
109
|
+
`dataType`, `dictionary`, `document`, `documentBlueprint`, `documentType`, `healthCheck`, `indexer`, `language`, `login`, `logViewer`, `media`, `mediaType`, `member`, `memberGroup`, `memberType`, `modelsBuilder`, `objectTypes`, `package`, `partialView`, `publishedCache`, `redirectManagement`, `relationType`, `script`, `smtp`, `stylesheet`, `telemetry`, `template`, `temporaryFile`, `user`, `userGroup`, `webhook`
|
|
110
|
+
|
|
111
|
+
### UI Helpers (`umbracoUi.*`)
|
|
112
|
+
|
|
113
|
+
`content`, `contentRender`, `currentUserProfile`, `dataType`, `dictionary`, `documentBlueprint`, `documentType`, `examineManagement`, `externalLogin`, `form`, `healthCheck`, `install`, `language`, `login`, `logViewer`, `media`, `mediaType`, `member`, `memberGroup`, `memberType`, `modelsBuilder`, `package`, `partialView`, `profiling`, `publishedStatus`, `redirectManagement`, `relationType`, `script`, `stylesheet`, `telemetryData`, `template`, `user`, `userGroup`, `webhook`, `welcomeDashboard`
|
|
114
|
+
|
|
115
|
+
## Configuration
|
|
116
|
+
|
|
117
|
+
### Environment Variables
|
|
118
|
+
|
|
119
|
+
| Variable | Description | Default |
|
|
120
|
+
|----------|-------------|---------|
|
|
121
|
+
| `URL` | Umbraco base URL | `https://localhost:44339` |
|
|
122
|
+
| `UMBRACO_USER_LOGIN` | Admin user email | `nge@umbraco.dk` |
|
|
123
|
+
| `UMBRACO_USER_PASSWORD` | Admin user password | `1234567890` |
|
|
124
|
+
| `UMBRACO_MEMBER_LOGIN` | Test member email | `member@example.com` |
|
|
125
|
+
| `UMBRACO_MEMBER_PASSWORD` | Test member password | `Umbraco9Rocks!` |
|
|
126
|
+
|
|
127
|
+
## Contributing
|
|
128
|
+
|
|
129
|
+
### Adding New Helpers
|
|
130
|
+
|
|
131
|
+
1. Create your helper file (e.g., `MacroApiHelper.ts`)
|
|
132
|
+
|
|
133
|
+
2. Import and add as a property in `ApiHelpers.ts`:
|
|
134
|
+
```typescript
|
|
135
|
+
import { MacroApiHelper } from "./MacroApiHelper";
|
|
136
|
+
|
|
30
137
|
export class ApiHelpers {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
138
|
+
macro: MacroApiHelper;
|
|
139
|
+
|
|
140
|
+
constructor(page: Page) {
|
|
141
|
+
this.macro = new MacroApiHelper(this);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
34
144
|
```
|
|
35
145
|
|
|
36
|
-
|
|
146
|
+
3. For UI helpers, extend `UiBaseLocators` and add to `UiHelpers.ts`
|
|
37
147
|
|
|
148
|
+
### Testing Changes Locally
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
npm run build
|
|
152
|
+
npm pack
|
|
153
|
+
npm i /path/to/umbraco-playwright-testhelpers-x.x.x.tgz
|
|
38
154
|
```
|
|
39
|
-
constructor(page: Page) {
|
|
40
|
-
this.macros = new MacroApiHelper(this);
|
|
41
|
-
...
|
|
42
|
-
}
|
|
43
|
-
```
|
|
44
155
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
If you have new changes, you can follow the same steps as before.
|
|
156
|
+
## License
|
|
157
|
+
|
|
158
|
+
MIT
|
|
@@ -192,6 +192,7 @@ export declare class ContentUiHelper extends UiBaseLocators {
|
|
|
192
192
|
waitForModalHidden(): Promise<void>;
|
|
193
193
|
clickSaveButtonForContent(): Promise<void>;
|
|
194
194
|
enterTextstring(text: string): Promise<void>;
|
|
195
|
+
isTextstringPropertyVisible(isVisible?: boolean): Promise<void>;
|
|
195
196
|
doesContentTreeHaveName(contentName: string): Promise<void>;
|
|
196
197
|
enterRichTextArea(value: string): Promise<void>;
|
|
197
198
|
enterTextArea(value: string): Promise<void>;
|
|
@@ -273,6 +274,7 @@ export declare class ContentUiHelper extends UiBaseLocators {
|
|
|
273
274
|
isDocumentTypeNameVisible(contentName: string, isVisible?: boolean): Promise<void>;
|
|
274
275
|
doesModalHaveText(text: string): Promise<void>;
|
|
275
276
|
isTabNameVisible(tabName: string): Promise<void>;
|
|
277
|
+
clickTabWithName(tabName: string): Promise<void>;
|
|
276
278
|
doesDocumentHaveName(name: string): Promise<void>;
|
|
277
279
|
doesDocumentTableColumnNameValuesMatch(expectedValues: string[]): Promise<void>;
|
|
278
280
|
searchByKeywordInCollection(keyword: string): Promise<void>;
|
|
@@ -455,4 +457,8 @@ export declare class ContentUiHelper extends UiBaseLocators {
|
|
|
455
457
|
isAddBlockListElementWithNameVisible(blockName: string): Promise<void>;
|
|
456
458
|
enterBlockPropertyValue(propertyName: string, value: string): Promise<void>;
|
|
457
459
|
isBlockPropertyEditable(propertyName: string, isEditable?: boolean): Promise<void>;
|
|
460
|
+
isInlineBlockPropertyVisible(propertyName: string, isVisible?: boolean): Promise<void>;
|
|
461
|
+
isInlineBlockPropertyVisibleForBlockWithName(blockName: string, propertyName: string, isVisible?: boolean, index?: number): Promise<void>;
|
|
462
|
+
enterInlineBlockPropertyValue(propertyName: string, value: string, index?: number): Promise<void>;
|
|
463
|
+
doesInlineBlockPropertyHaveValue(propertyName: string, value: string, index?: number): Promise<void>;
|
|
458
464
|
}
|
|
@@ -432,6 +432,14 @@ class ContentUiHelper extends UiBaseLocators_1.UiBaseLocators {
|
|
|
432
432
|
await this.textstringTxt.clear();
|
|
433
433
|
await this.textstringTxt.fill(text);
|
|
434
434
|
}
|
|
435
|
+
async isTextstringPropertyVisible(isVisible = true) {
|
|
436
|
+
if (isVisible) {
|
|
437
|
+
await (0, test_1.expect)(this.textstringTxt).toBeVisible();
|
|
438
|
+
}
|
|
439
|
+
else {
|
|
440
|
+
await (0, test_1.expect)(this.textstringTxt).not.toBeVisible();
|
|
441
|
+
}
|
|
442
|
+
}
|
|
435
443
|
async doesContentTreeHaveName(contentName) {
|
|
436
444
|
await (0, test_1.expect)(this.contentTree).toContainText(contentName);
|
|
437
445
|
}
|
|
@@ -766,6 +774,11 @@ class ContentUiHelper extends UiBaseLocators_1.UiBaseLocators {
|
|
|
766
774
|
async isTabNameVisible(tabName) {
|
|
767
775
|
return (0, test_1.expect)(this.tabItems.filter({ hasText: tabName })).toBeVisible();
|
|
768
776
|
}
|
|
777
|
+
async clickTabWithName(tabName) {
|
|
778
|
+
const tabLocator = this.tabItems.filter({ hasText: tabName });
|
|
779
|
+
await (0, test_1.expect)(tabLocator).toBeVisible();
|
|
780
|
+
await tabLocator.click();
|
|
781
|
+
}
|
|
769
782
|
async doesDocumentHaveName(name) {
|
|
770
783
|
return (0, test_1.expect)(this.enterAName).toHaveValue(name);
|
|
771
784
|
}
|
|
@@ -1568,6 +1581,25 @@ class ContentUiHelper extends UiBaseLocators_1.UiBaseLocators {
|
|
|
1568
1581
|
await (0, test_1.expect)(propertyLocator).toBeVisible();
|
|
1569
1582
|
await (0, test_1.expect)(propertyLocator).toBeEditable({ editable: isEditable });
|
|
1570
1583
|
}
|
|
1584
|
+
async isInlineBlockPropertyVisible(propertyName, isVisible = true) {
|
|
1585
|
+
const propertyLocator = this.blockListEntry.locator(this.blockProperty).filter({ hasText: propertyName });
|
|
1586
|
+
await (0, test_1.expect)(propertyLocator).toBeVisible({ visible: isVisible });
|
|
1587
|
+
}
|
|
1588
|
+
async isInlineBlockPropertyVisibleForBlockWithName(blockName, propertyName, isVisible = true, index = 0) {
|
|
1589
|
+
const blockEntryLocator = this.blockListEntry.filter({ hasText: blockName }).nth(index);
|
|
1590
|
+
const propertyLocator = blockEntryLocator.locator(this.blockProperty).filter({ hasText: propertyName });
|
|
1591
|
+
await (0, test_1.expect)(propertyLocator).toBeVisible({ visible: isVisible });
|
|
1592
|
+
}
|
|
1593
|
+
async enterInlineBlockPropertyValue(propertyName, value, index = 0) {
|
|
1594
|
+
const propertyLocator = this.blockListEntry.nth(index).locator(this.blockProperty).filter({ hasText: propertyName });
|
|
1595
|
+
await (0, test_1.expect)(propertyLocator).toBeVisible();
|
|
1596
|
+
await propertyLocator.locator('input').clear();
|
|
1597
|
+
await propertyLocator.locator('input').fill(value);
|
|
1598
|
+
}
|
|
1599
|
+
async doesInlineBlockPropertyHaveValue(propertyName, value, index = 0) {
|
|
1600
|
+
const propertyLocator = this.blockListEntry.nth(index).locator(this.blockProperty).filter({ hasText: propertyName }).locator('input');
|
|
1601
|
+
await (0, test_1.expect)(propertyLocator).toHaveValue(value);
|
|
1602
|
+
}
|
|
1571
1603
|
}
|
|
1572
1604
|
exports.ContentUiHelper = ContentUiHelper;
|
|
1573
1605
|
//# sourceMappingURL=ContentUiHelper.js.map
|