UNPKG

@umbraco/playwright-testhelpers

Version:

Test helpers for making playwright tests for Umbraco solutions

420 lines 18.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ApiHelpers = void 0; const umbraco_config_1 = require("../../umbraco.config"); const ReportHelper_1 = require("./ReportHelper"); const TelemetryDataApiHelper_1 = require("./TelemetryDataApiHelper"); const LanguageApiHelper_1 = require("./LanguageApiHelper"); const DictionaryApiHelper_1 = require("./DictionaryApiHelper"); const RelationTypeApiHelper_1 = require("./RelationTypeApiHelper"); const UserGroupApiHelper_1 = require("./UserGroupApiHelper"); const TemplateApiHelper_1 = require("./TemplateApiHelper"); const AliasHelper_1 = require("./AliasHelper"); const DataTypeApiHelper_1 = require("./DataTypeApiHelper"); const UserApiHelper_1 = require("./UserApiHelper"); const TemporaryFileApiHelper_1 = require("./TemporaryFileApiHelper"); const PackageApiHelper_1 = require("./PackageApiHelper"); const ScriptApiHelper_1 = require("./ScriptApiHelper"); const PartialViewApiHelper_1 = require("./PartialViewApiHelper"); const StylesheetApiHelper_1 = require("./StylesheetApiHelper"); const fs = require("fs"); const LogViewerApiHelper_1 = require("./LogViewerApiHelper"); const DocumentTypeApiHelper_1 = require("./DocumentTypeApiHelper"); const DocumentApiHelper_1 = require("./DocumentApiHelper"); const MediaTypeApiHelper_1 = require("./MediaTypeApiHelper"); const MediaApiHelper_1 = require("./MediaApiHelper"); const ObjectTypesApiHelper_1 = require("./ObjectTypesApiHelper"); const ModelsBuilderApiHelper_1 = require("./ModelsBuilderApiHelper"); const HealthCheckApiHelper_1 = require("./HealthCheckApiHelper"); const IndexerApiHelper_1 = require("./IndexerApiHelper"); const PublishedCacheApiHelper_1 = require("./PublishedCacheApiHelper"); const RedirectManagementApiHelper_1 = require("./RedirectManagementApiHelper"); const MemberGroupApiHelper_1 = require("./MemberGroupApiHelper"); const MemberApiHelper_1 = require("./MemberApiHelper"); const MemberTypeApiHelper_1 = require("./MemberTypeApiHelper"); const DocumentBlueprintApiHelper_1 = require("./DocumentBlueprintApiHelper"); const LoginApiHelper_1 = require("./LoginApiHelper"); const WebhookApiHelper_1 = require("./WebhookApiHelper"); const MediaDeliveryApiHelper_1 = require("./differentAppSettingsHelpers/MediaDeliveryApiHelper"); const ContentDeliveryApiHelper_1 = require("./differentAppSettingsHelpers/ContentDeliveryApiHelper"); class ApiHelpers { baseUrl = umbraco_config_1.umbracoConfig.environment.baseUrl; page; alias; report; telemetry; language; dictionary; relationType; userGroup; template; dataType; user; temporaryFile; documentType; document; package; script; partialView; stylesheet; logViewer; mediaType; media; objectTypes; modelsBuilder; healthCheck; indexer; publishedCache; redirectManagement; memberGroup; member; memberType; documentBlueprint; login; webhook; mediaDeliveryApi; contentDeliveryApi; constructor(page) { this.page = page; this.alias = new AliasHelper_1.AliasHelper(); this.report = new ReportHelper_1.ReportHelper(this); this.telemetry = new TelemetryDataApiHelper_1.TelemetryDataApiHelper(this); this.language = new LanguageApiHelper_1.LanguageApiHelper(this); this.dictionary = new DictionaryApiHelper_1.DictionaryApiHelper(this); this.relationType = new RelationTypeApiHelper_1.RelationTypeApiHelper(this); this.userGroup = new UserGroupApiHelper_1.UserGroupApiHelper(this); this.template = new TemplateApiHelper_1.TemplateApiHelper(this); this.dataType = new DataTypeApiHelper_1.DataTypeApiHelper(this); this.user = new UserApiHelper_1.UserApiHelper(this, page); this.temporaryFile = new TemporaryFileApiHelper_1.TemporaryFileApiHelper(this); this.documentType = new DocumentTypeApiHelper_1.DocumentTypeApiHelper(this); this.document = new DocumentApiHelper_1.DocumentApiHelper(this); this.package = new PackageApiHelper_1.PackageApiHelper(this); this.script = new ScriptApiHelper_1.ScriptApiHelper(this); this.partialView = new PartialViewApiHelper_1.PartialViewApiHelper(this); this.stylesheet = new StylesheetApiHelper_1.StylesheetApiHelper(this); this.logViewer = new LogViewerApiHelper_1.LogViewerApiHelper(this); this.mediaType = new MediaTypeApiHelper_1.MediaTypeApiHelper(this); this.media = new MediaApiHelper_1.MediaApiHelper(this); this.objectTypes = new ObjectTypesApiHelper_1.ObjectTypesApiHelper(this); this.modelsBuilder = new ModelsBuilderApiHelper_1.ModelsBuilderApiHelper(this); this.healthCheck = new HealthCheckApiHelper_1.HealthCheckApiHelper(this); this.indexer = new IndexerApiHelper_1.IndexerApiHelper(this); this.publishedCache = new PublishedCacheApiHelper_1.PublishedCacheApiHelper(this); this.redirectManagement = new RedirectManagementApiHelper_1.RedirectManagementApiHelper(this); this.memberGroup = new MemberGroupApiHelper_1.MemberGroupApiHelper(this); this.member = new MemberApiHelper_1.MemberApiHelper(this); this.memberType = new MemberTypeApiHelper_1.MemberTypeApiHelper(this); this.documentBlueprint = new DocumentBlueprintApiHelper_1.DocumentBlueprintApiHelper(this); this.login = new LoginApiHelper_1.LoginApiHelper(this, this.page); this.webhook = new WebhookApiHelper_1.WebhookApiHelper(this, this.page); this.mediaDeliveryApi = new MediaDeliveryApiHelper_1.MediaDeliveryApiHelper(this); this.contentDeliveryApi = new ContentDeliveryApiHelper_1.ContentDeliveryApiHelper(this); } async getAccessToken() { const authToken = await this.getLocalStorageAuthToken(); return authToken.access_token; } async getBearerToken() { return 'Bearer ' + await this.getAccessToken(); } async getCookie() { let someStorage = await this.page.context().storageState(); let cookieString = ""; for (let cookie of someStorage.cookies) { cookieString += cookie.name + '=' + cookie.value + ';'; } return cookieString; } async getHeaders() { return { 'Authorization': await this.readLocalBearerToken(), 'Cookie': await this.readLocalCookie(), }; } async get(url, params) { const options = { headers: await this.getHeaders(), params: params, ignoreHTTPSErrors: true }; return await this.page.request.get(url, options); } async saveCodeFile(codeFile) { if (codeFile == null) { return; } return await this.post(umbraco_config_1.umbracoConfig.environment.baseUrl + '/umbraco/backoffice/UmbracoApi/CodeFile/PostSave', codeFile); } async post(url, data) { const options = { headers: await this.getHeaders(), data: data, ignoreHTTPSErrors: true }; return await this.page.request.post(url, options); } async delete(url, data) { const options = { headers: await this.getHeaders(), data: data, ignoreHTTPSErrors: true }; return await this.page.request.delete(url, options); } async put(url, data) { const options = { headers: await this.getHeaders(), data: data, ignoreHTTPSErrors: true }; return await this.page.request.put(url, options); } async postMultiPartForm(url, id, name, mimeType, filePath) { const options = { headers: await this.getHeaders(), multipart: { Id: id, File: { name: name, mimeType: mimeType, buffer: fs.readFileSync(filePath) } }, ignoreHTTPSErrors: true }; return await this.page.request.post(url, options); } async getTokenIssuedTime() { const authToken = await this.getLocalStorageAuthToken(); return Number(authToken.issued_at); } async getTokenExpireTime() { const authToken = await this.getLocalStorageAuthToken(); return Number(authToken.expires_in); } async getRefreshToken() { const authToken = await this.getLocalStorageAuthToken(); return authToken.refresh_token; } async isAccessTokenValid() { const tokenTimeIssued = await this.getTokenIssuedTime(); const tokenExpireTime = await this.getTokenExpireTime(); // Should use a global value const globalTestTimeout = 45; // We want to have the date minus the globalTimeout, the reason for this is that while a test is running, the token could expire. // The refresh token lasts for 300 seconds, while the access token lasts for 60 seconds (NOT TOTALLY SURE) this is why we add 240 seconds const tokenRefreshTime = tokenTimeIssued + tokenExpireTime - (globalTestTimeout); // We need the currentTimeInEpoch so we can check if the tokenRefreshTime is close to expiring. const currentTimeInEpoch = await this.currentDateToEpoch(); if (tokenRefreshTime <= currentTimeInEpoch) { return await this.refreshAccessToken(umbraco_config_1.umbracoConfig.user.login, umbraco_config_1.umbracoConfig.user.password); } } async currentDateToEpoch() { const currentTime = new Date(Date.now()); return await this.dateToEpoch(currentTime); } async dateToEpoch(date) { const dateToEpoch = date.getTime(); // The epoch is in milliseconds, but we want it to be in seconds(Like it is in the token). const millisecondsToSeconds = dateToEpoch / 1000; // There is no need to have anything after . return Number(millisecondsToSeconds.toString().split('.')[0]); } async refreshAccessToken(userEmail, userPassword) { const response = await this.page.request.post(this.baseUrl + '/umbraco/management/api/v1/security/back-office/token', { headers: { 'Content-Type': 'application/x-www-form-urlencoded', Cookie: await this.readLocalCookie(), Origin: this.baseUrl }, form: { grant_type: 'refresh_token', client_id: 'umbraco-back-office', redirect_uri: this.baseUrl + '/umbraco/oauth_complete', refresh_token: await this.getRefreshToken() }, ignoreHTTPSErrors: true }); if (response.status() === 200) { const jsonStorageValue = await response.json(); return await this.updateLocalStorage(jsonStorageValue); } console.log('Error refreshing access token.'); return await this.updateTokenAndCookie(userEmail, userPassword); } async updateTokenAndCookie(userEmail, userPassword) { const storageStateValues = await this.login.login(userEmail, userPassword); await this.updateCookie(storageStateValues.cookie); await this.updateLocalStorage(storageStateValues.accessToken); return { cookie: storageStateValues.cookie, accessToken: storageStateValues.accessToken.access_token, refreshToken: storageStateValues.refreshToken.refresh_token }; } async readFileContent(filePath) { try { const jsonString = fs.readFileSync(filePath, 'utf-8'); return JSON.parse(jsonString); } catch (error) { console.log('Error reading file:', error); throw error; } } async readLocalBearerToken() { const filePath = process.env.STORAGE_STAGE_PATH; if (!filePath) { return await this.getBearerToken(); } try { const data = await JSON.parse(fs.readFileSync(filePath, 'utf-8')); const localStorageItem = await this.getLocalStorageToken(data, 'umb:userAuthTokenResponse'); const parsedValue = await JSON.parse(localStorageItem.value); return `Bearer ${parsedValue.access_token}`; } catch { // If the file is not found, return the current access token from the page context return await this.getBearerToken(); } } async readLocalCookie() { const filePath = process.env.STORAGE_STAGE_PATH; if (!filePath) { return await this.getCookie(); } try { const data = await JSON.parse(fs.readFileSync(filePath, 'utf-8')); return await data.cookies.map(cookie => `${cookie.name}=${cookie.value}`).join('; ') + ';'; } catch { // If the file is not found, return the current cookie from the page context return await this.getCookie(); } } async getLocalStorageToken(localStorage, tokenName) { return await localStorage.origins?.[0]?.localStorage?.find(item => item.name === tokenName); } async getLocalStorageAuthToken() { const currentStorageState = await this.page.context().storageState(); const currentStorageToken = await this.getLocalStorageToken(currentStorageState, 'umb:userAuthTokenResponse'); return JSON.parse(currentStorageToken.value); } async updateLocalStorage(localStorageValue) { // Parse the existing token value and update its fields let currentLocalStorageValue = await this.getLocalStorageAuthToken(); const newIssuedTime = await this.currentDateToEpoch(); currentLocalStorageValue.access_token = localStorageValue.access_token; currentLocalStorageValue.refresh_token = localStorageValue.refresh_token; currentLocalStorageValue.issued_at = newIssuedTime; currentLocalStorageValue.scope = localStorageValue.scope; currentLocalStorageValue.token_type = localStorageValue.token_type; currentLocalStorageValue.expires_in = localStorageValue.expires_in.toString(); const filePath = process.env.STORAGE_STAGE_PATH; // Updates the user.json file in our CMS project if (filePath) { try { const data = await this.readFileContent(filePath); const fileLocalStorageToken = await this.getLocalStorageToken(data, 'umb:userAuthTokenResponse'); fileLocalStorageToken.value = JSON.stringify(currentLocalStorageValue); // Converts the object to JSON string const updatedJsonString = JSON.stringify(data, null, 2); // Writes the updated JSON content to the file fs.writeFileSync(filePath, updatedJsonString, 'utf-8'); } catch (error) { console.error('Error updating token:', error); } } } async updateCookie(cookieString) { const currentStorageState = await this.page.context().storageState(); let currentCookie = currentStorageState.cookies[0]; const parts = cookieString.split(';').map(part => part.trim()); // Extract the main key-value pair const [nameValue, ...attributes] = parts; const [, value] = nameValue.split('='); // Updates the cookie value currentCookie.value = value; // Process each attribute for (const attr of attributes) { const [key, val] = attr.split('='); if (key.trim().toLowerCase() === 'expires') { // Updates the expires value and converts it to Epoch currentCookie.expires = await this.dateToEpoch(new Date(val)); } } const filePath = process.env.STORAGE_STAGE_PATH; if (filePath) { try { const data = await this.readFileContent(filePath); data.cookies[0] = currentCookie; const updatedJsonString = JSON.stringify(data, null, 2); fs.writeFileSync(filePath, updatedJsonString, 'utf-8'); } catch (error) { console.error('Error updating cookie:', error); } } } async revokeAccessToken(cookie, accessToken) { return await this.page.request.post(this.baseUrl + '/umbraco/management/api/v1/security/back-office/revoke', { headers: { 'Content-Type': 'application/x-www-form-urlencoded', Cookie: cookie, Origin: this.baseUrl }, form: { token: accessToken, token_type_hint: 'access_token', client_id: 'umbraco-back-office' }, ignoreHTTPSErrors: true }); } async revokeRefreshToken(cookie, refreshToken) { return await this.page.request.post(this.baseUrl + '/umbraco/management/api/v1/security/back-office/revoke', { headers: { 'Content-Type': 'application/x-www-form-urlencoded', Cookie: cookie, Origin: this.baseUrl }, form: { token: refreshToken, token_type_hint: 'refresh_token', client_id: 'umbraco-back-office' }, ignoreHTTPSErrors: true }); } async loginToAdminUser(testUserCookie, testUserAccessToken, testUserRefreshToken) { await this.revokeAccessToken(testUserCookie, testUserAccessToken); await this.revokeRefreshToken(testUserCookie, testUserRefreshToken); await this.updateTokenAndCookie(umbraco_config_1.umbracoConfig.user.login, umbraco_config_1.umbracoConfig.user.password); } async getCurrentTimePlusMinute(minute = 1) { const now = new Date(); now.setMinutes(now.getMinutes() + minute); // Add one minute const year = now.getFullYear(); const month = String(now.getMonth() + 1).padStart(2, '0'); const day = String(now.getDate()).padStart(2, '0'); const hours = String(now.getHours()).padStart(2, '0'); const minutes = String(now.getMinutes()).padStart(2, '0'); return `${year}-${month}-${day}T${hours}:${minutes}`; } async convertDateFormat(dateString) { return new Date(dateString).toLocaleString("en-US", { year: "numeric", month: "long", day: "numeric", hour: "numeric", minute: "numeric", second: "numeric", hour12: true, }); } } exports.ApiHelpers = ApiHelpers; //# sourceMappingURL=ApiHelpers.js.map