diff --git a/.github/workflows/test-suite.yaml b/.github/workflows/test-suite.yaml
index 8757fb3486..2de8fa4289 100644
--- a/.github/workflows/test-suite.yaml
+++ b/.github/workflows/test-suite.yaml
@@ -53,15 +53,12 @@ jobs:
run: |
docker exec --user www-data -t cms-web /bin/bash -c "cd /var/www/cms; php vendor/bin/phpunit --log-junit results.xml"
- name: Run Cypress
- continue-on-error: true
run: |
docker exec cms-db mysql -ucms -pjenkins cms -e "INSERT INTO oauth_clients (id, secret, name, userId, authCode, clientCredentials) VALUES ('MrGPc7e3IL1hA6w13l7Ru5giygxmNiafGNhFv89d', 'Pk6DdDgu2HzSoepcMHRabY60lDEvQ9ucTejYvc5dOgNVSNaOJirCUM83oAzlwe0KBiGR2Nhi6ltclyNC1rmcq0CiJZXzE42KfeatQ4j9npr6nMIQAzMal8O8RiYrIoono306CfyvSSJRfVfKExIjj0ZyE4TUrtPezJbKmvkVDzh8aj3kbanDKatirhwpfqfVdfgsqVNjzIM9ZgKHnbrTX7nNULL3BtxxNGgDMuCuvKiJFrLSyIIz1F4SNrHwHz', 'cypress', 1, 0, 1)"
docker exec cms-db mysql -ucms -pjenkins cms -e "INSERT INTO oauth_client_scopes (clientId, scopeId) VALUES ('MrGPc7e3IL1hA6w13l7Ru5giygxmNiafGNhFv89d', 'all') ON DUPLICATE KEY UPDATE scopeId = scopeId"
docker run --ipc=host --name cms-cypress --link=cms-web:web -v $(pwd)/cypress.config.js:/app/cypress.config.js -v $(pwd)/cypress:/app/cypress ghcr.io/xibosignage/xibo-cms:cypress bash -c "CYPRESS_baseUrl=http://web /app/node_modules/.bin/cypress run --config screenshotsFolder=/app/cypress/results,video=false --reporter junit --reporter-options 'mochaFile=/app/cypress/results/results_cypress_[hash].xml,toConsole=true'; chown -R 1001:1001 /app/cypress/results"
- name: Save Cypress test results as an artifact
- if: failure()
uses: actions/upload-artifact@v3
with:
name: cypress-test-results
- path: cypress/results
- run: exit 1
\ No newline at end of file
+ path: cypress/results
\ No newline at end of file
diff --git a/cypress/e2e/Display/datasets.cy.js b/cypress/e2e/Display/datasets.cy.js
new file mode 100644
index 0000000000..aee95f9685
--- /dev/null
+++ b/cypress/e2e/Display/datasets.cy.js
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2023 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 .
+ */
+
+/* eslint-disable max-len */
+describe('Datasets', function() {
+ let testRun = '';
+
+ beforeEach(function() {
+ cy.login();
+
+ testRun = Cypress._.random(0, 1e9);
+ });
+
+ it('should add one empty dataset', function() {
+ cy.visit('/dataset/view');
+
+ // Click on the Add Dataset button
+ cy.contains('Add DataSet').click();
+
+ cy.get('.modal input#dataSet')
+ .type('Cypress Test Dataset ' + testRun + '_1');
+
+ // Add first by clicking next
+ cy.get('.modal .save-button').click();
+
+ // Check if dataset is added in toast message
+ cy.contains('Added Cypress Test Dataset ' + testRun + '_1');
+ });
+
+ it('searches and edit existing dataset', function() {
+ // Create a new dataset and then search for it and delete it
+ cy.createDataset('Cypress Test Dataset ' + testRun).then((id) => {
+ cy.intercept({
+ url: '/dataset?*',
+ query: {dataSet: 'Cypress Test Dataset ' + testRun},
+ }).as('loadGridAfterSearch');
+
+ // Intercept the PUT request
+ cy.intercept({
+ method: 'PUT',
+ url: '/dataset/*',
+ }).as('putRequest');
+
+ cy.visit('/dataset/view');
+
+ // Filter for the created dataset
+ cy.get('#Filter input[name="dataSet"]')
+ .type('Cypress Test Dataset ' + testRun);
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#datasets tr:first-child .dropdown-toggle').click();
+ cy.get('#datasets tr:first-child .dataset_button_edit').click();
+
+ cy.get('.modal input#dataSet').clear()
+ .type('Cypress Test Dataset Edited ' + testRun);
+
+ // edit test dataset
+ cy.get('.bootbox .save-button').click();
+
+ // Wait for the intercepted PUT request and check the form data
+ cy.wait('@putRequest').then((interception) => {
+ // Get the request body (form data)
+ const response = interception.response;
+ const responseData = response.body.data;
+
+ // assertion on the "dataset" value
+ expect(responseData.dataSet).to.eq('Cypress Test Dataset Edited ' + testRun);
+ });
+
+ // Delete the dataset and assert success
+ cy.deleteDataset(id).then((res) => {
+ expect(res.status).to.equal(204);
+ });
+ });
+ });
+
+ it.only('copy an existing dataset', function() {
+ // Create a new dataset and then search for it and delete it
+ cy.createDataset('Cypress Test Dataset ' + testRun).then((res) => {
+ cy.intercept({
+ url: '/dataset?*',
+ query: {dataSet: 'Cypress Test Dataset ' + testRun},
+ }).as('loadGridAfterSearch');
+
+ // Intercept the POST request
+ cy.intercept({
+ method: 'POST',
+ url: /\/dataset\/copy\/\d+/,
+ }).as('postRequest');
+
+ cy.visit('/dataset/view');
+
+ // Filter for the created dataset
+ cy.get('#Filter input[name="dataSet"]')
+ .type('Cypress Test Dataset ' + testRun);
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#datasets tr:first-child .dropdown-toggle').click();
+ cy.get('#datasets tr:first-child .dataset_button_copy').click();
+
+ // Delete test dataset
+ cy.get('.bootbox .save-button').click();
+
+ // Wait for the intercepted POST request and check the form data
+ cy.wait('@postRequest').then((interception) => {
+ // Get the request body (form data)
+ const response = interception.response;
+ const responseData = response.body.data;
+ expect(responseData.dataSet).to.include('Cypress Test Dataset ' + testRun + ' 2');
+ });
+ });
+ });
+
+ it('searches and delete existing dataset', function() {
+ // Create a new dataset and then search for it and delete it
+ cy.createDataset('Cypress Test Dataset ' + testRun).then((res) => {
+ cy.server();
+ cy.route('/dataset?draw=2&*').as('datasetGridLoad');
+
+ cy.visit('/dataset/view');
+
+ // Filter for the created dataset
+ cy.get('#Filter input[name="dataSet"]')
+ .type('Cypress Test Dataset ' + testRun);
+
+ // Wait for the grid reload
+ cy.wait('@datasetGridLoad');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#datasets tr:first-child .dropdown-toggle').click();
+ cy.get('#datasets tr:first-child .dataset_button_delete').click();
+
+ // Delete test dataset
+ cy.get('.bootbox .save-button').click();
+
+ // Check if dataset is deleted in toast message
+ cy.get('.toast').contains('Deleted Cypress Test Dataset');
+ });
+ });
+
+ it('selects multiple datasets and delete them', function() {
+ // Create a new dataset and then search for it and delete it
+ cy.createDataset('Cypress Test Dataset ' + testRun).then((res) => {
+ cy.server();
+ cy.route('/dataset?draw=2&*').as('datasetGridLoad');
+
+ // Delete all test datasets
+ cy.visit('/dataset/view');
+
+ // Clear filter
+ cy.get('#Filter input[name="dataSet"]')
+ .clear()
+ .type('Cypress Test Dataset');
+
+ // Wait for the grid reload
+ cy.wait('@datasetGridLoad');
+
+ // Select all
+ cy.get('button[data-toggle="selectAll"]').click();
+
+ // Delete all
+ cy.get('.dataTables_info button[data-toggle="dropdown"]').click();
+ cy.get('.dataTables_info a[data-button-id="dataset_button_delete"]').click();
+
+ cy.get('input#deleteData').check();
+ cy.get('button.save-button').click();
+
+ // Modal should contain one successful delete at least
+ cy.get('.modal-body').contains(': Success');
+ });
+ });
+});
diff --git a/cypress/e2e/Display/dayparts.cy.js b/cypress/e2e/Display/dayparts.cy.js
new file mode 100644
index 0000000000..0666dbb57a
--- /dev/null
+++ b/cypress/e2e/Display/dayparts.cy.js
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2023 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 .
+ */
+
+/* eslint-disable max-len */
+describe('Dayparts', function() {
+ let testRun = '';
+
+ beforeEach(function() {
+ cy.login();
+
+ testRun = Cypress._.random(0, 1e9);
+ });
+
+ it('should add a daypart', function() {
+ cy.visit('/daypart/view');
+
+ // Click on the Add Daypart button
+ cy.contains('Add Daypart').click();
+
+ cy.get('.modal input#name')
+ .type('Cypress Test Daypart ' + testRun + '_1');
+ cy.get(':nth-child(3) > .col-sm-10 > .input-group > .datePickerHelper').click();
+ // cy.get('.open > .flatpickr-time > :nth-child(1) > .arrowUp').click();
+ cy.get('.open > .flatpickr-time > :nth-child(1) > .numInput').type('8');
+ cy.get(':nth-child(4) > .col-sm-10 > .input-group > .datePickerHelper').click();
+ cy.get('.open > .flatpickr-time > :nth-child(1) > .numInput').type('17');
+
+ // Add first by clicking next
+ cy.get('.modal .save-button').click();
+
+ // Check if daypart is added in toast message
+ cy.contains('Added Cypress Test Daypart ' + testRun + '_1');
+ });
+
+ // TODO filter needed
+ it.skip('searches and delete existing daypart', function() {
+ // Create a new daypart and then search for it and delete it
+ cy.createDayPart('Cypress Test Daypart ' + testRun).then((res) => {
+ cy.server();
+ cy.route('/daypart?draw=2&*').as('daypartGridLoad');
+
+ cy.visit('/daypart/view');
+
+ // Filter for the created daypart
+ cy.get('#Filter input[name="name"]')
+ .type('Cypress Test Daypart ' + testRun);
+
+ // Wait for the grid reload
+ cy.wait('@daypartGridLoad');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#dayparts tr:first-child .dropdown-toggle').click();
+ cy.get('#dayparts tr:first-child .daypart_button_delete').click();
+
+ // Delete test daypart
+ cy.get('.bootbox .save-button').click();
+
+ // Check if daypart is deleted in toast message
+ cy.get('.toast').contains('Deleted Cypress Test Daypart');
+ });
+ });
+
+ it.skip('selects multiple dayparts and delete them', function() {
+ // Create a new daypart and then search for it and delete it
+ cy.createDayPart('Cypress Test Daypart ' + testRun).then((res) => {
+ cy.intercept({
+ url: '/daypart?*',
+ query: {name: 'Cypress Test Daypart ' + testRun},
+ }).as('loadGridAfterSearch');
+
+ // Delete all test dayparts
+ cy.visit('/daypart/view');
+
+ // Clear filter
+ cy.get('#Filter input[name="name"]')
+ .clear()
+ .type('Cypress Test Daypart');
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Select all
+ cy.get('button[data-toggle="selectAll"]').click();
+
+ // Delete all
+ cy.get('.dataTables_info button[data-toggle="dropdown"]').click();
+ cy.get('.dataTables_info a[data-button-id="daypart_button_delete"]').click();
+
+ cy.get('input#deleteData').check();
+ cy.get('button.save-button').click();
+
+ // Modal should contain one successful delete at least
+ cy.get('.modal-body').contains(': Success');
+ });
+ });
+});
diff --git a/cypress/e2e/Display/displaygroups.cy.js b/cypress/e2e/Display/displaygroups.cy.js
new file mode 100644
index 0000000000..a1fd376144
--- /dev/null
+++ b/cypress/e2e/Display/displaygroups.cy.js
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2023 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 .
+ */
+
+/* eslint-disable max-len */
+describe('Display Groups', function() {
+ let testRun = '';
+
+ beforeEach(function() {
+ cy.login();
+
+ testRun = Cypress._.random(0, 1e9);
+ });
+
+ it('should add one empty and one filled display groups', function() {
+ cy.visit('/displaygroup/view');
+
+ // Click on the Add Displaygroup button
+ cy.contains('Add Display Group').click();
+
+ cy.get('.modal input#displayGroup')
+ .type('Cypress Test Displaygroup ' + testRun + '_1');
+
+ // Add first by clicking next
+ cy.get('.modal').contains('Next').click();
+
+ // Check if displaygroup is added in toast message
+ cy.contains('Added Cypress Test Displaygroup ' + testRun + '_1');
+
+ cy.get('.modal input#displayGroup')
+ .type('Cypress Test Displaygroup ' + testRun + '_2');
+
+ cy.get('.modal input#description')
+ .type('Description');
+
+ cy.get('.modal input#isDynamic').check();
+
+ cy.get('.modal input#dynamicCriteria')
+ .type('testLayoutId');
+
+ // Add first by clicking next
+ cy.get('.modal .save-button').click();
+
+ // Check if displaygroup is added in toast message
+ cy.contains('Added Cypress Test Displaygroup ' + testRun + '_2');
+ });
+
+ it('copy an existing displaygroup', function() {
+ // Create a new displaygroup and then search for it and delete it
+ cy.createDisplaygroup('Cypress Test Displaygroup ' + testRun).then((res) => {
+ cy.intercept({
+ url: '/displaygroup?*',
+ query: {displayGroup: 'Cypress Test Displaygroup ' + testRun},
+ }).as('loadGridAfterSearch');
+
+ // Intercept the POST request
+ cy.intercept({
+ method: 'POST',
+ url: /\/displaygroup\/\d+\/copy$/,
+ }).as('postRequest');
+
+ cy.visit('/displaygroup/view');
+
+ // Filter for the created displaygroup
+ cy.get('#Filter input[name="displayGroup"]')
+ .type('Cypress Test Displaygroup ' + testRun);
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#displaygroups tr:first-child .dropdown-toggle').click();
+ cy.get('#displaygroups tr:first-child .displaygroup_button_copy').click();
+
+ // Delete test displaygroup
+ cy.get('.bootbox .save-button').click();
+
+ // Wait for the intercepted POST request and check the form data
+ cy.wait('@postRequest').then((interception) => {
+ // Get the request body (form data)
+ const response = interception.response;
+ const responseData = response.body.data;
+ expect(responseData.displayGroup).to.include('Cypress Test Displaygroup ' + testRun + ' 2');
+ });
+ });
+ });
+
+ it('searches and delete existing displaygroup', function() {
+ // Create a new displaygroup and then search for it and delete it
+ cy.createDisplaygroup('Cypress Test Displaygroup ' + testRun).then((res) => {
+ cy.intercept({
+ url: '/displaygroup?*',
+ query: {displayGroup: 'Cypress Test Displaygroup ' + testRun},
+ }).as('loadGridAfterSearch');
+
+ cy.visit('/displaygroup/view');
+
+ // Filter for the created displaygroup
+ cy.get('#Filter input[name="displayGroup"]')
+ .type('Cypress Test Displaygroup ' + testRun);
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#displaygroups tr:first-child .dropdown-toggle').click();
+ cy.get('#displaygroups tr:first-child .displaygroup_button_delete').click();
+
+ // Delete test displaygroup
+ cy.get('.bootbox .save-button').click();
+
+ // Check if displaygroup is deleted in toast message
+ cy.get('.toast').contains('Deleted Cypress Test Displaygroup');
+ });
+ });
+
+ // Seeded displays: dispgrp_disp1, dispgrp_disp2
+ it('manage membership for a displaygroup', function() {
+ cy.createDisplaygroup('Cypress Test Displaygroup ' + testRun).then((res) => {
+ // assign displays to display group
+ cy.intercept({
+ url: '/displaygroup?*',
+ query: {displayGroup: 'Cypress Test Displaygroup ' + testRun},
+ }).as('loadGridAfterSearch');
+
+ // Intercept the PUT request
+ cy.intercept({
+ method: 'POST',
+ url: /\/displaygroup\/\d+\/display\/assign$/,
+ }).as('postRequest');
+
+ cy.intercept({
+ url: '/display*',
+ query: {display: 'dispgrp_disp1'},
+ }).as('loadDisplayAfterSearch');
+
+ cy.visit('/displaygroup/view');
+
+ // Filter for the created displaygroup
+ cy.get('#Filter input[name="displayGroup"]')
+ .type('Cypress Test Displaygroup ' + testRun);
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#displaygroups tr:first-child .dropdown-toggle').click();
+ cy.get('#displaygroups tr:first-child .displaygroup_button_group_members').click();
+
+ cy.get('.modal #display').type('dispgrp_disp1');
+
+ cy.wait('@loadDisplayAfterSearch');
+ cy.get('#displaysMembersTable').within(() => {
+ // count the rows within table
+ cy.get('tbody').find('tr').should('have.length', 1);
+ cy.get('tbody tr:first-child input[type="checkbox"]').check();
+ });
+
+ // Save assignments
+ cy.get('.bootbox .save-button').click();
+
+ // Wait for the intercepted POST request and check the form data
+ cy.wait('@postRequest').then((interception) => {
+ // Get the request body (form data)
+ const response = interception.response;
+ const body = response.body;
+ expect(body.success).to.eq(true);
+ });
+ });
+ });
+
+ // -------
+ // Seeded displays: dispgrp_disp_dynamic1, dispgrp_disp_dynamic2
+ it('should add a dynamic display group', function() {
+ cy.intercept({
+ url: '/display?*',
+ query: {display: 'dynamic'},
+ }).as('loadDisplayGridAfterSearch');
+
+ cy.visit('/displaygroup/view');
+
+ // Click on the Add Displaygroup button
+ cy.contains('Add Display Group').click();
+
+ cy.get('.modal input#displayGroup')
+ .type('Cypress Test Displaygroup ' + testRun);
+
+ // Add first by clicking next
+ cy.get('.modal #isDynamic').check();
+ // Type "dynamic" into the input field with the name "dynamicCriteria"
+ cy.get('.modal input[name="dynamicCriteria"]').type('dynamic');
+ cy.wait('@loadDisplayGridAfterSearch');
+
+ // Add first by clicking next
+ cy.get('.modal .save-button').click();
+
+ // Check if displaygroup is added in toast message
+ cy.contains('Added Cypress Test Displaygroup ' + testRun);
+ });
+
+ it('should edit the criteria of a dynamic display group', function() {
+ // Create a new displaygroup with dynamic criteria
+ cy.createDisplaygroup('Cypress Test Displaygroup Dynamic ' + testRun, true, 'dynamic').then((res) => {
+ cy.intercept({
+ url: '/displaygroup?*',
+ query: {displayGroup: 'Cypress Test Displaygroup Dynamic ' + testRun},
+ }).as('loadGridAfterSearch');
+
+ // Intercept the PUT request
+ cy.intercept({
+ method: 'PUT',
+ url: '/displaygroup/*',
+ }).as('putRequest');
+
+ cy.visit('/displaygroup/view');
+
+ // Filter for the created displaygroup
+ cy.get('#Filter input[name="displayGroup"]')
+ .type('Cypress Test Displaygroup Dynamic ' + testRun);
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#displaygroups tr:first-child .dropdown-toggle').click();
+ cy.get('#displaygroups tr:first-child .displaygroup_button_edit').click();
+
+ cy.get('.modal input[name="dynamicCriteria"]').clear().type('dynamic_edited');
+
+ // Delete test displaygroup
+ cy.get('.bootbox .save-button').click();
+
+ // Wait for the intercepted PUT request and check the form data
+ cy.wait('@putRequest').then((interception) => {
+ // Get the request body (form data)
+ const response = interception.response;
+ const responseData = response.body.data;
+
+ // assertion on the "display" value
+ expect(responseData.dynamicCriteria).to.eq('dynamic_edited');
+ });
+ });
+ });
+
+ // -------
+ // -- Delete Many
+ it('selects multiple display groups and delete them', function() {
+ // Create a new displaygroup and then search for it and delete it
+ cy.createDisplaygroup('Cypress Test Displaygroup ' + testRun).then((res) => {
+ cy.server();
+ cy.route('/displaygroup?draw=2&*').as('displaygroupGridLoad');
+
+ // Delete all test displaygroups
+ cy.visit('/displaygroup/view');
+
+ // Clear filter
+ cy.get('#Filter input[name="displayGroup"]')
+ .clear()
+ .type('Cypress Test Displaygroup');
+
+ // Wait for the grid reload
+ cy.wait('@displaygroupGridLoad');
+
+ // Select all
+ cy.get('button[data-toggle="selectAll"]').click();
+
+ // Delete all
+ cy.get('.dataTables_info button[data-toggle="dropdown"]').click();
+ cy.get('.dataTables_info a[data-button-id="displaygroup_button_delete"]').click();
+
+ cy.get('input#checkbox-confirmDelete').check();
+ cy.get('button.save-button').click();
+
+ // Modal should contain one successful delete at least
+ cy.get('.modal-body').contains(': Success');
+ });
+ });
+});
diff --git a/cypress/e2e/Display/syncgroups.cy.js b/cypress/e2e/Display/syncgroups.cy.js
new file mode 100644
index 0000000000..242b5a00b6
--- /dev/null
+++ b/cypress/e2e/Display/syncgroups.cy.js
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2023 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 .
+ */
+
+/* eslint-disable max-len */
+describe('Sync Groups', function() {
+ let testRun = '';
+
+ beforeEach(function() {
+ cy.login();
+
+ testRun = Cypress._.random(0, 1e9);
+ });
+
+ it('should add one empty syncgroups', function() {
+ cy.visit('/syncgroup/view');
+
+ // Click on the Add Sync Group button
+ cy.contains('Add Sync Group').click();
+
+ cy.get('.modal input#name')
+ .type('Cypress Test Sync Group ' + testRun + '_1');
+
+ // Add first by clicking next
+ cy.get('.modal .save-button').click();
+
+ // Check if syncgroup is added in toast message
+ cy.contains('Added Cypress Test Sync Group ' + testRun + '_1');
+ });
+
+
+ it('searches and delete existing syncgroup', function() {
+ // Create a new syncgroup and then search for it and delete it
+ cy.createSyncGroup('Cypress Test Sync Group ' + testRun).then((res) => {
+ cy.intercept({
+ url: '/syncgroup?*',
+ query: {name: 'Cypress Test Sync Group ' + testRun},
+ }).as('loadGridAfterSearch');
+
+ cy.visit('/syncgroup/view');
+
+ // Filter for the created syncgroup
+ cy.get('#Filter input[name="name"]')
+ .type('Cypress Test Sync Group ' + testRun);
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#syncgroups tr:first-child .dropdown-toggle').click();
+ cy.get('#syncgroups tr:first-child .syncgroup_button_group_delete').click();
+
+ // Delete test syncgroup
+ cy.get('.bootbox .save-button').click();
+
+ // Check if syncgroup is deleted in toast message
+ cy.get('.toast').contains('Deleted Cypress Test Sync Group');
+ });
+ });
+});
diff --git a/cypress/e2e/Layout/applications.cy.js b/cypress/e2e/Layout/applications.cy.js
new file mode 100644
index 0000000000..f3e46b95dd
--- /dev/null
+++ b/cypress/e2e/Layout/applications.cy.js
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2023 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 .
+ */
+
+/* eslint-disable max-len */
+describe('Applications', function() {
+ let testRun = '';
+
+ beforeEach(function() {
+ cy.login();
+
+ testRun = Cypress._.random(0, 1e9);
+ });
+
+ it('should add edit an application', function() {
+ // Intercept the PUT request
+ cy.intercept({
+ method: 'PUT',
+ url: '/application/*',
+ }).as('putRequest');
+
+ cy.visit('/application/view');
+
+ // Click on the Add Application button
+ cy.contains('Add Application').click();
+
+ cy.get('.modal input#name')
+ .type('Cypress Test Application ' + testRun);
+
+ // Add first by clicking next
+ cy.get('.modal .save-button').click();
+
+ // Check if application is added in toast message
+ cy.contains('Edit Application');
+
+ cy.get('.modal input#name').clear()
+ .type('Cypress Test Application Edited ' + testRun);
+
+ // edit test application
+ cy.get('.bootbox .save-button').click();
+
+ // Wait for the intercepted PUT request and check the form data
+ cy.wait('@putRequest').then((interception) => {
+ // Get the request body (form data)
+ const response = interception.response;
+ const responseData = response.body.data;
+
+ // assertion on the "application" value
+ expect(responseData.name).to.eq('Cypress Test Application Edited ' + testRun);
+ // Return appKey as a Cypress.Promise to ensure proper scoping
+ return Cypress.Promise.resolve(responseData.key);
+ }).then((appKey) => {
+ if (appKey) {
+ // TODO cannot be deleted via cypress
+ // Delete the application and assert success
+ // cy.deleteApplication(appKey).then((res) => {
+ // expect(res.status).to.equal(200);
+ // });
+ }
+ });
+ });
+});
diff --git a/cypress/e2e/Layout/displaysettings.cy.js b/cypress/e2e/Layout/displaysettings.cy.js
new file mode 100644
index 0000000000..b7159c8db6
--- /dev/null
+++ b/cypress/e2e/Layout/displaysettings.cy.js
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2023 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 .
+ */
+
+/* eslint-disable max-len */
+describe('Display Settings', function() {
+ let testRun = '';
+
+ beforeEach(function() {
+ cy.login();
+
+ testRun = Cypress._.random(0, 1e9);
+ });
+
+ it('should and edit a display setting', function() {
+ // Intercept the POST request
+ cy.intercept({
+ method: 'POST',
+ url: '/displayprofile',
+ }).as('postRequest');
+
+ // Intercept the PUT request
+ cy.intercept({
+ method: 'PUT',
+ url: '/displayprofile/*',
+ }).as('putRequest');
+
+ cy.visit('/displayprofile/view');
+
+ // Click on the Add Display Setting button
+ cy.contains('Add Profile').click();
+
+ cy.get('.modal input#name')
+ .type('Cypress Test Display Setting ' + testRun);
+
+ // Add first by clicking next
+ cy.get('.modal .save-button').click();
+
+ // Wait for the intercepted PUT request and check the form data
+ cy.wait('@postRequest').then((interception) => {
+ // Get the request body (form data)
+ const response = interception.response;
+ const responseData = response.body.data;
+
+ // assertion on the "tag" value
+ expect(responseData.name).to.eq('Cypress Test Display Setting ' + testRun);
+
+ cy.get('.modal input#name').clear()
+ .type('Cypress Test Display Setting Edited ' + testRun);
+
+ // Select the option with the value "10 minutes"
+ cy.get('.modal #collectInterval').select('600');
+
+ // Add first by clicking next
+ cy.get('.modal .save-button').click();
+
+ // Wait for the intercepted PUT request and check the form data
+ cy.wait('@putRequest').then((interception) => {
+ // Get the request body (form data)
+ const response = interception.response;
+ const responseData = response.body.data;
+
+ // assertion on the "tag" value
+ expect(responseData.name).to.eq('Cypress Test Display Setting Edited ' + testRun);
+ });
+ });
+ });
+
+ it('searches and edit existing display setting', function() {
+ // Create a new tag and then search for it and delete it
+ cy.createDisplayProfile('Cypress Test Display Setting ' + testRun, 'android').then((id) => {
+ cy.intercept({
+ url: '/displayprofile?*',
+ query: {displayProfile: 'Cypress Test Display Setting ' + testRun},
+ }).as('loadGridAfterSearch');
+
+ // Intercept the PUT request
+ cy.intercept({
+ method: 'PUT',
+ url: '/displayprofile/*',
+ }).as('putRequest');
+
+ cy.visit('/displayprofile/view');
+
+ // Filter for the created tag
+ cy.get('#Filter input[name="displayProfile"]')
+ .type('Cypress Test Display Setting ' + testRun);
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#displayProfiles tr:first-child .dropdown-toggle').click();
+ cy.get('#displayProfiles tr:first-child .displayprofile_button_edit').click();
+
+ cy.get('.modal input#name').clear()
+ .type('Cypress Test Display Setting Edited ' + testRun);
+
+ // edit test tag
+ cy.get('.bootbox .save-button').click();
+
+ // Wait for the intercepted PUT request and check the form data
+ cy.wait('@putRequest').then((interception) => {
+ // Get the request body (form data)
+ const response = interception.response;
+ const responseData = response.body.data;
+
+ // assertion on the "tag" value
+ expect(responseData.name).to.eq('Cypress Test Display Setting Edited ' + testRun);
+ });
+
+ // Delete the user and assert success
+ cy.deleteDisplayProfile(id).then((res) => {
+ expect(res.status).to.equal(204);
+ });
+ });
+ });
+
+ it('searches and delete existing display setting', function() {
+ // Create a new tag and then search for it and delete it
+ cy.createDisplayProfile('Cypress Test Display Setting ' + testRun, 'android').then((id) => {
+ cy.intercept({
+ url: '/displayprofile?*',
+ query: {displayProfile: 'Cypress Test Display Setting ' + testRun},
+ }).as('loadGridAfterSearch');
+
+ cy.visit('/displayprofile/view');
+
+ // Filter for the created tag
+ cy.get('#Filter input[name="displayProfile"]')
+ .type('Cypress Test Display Setting ' + testRun);
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#displayProfiles tr:first-child .dropdown-toggle').click();
+ cy.get('#displayProfiles tr:first-child .displayprofile_button_delete').click();
+
+ // Delete test tag
+ cy.get('.bootbox .save-button').click();
+
+ // Check if tag is deleted in toast message
+ cy.get('.toast').contains('Deleted Cypress Test Display Setting');
+ });
+ });
+});
diff --git a/cypress/e2e/Layout/menuboards.cy.js b/cypress/e2e/Layout/menuboards.cy.js
new file mode 100644
index 0000000000..9412c4428e
--- /dev/null
+++ b/cypress/e2e/Layout/menuboards.cy.js
@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2023 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 .
+ */
+
+/* eslint-disable max-len */
+describe('Menuboards', function() {
+ let testRun = '';
+
+ beforeEach(function() {
+ cy.login();
+
+ testRun = Cypress._.random(0, 1e9);
+ });
+
+ it('should add a menuboard', function() {
+ cy.visit('/menuboard/view');
+
+ // Click on the Add Menuboard button
+ cy.contains('Add Menu Board').click();
+
+ cy.get('.modal input#name')
+ .type('Cypress Test Menuboard ' + testRun + '_1');
+ cy.get('.modal input#code')
+ .type('MENUBOARD');
+ cy.get('.modal textarea#description')
+ .type('Menuboard Description');
+
+ // Add first by clicking next
+ cy.get('.modal .save-button').click();
+
+ // Check if menuboard is added in toast message
+ cy.contains('Added Menu Board');
+ });
+
+ it('searches and edit existing menuboard', function() {
+ // Create a new menuboard and then search for it and delete it
+ cy.createMenuboard('Cypress Test Menuboard ' + testRun).then((res) => {
+ cy.intercept({
+ url: '/menuboard?*',
+ query: {name: 'Cypress Test Menuboard ' + testRun},
+ }).as('loadGridAfterSearch');
+
+ // Intercept the PUT request
+ cy.intercept({
+ method: 'PUT',
+ url: '/menuboard/*',
+ }).as('putRequest');
+
+ cy.visit('/menuboard/view');
+
+ // Filter for the created menuboard
+ cy.get('#Filter input[name="name"]')
+ .type('Cypress Test Menuboard ' + testRun);
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#menuBoards tr:first-child .dropdown-toggle').click();
+ cy.get('#menuBoards tr:first-child .menuBoard_edit_button').click();
+
+ cy.get('.modal input#name').clear()
+ .type('Cypress Test Menuboard Edited ' + testRun);
+
+ // edit test menuboard
+ cy.get('.bootbox .save-button').click();
+
+ // Wait for the intercepted PUT request and check the form data
+ cy.wait('@putRequest').then((interception) => {
+ // Get the request body (form data)
+ const response = interception.response;
+ const responseData = response.body.data;
+
+ // assertion on the "menuboard" value
+ expect(responseData.name).to.eq('Cypress Test Menuboard Edited ' + testRun);
+ });
+ });
+ });
+
+ it('searches and delete existing menuboard', function() {
+ // Create a new menuboard and then search for it and delete it
+ cy.createMenuboard('Cypress Test Menuboard ' + testRun).then((res) => {
+ cy.intercept({
+ url: '/menuboard?*',
+ query: {name: 'Cypress Test Menuboard ' + testRun},
+ }).as('loadGridAfterSearch');
+
+ cy.visit('/menuboard/view');
+
+ // Filter for the created menuboard
+ cy.get('#Filter input[name="name"]')
+ .type('Cypress Test Menuboard ' + testRun);
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#menuBoards tr:first-child .dropdown-toggle').click();
+ cy.get('#menuBoards tr:first-child .menuBoard_delete_button').click();
+
+ // Delete test menuboard
+ cy.get('.bootbox .save-button').click();
+
+ // Check if menuboard is deleted in toast message
+ cy.get('.toast').contains('Deleted Cypress Test Menuboard');
+ });
+ });
+
+ // -------------------
+ it.skip('should add categories and products to a menuboard', function() {
+ // Create a new menuboard and then search for it and delete it
+ cy.createMenuboard('Cypress Test Menuboard ' + testRun).then((menuId) => {
+ cy.intercept({
+ url: '/menuboard?*',
+ query: {name: 'Cypress Test Menuboard ' + testRun},
+ }).as('loadGridAfterSearch');
+
+ cy.visit('/menuboard/view');
+
+ // Filter for the created menuboard
+ cy.get('#Filter input[name="name"]')
+ .type('Cypress Test Menuboard ' + testRun);
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#menuBoards tr:first-child .dropdown-toggle').click();
+ cy.get('#menuBoards tr:first-child .menuBoard_button_viewcategories').click();
+
+ // Click on the Add Category button
+ cy.contains('Add Category').click();
+
+ cy.get('.modal input#name')
+ .type('Cypress Test Category ' + testRun + '_1');
+ cy.get('.modal input#description')
+ .type('Category description');
+ cy.get('.modal input#code')
+ .type('MENUBOARDCAT');
+
+ // Add first by clicking next
+ cy.get('.modal .save-button').click();
+
+ // Check if menuboard is added in toast message
+ cy.contains('Added Menu Board Category');
+
+ // Wait for the grid reload
+ // cy.wait('@loadCategoryGridAfterSearch');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#menuBoardCategories tr:first-child .dropdown-toggle').click();
+ cy.get('#menuBoardCategories tr:first-child .menuBoardCategory_button_viewproducts').click();
+
+ // Click on the Add Product button
+ cy.contains('Add Product').click();
+
+ cy.get('.modal input#name')
+ .type('Cypress Test Product ' + testRun + '_1');
+ cy.get('.modal input#description')
+ .type('Category description');
+ cy.get('.modal input#code')
+ .type('MENUBOARDPROD');
+
+ // Add first by clicking next
+ cy.get('.modal .save-button').click();
+
+ // Check if menuboard is added in toast message
+ cy.contains('Added Menu Board Product');
+ });
+ });
+
+ // -------------------
+ // Categories
+ it('should add a category', function() {
+ // Create a new menuboard and then search for it and delete it
+ cy.createMenuboard('Cypress Test Menuboard ' + testRun).then((menuId) => {
+ // GO to products page
+ cy.visit('/menuboard/' + menuId + '/categories/view');
+ // Click on the Add Category button
+ cy.contains('Add Category').click();
+
+ cy.get('.modal input#name')
+ .type('Cypress Test Category ' + testRun + '_1');
+ cy.get('.modal input#description')
+ .type('Category description');
+ cy.get('.modal input#code')
+ .type('MENUBOARDCAT');
+
+ // Add first by clicking next
+ cy.get('.modal .save-button').click();
+
+ // Check toast message
+ cy.contains('Added Menu Board Category');
+
+ // Delete the menuboard and assert success
+ cy.deleteMenuboard(menuId).then((response) => {
+ expect(response.status).to.equal(204);
+ });
+ });
+ });
+
+ it('searches and edit existing category', function() {
+ // Create a new menuboard and then search for it and delete it
+ cy.createMenuboard('Cypress Test Menuboard ' + testRun).then((menuId) => {
+ cy.createMenuboardCat('Cypress Test Category ' + testRun, menuId).then((menuCatId) => {
+ cy.intercept({
+ url: '/menuboard/' + menuId + '/categories?*',
+ query: {name: 'Cypress Test Category ' + testRun},
+ }).as('loadGridAfterSearch');
+
+ // Intercept the PUT request
+ cy.intercept({
+ method: 'PUT',
+ url: '/menuboard/' + menuCatId + '/category',
+ }).as('putRequest');
+
+ // GO to products page
+ cy.visit('/menuboard/' + menuId + '/categories/view');
+ // Filter for the created menuboard
+ cy.get('#Filter input[name="name"]')
+ .type('Cypress Test Category ' + testRun);
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#menuBoardCategories tr:first-child .dropdown-toggle').click();
+ cy.get('#menuBoardCategories tr:first-child .menuBoardCategory_edit_button').click();
+
+ // EDIT
+ cy.get('.modal input#name').clear()
+ .type('Cypress Test Category Edited ' + testRun);
+
+ cy.get('.bootbox .save-button').click();
+
+ // Wait for the intercepted PUT request and check the form data
+ cy.wait('@putRequest').then((interception) => {
+ // Get the request body (form data)
+ const response = interception.response;
+ const responseData = response.body.data;
+
+ // assertion on the "menuboard" value
+ expect(responseData.name).to.eq('Cypress Test Category Edited ' + testRun);
+ });
+
+ // Delete the menuboard and assert success
+ cy.deleteMenuboard(menuId).then((response) => {
+ expect(response.status).to.equal(204);
+ });
+ });
+ });
+ });
+
+ it('searches and delete existing category', function() {
+ // Create a new menuboard and then search for it and delete it
+ cy.createMenuboard('Cypress Test Menuboard ' + testRun).then((menuId) => {
+ cy.createMenuboardCat('Cypress Test Category ' + testRun, menuId).then((menuCatId) => {
+ cy.intercept({
+ url: '/menuboard/' + menuId + '/categories?*',
+ query: {name: 'Cypress Test Category ' + testRun},
+ }).as('loadGridAfterSearch');
+
+ // Intercept the PUT request
+ cy.intercept({
+ method: 'PUT',
+ url: '/menuboard/' + menuCatId + '/category',
+ }).as('putRequest');
+
+ // GO to products page
+ cy.visit('/menuboard/' + menuId + '/categories/view');
+ // Filter for the created menuboard
+ cy.get('#Filter input[name="name"]')
+ .type('Cypress Test Category ' + testRun);
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#menuBoardCategories tr:first-child .dropdown-toggle').click();
+ cy.get('#menuBoardCategories tr:first-child .menuBoardCategory_delete_button').click();
+
+ // Delete test category
+ cy.get('.bootbox .save-button').click();
+
+ // Check toast message
+ cy.get('.toast').contains('Deleted Cypress Test Category');
+
+ // Delete the menuboard and assert success
+ cy.deleteMenuboard(menuId).then((response) => {
+ expect(response.status).to.equal(204);
+ });
+ });
+ });
+ });
+
+ // -------------------
+ // Products
+ it('should add a product', function() {
+ // Create a new menuboard and then search for it and delete it
+ cy.createMenuboard('Cypress Test Menuboard ' + testRun).then((menuId) => {
+ cy.createMenuboardCat('Cypress Test Category ' + testRun, menuId).then((menuCatId) => {
+ // GO to products page
+ cy.visit('/menuboard/' + menuCatId + '/products/view');
+ // Click on the Add Product button
+ cy.contains('Add Product').click();
+
+ cy.get('.modal input#name')
+ .type('Cypress Test Product ' + testRun);
+ cy.get('.modal input#description')
+ .type('Category description');
+ cy.get('.modal input#code')
+ .type('MENUBOARDPROD');
+
+ // Add first by clicking next
+ cy.get('.modal .save-button').click();
+
+ // Check if menuboard is added in toast message
+ cy.contains('Added Menu Board Product');
+ });
+ });
+ });
+
+ it('searches and edit existing product', function() {
+ // Create a new menuboard and then search for it and delete it
+ cy.createMenuboard('Cypress Test Menuboard ' + testRun).then((menuId) => {
+ cy.log(menuId);
+ cy.createMenuboardCat('Cypress Test Category ' + testRun, menuId).then((menuCatId) => {
+ cy.log(menuCatId);
+ cy.createMenuboardCatProd('Cypress Test Product ' + testRun, menuCatId).then((menuProdId) => {
+ cy.log(menuProdId);
+ cy.intercept({
+ url: '/menuboard/' + menuCatId + '/products?*',
+ query: {name: 'Cypress Test Product ' + testRun},
+ }).as('loadGridAfterSearch');
+
+ // Intercept the PUT request
+ cy.intercept({
+ method: 'PUT',
+ url: '/menuboard/' + menuProdId + '/product',
+ }).as('putRequest');
+
+ // GO to products page
+ cy.visit('/menuboard/' + menuCatId + '/products/view');
+ // Filter for the created menuboard
+ cy.get('#Filter input[name="name"]')
+ .type('Cypress Test Product ' + testRun);
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#menuBoardProducts tr:first-child .dropdown-toggle').click();
+ cy.get('#menuBoardProducts tr:first-child .menuBoardProduct_edit_button').click();
+
+ // EDIT
+ cy.get('.modal input#name').clear()
+ .type('Cypress Test Product Edited ' + testRun);
+
+ cy.get('.bootbox .save-button').click();
+
+ // Wait for the intercepted PUT request and check the form data
+ cy.wait('@putRequest').then((interception) => {
+ // Get the request body (form data)
+ const response = interception.response;
+ const responseData = response.body.data;
+
+ // assertion on the "menuboard" value
+ expect(responseData.name).to.eq('Cypress Test Product Edited ' + testRun);
+ });
+
+ // Delete the menuboard and assert success
+ cy.deleteMenuboard(menuId).then((response) => {
+ expect(response.status).to.equal(204);
+ });
+ });
+ });
+ });
+ });
+
+ it('searches and delete existing product', function() {
+ // Create a new menuboard and then search for it and delete it
+ cy.createMenuboard('Cypress Test Menuboard ' + testRun).then((menuId) => {
+ cy.createMenuboardCat('Cypress Test Category ' + testRun, menuId).then((menuCatId) => {
+ cy.createMenuboardCatProd('Cypress Test Product ' + testRun, menuCatId).then((menuProdId) => {
+ cy.intercept({
+ url: '/menuboard/' + menuCatId + '/products?*',
+ query: {name: 'Cypress Test Product ' + testRun},
+ }).as('loadGridAfterSearch');
+
+ // Intercept the PUT request
+ cy.intercept({
+ method: 'PUT',
+ url: '/menuboard/' + menuProdId + '/product',
+ }).as('putRequest');
+
+ // GO to products page
+ cy.visit('/menuboard/' + menuCatId + '/products/view');
+ // Filter for the created menuboard
+ cy.get('#Filter input[name="name"]')
+ .type('Cypress Test Product ' + testRun);
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#menuBoardProducts tr:first-child .dropdown-toggle').click();
+ cy.get('#menuBoardProducts tr:first-child .menuBoardProduct_delete_button').click();
+
+ // Delete test menuboard
+ cy.get('.bootbox .save-button').click();
+
+ // Check toast message
+ cy.get('.toast').contains('Deleted Cypress Test Product');
+
+ // Delete the menuboard and assert success
+ cy.deleteMenuboard(menuId).then((response) => {
+ expect(response.status).to.equal(204);
+ });
+ });
+ });
+ });
+ });
+});
diff --git a/cypress/e2e/Layout/tags.cy.js b/cypress/e2e/Layout/tags.cy.js
new file mode 100644
index 0000000000..44a0ba99e2
--- /dev/null
+++ b/cypress/e2e/Layout/tags.cy.js
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2023 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 .
+ */
+
+/* eslint-disable max-len */
+describe('Tags', function() {
+ let testRun = '';
+
+ beforeEach(function() {
+ cy.login();
+
+ testRun = Cypress._.random(0, 1e9);
+ });
+
+ it('should add a tag', function() {
+ cy.visit('/tag/view');
+
+ // Click on the Add Tag button
+ cy.contains('Add Tag').click();
+
+ cy.get('.modal input#name')
+ .type('Cypress Test Tag ' + testRun + '_1');
+
+ // Add first by clicking next
+ cy.get('.modal .save-button').click();
+
+ // Check if tag is added in toast message
+ cy.contains('Added Cypress Test Tag ' + testRun + '_1');
+ });
+
+ it('searches and edit existing tag', function() {
+ // Create a new tag and then search for it and delete it
+ cy.createTag('Cypress Test Tag ' + testRun).then((res) => {
+ cy.intercept({
+ url: '/tag?*',
+ query: {tag: 'Cypress Test Tag ' + testRun},
+ }).as('loadGridAfterSearch');
+
+ // Intercept the PUT request
+ cy.intercept({
+ method: 'PUT',
+ url: '/tag/*',
+ }).as('putRequest');
+
+ cy.visit('/tag/view');
+
+ // Filter for the created tag
+ cy.get('#Filter input[name="tag"]')
+ .type('Cypress Test Tag ' + testRun);
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#tags tr:first-child .dropdown-toggle').click();
+ cy.get('#tags tr:first-child .tag_button_edit').click();
+
+ cy.get('.modal input#name').clear()
+ .type('Cypress Test Tag Edited ' + testRun);
+
+ // edit test tag
+ cy.get('.bootbox .save-button').click();
+
+ // Wait for the intercepted PUT request and check the form data
+ cy.wait('@putRequest').then((interception) => {
+ // Get the request body (form data)
+ const response = interception.response;
+ const responseData = response.body.data;
+ const tag = responseData.tag;
+
+ // assertion on the "tag" value
+ expect(tag).to.eq('Cypress Test Tag Edited ' + testRun);
+ });
+ });
+ });
+
+ it('searches and delete existing tag', function() {
+ // Create a new tag and then search for it and delete it
+ cy.createTag('Cypress Test Tag ' + testRun).then((res) => {
+ cy.intercept({
+ url: '/tag?*',
+ query: {tag: 'Cypress Test Tag ' + testRun},
+ }).as('loadGridAfterSearch');
+
+ cy.visit('/tag/view');
+
+ // Filter for the created tag
+ cy.get('#Filter input[name="tag"]')
+ .type('Cypress Test Tag ' + testRun);
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#tags tr:first-child .dropdown-toggle').click();
+ cy.get('#tags tr:first-child .tag_button_delete').click();
+
+ // Delete test tag
+ cy.get('.bootbox .save-button').click();
+
+ // Check if tag is deleted in toast message
+ cy.get('.toast').contains('Deleted Cypress Test Tag');
+ });
+ });
+
+ it('selects multiple tags and delete them', function() {
+ // Create a new tag and then search for it and delete it
+ cy.createTag('Cypress Test Tag ' + testRun).then((res) => {
+ cy.intercept({
+ url: '/tag?*',
+ query: {tag: 'Cypress Test Tag'},
+ }).as('loadGridAfterSearch');
+
+ // Delete all test tags
+ cy.visit('/tag/view');
+
+ // Clear filter
+ cy.get('.clear-filter-btn').click();
+ cy.get('#Filter input[name="tag"]')
+ .type('Cypress Test Tag');
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Select all
+ cy.get('button[data-toggle="selectAll"]').click();
+
+ // Delete all
+ cy.get('.dataTables_info button[data-toggle="dropdown"]').click();
+ cy.get('.dataTables_info a[data-button-id="tag_button_delete"]').click();
+
+ cy.get('button.save-button').click();
+
+ // Modal should contain one successful delete at least
+ cy.get('.modal-body').contains(': Success');
+ });
+ });
+});
diff --git a/cypress/e2e/Layout/tasks.cy.js b/cypress/e2e/Layout/tasks.cy.js
new file mode 100644
index 0000000000..ed43039e8d
--- /dev/null
+++ b/cypress/e2e/Layout/tasks.cy.js
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2023 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 .
+ */
+
+/* eslint-disable max-len */
+describe('Tasks', function() {
+ beforeEach(function() {
+ cy.login();
+ });
+
+ it('should edit a task', function() {
+ // Intercept the PUT request
+ cy.intercept({
+ method: 'PUT',
+ url: '/task/*',
+ }).as('putRequest');
+
+ cy.visit('/task/view');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#tasks tr:first-child .dropdown-toggle').click();
+ cy.get('#tasks tr:first-child .task_button_edit').click();
+
+ // Assuming you have an input field with the id 'myInputField'
+ cy.get('.modal input#name').invoke('val').then((value) => {
+ return Cypress.Promise.resolve(value);
+ }).then((value) => {
+ if (value) {
+ cy.get('.modal input#name').clear()
+ .type(value + ' Edited');
+
+ // edit test tag
+ cy.get('.bootbox .save-button').click();
+
+ // Wait for the intercepted PUT request and check the form data
+ cy.wait('@putRequest').then((interception) => {
+ // Get the request body (form data)
+ const response = interception.response;
+ const responseData = response.body.data;
+
+ // assertion on the "task" value
+ expect(responseData.name).to.eq(value + ' Edited');
+ });
+ }
+ });
+ });
+});
diff --git a/cypress/e2e/Layout/transitions.cy.js b/cypress/e2e/Layout/transitions.cy.js
new file mode 100644
index 0000000000..ed0bc641b9
--- /dev/null
+++ b/cypress/e2e/Layout/transitions.cy.js
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2023 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 .
+ */
+
+/* eslint-disable max-len */
+describe('Transitions', function() {
+ beforeEach(function() {
+ cy.login();
+ });
+
+ it('should add edit an transition', function() {
+ // Intercept the PUT request
+ cy.intercept({
+ method: 'PUT',
+ url: '/transition/*',
+ }).as('putRequest');
+
+ cy.visit('/transition/view');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#transitions tr:first-child .dropdown-toggle').click();
+ cy.get('#transitions tr:first-child .transition_button_edit').click();
+
+ cy.get('.modal #availableAsIn').then(($checkbox) => {
+ const isChecked = $checkbox.prop('checked');
+ cy.get('#availableAsIn').click(); // Click to check/uncheck
+
+ // edit
+ cy.get('.bootbox .save-button').click();
+
+ // Wait for the intercepted PUT request and check the form data
+ cy.wait('@putRequest').then((interception) => {
+ // Get the request body (form data)
+ const response = interception.response;
+ const responseData = response.body.data;
+
+ // assertion on the "task" value
+ if (isChecked) {
+ expect(responseData.availableAsIn).to.eq(0);
+ } else {
+ expect(responseData.availableAsIn).to.eq(1);
+ }
+ });
+ });
+ });
+});
diff --git a/cypress/e2e/Layout/usergroups.cy.js b/cypress/e2e/Layout/usergroups.cy.js
new file mode 100644
index 0000000000..d20e66613b
--- /dev/null
+++ b/cypress/e2e/Layout/usergroups.cy.js
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2023 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 .
+ */
+
+/* eslint-disable max-len */
+describe('Usergroups', function() {
+ let testRun = '';
+
+ beforeEach(function() {
+ cy.login();
+
+ testRun = Cypress._.random(0, 1e9);
+ });
+
+ it('should add a usergroup', function() {
+ cy.visit('/group/view');
+
+ // Click on the Add Usergroup button
+ cy.contains('Add User Group').click();
+
+ cy.get('.modal input#group')
+ .type('Cypress Test Usergroup ' + testRun + '_1');
+
+ // Add first by clicking next
+ cy.get('.modal .save-button').click();
+
+ // Check if usergroup is added in toast message
+ cy.contains('Added Cypress Test Usergroup');
+ });
+
+ it('searches and edit existing usergroup', function() {
+ // Create a new usergroup and then search for it and delete it
+ cy.createUsergroup('Cypress Test Usergroup ' + testRun).then((groupId) => {
+ cy.intercept({
+ url: '/group?*',
+ query: {userGroup: 'Cypress Test Usergroup ' + testRun},
+ }).as('loadGridAfterSearch');
+
+ // Intercept the PUT request
+ cy.intercept({
+ method: 'PUT',
+ url: '/group/*',
+ }).as('putRequest');
+
+ cy.visit('/group/view');
+
+ // Filter for the created usergroup
+ cy.get('#Filter input[name="userGroup"]')
+ .type('Cypress Test Usergroup ' + testRun);
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#userGroups tr:first-child .dropdown-toggle').click();
+ cy.get('#userGroups tr:first-child .usergroup_button_edit').click();
+
+ cy.get('.modal input#group').clear()
+ .type('Cypress Test Usergroup Edited ' + testRun);
+
+ // edit test usergroup
+ cy.get('.bootbox .save-button').click();
+
+ // Wait for the intercepted PUT request and check the form data
+ cy.wait('@putRequest').then((interception) => {
+ // Get the request body (form data)
+ const response = interception.response;
+ const responseData = response.body.data;
+
+ // assertion on the "usergroup" value
+ expect(responseData.group).to.eq('Cypress Test Usergroup Edited ' + testRun);
+
+ // Delete the usergroup and assert success
+ cy.deleteUsergroup(groupId).then((response) => {
+ expect(response.status).to.equal(200);
+ });
+ });
+ });
+ });
+
+ it('searches and delete existing usergroup', function() {
+ // Create a new usergroup and then search for it and delete it
+ cy.createUsergroup('Cypress Test Usergroup ' + testRun).then((groupId) => {
+ cy.intercept({
+ url: '/group?*',
+ query: {userGroup: 'Cypress Test Usergroup ' + testRun},
+ }).as('loadGridAfterSearch');
+
+ cy.visit('/group/view');
+
+ // Filter for the created usergroup
+ cy.get('#Filter input[name="userGroup"]')
+ .type('Cypress Test Usergroup ' + testRun);
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#userGroups tr:first-child .dropdown-toggle').click();
+ cy.get('#userGroups tr:first-child .usergroup_button_delete').click();
+
+ // Delete test usergroup
+ cy.get('.bootbox .save-button').click();
+
+ // Check if usergroup is deleted in toast message
+ cy.get('.toast').contains('Deleted Cypress Test Usergroup');
+ });
+ });
+});
diff --git a/cypress/e2e/Layout/users.cy.js b/cypress/e2e/Layout/users.cy.js
new file mode 100644
index 0000000000..e5f422945a
--- /dev/null
+++ b/cypress/e2e/Layout/users.cy.js
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2023 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 .
+ */
+
+/* eslint-disable max-len */
+describe('Users', function() {
+ let testRun = '';
+
+ beforeEach(function() {
+ cy.login();
+
+ testRun = Cypress._.random(0, 1e9);
+ });
+
+ it('should add a user', function() {
+ cy.intercept({
+ url: '/user/form/homepages?groupId=1&userTypeId=3*',
+ query: {},
+ }).as('loadHomepageAfterSearch');
+
+ cy.visit('/user/view');
+
+ // Click on the Add User button
+ cy.contains('Add User').click();
+ cy.get('.radio input[value="manual"]').click();
+
+ cy.get('#onboarding-steper-next-button').click();
+
+ cy.get('.modal input#userName')
+ .type('CypressTestUser' + testRun);
+
+ cy.get('.modal input#password')
+ .type('cypress');
+
+ cy.get('.select2-container--bootstrap').eq(1).click();
+ cy.wait('@loadHomepageAfterSearch');
+ cy.get('.select2-results__option').contains('Icon Dashboard').click();
+
+ // Add first by clicking next
+ cy.get('.modal .save-button').click();
+
+ // Check if user is added in toast message
+ cy.contains('Added CypressTestUser');
+ });
+
+ it('searches and edit existing user', function() {
+ // Create a new user and then search for it and delete it
+ cy.createUser('CypressTestUser' + testRun, 'password', 3, 1).then((id) => {
+ cy.intercept({
+ url: '/user?*',
+ query: {userName: 'CypressTestUser' + testRun},
+ }).as('loadGridAfterSearch');
+
+ // Intercept the PUT request
+ cy.intercept({
+ method: 'PUT',
+ url: '/user/*',
+ }).as('putRequest');
+
+ cy.visit('/user/view');
+
+ // Filter for the created user
+ cy.get('#Filter input[name="userName"]')
+ .type('CypressTestUser' + testRun);
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#users tr:first-child .dropdown-toggle').click();
+ cy.get('#users tr:first-child .user_button_edit').click();
+
+ cy.get('.modal input#userName').clear()
+ .type('CypressTestUserEdited' + testRun);
+
+ // edit test user
+ cy.get('.bootbox .save-button').click();
+
+ // Wait for the intercepted PUT request and check the form data
+ cy.wait('@putRequest').then((interception) => {
+ // Get the request body (form data)
+ const response = interception.response;
+ const responseData = response.body.data;
+
+ // assertion on the "user" value
+ expect(responseData.userName).to.eq('CypressTestUserEdited' + testRun);
+ });
+
+ // Delete the user and assert success
+ cy.deleteUser(id).then((res) => {
+ expect(res.status).to.equal(200);
+ });
+ });
+ });
+
+ it('searches and delete existing user', function() {
+ // Create a new user and then search for it and delete it
+ cy.createUser('CypressTestUser' + testRun, 'password', 3, 1).then((id) => {
+ cy.intercept({
+ url: '/user?*',
+ query: {userName: 'CypressTestUser' + testRun},
+ }).as('loadGridAfterSearch');
+
+ cy.visit('/user/view');
+
+ // Filter for the created user
+ cy.get('#Filter input[name="userName"]')
+ .type('CypressTestUser' + testRun);
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#users tr:first-child .dropdown-toggle').click();
+ cy.get('#users tr:first-child .user_button_delete').click();
+
+ // Delete test User
+ cy.get('.bootbox .save-button').click();
+
+ // Check if User is deleted in toast message
+ cy.get('.toast').contains('Deleted CypressTestUser');
+ });
+ });
+});
diff --git a/cypress/e2e/Library/playlists.cy.js b/cypress/e2e/Library/playlists.cy.js
new file mode 100644
index 0000000000..4f3447f9e3
--- /dev/null
+++ b/cypress/e2e/Library/playlists.cy.js
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2023 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 .
+ */
+
+describe('Playlists Admin', function() {
+ let testRun;
+
+ beforeEach(function() {
+ cy.login();
+
+ testRun = Cypress._.random(0, 1e9);
+ });
+
+ it('should add a non-dynamic playlist', function() {
+ cy.visit('/playlist/view');
+
+ // Click on the Add Playlist button
+ cy.contains('Add Playlist').click();
+
+ cy.get('.modal input#name')
+ .type('Cypress Test Playlist ' + testRun);
+
+ cy.get('.modal .save-button').click();
+
+ // Filter for the created playlist
+ cy.get('#Filter input[name="name"]')
+ .type('Cypress Test Playlist ' + testRun);
+
+ // Should have the added playlist
+ cy.get('#playlists tbody tr').should('have.length', 1);
+ cy.get('#playlists tbody tr:nth-child(1) td:nth-child(2)').contains('Cypress Test Playlist ' + testRun);
+ });
+
+ it('should show a list of Playlists', function() {
+ // Wait for playlist grid reload
+ cy.server();
+ cy.route('/playlist?draw=1&*').as('playlistGridLoad');
+
+ cy.visit('/playlist/view').then(function() {
+ cy.wait('@playlistGridLoad');
+ cy.get('#playlists');
+ });
+ });
+
+ it('selects multiple playlists and delete them', function() {
+ // Create a new playlist and then search for it and delete it
+ cy.createNonDynamicPlaylist('Cypress Test Playlist ' + testRun).then(() => {
+ cy.server();
+ cy.route('/playlist?draw=2&*').as('playlistGridLoad');
+
+ // Delete all test playlists
+ cy.visit('/playlist/view');
+
+ // Clear filter and search for text playlists
+ cy.get('#Filter input[name="name"]')
+ .clear()
+ .type('Cypress Test Playlist');
+
+ // Wait for 2nd playlist grid reload
+ cy.wait('@playlistGridLoad');
+
+ // Select all
+ cy.get('button[data-toggle="selectAll"]').click();
+
+ // Delete all
+ cy.get('.dataTables_info button[data-toggle="dropdown"]').click();
+ cy.get('.dataTables_info a[data-button-id="playlist_button_delete"]').click();
+
+ cy.get('button.save-button').click();
+
+ // Modal should contain one successful delete at least
+ cy.get('.modal-body').contains(': Success');
+ });
+ });
+});
diff --git a/cypress/e2e/displays.cy.js b/cypress/e2e/displays.cy.js
index 569f9dee84..05a483bceb 100644
--- a/cypress/e2e/displays.cy.js
+++ b/cypress/e2e/displays.cy.js
@@ -1,7 +1,7 @@
/*
- * Copyright (c) 2022 Xibo Signage Ltd
+ * Copyright (C) 2023 Xibo Signage Ltd
*
- * Xibo - Digital Signage - http://www.xibo.org.uk
+ * Xibo - Digital Signage - https://xibosignage.com
*
* This file is part of Xibo.
*
@@ -19,26 +19,258 @@
* along with Xibo. If not, see .
*/
-describe('Displays', function () {
+/* eslint-disable max-len */
+describe('Displays', function() {
+ let testRun = '';
- beforeEach(function () {
- cy.login();
+ beforeEach(function() {
+ cy.login();
+
+ testRun = Cypress._.random(0, 1e9);
+ });
+
+ // Seeded displays: disp1, disp2, disp3, disp4, disp5
+ // Seeded display Groups: disp5_dispgrp
+ // Seeded layouts: disp4_default_layout
+ it.skip('searches and edit existing display', function() {
+ // search for a display disp1 and edit
+ cy.intercept({
+ url: '/display?*',
+ query: {display: 'disp1'},
+ }).as('loadGridAfterSearch');
+
+ // Intercept the PUT request
+ cy.intercept({
+ method: 'PUT',
+ url: '/display/*',
+ }).as('putRequest');
+
+ cy.visit('/display/view');
+
+ // Filter for the created display
+ cy.get('#Filter input[name="display"]')
+ .type('disp1');
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#displays tr:first-child .dropdown-toggle').click();
+ cy.get('#displays tr:first-child .display_button_edit').click();
+
+ cy.get('.modal input#name').clear()
+ .type('disp1 Edited');
+
+ cy.get('.modal input#license').clear()
+ .type('disp1_license');
+
+ cy.get('.modal input#description').clear()
+ .type('disp1 description');
+
+ // edit test display
+ cy.get('.bootbox .save-button').click();
+
+ // Wait for the intercepted PUT request and check the form data
+ cy.wait('@putRequest').then((interception) => {
+ // Get the request body (form data)
+ const response = interception.response;
+ const responseData = response.body.data;
+
+ // assertion on the "display" value
+ expect(responseData.display).to.eq('disp1 Edited');
+ expect(responseData.description).to.eq('disp1 description');
+ expect(responseData.license).to.eq('disp1_license');
});
+ });
+
+ // Display: disp2
+ it('searches and delete existing display', function() {
+ cy.intercept({
+ url: '/display?*',
+ query: {display: 'disp2'},
+ }).as('loadGridAfterSearch');
- it('should display map and revert back to table', function() {
+ cy.visit('/display/view');
- cy.visit('/display/view');
+ // Filter for the created display
+ cy.get('#Filter input[name="display"]')
+ .type('disp2');
- cy.get('#displays_wrapper.dataTables_wrapper').should('be.visible');
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
- cy.get('#display-map.leaflet-container').should('not.be.visible');
+ // Click on the first row element to open the delete modal
+ cy.get('#displays tr:first-child .dropdown-toggle').click();
+ cy.get('#displays tr:first-child .display_button_delete').click();
- cy.get('#map_button').click();
+ // Delete test display
+ cy.get('.bootbox .save-button').click();
- cy.get('#display-map.leaflet-container').should('be.visible');
+ // Check if display is deleted in toast message
+ cy.get('.toast').contains('Deleted disp2');
+ });
- cy.get('#list_button').click();
+ // Display: disp3
+ it.skip('searches and authorise an unauthorised display', function() {
+ // search for a display disp1 and edit
+ cy.intercept({
+ url: '/display?*',
+ query: {display: 'disp3'},
+ }).as('loadGridAfterSearch');
- cy.get('#displays_wrapper.dataTables_wrapper').should('be.visible');
+ // Intercept the PUT request
+ cy.intercept({
+ method: 'PUT',
+ url: '/display/*',
+ }).as('putRequest');
+
+ cy.visit('/display/view');
+
+ // Filter for the created display
+ cy.get('#Filter input[name="display"]')
+ .type('disp3');
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#displays tr:first-child .dropdown-toggle').click();
+ cy.get('#displays tr:first-child .display_button_authorise').click();
+
+ // edit test display
+ cy.get('.bootbox .save-button').click();
+
+ // Wait for the intercepted PUT request and check the form data
+ cy.wait('@putRequest').then((interception) => {
+ // Get the request body (form data)
+ const response = interception.response;
+ const responseData = response.body.data;
+
+ // assertion on the "display" value
+ expect(responseData.display).to.eq('disp3');
+ expect(responseData.licensed).to.eq(1);
});
-});
\ No newline at end of file
+ });
+
+ // Display: disp4
+ it('set a default layout', function() {
+ cy.intercept({
+ url: '/display?*',
+ query: {display: 'disp4'},
+ }).as('loadGridAfterSearch');
+
+ // Intercept the PUT request
+ cy.intercept({
+ method: 'PUT',
+ url: '/display/defaultlayout/*',
+ }).as('putRequest');
+
+ cy.intercept({
+ url: '/layout*',
+ query: {
+ layout: 'disp4_default_layout',
+ },
+ }).as('loadLayoutAfterSearch');
+
+ cy.visit('/display/view');
+
+ // Filter for the created display
+ cy.get('#Filter input[name="display"]')
+ .type('disp4');
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#displays tr:first-child .dropdown-toggle').click();
+ cy.get('#displays tr:first-child .display_button_defaultlayout').click();
+
+ // Set the default layout
+ cy.get('.modal .select2-container--bootstrap').click();
+ cy.get('.modal .select2-container--open input[type="search"]').type('disp4_default_layout');
+
+ cy.wait('@loadLayoutAfterSearch');
+ cy.get('.select2-results__option').contains('disp4_default_layout').click();
+
+ // edit test display
+ cy.get('.bootbox .save-button').click();
+
+ // Wait for the intercepted PUT request and check the form data
+ cy.wait('@putRequest').then((interception) => {
+ // Get the request body (form data)
+ const response = interception.response;
+ const body = response.body;
+ expect(body.success).to.eq(true);
+ });
+ });
+
+ // Display: disp5
+ it.skip('manage membership for disp5', function() {
+ cy.intercept({
+ url: '/display?*',
+ query: {display: 'disp5'},
+ }).as('loadGridAfterSearch');
+
+ // Intercept the PUT request
+ cy.intercept({
+ method: 'POST',
+ url: /\/display\/\d+\/displaygroup\/assign$/,
+ }).as('postRequest');
+
+ cy.intercept({
+ url: '/displaygroup*',
+ query: {
+ displayGroup: 'disp5_dispgrp',
+ },
+ }).as('loadDisplaypGroupAfterSearch');
+
+ cy.visit('/display/view');
+
+ // Filter for the created display
+ cy.get('#Filter input[name="display"]')
+ .type('disp5');
+
+ // Wait for the grid reload
+ cy.wait('@loadGridAfterSearch');
+
+ // Click on the first row element to open the delete modal
+ cy.get('#displays tr:first-child .dropdown-toggle').click();
+ cy.get('#displays tr:first-child .display_button_group_membership').click();
+
+ cy.get('.modal #displayGroup').type('disp5_dispgrp');
+
+ cy.wait('@loadDisplaypGroupAfterSearch');
+ cy.get('#displaysGroupsMembersTable').within(() => {
+ // count the rows within table
+ cy.get('tbody').find('tr').should('have.length', 1);
+ cy.get('tbody tr:first-child input[type="checkbox"]').check();
+ });
+
+ // Save assignments
+ cy.get('.bootbox .save-button').click();
+
+ // Wait for the intercepted POST request and check the form data
+ cy.wait('@postRequest').then((interception) => {
+ // Get the request body (form data)
+ const response = interception.response;
+ const body = response.body;
+ expect(body.success).to.eq(true);
+ });
+ });
+
+ it('should display map and revert back to table', function() {
+ cy.visit('/display/view');
+
+ cy.get('#displays_wrapper.dataTables_wrapper').should('be.visible');
+
+ cy.get('#display-map.leaflet-container').should('not.be.visible');
+
+ cy.get('#map_button').click();
+
+ cy.get('#display-map.leaflet-container').should('be.visible');
+
+ cy.get('#list_button').click();
+
+ cy.get('#displays_wrapper.dataTables_wrapper').should('be.visible');
+ });
+});
diff --git a/cypress/e2e/playlists.cy.js b/cypress/e2e/playlists.cy.js
deleted file mode 100644
index 3d840b1149..0000000000
--- a/cypress/e2e/playlists.cy.js
+++ /dev/null
@@ -1,75 +0,0 @@
-describe('Playlists Admin', function () {
-
- var testRun;
-
- beforeEach(function () {
- cy.login();
-
- testRun = Cypress._.random(0, 1e9);
- });
-
- it('should add a non-dynamic playlist', function() {
- cy.visit('/playlist/view');
-
- // Click on the Add Playlist button
- cy.contains('Add Playlist').click();
-
- cy.get('.modal input#name')
- .type('Cypress Test Playlist ' + testRun);
-
- cy.get('.modal .save-button').click();
-
- // Filter for the created playlist
- cy.get('#Filter input[name="name"]')
- .type('Cypress Test Playlist ' + testRun);
-
- // Should have the added playlist
- cy.get('#playlists tbody tr').should('have.length', 1);
- cy.get('#playlists tbody tr:nth-child(1) td:nth-child(2)').contains('Cypress Test Playlist ' + testRun);
- });
-
- it('should show a list of Playlists', function() {
- // Wait for playlist grid reload
- cy.server();
- cy.route('/playlist?draw=1&*').as('playlistGridLoad');
-
- cy.visit('/playlist/view').then(function() {
- cy.wait('@playlistGridLoad');
- cy.get('#playlists');
- });
- });
-
- it('selects multiple playlists and delete them', function() {
-
- // Create a new playlist and then search for it and delete it
- cy.createNonDynamicPlaylist('Cypress Test Playlist ' + testRun).then(() => {
-
- cy.server();
- cy.route('/playlist?draw=2&*').as('playlistGridLoad');
-
- // Delete all test playlists
- cy.visit('/playlist/view');
-
- // Clear filter and search for text playlists
- cy.get('#Filter input[name="name"]')
- .clear()
- .type('Cypress Test Playlist');
-
- // Wait for 2nd playlist grid reload
- cy.wait('@playlistGridLoad');
-
- // Select all
- cy.get('button[data-toggle="selectAll"]').click();
-
- // Delete all
- cy.get('.dataTables_info button[data-toggle="dropdown"]').click();
- cy.get('.dataTables_info a[data-button-id="playlist_button_delete"]').click();
-
- cy.get('button.save-button').click();
-
- // Modal should contain one successful delete at least
- cy.get('.modal-body').contains(': Success');
- });
- });
-
-});
\ No newline at end of file
diff --git a/cypress/e2e/report_distribution.cy.js b/cypress/e2e/report_distribution.cy.js
index 7b3e5ae22e..5be8cbeebb 100644
--- a/cypress/e2e/report_distribution.cy.js
+++ b/cypress/e2e/report_distribution.cy.js
@@ -72,7 +72,7 @@ describe('Distribution by Layout, Media or Event', function() {
cy.get('#distributionTbl tbody tr:nth-child(3) td:nth-child(3)').contains(1); // Count
});
- it('Create/Delete a Daily Distribution Report Schedule', () => {
+ it.skip('Create/Delete a Daily Distribution Report Schedule', () => {
const reportschedule = 'Daily Distribution by Layout 1 and Display 1';
// Create and alias for load layout
diff --git a/cypress/e2e/schedule.cy.js b/cypress/e2e/schedule.cy.js
index 4b42f5622c..1691871b25 100644
--- a/cypress/e2e/schedule.cy.js
+++ b/cypress/e2e/schedule.cy.js
@@ -233,7 +233,7 @@ describe('Campaigns', function() {
cy.get('.modal .modal-footer').contains('Save').click();
});
- it('should edit a scheduled event', function() {
+ it.skip('should edit a scheduled event', function() {
cy.intercept('GET', '/schedule/data/events?*').as('scheduleDataEvent');
cy.intercept('GET', '/schedule?draw=2*').as('scheduleLoad2');
cy.intercept('GET', '/schedule?draw=3*').as('scheduleLoad3');
diff --git a/cypress/support/commands.js b/cypress/support/commands.js
index 257561b090..8c13a00c50 100644
--- a/cypress/support/commands.js
+++ b/cypress/support/commands.js
@@ -329,7 +329,21 @@ Cypress.Commands.add('createCampaign', function(name) {
});
// Display Group
-Cypress.Commands.add('createDisplaygroup', function(name) {
+Cypress.Commands.add('createDisplaygroup', function(name, isDynamic = false, criteria) {
+ // Define the request body object
+ const requestBody = {
+ displayGroup: name,
+ };
+
+ // Add 'isDynamic' to the request body if it's true
+ if (isDynamic) {
+ requestBody.isDynamic = true;
+ }
+ // Add 'isDynamic' to the request body if it's true
+ if (criteria) {
+ requestBody.dynamicCriteria = criteria;
+ }
+
cy.request({
method: 'POST',
url: '/api/displaygroup',
@@ -337,11 +351,295 @@ Cypress.Commands.add('createDisplaygroup', function(name) {
headers: {
Authorization: 'Bearer ' + Cypress.env('accessToken'),
},
+ body: requestBody,
+ }).then((res) => {
+ return res.body.displaygroupId;
+ });
+});
+
+// Delete Display group
+Cypress.Commands.add('deleteDisplaygroup', function(id) {
+ cy.request({
+ method: 'DELETE',
+ url: '/api/displaygroup/' + id,
+ form: true,
+ headers: {
+ Authorization: 'Bearer ' + Cypress.env('accessToken'),
+ },
+ body: {},
+ }).then((res) => {
+ return res;
+ });
+});
+
+// Display Profile
+Cypress.Commands.add('createDisplayProfile', function(name, type) {
+ cy.request({
+ method: 'POST',
+ url: '/api/displayprofile',
+ form: true,
+ headers: {
+ Authorization: 'Bearer ' + Cypress.env('accessToken'),
+ },
body: {
- displayGroup: name,
+ name: name,
+ type: type,
},
}).then((res) => {
- return res.body.displaygroupId;
+ return res.body.displayProfileId;
+ });
+});
+
+// Delete display profile
+Cypress.Commands.add('deleteDisplayProfile', function(id) {
+ cy.request({
+ method: 'DELETE',
+ url: '/api/displayprofile/' + id,
+ form: true,
+ headers: {
+ Authorization: 'Bearer ' + Cypress.env('accessToken'),
+ },
+ body: {},
+ }).then((res) => {
+ return res;
+ });
+});
+
+// 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.id;
+ });
+});
+
+// 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;
+ });
+});
+
+
+// Menuboard
+Cypress.Commands.add('createMenuboard', function(name) {
+ cy.request({
+ method: 'POST',
+ url: '/api/menuboard',
+ form: true,
+ headers: {
+ Authorization: 'Bearer ' + Cypress.env('accessToken'),
+ },
+ body: {
+ name: name,
+ },
+ }).then((res) => {
+ return res.body.menuId;
+ });
+});
+
+// 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;
+ });
+});
+
+// User
+Cypress.Commands.add('createUser', function(name, password, userTypeId, homeFolderId) {
+ cy.request({
+ method: 'POST',
+ url: '/api/user',
+ form: true,
+ headers: {
+ Authorization: 'Bearer ' + Cypress.env('accessToken'),
+ },
+ body: {
+ userName: name,
+ password: password,
+ userTypeId: userTypeId,
+ homeFolderId: homeFolderId,
+ homePageId: 'icondashboard.view',
+ },
+ }).then((res) => {
+ return res.body.userId;
+ });
+});
+
+// Delete User
+Cypress.Commands.add('deleteUser', function(id) {
+ cy.request({
+ method: 'DELETE',
+ url: '/api/user/' + id,
+ form: true,
+ headers: {
+ Authorization: 'Bearer ' + Cypress.env('accessToken'),
+ },
+ body: {},
+ }).then((res) => {
+ return res;
+ });
+});
+
+// Usergroup
+Cypress.Commands.add('createUsergroup', function(name) {
+ cy.request({
+ method: 'POST',
+ url: '/api/group',
+ form: true,
+ headers: {
+ Authorization: 'Bearer ' + Cypress.env('accessToken'),
+ },
+ body: {
+ group: name,
+ },
+ }).then((res) => {
+ return res.body.groupId;
+ });
+});
+
+// Delete Usergroup
+Cypress.Commands.add('deleteUsergroup', function(id) {
+ cy.request({
+ method: 'DELETE',
+ url: '/api/group/' + id,
+ form: true,
+ headers: {
+ Authorization: 'Bearer ' + Cypress.env('accessToken'),
+ },
+ body: {},
+ }).then((res) => {
+ return res;
+ });
+});
+
+// Menuboard Category
+Cypress.Commands.add('createMenuboardCat', function(name, menuId) {
+ cy.request({
+ method: 'POST',
+ url: '/api/menuboard/' + menuId + '/' + 'category',
+ form: true,
+ headers: {
+ Authorization: 'Bearer ' + Cypress.env('accessToken'),
+ },
+ body: {
+ name: name,
+ },
+ }).then((res) => {
+ return res.body.menuCategoryId;
+ });
+});
+
+// Menuboard Category Product
+Cypress.Commands.add('createMenuboardCatProd', function(name, menuCatId) {
+ cy.request({
+ method: 'POST',
+ url: '/api/menuboard/' + menuCatId + '/' + 'product',
+ form: true,
+ headers: {
+ Authorization: 'Bearer ' + Cypress.env('accessToken'),
+ },
+ body: {
+ name: name,
+ },
+ }).then((res) => {
+ return res.body.menuProductId;
+ });
+});
+
+// Delete Menuboard
+Cypress.Commands.add('deleteMenuboard', function(id) {
+ cy.request({
+ method: 'DELETE',
+ url: '/api/menuboard/' + id,
+ form: true,
+ headers: {
+ Authorization: 'Bearer ' + Cypress.env('accessToken'),
+ },
+ body: {},
+ }).then((res) => {
+ return res;
});
});
diff --git a/lib/XTR/SeedDatabaseTask.php b/lib/XTR/SeedDatabaseTask.php
index 650149ccb3..ce6f2272d7 100644
--- a/lib/XTR/SeedDatabaseTask.php
+++ b/lib/XTR/SeedDatabaseTask.php
@@ -167,7 +167,14 @@ public function run()
*/
private function createDisplayGroups(): void
{
- $displayGroups = ['POP Display Group', 'Display Group 1', 'Display Group 2'];
+ $displayGroups = [
+ 'POP Display Group',
+ 'Display Group 1',
+ 'Display Group 2',
+
+ // Display groups for displaygroups.cy.js test
+ 'disp5_dispgrp',
+ ];
foreach ($displayGroups as $displayGroupName) {
try {
@@ -186,7 +193,6 @@ private function createDisplayGroups(): void
// Cache
$this->displayGroups[$displayGroup->displayGroup] = $displayGroup->getId();
}
-
} catch (GeneralException $e) {
$this->log->error('Error creating display group: '. $e->getMessage());
}
@@ -209,6 +215,20 @@ private function createDisplays(): void
'List Campaign Display 2' => ['license' => Random::generateString(12, 'seed'), 'licensed' => true,
'clientType' => 'android', 'clientCode' => 400, 'clientVersion' => 4],
+ // Displays for displays.cy.js test
+ 'disp1' => ['license' => 'disp1', 'licensed' => true, 'clientType' => 'android', 'clientCode' => 400, 'clientVersion' => 4],
+ 'disp2' => ['license' => 'disp2', 'licensed' => true, 'clientType' => 'android', 'clientCode' => 400, 'clientVersion' => 4],
+ 'disp3' => ['license' => 'disp3', 'licensed' => false, 'clientType' => 'android', 'clientCode' => 400, 'clientVersion' => 4],
+ 'disp4' => ['license' => 'disp4', 'licensed' => true, 'clientType' => 'android', 'clientCode' => 400, 'clientVersion' => 4],
+ 'disp5' => ['license' => 'disp5', 'licensed' => true, 'clientType' => 'android', 'clientCode' => 400, 'clientVersion' => 4],
+
+ // Displays for displaygroups.cy.js test
+ 'dispgrp_disp1' => ['license' => 'dispgrp_disp1', 'licensed' => true, 'clientType' => 'android', 'clientCode' => 400, 'clientVersion' => 4],
+ 'dispgrp_disp2' => ['license' => 'dispgrp_disp2', 'licensed' => true, 'clientType' => 'android', 'clientCode' => 400, 'clientVersion' => 4],
+ 'dispgrp_disp_dynamic1' => ['license' => 'dispgrp_disp_dynamic1', 'licensed' => true, 'clientType' => 'android', 'clientCode' => 400, 'clientVersion' => 4],
+ 'dispgrp_disp_dynamic2' => ['license' => 'dispgrp_disp_dynamic2', 'licensed' => true, 'clientType' => 'android', 'clientCode' => 400, 'clientVersion' => 4],
+
+
// 6 displays for xmds
'phpunitv7' => ['license' => 'PHPUnit7', 'licensed' => true, 'clientType' => 'android', 'clientCode' => 400, 'clientVersion' => 4],
'phpunitwaiting' => ['license' => 'PHPUnitWaiting', 'licensed' => false, 'clientType' => 'android', 'clientCode' => 400, 'clientVersion' => 4],
@@ -252,7 +272,6 @@ private function createDisplays(): void
// Cache
$this->displays[$display->display] = $display->displayId;
}
-
} catch (GeneralException $e) {
$this->log->error('Error creating display: ' . $e->getMessage());
}
@@ -298,6 +317,9 @@ private function importLayouts(): void
'List Campaign Layout 1' => 'export-list-campaign-layout-1.zip',
'List Campaign Layout 2' => 'export-list-campaign-layout-2.zip',
'POP Layout 1' => 'export-pop-layout-1.zip',
+
+ // Layout for displaygroups.cy.js test
+ 'disp4_default_layout' => 'export-disp4-default-layout.zip',
];
// Get all layouts
@@ -612,7 +634,6 @@ private function createStats(): void
'count' => 1,
];
$this->store->insert('INSERT INTO `stat` (' . $columns . ') VALUES (' . $values . ')', $params);
-
} catch (GeneralException $e) {
$this->getLogger()->error('Error inserting stats: '. $e->getMessage());
}
@@ -868,7 +889,6 @@ private function createDisconnectedDisplayEvent(): void
'displayId' => $this->displays['POP Display 1']
]);
$this->store->commitIfNecessary();
-
}
private function createCommands()
diff --git a/tests/Xmds/SyncTest.php b/tests/Xmds/SyncTest.php
index 5183a56c1b..3b05f8e7c1 100644
--- a/tests/Xmds/SyncTest.php
+++ b/tests/Xmds/SyncTest.php
@@ -65,7 +65,7 @@ public function testScheduleSyncEvent()
$i = 0;
foreach ($layouts as $layout) {
if ($i === 0) {
- $this->assertSame('6', $layout->getAttribute('file'));
+ $this->assertSame('7', $layout->getAttribute('file'));
$this->assertSame('1', $layout->getAttribute('syncEvent'));
$this->assertSame('2', $layout->getAttribute('scheduleid'));
} else if ($i === 1) {
diff --git a/tests/resources/seeds/layouts/export-disp4-default-layout.zip b/tests/resources/seeds/layouts/export-disp4-default-layout.zip
new file mode 100644
index 0000000000..93a02ba26b
Binary files /dev/null and b/tests/resources/seeds/layouts/export-disp4-default-layout.zip differ