/*
* Copyright (C) 2024 Xibo Signage Ltd
*
* Xibo - Digital Signage - https://xibosignage.com
*
* This file is part of Xibo.
*
* Xibo is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* Xibo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Xibo. If not, see .
*/
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add("login", (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This is will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
/* eslint-disable max-len */
Cypress.Commands.add('login', function(callbackRoute = '/login') {
cy.session('saveSession', () => {
cy.visit(callbackRoute);
cy.request({
method: 'POST',
url: '/login',
form: true,
body: {
username: 'xibo_admin',
password: 'password',
},
}).then((res) => {
// Get access token and save it as a environment variable
cy.getAccessToken().then(function() {
cy.getCookie('PHPSESSID').should('exist');
});
});
});
});
Cypress.Commands.add('getAccessToken', function() {
cy.request({
method: 'POST',
url: '/api/authorize/access_token',
form: true,
body: {
client_id: Cypress.env('client_id'),
client_secret: Cypress.env('client_secret'),
grant_type: 'client_credentials',
},
}).then((res) => {
Cypress.env('accessToken', res.body.access_token);
});
});
Cypress.Commands.add('tutorialClose', function() {
const csrf_token = Cypress.$('meta[name="token"]').attr('content');
// Make the ajax request to hide the user welcome tutorial
Cypress.$.ajax({
url: '/user/welcome',
type: 'PUT',
headers: {
'X-XSRF-TOKEN': csrf_token,
},
});
});
Cypress.Commands.add('formRequest', (method, url, formData) => {
return new Promise(function(resolve, reject) {
const xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.setRequestHeader('Authorization', 'Bearer ' + Cypress.env('accessToken'));
xhr.onload = function() {
if (this.status >= 200 && this.status < 300) {
resolve(xhr.response);
} else {
reject({
status: this.status,
statusText: xhr.statusText,
});
}
};
xhr.onerror = function() {
reject({
status: this.status,
statusText: xhr.statusText,
});
};
xhr.send(formData);
});
});
Cypress.Commands.add('addMediaToLibrary', (fileName) => {
// Declarations
const method = 'POST';
const url = '/api/library';
const fileType = '*/*';
// Get file from fixtures as binary
return cy.fixture(fileName, 'binary').then((zipBin) => {
// File in binary format gets converted to blob so it can be sent as Form data
const fileBlob = Cypress.Blob.binaryStringToBlob(zipBin, fileType);
// Build up the form
const formData = new FormData();
formData.set('files[]', fileBlob, fileName); // adding a file to the form
// Perform the request
return cy.formRequest(method, url, formData).then((response) => {
const { files } = JSON.parse(response);
// Return id
return files[0].name;
});
});
});
// Campaign
Cypress.Commands.add('createCampaign', function(name) {
cy.request({
method: 'POST',
url: '/api/campaign',
form: true,
headers: {
Authorization: 'Bearer ' + Cypress.env('accessToken'),
},
body: {
name: name,
},
}).then((res) => {
return res.body.campaignId;
});
});
// Dataset
Cypress.Commands.add('createDataset', function(name) {
cy.request({
method: 'POST',
url: '/api/dataset',
form: true,
headers: {
Authorization: 'Bearer ' + Cypress.env('accessToken'),
},
body: {
dataSet: name,
},
}).then((res) => {
return res.body.dataSetId;
});
});
// Delete Dataset
Cypress.Commands.add('deleteDataset', function(id) {
cy.request({
method: 'DELETE',
url: '/api/dataset/' + id,
form: true,
headers: {
Authorization: 'Bearer ' + Cypress.env('accessToken'),
},
body: {},
}).then((res) => {
return res;
});
});
// Sync Group
Cypress.Commands.add('createSyncGroup', function(name) {
cy.request({
method: 'POST',
url: '/api/syncgroup/add',
form: true,
headers: {
Authorization: 'Bearer ' + Cypress.env('accessToken'),
},
body: {
name: name,
syncPublisherPort: 9590,
},
}).then((res) => {
return res.body.datasetId;
});
});
// DayPart
Cypress.Commands.add('createDayPart', function(name) {
cy.request({
method: 'POST',
url: '/api/daypart',
form: true,
headers: {
Authorization: 'Bearer ' + Cypress.env('accessToken'),
},
body: {
name: name,
startTime: '01:00:00',
endTime: '02:00:00',
},
}).then((res) => {
return res.body.dayPartId;
});
});
// Delete DayPart
Cypress.Commands.add('deleteDayPart', function(id) {
cy.request({
method: 'DELETE',
url: '/api/daypart/' + id,
form: true,
headers: {
Authorization: 'Bearer ' + Cypress.env('accessToken'),
},
body: {},
}).then((res) => {
return res;
});
});
// Tag
Cypress.Commands.add('createTag', function(name) {
cy.request({
method: 'POST',
url: '/api/tag',
form: true,
headers: {
Authorization: 'Bearer ' + Cypress.env('accessToken'),
},
body: {
name: name,
},
}).then((res) => {
return res.body.id;
});
});
// Application
Cypress.Commands.add('createApplication', function(name) {
cy.request({
method: 'POST',
url: '/api/application',
form: true,
headers: {
Authorization: 'Bearer ' + Cypress.env('accessToken'),
},
body: {
name: name,
},
}).then((res) => {
return res.body.key;
});
});
/**
* Open playlist editor modal and wait for toolbar user prefs to load
* @param {String} playlistName
*/
Cypress.Commands.add('openPlaylistEditorAndLoadPrefs', function(playlistId) {
cy.intercept('GET', '/user/pref?preference=toolbar').as('userPrefsLoad');
// Reload playlist table page
cy.visit('/playlist/view');
// Clear toolbar preferences
cy.clearToolbarPrefs();
cy.window().then((win) => {
win.XiboCustomFormRender(win.$('
'));
// Wait for user prefs to load
cy.wait('@userPrefsLoad');
});
});
/**
* Add media items to library
*/
Cypress.Commands.add('populateLibraryWithMedia', function() {
// Add audio media to library
cy.addMediaToLibrary('../assets/audioSample.mp3');
// Add image media to library
cy.addMediaToLibrary('../assets/imageSample.png');
});
/**
* Drag one element to another one
* @param {string} draggableSelector
* @param {string} dropableSelector
*/
Cypress.Commands.add('dragToElement', function(draggableSelector, dropableSelector) {
return cy.get(dropableSelector).then(($el) => {
const position = {
x: $el.offset().left + $el.width() / 2 + window.scrollX,
y: $el.offset().top + $el.height() / 2 + window.scrollY,
};
cy.get(draggableSelector).invoke('show');
cy.get(draggableSelector)
.trigger('mousedown', {
which: 1,
})
.trigger('mousemove', {
which: 1,
pageX: position.x,
pageY: position.y,
})
.trigger('mouseup');
});
});
/**
* Go to layout editor page and wait for toolbar user prefs to load
* @param {number} layoutId
*/
Cypress.Commands.add('goToLayoutAndLoadPrefs', function(layoutId) {
cy.intercept('GET', '/user/pref?preference=toolbar').as('userPrefsLoad');
cy.clearToolbarPrefs();
cy.visit('/layout/designer/' + layoutId);
// Wait for user prefs to load
cy.wait('@userPrefsLoad');
});
Cypress.Commands.add('removeAllSelectedOptions', (select2) => {
cy.get(select2)
.as('select2Container');
cy.get('@select2Container')
.then(($select2Container) => {
if ($select2Container.find('.select2-selection__choice').length > 0) {
cy.wrap($select2Container)
.find('.select2-selection__choice')
.each(($selectedOption) => {
cy.wrap($selectedOption)
.find('.select2-selection__choice__remove')
.click(); // Click on the remove button for each selected option
});
} else {
// No options are selected
cy.log('No options are selected');
}
});
});
// Select an item from the select2 dropdown
Cypress.Commands.add('selectFromDropdown', (selector, searchText, expected, alias, index = 0) => {
cy.get(selector).type(searchText);
if (alias) {
cy.wait(alias).its('response.statusCode').should('eq', 200);
}
cy.get('.select2-container--open .select2-dropdown .select2-results > ul')
.should('contain', expected);
cy.get('.select2-container--open .select2-dropdown .select2-results > ul > li')
.eq(index)
.click();
});
// Select an option from the select2
Cypress.Commands.add('selectOption', (content) => {
cy.get('.select2-container--open').contains(content);
cy.get('.select2-container--open .select2-results > ul > li').should('have.length', 1);
cy.get('.select2-container--open .select2-results > ul > li:first').contains(content).click();
});
// Schedule a layout
Cypress.Commands.add('scheduleCampaign', function(campaignId, displayName) {
cy.request({
method: 'POST',
url: '/api/scheduleCampaign',
form: true,
headers: {
Authorization: 'Bearer ' + Cypress.env('accessToken'),
},
body: {
campaignId: campaignId,
displayName: displayName,
},
}).then((res) => {
return res.body.eventId;
});
});
// Open Options Menu within the Layout Editor
Cypress.Commands.add('openOptionsMenu', () => {
cy.get('.navbar-submenu')
.should('be.visible')
.within(() => {
cy.get('#optionsContainerTop')
.should('be.visible')
.and('not.be.disabled')
.click({force: true})
.should('have.attr', 'aria-expanded', 'true');
});
});
// Open Row Menu of the first item on the Layouts page
Cypress.Commands.add('openRowMenu', () => {
cy.get('#layouts tbody tr').first().within(() => {
cy.get('.btn-group .btn.dropdown-toggle')
.click()
.should('have.attr', 'aria-expanded', 'true');
});
});
/**
* Update data on CKEditor instance
* @param {string} ckeditorId
* @param {string} value
*/
Cypress.Commands.add('updateCKEditor', function(ckeditorId, value) {
cy.get('textarea[name="' + ckeditorId + '"]').invoke('prop', 'id').then((id) => {
cy.window().then((win) => {
win.formHelpers.getCKEditorInstance(
id,
).setData(value);
});
});
});