@umbraco/playwright-testhelpers 17.0.8 → 17.0.10

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.
@@ -6,16 +6,12 @@ export declare class LoginApiHelper {
6
6
  constructor(api: ApiHelpers, page: Page);
7
7
  login(userEmail: string, password: string): Promise<{
8
8
  cookie: string;
9
- accessToken: "" | {
10
- value: string;
11
- } | undefined;
12
- refreshToken: "" | {
13
- value: string;
14
- } | undefined;
9
+ setCookies: string;
15
10
  }>;
11
+ extractPKCECodeFromSetCookie(setCookies: string): Promise<string>;
16
12
  getCookie(userEmail: string, password: string): Promise<string>;
17
13
  createCodeChallenge(codeVerifier: string): Promise<string>;
18
- getAuthorizationCode(codeChallenge: string, cookie: string, stateValue: string): Promise<string | null>;
19
- getCookiesWithAccessTokenAndRefreshToken(cookie: string, codeVerifier: string, authorizationCode: any): Promise<string>;
14
+ getAuthorizationSetCookie(codeChallenge: string, cookie: string, stateValue: string): Promise<string>;
15
+ getCookiesWithAccessTokenAndRefreshToken(cookie: string, codeVerifier: string, PKCECookie: string): Promise<string>;
20
16
  getAccessToken(cookie: string, refreshToken: string): Promise<any>;
21
17
  }
@@ -14,12 +14,14 @@ class LoginApiHelper {
14
14
  const stateValue = 'myStateValue'; // A static state value for testing
15
15
  const cookie = await this.getCookie(userEmail, password);
16
16
  const codeChallenge = await this.createCodeChallenge(codeVerifier);
17
- const authorizationCode = await this.getAuthorizationCode(codeChallenge, cookie, stateValue);
18
- const setCookies = await this.getCookiesWithAccessTokenAndRefreshToken(cookie, codeVerifier, authorizationCode);
19
- let tokens = await this.api.updateLocalStorageTokens(setCookies);
20
- const accessToken = tokens.accessToken;
21
- const refreshToken = tokens.refreshToken;
22
- return { cookie, accessToken, refreshToken };
17
+ const authorizationSetCookie = await this.getAuthorizationSetCookie(codeChallenge, cookie, stateValue);
18
+ const PKCECookie = await this.extractPKCECodeFromSetCookie(authorizationSetCookie);
19
+ const setCookies = await this.getCookiesWithAccessTokenAndRefreshToken(cookie, codeVerifier, PKCECookie);
20
+ return { cookie, setCookies };
21
+ }
22
+ async extractPKCECodeFromSetCookie(setCookies) {
23
+ const match = setCookies.match(/.*(__Host-umbPkceCode=[A-Za-z0-9_-]+;)/s);
24
+ return match?.[1] ?? "";
23
25
  }
