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