@umbraco/playwright-testhelpers
Version:
Test helpers for making playwright tests for Umbraco solutions
420 lines • 18.8 kB
JavaScript
"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