24
26
  async getCookie(userEmail, password) {
25
27
  const response = await this.page.request.post(this.api.baseUrl + '/umbraco/management/api/v1/security/back-office/login', {
@@ -40,7 +42,7 @@ class LoginApiHelper {
40
42
  async createCodeChallenge(codeVerifier) {
41
43
  return (0, crypto_1.createHash)('sha256').update(codeVerifier, 'utf8').digest('base64').replace(/=/g, '').trim();
42
44
  }
43
- async getAuthorizationCode(codeChallenge, cookie, stateValue) {
45
+ async getAuthorizationSetCookie(codeChallenge, cookie, stateValue) {
44
46
  const authorizationUrl = `${this.api.baseUrl}/umbraco/management/api/v1/security/back-office/authorize?client_id=umbraco-back-office&response_type=code&redirect_uri=${encodeURIComponent(this.api.baseUrl + '/umbraco/oauth_complete')}&code_challenge_method=S256&code_challenge=${codeChallenge}&state=${stateValue}&scope=offline_access&prompt=consent&access_type=offline`;
45
47
  const response = await this.page.request.get(authorizationUrl, {
46
48
  headers: {
@@ -50,26 +52,23 @@ class LoginApiHelper {
50
52
  ignoreHTTPSErrors: true,
51
53
  maxRedirects: 0
52
54
  });
53
- // Parse the authorization code from the redirect URL
54
- const locationHeader = response.headers()['location'];
55
- if (!locationHeader) {
56
- throw new Error('Authorization redirect location not found');
55
+ if (response.status() !== 200) {
56
+ console.error('Failed to retrieve cookie');
57
57
  }
58
- // Extract the authorization code from the location header
59
- return new URLSearchParams(locationHeader.split('?')[1]).get('code');
58
+ return response.headers()['set-cookie'];
60
59
  }
61
- async getCookiesWithAccessTokenAndRefreshToken(cookie, codeVerifier, authorizationCode) {
60
+ async getCookiesWithAccessTokenAndRefreshToken(cookie, codeVerifier, PKCECookie) {
62
61
  const response = await this.page.request.post(this.api.baseUrl + '/umbraco/management/api/v1/security/back-office/token', {
63
62
  headers: {
64
63
  'Content-Type': 'application/x-www-form-urlencoded',
65
- Cookie: cookie,
64
+ Cookie: PKCECookie + cookie,
66
65
  Origin: this.api.baseUrl
67
66
  },
68
67
  form: {
69
68
  grant_type: 'authorization_code',
70
69
  client_id: 'umbraco-back-office',
71
70
  redirect_uri: this.api.baseUrl + '/umbraco/oauth_complete',
72
- code: authorizationCode,
71
+ code: '[redacted]',
73
72
  code_verifier: codeVerifier
74
73
  },
75
74
  ignoreHTTPSErrors: true
@@ -1 +1 @@
1
- {"version":3,"file":"LoginApiHelper.js","sourceRoot":"","sources":["../../../lib/helpers/LoginApiHelper.ts"],"names":[],"mappings":"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","sourcesContent":["import {ApiHelpers} from \"./ApiHelpers\";\nimport {Page} from \"@playwright/test\";\nimport {createHash} from \"crypto\";\n\nexport class LoginApiHelper {\n api: ApiHelpers;\n page: Page;\n\n constructor(api: ApiHelpers, page: Page) {\n this.api = api;\n this.page = page;\n }\n\n public async login(userEmail: string, password: string) {\n const codeVerifier = \"12345\"; // A static state value for testing\n const stateValue = 'myStateValue'; // A static state value for testing\n const cookie = await this.getCookie(userEmail, password);\n const codeChallenge = await this.createCodeChallenge(codeVerifier);\n const authorizationCode = await this.getAuthorizationCode(codeChallenge, cookie, stateValue);\n const setCookies = await this.getCookiesWithAccessTokenAndRefreshToken(cookie, codeVerifier, authorizationCode);\n let tokens = await this.api.updateLocalStorageTokens(setCookies);\n const accessToken = tokens.accessToken;\n const refreshToken = tokens.refreshToken;\n return {cookie, accessToken, refreshToken};\n }\n\n async getCookie(userEmail: string, password: string) {\n const response = await this.page.request.post(this.api.baseUrl + '/umbraco/management/api/v1/security/back-office/login', {\n headers: {\n 'Content-Type': 'application/json',\n Referer: this.api.baseUrl,\n Origin: this.api.baseUrl,\n },\n data: {\n username: userEmail,\n password: password\n },\n ignoreHTTPSErrors: true\n });\n\n // Ensure the cookie is properly captured\n return response.headers()['set-cookie'];\n }\n\n async createCodeChallenge(codeVerifier: string) {\n return createHash('sha256').update(codeVerifier, 'utf8').digest('base64').replace(/=/g, '').trim();\n }\n\n async getAuthorizationCode(codeChallenge: string, cookie: string, stateValue: string) {\n const authorizationUrl = `${this.api.baseUrl}/umbraco/management/api/v1/security/back-office/authorize?client_id=umbraco-back-office&response_type=code&redirect_uri=${encodeURIComponent(this.api.baseUrl + '/umbraco/oauth_complete')}&code_challenge_method=S256&code_challenge=${codeChallenge}&state=${stateValue}&scope=offline_access&prompt=consent&access_type=offline`;\n const response = await this.page.request.get(authorizationUrl, {\n headers: {\n Cookie: cookie,\n Referer: this.api.baseUrl,\n },\n ignoreHTTPSErrors: true,\n maxRedirects: 0\n });\n\n // Parse the authorization code from the redirect URL\n const locationHeader = response.headers()['location'];\n if (!locationHeader) {\n throw new Error('Authorization redirect location not found');\n }\n // Extract the authorization code from the location header\n return new URLSearchParams(locationHeader.split('?')[1]).get('code');\n }\n\n async getCookiesWithAccessTokenAndRefreshToken(cookie: string, codeVerifier: string, authorizationCode) {\n const response = await this.page.request.post(this.api.baseUrl + '/umbraco/management/api/v1/security/back-office/token', {\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Cookie: cookie,\n Origin: this.api.baseUrl\n },\n form: {\n grant_type: 'authorization_code',\n client_id: 'umbraco-back-office',\n redirect_uri: this.api.baseUrl + '/umbraco/oauth_complete',\n code: authorizationCode,\n code_verifier: codeVerifier\n },\n ignoreHTTPSErrors: true\n });\n\n if (response.status() !== 200) {\n console.error('Failed to retrieve cookie');\n }\n return response.headers()['set-cookie'];\n }\n\n async getAccessToken(cookie: string, refreshToken: string) {\n const response = await this.page.request.post(this.api.baseUrl + '/umbraco/management/api/v1/security/back-office/token', {\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Cookie: cookie,\n Origin: this.api.baseUrl\n },\n form: {\n grant_type: 'refresh_token',\n client_id: 'umbraco-back-office',\n redirect_uri: this.api.baseUrl + '/umbraco/oauth_complete',\n refresh_token: refreshToken,\n },\n ignoreHTTPSErrors: true\n });\n\n if (response.status() === 200) {\n console.log('Login successful');\n } else {\n console.error('Login failed');\n }\n return await response.json();\n }\n}\n"]}
1
+ {"version":3,"file":"LoginApiHelper.js","sourceRoot":"","sources":["../../../lib/helpers/LoginApiHelper.ts"],"names":[],"mappings":"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","sourcesContent":["import {ApiHelpers} from \"./ApiHelpers\";\nimport {Page} from \"@playwright/test\";\nimport {createHash} from \"crypto\";\n\nexport class LoginApiHelper {\n api: ApiHelpers;\n page: Page;\n\n constructor(api: ApiHelpers, page: Page) {\n this.api = api;\n this.page = page;\n }\n\n public async login(userEmail: string, password: string) {\n const codeVerifier = \"12345\"; // A static state value for testing\n const stateValue = 'myStateValue'; // A static state value for testing\n const cookie = await this.getCookie(userEmail, password);\n const codeChallenge = await this.createCodeChallenge(codeVerifier);\n const authorizationSetCookie = await this.getAuthorizationSetCookie(codeChallenge, cookie, stateValue);\n const PKCECookie = await this.extractPKCECodeFromSetCookie(authorizationSetCookie);\n const setCookies = await this.getCookiesWithAccessTokenAndRefreshToken(cookie, codeVerifier, PKCECookie);\n return {cookie, setCookies};\n }\n\n async extractPKCECodeFromSetCookie(setCookies: string) {\n const match = setCookies.match(/.*(__Host-umbPkceCode=[A-Za-z0-9_-]+;)/s);\n return match?.[1] ?? \"\";\n }\n\n async getCookie(userEmail: string, password: string) {\n const response = await this.page.request.post(this.api.baseUrl + '/umbraco/management/api/v1/security/back-office/login', {\n headers: {\n 'Content-Type': 'application/json',\n Referer: this.api.baseUrl,\n Origin: this.api.baseUrl,\n },\n data: {\n username: userEmail,\n password: password\n },\n ignoreHTTPSErrors: true\n });\n\n // Ensure the cookie is properly captured\n return response.headers()['set-cookie'];\n }\n\n async createCodeChallenge(codeVerifier: string) {\n return createHash('sha256').update(codeVerifier, 'utf8').digest('base64').replace(/=/g, '').trim();\n }\n\n async getAuthorizationSetCookie(codeChallenge: string, cookie: string, stateValue: string) {\n const authorizationUrl = `${this.api.baseUrl}/umbraco/management/api/v1/security/back-office/authorize?client_id=umbraco-back-office&response_type=code&redirect_uri=${encodeURIComponent(this.api.baseUrl + '/umbraco/oauth_complete')}&code_challenge_method=S256&code_challenge=${codeChallenge}&state=${stateValue}&scope=offline_access&prompt=consent&access_type=offline`;\n const response = await this.page.request.get(authorizationUrl, {\n headers: {\n Cookie: cookie,\n Referer: this.api.baseUrl,\n },\n ignoreHTTPSErrors: true,\n maxRedirects: 0\n });\n\n if (response.status() !== 200) {\n console.error('Failed to retrieve cookie');\n }\n return response.headers()['set-cookie'];\n }\n\n async getCookiesWithAccessTokenAndRefreshToken(cookie: string, codeVerifier: string, PKCECookie: string) {\n const response = await this.page.request.post(this.api.baseUrl + '/umbraco/management/api/v1/security/back-office/token', {\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Cookie: PKCECookie + cookie,\n Origin: this.api.baseUrl\n },\n form: {\n grant_type: 'authorization_code',\n client_id: 'umbraco-back-office',\n redirect_uri: this.api.baseUrl + '/umbraco/oauth_complete',\n code: '[redacted]',\n code_verifier: codeVerifier\n },\n ignoreHTTPSErrors: true\n });\n\n if (response.status() !== 200) {\n console.error('Failed to retrieve cookie');\n }\n return response.headers()['set-cookie'];\n }\n\n async getAccessToken(cookie: string, refreshToken: string) {\n const response = await this.page.request.post(this.api.baseUrl + '/umbraco/management/api/v1/security/back-office/token', {\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Cookie: cookie,\n Origin: this.api.baseUrl\n },\n form: {\n grant_type: 'refresh_token',\n client_id: 'umbraco-back-office',\n redirect_uri: this.api.baseUrl + '/umbraco/oauth_complete',\n refresh_token: refreshToken,\n },\n ignoreHTTPSErrors: true\n });\n\n if (response.status() === 200) {\n console.log('Login successful');\n } else {\n console.error('Login failed');\n }\n return await response.json();\n }\n}\n"]}
@@ -151,8 +151,12 @@ export declare class UiBaseLocators {
151
151
  readonly openedModal: Locator;
152
152
  readonly uiLoader: Locator;
153
153
  readonly createDocumentBlueprintModal: Locator;
154
+ readonly inputDropzone: Locator;
155
+ readonly imageCropperField: Locator;
156
+ readonly inputUploadField: Locator;
154
157
  readonly entityItem: Locator;
155
158
  readonly sectionLinks: Locator;
159
+ readonly backOfficeMain: Locator;
156
160
  constructor(page: Page);
157
161
  clickActionsMenuForNameInSectionSidebar(name: string): Promise<void>;
158
162
  clickActionsMenuForName(name: string): Promise<void>;
@@ -357,4 +361,8 @@ export declare class UiBaseLocators {
357
361
  enterMonacoEditorValue(value: string): Promise<void>;
358
362
  waitUntilUiLoaderIsNoLongerVisible(): Promise<void>;
359
363
  isWorkspaceViewTabWithAliasVisible(alias: string, isVisible?: boolean): Promise<void>;
364
+ isInputDropzoneVisible(isVisible?: boolean): Promise<void>;
365
+ isImageCropperFieldVisible(isVisible?: boolean): Promise<void>;
366
+ isInputUploadFieldVisible(isVisible?: boolean): Promise<void>;
367
+ isBackOfficeMainVisible(isVisible?: boolean): Promise<void>;
360
368
  }
@@ -155,8 +155,12 @@ class UiBaseLocators {
155
155
  openedModal;
156
156
  uiLoader;
157
157
  createDocumentBlueprintModal;
158
+ inputDropzone;
159
+ imageCropperField;
160
+ inputUploadField;
158
161
  entityItem;
159
162
  sectionLinks;
163
+ backOfficeMain;
160
164
  constructor(page) {
161
165
  this.page = page;
162
166
  this.saveBtn = page.getByLabel('Save', { exact: true });
@@ -313,7 +317,11 @@ class UiBaseLocators {
313
317
  this.monacoEditor = page.locator('.monaco-editor');
314
318
  this.openedModal = page.locator('uui-modal-container[backdrop]');
315
319
  this.uiLoader = page.locator('uui-loader');
320
+ this.inputDropzone = page.locator('umb-input-dropzone');
321
+ this.imageCropperField = page.locator('umb-image-cropper-field');
322
+ this.inputUploadField = page.locator('umb-input-upload-field').locator('#wrapperInner');
316
323
  this.entityItem = page.locator('umb-entity-item-ref');
324
+ this.backOfficeMain = page.locator('umb-backoffice-main');
317
325
  }
318
326
  async clickActionsMenuForNameInSectionSidebar(name) {
319
327
  await this.sectionSidebar.locator('[label="' + name + '"]').hover();
@@ -727,7 +735,10 @@ class UiBaseLocators {
727
735
  await this.page.waitForTimeout(400);
728
736
  await this.unnamedTabTxt.clear();
729
737
  await this.unnamedTabTxt.fill(tabName);
730
- await (0, test_1.expect)(this.page.getByTestId('tab:' + tabName)).toBeVisible();
738
+ // We use this to make sure the test id is updated
739
+ await this.page.getByRole('tab', { name: 'Design' }).click();
740
+ // We click again to make sure the tab is focused
741
+ await this.page.getByTestId('tab:' + tabName).click();
731
742
  }
732
743
  async searchForTypeToFilterValue(searchValue) {
733
744
  await (0, test_1.expect)(this.typeToFilterSearchTxt).toBeVisible();
@@ -1244,6 +1255,18 @@ class UiBaseLocators {
1244
1255
  async isWorkspaceViewTabWithAliasVisible(alias, isVisible = true) {
1245
1256
  await (0, test_1.expect)(this.page.getByTestId('workspace:view-link:' + alias)).toBeVisible({ visible: isVisible });
1246
1257
  }
1258
+ async isInputDropzoneVisible(isVisible = true) {
1259
+ await (0, test_1.expect)(this.inputDropzone).toBeVisible({ visible: isVisible });
1260
+ }
1261
+ async isImageCropperFieldVisible(isVisible = true) {
1262
+ await (0, test_1.expect)(this.imageCropperField).toBeVisible({ visible: isVisible });
1263
+ }
1264
+ async isInputUploadFieldVisible(isVisible = true) {
1265
+ await (0, test_1.expect)(this.inputUploadField).toBeVisible({ visible: isVisible });
1266
+ }
1267
+ async isBackOfficeMainVisible(isVisible = true) {
1268
+ await (0, test_1.expect)(this.backOfficeMain).toBeVisible({ visible: isVisible });
1269
+ }
1247
1270
  }
1248
1271
  exports.UiBaseLocators = UiBaseLocators;
1249
1272
  //# sourceMappingURL=UiBaseLocators.js.map