@axinom/mosaic-e2e-page-model 0.2.5-rc.9 → 0.3.0-rc.1
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/package.json +5 -4
- package/src/index.ts +5 -0
- package/src/managed-services/channel-service.ts +231 -0
- package/src/managed-services/image-service/image-selection-explorer.ts +40 -0
- package/src/managed-services/image-service/image-service.ts +142 -0
- package/src/managed-services/image-service/index.ts +2 -0
- package/src/managed-services/index.ts +4 -0
- package/src/managed-services/managed-service-model.ts +31 -0
- package/src/managed-services/monetization-service/claim-set-control.ts +84 -0
- package/src/managed-services/monetization-service/index.ts +3 -0
- package/src/managed-services/monetization-service/monetization-service.ts +560 -0
- package/src/managed-services/monetization-service/payment-plan-recurrence-period-field.ts +43 -0
- package/src/managed-services/monetization-service/payment-provider-settings-field.ts +76 -0
- package/src/managed-services/video-service.ts +211 -0
- package/src/page-model.ts +86 -0
- package/src/service-model.ts +29 -0
- package/src/sign-in/index.ts +4 -0
- package/src/sign-in/sign-in-page.ts +40 -0
- package/src/sign-in/sign-in-with-ax-auth-form.ts +58 -0
- package/src/sign-in/sign-in-with-google-form.ts +55 -0
- package/src/sign-in/sign-in-with-microsoft-form.ts +66 -0
- package/src/ui-selectors/breadcrumbs.ts +48 -0
- package/src/ui-selectors/index.ts +2 -0
- package/src/ui-selectors/ui-shell-model.ts +177 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axinom/mosaic-e2e-page-model",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0-rc.1",
|
|
4
4
|
"description": "A page model for testing an Axinom Mosaic Management System with Playwright.",
|
|
5
5
|
"author": "Axinom",
|
|
6
6
|
"license": "PROPRIETARY",
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"axinom mosaic"
|
|
11
11
|
],
|
|
12
12
|
"files": [
|
|
13
|
-
"dist"
|
|
13
|
+
"dist",
|
|
14
|
+
"src"
|
|
14
15
|
],
|
|
15
16
|
"main": "dist/index.js",
|
|
16
17
|
"types": "dist/index.d.ts",
|
|
@@ -21,7 +22,7 @@
|
|
|
21
22
|
"dev": "tsc -w"
|
|
22
23
|
},
|
|
23
24
|
"dependencies": {
|
|
24
|
-
"@axinom/mosaic-e2e-ui-selectors": "^0.
|
|
25
|
+
"@axinom/mosaic-e2e-ui-selectors": "^0.3.0-rc.1"
|
|
25
26
|
},
|
|
26
27
|
"devDependencies": {
|
|
27
28
|
"@types/node": "^14.18.0",
|
|
@@ -34,5 +35,5 @@
|
|
|
34
35
|
"publishConfig": {
|
|
35
36
|
"access": "public"
|
|
36
37
|
},
|
|
37
|
-
"gitHead": "
|
|
38
|
+
"gitHead": "ead0510054dde1f3bc61b39a57e83e541d251b59"
|
|
38
39
|
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { ManagedServiceModel } from './managed-service-model';
|
|
2
|
+
|
|
3
|
+
export class ChannelService extends ManagedServiceModel {
|
|
4
|
+
/**
|
|
5
|
+
* This method creates a channel by title.
|
|
6
|
+
* The management system must be loaded & signed in before using this method.
|
|
7
|
+
*
|
|
8
|
+
* The following steps will be taken:
|
|
9
|
+
* - Navigate to the channels station
|
|
10
|
+
* - Click on [New] button
|
|
11
|
+
* - Populate channel's title and click on [Proceed] button in order to save newly created channel
|
|
12
|
+
*
|
|
13
|
+
* @param args.channelTitle The title of the channel
|
|
14
|
+
*/
|
|
15
|
+
async createChannel(args: { channelTitle: string }): Promise<void> {
|
|
16
|
+
const { uiShell, uiManagedWorkflows } = this;
|
|
17
|
+
|
|
18
|
+
// create channel
|
|
19
|
+
await uiShell.navigateToLandingPageTile('Channels');
|
|
20
|
+
await uiManagedWorkflows.list.waitForData();
|
|
21
|
+
await uiShell.waitForPageTransition(
|
|
22
|
+
uiManagedWorkflows.pageHeader.actions.getActionByLabel('NEW').click(),
|
|
23
|
+
);
|
|
24
|
+
await uiManagedWorkflows.form
|
|
25
|
+
.getFieldByLabel('Title')
|
|
26
|
+
.asSingleLineTextField()
|
|
27
|
+
.setValue(args.channelTitle);
|
|
28
|
+
await uiShell.waitForPageTransition(
|
|
29
|
+
uiManagedWorkflows.actions.getActionByLabel('Proceed').click(),
|
|
30
|
+
);
|
|
31
|
+
await uiManagedWorkflows.form.waitForData();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* This method opens channel properties page for a channel.
|
|
36
|
+
* The management system must be loaded & signed in before using this method.
|
|
37
|
+
*
|
|
38
|
+
* The following steps will be taken:
|
|
39
|
+
* - Navigate to the channels station
|
|
40
|
+
* - Filter out for the particular channel by title
|
|
41
|
+
* - Open channel properties page
|
|
42
|
+
*
|
|
43
|
+
* @param args.channelTitle The title of the channel
|
|
44
|
+
*/
|
|
45
|
+
async navigateToChannelProperties(args: {
|
|
46
|
+
channelTitle: string;
|
|
47
|
+
}): Promise<void> {
|
|
48
|
+
const { uiShell, uiManagedWorkflows } = this;
|
|
49
|
+
|
|
50
|
+
// filter out newly created channel
|
|
51
|
+
await uiShell.navigateToLandingPageTile('Channels');
|
|
52
|
+
await uiManagedWorkflows.list.waitForData();
|
|
53
|
+
await uiManagedWorkflows.filters
|
|
54
|
+
.getFilterByName('title')
|
|
55
|
+
.asFreeTextFilter()
|
|
56
|
+
.setValue(args.channelTitle);
|
|
57
|
+
await uiManagedWorkflows.list.waitForData();
|
|
58
|
+
|
|
59
|
+
// navigate to the channel properties station
|
|
60
|
+
await uiShell.waitForPageTransition(
|
|
61
|
+
uiManagedWorkflows.list.getRow(1).actionButton.click(),
|
|
62
|
+
);
|
|
63
|
+
await uiManagedWorkflows.form.waitForData();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* This method publishes a channel.
|
|
68
|
+
* The management system must be loaded & signed in before using this method.
|
|
69
|
+
*
|
|
70
|
+
* The following steps will be taken:
|
|
71
|
+
* - Navigate to the channels station
|
|
72
|
+
* - Filter out for the particular channel by title
|
|
73
|
+
* - Open channel properties page
|
|
74
|
+
* - Publish the channel
|
|
75
|
+
*
|
|
76
|
+
* @param args.channelTitle The title of the channel
|
|
77
|
+
*/
|
|
78
|
+
async publishChannel(args: { channelTitle: string }): Promise<void> {
|
|
79
|
+
const { uiShell, uiManagedWorkflows } = this;
|
|
80
|
+
|
|
81
|
+
this.navigateToChannelProperties({
|
|
82
|
+
channelTitle: args.channelTitle,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// click on [Publishing] button
|
|
86
|
+
await uiManagedWorkflows.form.waitForData();
|
|
87
|
+
await uiShell.waitForPageTransition(
|
|
88
|
+
uiManagedWorkflows.actions.getActionByLabel('Publishing').click(),
|
|
89
|
+
);
|
|
90
|
+
// publish the channel
|
|
91
|
+
await uiManagedWorkflows.actions.getActionByLabel('Publish').click(),
|
|
92
|
+
await uiShell.waitForPageTransition(
|
|
93
|
+
uiManagedWorkflows.actions.confirmButton.click(),
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* This method unpublishes a channel.
|
|
99
|
+
* The management system must be loaded & signed in before using this method.
|
|
100
|
+
*
|
|
101
|
+
* The following steps will be taken:
|
|
102
|
+
* - Navigate to the channels station
|
|
103
|
+
* - Filter out for the particular channel by title
|
|
104
|
+
* - Open channel properties page
|
|
105
|
+
* - Unpublish the channel
|
|
106
|
+
*
|
|
107
|
+
* @param args.channelTitle The title of the channel
|
|
108
|
+
*/
|
|
109
|
+
async unpublishChannel(args: { channelTitle: string }): Promise<void> {
|
|
110
|
+
const { uiShell, uiManagedWorkflows } = this;
|
|
111
|
+
|
|
112
|
+
this.navigateToChannelProperties({
|
|
113
|
+
channelTitle: args.channelTitle,
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
await uiManagedWorkflows.actions.getActionByLabel('Unpublish').click(),
|
|
117
|
+
await uiShell.waitForPageTransition(
|
|
118
|
+
uiManagedWorkflows.actions.confirmButton.click(),
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* This method deletes a channel.
|
|
124
|
+
* The management system must be loaded & signed in before using this method.
|
|
125
|
+
*
|
|
126
|
+
* The following steps will be taken:
|
|
127
|
+
* - Navigate to the channels station
|
|
128
|
+
* - Filter out for the particular channel by title
|
|
129
|
+
* - Open channel properties page
|
|
130
|
+
* - Delete the channel
|
|
131
|
+
*
|
|
132
|
+
* @param args.channelTitle The title of the channel
|
|
133
|
+
*/
|
|
134
|
+
async deleteChannel(args: { channelTitle: string }): Promise<void> {
|
|
135
|
+
const { uiShell, uiManagedWorkflows } = this;
|
|
136
|
+
|
|
137
|
+
this.navigateToChannelProperties({
|
|
138
|
+
channelTitle: args.channelTitle,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
const action = uiManagedWorkflows.actions.getActionByLabel('Delete');
|
|
142
|
+
try {
|
|
143
|
+
await action.waitFor({ state: 'visible' });
|
|
144
|
+
} catch {
|
|
145
|
+
throw new Error(`The "Delete" action is not visible.`);
|
|
146
|
+
}
|
|
147
|
+
await action.click();
|
|
148
|
+
await uiShell.waitForPageTransition(
|
|
149
|
+
uiManagedWorkflows.actions.confirmButton.click(),
|
|
150
|
+
);
|
|
151
|
+
await uiManagedWorkflows.list.waitForData();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* This method creates a playlist for a channel.
|
|
156
|
+
* The management system must be loaded & signed in before using this method.
|
|
157
|
+
*
|
|
158
|
+
* The following steps will be taken:
|
|
159
|
+
* - Navigate to the channels station
|
|
160
|
+
* - Filter out for the particular channel by title
|
|
161
|
+
* - Open channel properties page
|
|
162
|
+
* - Click on [Playlists] button
|
|
163
|
+
* - Click on [New] button on the Playlists station
|
|
164
|
+
* - Populate Scheduled Start date and proceed in order to save newly created playlist
|
|
165
|
+
*
|
|
166
|
+
* @param args.channelTitle The title of the channel
|
|
167
|
+
* @param args.scheduledStart The start date/time of the playlist
|
|
168
|
+
*/
|
|
169
|
+
async createPlaylist(args: {
|
|
170
|
+
channelTitle: string;
|
|
171
|
+
scheduledStart: string;
|
|
172
|
+
}): Promise<void> {
|
|
173
|
+
const { uiShell, uiManagedWorkflows } = this;
|
|
174
|
+
|
|
175
|
+
this.navigateToChannelProperties({
|
|
176
|
+
channelTitle: args.channelTitle,
|
|
177
|
+
});
|
|
178
|
+
await uiShell.waitForPageTransition(
|
|
179
|
+
uiManagedWorkflows.actions.getActionByLabel('Playlists').click(),
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
// create playlist
|
|
183
|
+
await uiShell.waitForPageTransition(
|
|
184
|
+
uiManagedWorkflows.pageHeader.actions.getActionByLabel('NEW').click(),
|
|
185
|
+
);
|
|
186
|
+
await uiManagedWorkflows.form
|
|
187
|
+
.getFieldByLabel('Scheduled Start')
|
|
188
|
+
.asDateTimeField()
|
|
189
|
+
.setValue(args.scheduledStart);
|
|
190
|
+
await uiShell.waitForPageTransition(
|
|
191
|
+
uiManagedWorkflows.actions.getActionByLabel('Proceed').click(),
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* This method publishes a playlist.
|
|
197
|
+
* The management system must be loaded & signed in before using this method.
|
|
198
|
+
*
|
|
199
|
+
* The following steps will be taken:
|
|
200
|
+
* - Navigate to the channels station
|
|
201
|
+
* - Filter out for the particular channel by title
|
|
202
|
+
* - Open channel properties page
|
|
203
|
+
* - Click on [Playlists] button
|
|
204
|
+
* - Click on first playlist found
|
|
205
|
+
* - Publish the playlist
|
|
206
|
+
*
|
|
207
|
+
* @param args.channelTitle The title of the channel
|
|
208
|
+
*/
|
|
209
|
+
async publishPlaylist(args: { channelTitle: string }): Promise<void> {
|
|
210
|
+
const { uiShell, uiManagedWorkflows } = this;
|
|
211
|
+
|
|
212
|
+
this.navigateToChannelProperties({
|
|
213
|
+
channelTitle: args.channelTitle,
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// publish playlist
|
|
217
|
+
await uiShell.waitForPageTransition(
|
|
218
|
+
uiManagedWorkflows.actions.getActionByLabel('Playlists').click(),
|
|
219
|
+
);
|
|
220
|
+
await uiShell.waitForPageTransition(
|
|
221
|
+
uiManagedWorkflows.list.getRow(1).actionButton.click(),
|
|
222
|
+
);
|
|
223
|
+
await uiShell.waitForPageTransition(
|
|
224
|
+
uiManagedWorkflows.actions.getActionByLabel('Publishing').click(),
|
|
225
|
+
);
|
|
226
|
+
await uiManagedWorkflows.actions.getActionByLabel('Publish').click(),
|
|
227
|
+
await uiShell.waitForPageTransition(
|
|
228
|
+
uiManagedWorkflows.actions.confirmButton.click(),
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { SelectionExplorer } from '@axinom/mosaic-e2e-ui-selectors';
|
|
2
|
+
|
|
3
|
+
/** A mod*e*l for the mod*a*l image explorer component used to select images. */
|
|
4
|
+
export class ImageSelectionExplorer extends SelectionExplorer {
|
|
5
|
+
/**
|
|
6
|
+
* Select an image by title.
|
|
7
|
+
* If the image explorer modal is not showing or the selected title does not exist then an exception will be raised.
|
|
8
|
+
*
|
|
9
|
+
* The following steps will be taken:
|
|
10
|
+
* - Verify that the page header title is 'Select Image'
|
|
11
|
+
* - Filter by title and verify that at least one result is shown
|
|
12
|
+
* - Select the first result by row action
|
|
13
|
+
* - Wait for the modal to be closed
|
|
14
|
+
*/
|
|
15
|
+
async selectImageByTitle(imageTitle: string): Promise<void> {
|
|
16
|
+
// verify the modal header
|
|
17
|
+
await this.pageHeader.title.waitFor({ state: 'visible' });
|
|
18
|
+
if ((await this.pageHeader.title.textContent()) !== 'Select Image') {
|
|
19
|
+
throw new Error('Image explorer modal must be showing.');
|
|
20
|
+
}
|
|
21
|
+
await this.waitToOpen();
|
|
22
|
+
await this.list.waitForData();
|
|
23
|
+
|
|
24
|
+
await this.filters
|
|
25
|
+
.getFilterByName('title')
|
|
26
|
+
.asFreeTextFilter()
|
|
27
|
+
.setValue(imageTitle);
|
|
28
|
+
await this.list.waitForData();
|
|
29
|
+
|
|
30
|
+
// verify that one result is showing
|
|
31
|
+
if ((await this.list.allVisibleRows.count()) === 0) {
|
|
32
|
+
throw new Error('An image with the specified title was not found.');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
await this.list.getRow(1).selectButton.click();
|
|
36
|
+
|
|
37
|
+
// wait for the modal to close
|
|
38
|
+
await this.waitToClose();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { ActionLabel } from '@axinom/mosaic-e2e-ui-selectors';
|
|
2
|
+
import { ManagedServiceModel } from '../managed-service-model';
|
|
3
|
+
import { ImageSelectionExplorer } from './image-selection-explorer';
|
|
4
|
+
|
|
5
|
+
/** A model for the managed image service. */
|
|
6
|
+
export class ImageService extends ManagedServiceModel {
|
|
7
|
+
/**
|
|
8
|
+
* This method navigates to an image details station by title.
|
|
9
|
+
* The management system must be loaded & signed in before using this method.
|
|
10
|
+
* If there is not exactly one matching image an exception will be raised.
|
|
11
|
+
*
|
|
12
|
+
* The following steps will be taken:
|
|
13
|
+
* - Navigate to the home breadcrumb then the 'Images' tile
|
|
14
|
+
* - Filter by title and click the image row action
|
|
15
|
+
* - Wait for the image details station to load
|
|
16
|
+
*/
|
|
17
|
+
async navigateToImageDetails(args: {
|
|
18
|
+
/** A unique image title. */
|
|
19
|
+
title: string;
|
|
20
|
+
}): Promise<void> {
|
|
21
|
+
const { uiShell, uiManagedWorkflows } = this;
|
|
22
|
+
await uiShell.navigateToLandingPageTile('Images');
|
|
23
|
+
await uiManagedWorkflows.list.waitForData();
|
|
24
|
+
|
|
25
|
+
// filter to the item
|
|
26
|
+
await uiManagedWorkflows.filters
|
|
27
|
+
.getFilterByName('title')
|
|
28
|
+
.asFreeTextFilter()
|
|
29
|
+
.setValue(args.title);
|
|
30
|
+
await uiManagedWorkflows.list.waitForData();
|
|
31
|
+
|
|
32
|
+
// Verify that there is exactly one matching row
|
|
33
|
+
if ((await uiManagedWorkflows.list.allVisibleRows.count()) !== 1) {
|
|
34
|
+
throw new Error(
|
|
35
|
+
`Failed to find exactly one non-archived image with title '${args.title}'.`,
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// navigate
|
|
40
|
+
await uiShell.waitForPageTransition(
|
|
41
|
+
uiManagedWorkflows.list.getRow(1).actionButton.click(),
|
|
42
|
+
);
|
|
43
|
+
await uiManagedWorkflows.form.waitForData();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* This method uploads an image file from the local file system.
|
|
48
|
+
* The management system must be loaded & signed in before using this method.
|
|
49
|
+
* A unique image title and a valid image type must be provided.
|
|
50
|
+
*
|
|
51
|
+
* The following steps will be taken:
|
|
52
|
+
* - Navigate to the home breadcrumb then the 'Images' tile
|
|
53
|
+
* - Click the 'Upload' action
|
|
54
|
+
* - Enter file and image type inputs then click 'Proceed'
|
|
55
|
+
* - Edit the image title
|
|
56
|
+
* - Click the 'refresh' breadcrumb and wait for the image details station to reload
|
|
57
|
+
*/
|
|
58
|
+
async uploadImage(properties: {
|
|
59
|
+
/** Path to a local image file. */
|
|
60
|
+
sourceFile: string;
|
|
61
|
+
/** A unique image title. */
|
|
62
|
+
title: string;
|
|
63
|
+
/** An existing image type (display value). */
|
|
64
|
+
imageType: string;
|
|
65
|
+
}): Promise<void> {
|
|
66
|
+
const { uiShell, uiManagedWorkflows } = this;
|
|
67
|
+
await uiShell.navigateToLandingPageTile('Images');
|
|
68
|
+
await uiShell.waitForPageTransition(
|
|
69
|
+
uiManagedWorkflows.pageHeader.actions.getActionByLabel('Upload').click(),
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
// Setting image upload input
|
|
73
|
+
await uiManagedWorkflows.form
|
|
74
|
+
.getFieldByName('file')
|
|
75
|
+
.asFileUploadField()
|
|
76
|
+
.setValue(properties.sourceFile);
|
|
77
|
+
|
|
78
|
+
// Set image type.
|
|
79
|
+
await uiManagedWorkflows.form
|
|
80
|
+
.getFieldByName('imageType')
|
|
81
|
+
.asSelectField()
|
|
82
|
+
.setValueByLabel(properties.imageType);
|
|
83
|
+
|
|
84
|
+
// Submitting the upload
|
|
85
|
+
await uiShell.waitForPageTransition(
|
|
86
|
+
uiManagedWorkflows.actions.getActionByLabel(ActionLabel.Proceed).click(),
|
|
87
|
+
);
|
|
88
|
+
await uiManagedWorkflows.form.waitForData();
|
|
89
|
+
|
|
90
|
+
// Set image title.
|
|
91
|
+
await uiManagedWorkflows.form
|
|
92
|
+
.getFieldByName('title')
|
|
93
|
+
.asSingleLineTextField()
|
|
94
|
+
.setValue(properties.title);
|
|
95
|
+
|
|
96
|
+
// Refresh to save
|
|
97
|
+
await uiShell.navigateToBreadcrumbRefresh();
|
|
98
|
+
await uiManagedWorkflows.form.waitForData();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* This method archives an image by title.
|
|
103
|
+
* The management system must be loaded & signed in before using this method.
|
|
104
|
+
* If a single matching, non-archived image is not found then an exception will be raised.
|
|
105
|
+
*
|
|
106
|
+
* The following steps will be taken:
|
|
107
|
+
* - Navigate to the home breadcrumb then the 'Images' tile
|
|
108
|
+
* - Filter by title and click the image row action
|
|
109
|
+
* - Click 'Archive' and confirm
|
|
110
|
+
* - Wait for the image explorer station to load
|
|
111
|
+
*/
|
|
112
|
+
async archiveImage(args: {
|
|
113
|
+
/** A unique image title. */
|
|
114
|
+
title: string;
|
|
115
|
+
}): Promise<void> {
|
|
116
|
+
const { uiShell, uiManagedWorkflows } = this;
|
|
117
|
+
await this.navigateToImageDetails(args);
|
|
118
|
+
try {
|
|
119
|
+
await uiManagedWorkflows.actions
|
|
120
|
+
.getActionByLabel('Archive')
|
|
121
|
+
.waitFor({ state: 'visible' });
|
|
122
|
+
} catch {
|
|
123
|
+
throw new Error(`The image archive button is not visible.`);
|
|
124
|
+
}
|
|
125
|
+
await uiManagedWorkflows.actions.getActionByLabel('Archive').click();
|
|
126
|
+
await uiShell.waitForPageTransition(
|
|
127
|
+
uiManagedWorkflows.actions.confirmButton.click(),
|
|
128
|
+
);
|
|
129
|
+
await uiManagedWorkflows.list.waitForData();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* A reference to the ImageSelectionExplorer component mod*e*l which can be used
|
|
134
|
+
* to select images in a mod*a*l. e.g.
|
|
135
|
+
* ```
|
|
136
|
+
* await app.ui.form.modal
|
|
137
|
+
* .as(app.imageService.ImageSelectionExplorer)
|
|
138
|
+
* .selectImage('My image title');
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
readonly ImageSelectionExplorer = ImageSelectionExplorer;
|
|
142
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { UiWorkflowsModel } from '@axinom/mosaic-e2e-ui-selectors';
|
|
2
|
+
import { Page } from 'playwright-core';
|
|
3
|
+
import { UiShellModel } from '../ui-selectors/ui-shell-model';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* An abstract model representing a Mosaic managed service.
|
|
7
|
+
*/
|
|
8
|
+
export abstract class ManagedServiceModel {
|
|
9
|
+
constructor(
|
|
10
|
+
/** The playwright page object. */
|
|
11
|
+
protected readonly page: Page,
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A model representing the Mosaic UI shell including methods for navigation.
|
|
15
|
+
*
|
|
16
|
+
* Use this model to interact with:
|
|
17
|
+
* - The breadcrumbs bar (on any page)
|
|
18
|
+
* - The landing page
|
|
19
|
+
* - The settings hub page
|
|
20
|
+
*/
|
|
21
|
+
protected readonly uiShell: UiShellModel,
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* A model representing Mosaic UI workflows.
|
|
25
|
+
*
|
|
26
|
+
* Use this model to interact with workflows or mod*a*ls of any managed
|
|
27
|
+
* service (Image, Video, Monetization, etc).
|
|
28
|
+
*/
|
|
29
|
+
protected readonly uiManagedWorkflows: UiWorkflowsModel,
|
|
30
|
+
) {}
|
|
31
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Accordion,
|
|
3
|
+
AccordionItem,
|
|
4
|
+
ComponentModel,
|
|
5
|
+
DynamicDataList,
|
|
6
|
+
Modal,
|
|
7
|
+
} from '@axinom/mosaic-e2e-ui-selectors';
|
|
8
|
+
import { FrameLocator, Locator, Page } from 'playwright-core';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A model for the a claim row in the claims editor station. This model should not be used directly.
|
|
12
|
+
* It is used internally by methods of the `MonetizationService` model.
|
|
13
|
+
*/
|
|
14
|
+
export class ClaimRow extends ComponentModel {
|
|
15
|
+
/** Get a locator to the appropriate input element to select this claim. */
|
|
16
|
+
async getInput(): Promise<Locator> {
|
|
17
|
+
const radioLabel = this.getLocator('//label', -1);
|
|
18
|
+
const checkBox = this.getLocator('//input', -1);
|
|
19
|
+
return (await radioLabel.isVisible()) ? radioLabel : checkBox;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** This method toggles the claim selection. */
|
|
23
|
+
async toggle(): Promise<void> {
|
|
24
|
+
const input = await this.getInput();
|
|
25
|
+
await input.check();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* A model for the a claim group in the claims editor station. This model should not be used directly.
|
|
31
|
+
* It is used internally by methods of the `MonetizationService` model.
|
|
32
|
+
*/
|
|
33
|
+
export class ClaimGroup extends AccordionItem {
|
|
34
|
+
/** A model for the dynamic data list used to for claim multiple select. */
|
|
35
|
+
readonly dataList = new DynamicDataList(this);
|
|
36
|
+
|
|
37
|
+
/** A model for the modal opened by the dynamic data list. */
|
|
38
|
+
readonly explorerModal = new Modal(this).asSelectionExplorer();
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* This method will determine whether the claim group uses modal input.
|
|
42
|
+
* If this returns true, then claims should be selected with the `dataList` and `explorerModal` properties.
|
|
43
|
+
* If it returns false then the `getClaimRowByLabel` method should be used.
|
|
44
|
+
*/
|
|
45
|
+
async isDataListEntry(): Promise<boolean> {
|
|
46
|
+
return this.dataList.getLocator().isVisible();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** This method gets a claim row by label. */
|
|
50
|
+
getClaimRowByLabel(claimLabel: string): ClaimRow {
|
|
51
|
+
return new ClaimRow(
|
|
52
|
+
this,
|
|
53
|
+
`//*[contains(@data-test-id, "claim:") and .//*[@data-test-id="claim-label" and text()="${claimLabel}"]]`,
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* A model for the claims editor station. This model should not be used directly.
|
|
60
|
+
* It is used internally by methods of the `MonetizationService` model.
|
|
61
|
+
*/
|
|
62
|
+
export class ClaimsEditor extends ComponentModel {
|
|
63
|
+
/**
|
|
64
|
+
* A model for an accordion component.
|
|
65
|
+
* @param parent The parent playwright page, frame or component model.
|
|
66
|
+
* @param xpath A relative xpath selector to this element from the parent.
|
|
67
|
+
*/
|
|
68
|
+
constructor(parent: Page | FrameLocator | ComponentModel, xpath = '//form') {
|
|
69
|
+
super(parent, xpath);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private accordion = new Accordion(this.root, this.xpath);
|
|
73
|
+
|
|
74
|
+
/** This method gets a claim row by claim value. */
|
|
75
|
+
getClaimRow(claim: string): ClaimRow {
|
|
76
|
+
return new ClaimRow(this.accordion, `//*[@data-test-id="claim:${claim}"]`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** This method gets a claim group by label. */
|
|
80
|
+
getClaimGroup(claimGroupLabel: string): ClaimGroup {
|
|
81
|
+
const accordionItem = this.accordion.getItemContainingText(claimGroupLabel);
|
|
82
|
+
return new ClaimGroup(this.root, accordionItem.xpath);
|
|
83
|
+
}
|
|
84
|
+
}
|