From 847d3262270daa5a2e09bd428fa0cfa59455e63f Mon Sep 17 00:00:00 2001 From: otaylor Date: Tue, 14 Oct 2025 11:12:40 +0100 Subject: [PATCH 1/2] Adds Cypress Axe for accessiblility test and greatly extends the original e2e test set --- cypress.config.ts | 9 +- .../functionality/06-tables-and-wizard.cy.ts | 97 ++-- cypress/e2e/functionality/07-layouts.cy.ts | 7 + cypress/e2e/functionality/08-data-view.cy.ts | 66 --- .../08-set-table-permissions.cy.ts | 174 ++++++ .../functionality/09-bulk-table-actions.cy.ts | 127 +++++ cypress/e2e/functionality/10-views.cy.ts | 367 +++++++++++++ .../e2e/functionality/11-create-record.cy.ts | 320 +++++++++++ cypress/e2e/functionality/12-edit-table.cy.ts | 290 ++++++++++ .../e2e/functionality/13-data-tables.cy.ts | 248 +++++++++ cypress/e2e/functionality/14-reports.cy.ts | 55 ++ cypress/e2e/functionality/15-WCAGAA.cy.ts | 154 ++++++ cypress/e2e/functionality/16-curvals.cy.ts | 351 ++++++++++++ cypress/fixtures/Import-test-data.csv | 8 + .../support/builders/layout/LayoutBuilder.ts | 12 +- .../support/builders/layout/definitions.ts | 29 + cypress/support/commands.ts | 517 ++++++++++-------- cypress/support/constants.ts | 4 + package.json | 1 + 19 files changed, 2478 insertions(+), 358 deletions(-) delete mode 100644 cypress/e2e/functionality/08-data-view.cy.ts create mode 100644 cypress/e2e/functionality/08-set-table-permissions.cy.ts create mode 100644 cypress/e2e/functionality/09-bulk-table-actions.cy.ts create mode 100644 cypress/e2e/functionality/10-views.cy.ts create mode 100644 cypress/e2e/functionality/11-create-record.cy.ts create mode 100644 cypress/e2e/functionality/12-edit-table.cy.ts create mode 100644 cypress/e2e/functionality/13-data-tables.cy.ts create mode 100644 cypress/e2e/functionality/14-reports.cy.ts create mode 100644 cypress/e2e/functionality/15-WCAGAA.cy.ts create mode 100644 cypress/e2e/functionality/16-curvals.cy.ts create mode 100644 cypress/fixtures/Import-test-data.csv create mode 100644 cypress/support/builders/layout/definitions.ts diff --git a/cypress.config.ts b/cypress.config.ts index d8489da64..5bb30a51f 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -4,7 +4,14 @@ export default defineConfig({ e2e: { redirectionLimit: 50, setupNodeEvents(on, config) { - // implement node event listeners here + on("task", { + log(message) { + console.log(message); + return null; + }, + }); + return config; }, }, }); + diff --git a/cypress/e2e/functionality/06-tables-and-wizard.cy.ts b/cypress/e2e/functionality/06-tables-and-wizard.cy.ts index 715778acb..d7165c914 100644 --- a/cypress/e2e/functionality/06-tables-and-wizard.cy.ts +++ b/cypress/e2e/functionality/06-tables-and-wizard.cy.ts @@ -1,61 +1,64 @@ import { goodPassword, goodUser } from "../../support/constants"; -describe('Another Test Suite', () => { - beforeEach(() => { - cy.loginAndGoTo(goodUser, goodPassword, 'http://localhost:3000/table'); - cy.location("pathname").should("include", "/table"); - }); +describe("Creating Tables using the Wizard", () => { + beforeEach(() => { + cy.loginAndGoTo(goodUser, goodPassword, "http://localhost:3000/table"); + cy.location("pathname").should("include", "/table"); + }); + + context("Basic Add/Delete tests", () => { + // Skipped test: known issue where error not appearing for invalid shorname. + it.skip("should fail to save new table with invalid shortname", () => { + cy.get('[data-target="#newTableModal"]').click(); + cy.get("#shortName").type("This value wont $4v£"); + cy.get("#name").type("table to fail"); + cy.get(".btn-js-next").first().click(); + cy.get(".btn-js-save").first().click(); - //attempt save with incorrect (fails) - it.skip('should fail to save new table with invalid shortname ', () => { - cy.get('[data-target="#newTableModal"]').click(); - cy.get('#shortName').type('This value wont $4v£'); - cy.get("#name").type("table to fail"); - cy.get('.btn-js-next').eq(0).click(); - cy.get('.btn-js-save').eq(0).click(); - cy.get('div.alert.alert-danger') - .should('be.visible') - .and('contain', 'Invalid short name for table'); + // Check for failed save error + cy.get("div.alert.alert-danger") + .should("be.visible") + .and("contain", "Invalid short name for table"); }); - it('should save a new table successfully', () => { - cy.get('[data-target="#newTableModal"]').click(); - cy.get('#shortName').type('1-test_table'); - cy.get("#name").type("1-test-table"); - cy.get('.btn-js-next').eq(0).click(); - cy.get('.btn-js-save').eq(0).click(); - cy.location("pathname").should("include", "/table"); - cy.contains('1-test-table').should('exist'); + it("should save a new empty table successfully", () => { + cy.createInstance("1-test-table"); + + // Check new table is displayed on table page + cy.location("pathname").should("include", "/table"); + cy.contains("1-test-table").should("exist"); }); + it("should make the new table accessible", () => { + // Check table edit page is accessible + cy.contains("tr", "1-test-table") + .contains("a", "Edit table") + .click(); - it('table is accessible', () => { - cy.contains('tr', '1-test-table') - .contains('a', 'Edit table') - .click(); - cy.location("pathname").should("include", "1-test_table/edit"); + cy.location("pathname").should("include", "1-test-table/edit"); }); - it('table can be deleted', () => { - cy.visit('http://localhost:3000/1-test_table/edit'); - cy.location("pathname").should("include", "1-test_table/edit"); - cy.contains('button', 'Delete table').click(); - cy.get('.modal-dialog').within(() => { - cy.contains('h3.modal-title', 'Delete - 1-test-table').should('exist'); - }); - cy.get('.modal-footer__right').contains('button', 'Delete').click(); - cy.location("pathname").should("include", "/table"); - cy.contains('.alert.alert-success', 'The table has been deleted successfully').should('exist'); - cy.contains('1-test-table').should('not.exist'); + it("should delete the table successfully", () => { + cy.deleteInstanceByShortName("1-test-table"); + + // Check table no longer appears on table page + cy.location("pathname").should("include", "/table"); + cy.contains( + ".alert.alert-success", + "The table has been deleted successfully" + ).should("exist"); + cy.contains("1-test-table").should("not.exist"); }); - it('Deleted table no longer accessible', () => { - cy.request({ - url: 'http://localhost:3000/1-test_table/edit', - failOnStatusCode: false // Prevent Cypress from failing the test on non-2xx status codes - }).then((response) => { - // Check if the response status is either 302 or 404 - expect(response.status).to.be.oneOf([302, 404]); - }); + it("should confirm deleted table is no longer accessible", () => { + // Attempt to access the deleted table URL directly + cy.request({ + url: "http://localhost:3000/1-test-table/edit", + failOnStatusCode: false, // Prevent Cypress from failing on 404/302 + }).then((response) => { + expect(response.status).to.be.oneOf([302, 404]); + }); }); + }); }); + diff --git a/cypress/e2e/functionality/07-layouts.cy.ts b/cypress/e2e/functionality/07-layouts.cy.ts index fec74f5ed..c75536189 100644 --- a/cypress/e2e/functionality/07-layouts.cy.ts +++ b/cypress/e2e/functionality/07-layouts.cy.ts @@ -5,6 +5,13 @@ import { goodPassword, goodUser } from "../../support/constants"; describe("Layout creation tests", () => { const refShortName = "tr"; + + before(() => { + cy.log("login").login(goodUser, goodPassword); + cy.log("update user groups").addUserToDefaultGroup("test@example.com", "check"); + cy.logout(); + }); + beforeEach(() => { cy.login(goodUser, goodPassword); diff --git a/cypress/e2e/functionality/08-data-view.cy.ts b/cypress/e2e/functionality/08-data-view.cy.ts deleted file mode 100644 index f5b4dd9d1..000000000 --- a/cypress/e2e/functionality/08-data-view.cy.ts +++ /dev/null @@ -1,66 +0,0 @@ -import "../../support/commands"; -import { goodPassword, goodUser } from "../../support/constants" - -// This test suite is just to ensure the data table menu items are present and correct -describe('Data table', () => { - // This section is for the admin user in order to check all permissions work and can be applied correctly - describe('Admin user', () => { - beforeEach(() => { - cy.loginAndGoTo(goodUser, goodPassword, 'http://localhost:3000/table1/data'); - }); - - it('All expected tabs and title are present', () => { - cy.get('.table-header__title').should('exist').contains('WebDriverTestSheet'); - const tb = cy.get('.table-header-bottom'); - tb.should('exist'); - const tabs = tb.find('ul').find('li'); - tabs.should('exist').should('have.length', 4); - const tabContent = ['Records', 'Dashboard', 'Edit table', 'Reports']; - tabs.each((tab, idx) => { - cy.wrap(tab).should('exist').contains(tabContent[idx]); - }); - }); - - it('Has the correct items in the left navigation', () => { - const nl = cy.get('.content-block__navigation-left'); - nl.should('exist'); - nl.find('.dropdown').should('exist').contains('Current view'); - const vt = cy.get('.content-block__navigation-left').find('ul').find('li').eq(1); - vt.should('exist'); - vt.find('ul').find('li').should('exist').should('have.length', 3); - const viewTypes = ['Table', 'Graph', 'Timeline']; - cy.get('.content-block__navigation-left').find('ul').find('li').eq(1).find('ul').find('li').each((li, idx) => { - cy.wrap(li).should('exist').contains(viewTypes[idx]); - }); - }); - - it('Has the correct items in the right navigation', () => { - // Add the user to the group - cy.addUserToGroup('test@example.com', 'basic', 'http://localhost:3000/table1/data'); - // Set all table permissions - cy.setAllTablePermissions(); - // Check everything is as expected - cy.get('.content-block__navigation-right').should('exist'); - cy.get('.content-block__navigation-right').find('.dropdown').should('exist').should('have.length', 2); - const dropdowns = ['Manage views', 'Actions']; - cy.get('.content-block__navigation-right').find('.dropdown').each((dropdown,idx)=>{ - cy.wrap(dropdown).should('exist').contains(dropdowns[idx]); - }); - }); - - it('Has the correct items in the right navigation dropdowns', ()=>{ - const dropdownData = { - 'Manage views': ['Add a view', 'Manage views of another user', 'Historic view'], - 'Actions': ['Import records','Delete all records in this view','Update all records in this view','Clone all records in this view','Download records','Manage deleted records','Field Data Purge'] - } - for(const key in dropdownData) { - cy.get('.content-block__navigation-right').find('.dropdown').contains(key).click(); - cy.get('.dropdown-menu').should('exist'); - cy.get('.content-block__navigation-right').find('.dropdown').contains(key).parent().find('li').each((li, idx) => { - cy.wrap(li).should('exist').contains(dropdownData[key][idx]); - }); - cy.get('.content-block__navigation-right').find('.dropdown').contains(key).click(); - } - }); - }); -}); \ No newline at end of file diff --git a/cypress/e2e/functionality/08-set-table-permissions.cy.ts b/cypress/e2e/functionality/08-set-table-permissions.cy.ts new file mode 100644 index 000000000..466738612 --- /dev/null +++ b/cypress/e2e/functionality/08-set-table-permissions.cy.ts @@ -0,0 +1,174 @@ +import { LUA } from "../../../src/frontend/js/lib/util/formatters/lua"; +import { LayoutBuilder } from "../../support/builders/layout/LayoutBuilder"; +import { + ICodeLayoutBuilder, + ICurvalLayoutBuilder, + IDropdownLayoutBuilder, + ILayoutBuilder, +} from "../../support/builders/layout/interfaces"; +import { goodPassword, goodUser } from "../../support/constants"; + +describe("Layout creation tests", () => { + const refShortName = "tr"; + const table_shortname = "table1"; + + before(() => { + cy.login(goodUser, goodPassword); + cy.log("update user groups").addUserToDefaultGroup("test@example.com", "check"); + cy.logout(); + }); + + beforeEach(() => { + cy.login(goodUser, goodPassword); + }); + + after(() => { + // Clear permissions and reset user group + cy.clearAllTablePermissions("table1"); + cy.addUserToDefaultGroup("test@example.com", "uncheck"); + }); + + + // Set individual table permissions + context("Set individual permissions", () => { + [ + "Bulk import record", + "Purge deleted records", + "Download records", + "Delete records", + "Bulk update records", + "Bulk delete records", + "Manage linked records", + "Manage child records", + "Manage views", + "Manage group views", + "Select extra view limits", + "Manage fields", + "Send messages", + ].forEach((permissionName) => { + it(`should set ${permissionName} for table: ${table_shortname}`, () => { + cy.setTablePermissionsByShortName(table_shortname, { + [permissionName]: true, + }); + }); + }); + }); + + // Check Manage Views dropdown visibility and options + context("Check view options are available", () => { + it("should navigate to data page and click the Manage views dropdown", () => { + cy.visit(`http://localhost:3000/${table_shortname}/data`); + + cy.get("button#manage_views") + .should("be.visible") + .and("contain", "Manage views") + .click(); + + cy.get(".dropdown__list").first().within(() => { + cy.contains("a", "Add a view").should("be.visible"); + cy.contains("a", "Manage views of another user").should("be.visible"); + cy.contains("a", "Historic view").should("be.visible"); + }); + }); + }); + + // Check Actions dropdown visibility and options + context("Check view options are available", () => { + it("should navigate to data page and click the Actions dropdown", () => { + cy.visit(`http://localhost:3000/${table_shortname}/data`); + + cy.get("span") + .contains("Actions") + .should("be.visible") + .click(); + + cy.get('.dropdown-menu.dropdown__menu.show .dropdown__list').within(() => { + + //commented out the following because they require records in the table to appear + //cy.contains("a", "Download records").should("be.visible"); + //cy.contains("a", "Field Data Purge").should("be.visible"); + + //know issue: purge options dont display unless there is live records in the table + //cy.contains("a", "Field Data Purge").should("be.visible"); + //cy.contains("a", "Manage deleted records").should("be.visible"); + + cy.contains('a', 'Import records').should('be.visible'); + cy.contains('a', 'Delete all records in this view').should('be.visible'); + cy.contains("a", "Update all records in this view").should("be.visible"); + cy.contains("a", "Clone all records in this view").should("be.visible"); + }); + }); + }); + + // Ensure related endpoints load successfully + context("Check related endpoints are accessible", () => { + const urls = [ + `/historic_purge/`, + `/purge/`, + `/bulk/clone/`, + `/bulk/update/`, + `/import/`, + `/view/0`, + ]; + + urls.forEach((path) => { + it(`should successfully load ${path}`, () => { + cy.visit(`http://localhost:3000/${table_shortname}${path}`); + + // Basic sanity check: body exists and is not empty + cy.get("body").should("exist").and("not.be.empty"); + }); + }); + }); + + // Clear permissions + context("Clear all table permissions", () => { + it(`Should clear all permissions for ${table_shortname}`, () => { + cy.clearAllTablePermissions(table_shortname); + }); + }); + + // Verify that restricted UI elements are gone + context("Ensure both dropdown lists are no longer present", () => { + it("Ensure the Actions dropdown does not exist on the page", () => { + cy.visit(`http://localhost:3000/${table_shortname}/data`); + + cy.get("span") + .contains("Actions") + .should("not.exist"); + }); + + it("Ensure the manage views dropdown does not exist on the page", () => { + cy.visit(`http://localhost:3000/${table_shortname}/data`); + + cy.get("span") + .contains("manage_views") + .should("not.exist"); + }); + }); + + // Check endpoints after permissions are cleared + context("Check restricted endpoints show permission error", () => { + const urls = [ + `/historic_purge/`, + `/purge/`, + `/bulk/clone/`, + `/bulk/update/`, + `/import/`, + // `/view/0`, + ]; + + urls.forEach((path) => { + it(`should block access to ${path}`, () => { + cy.visit(`http://localhost:3000/${table_shortname}${path}`, { + failOnStatusCode: false, + }); + + cy.get('div.alert.alert-danger[role="alert"]') + .should("be.visible") + .and("contain.text", "You do not have permission to"); + }); + }); + }); +}); + diff --git a/cypress/e2e/functionality/09-bulk-table-actions.cy.ts b/cypress/e2e/functionality/09-bulk-table-actions.cy.ts new file mode 100644 index 000000000..f2e33437c --- /dev/null +++ b/cypress/e2e/functionality/09-bulk-table-actions.cy.ts @@ -0,0 +1,127 @@ +import "../../support/commands"; +import { goodPassword, goodUser } from "../../support/constants"; + +describe("Bulk record and table action tests", () => { + const table_shortname = "table1"; + + before(() => { + cy.log("login").login(goodUser, goodPassword); + + // Add user to base group + cy.log("update user groups").addUserToDefaultGroup("test@example.com", "check"); + + // Set required table permissions + cy.log("setup table permissions"); + const permissionObject = {}; + ["Bulk import records", "Purge deleted records", "Delete records", "Bulk delete records"].forEach((permissionName) => { + permissionObject[permissionName] = true; + }); + cy.setTablePermissionsByShortName(table_shortname, permissionObject); + + // Create layouts + cy.log("create layouts"); + cy.populateTableWithLayouts("my_table_shortname"); + + cy.logout(); + }); + + after(() => { + cy.cleanTableOfLayouts(table_shortname); + cy.clearAllTablePermissions(table_shortname); + cy.addUserToDefaultGroup("test@example.com", "uncheck"); + }); + + beforeEach(() => { + cy.login(goodUser, goodPassword); + }); + + context('Bulk import tests', () => { + it("Should show error for invalid file upload during Import", () => { + cy.visit("http://localhost:3000/table1/data"); + + //find and check for import pages + cy.get("button#bulk_actions").click(); + cy.get('a[href="/table1/import/"]').click(); + cy.get("h2.table-header__page-title").should("contain.text", "Import records"); + cy.get('a[href="/table1/import/data/"]').click(); + cy.get("h2.table-header__page-title").should("contain.text", "Upload"); + + // Upload invalid file + cy.get('input[type="file"]').selectFile("cypress/fixtures/testfile.html", { force: true }); + cy.contains("Submit").click(); + + // Check for error message + cy.get(".alert-danger") + .should("be.visible") + .and("contain", "import headings not found in table"); + }); + + it("Should clear completed imports and verify empty table", () => { + cy.clearImports(table_shortname); + }); + + it("Should import with dry run, then confirm no errors", () => { + cy.visit("http://localhost:3000/table1/data"); + + //find and check for import pages + cy.get("button#bulk_actions").click(); + cy.get('a[href="/table1/import/"]').click(); + cy.get("h2.table-header__page-title").should("contain.text", "Import records"); + cy.get('a[href="/table1/import/data/"]').click(); + cy.get("h2.table-header__page-title").should("contain.text", "Upload"); + + // Upload csv file and start dryrun + cy.get('input[type="file"]').selectFile("cypress/fixtures/Import-test-data.csv", { force: true }); + cy.contains("Submit").click(); + cy.get(".alert.alert-success") + .should("be.visible") + .and("contain.text", "The file import process has been started"); + + //No way to check upload progress so wait 5s + cy.wait(5000); + + // Check upload finished without errs + cy.visit("http://localhost:3000/table1/import/"); + cy.get("a.link--plain").contains("Completed").should("exist"); + cy.get("a.link--plain").contains(/errors:\s*0/); + cy.get("a.link--plain").contains(/skipped:\s*0/); + + // Check no records actually imported (dry run) + cy.visit("http://localhost:3000/table1/data"); + cy.get("td.dt-empty") + .should("be.visible") + .and("contain", "There are no records available"); + }); + + it("Should perform full bulk Import and check new records exist", () => { + cy.bulkImportRecords(); + }); + + it("Should clear completed reports and verify empty state", () => { + cy.clearImports("table1"); + }); + }); + + context('Bulk Delete and purge tests', () => { + it("Should delete all records and verify empty table", () => { + cy.visit(`http://localhost:3000/${table_shortname}/data`); + cy.get("button#bulk_actions").click(); + cy.get("a#delete_href") + .should("be.visible") + .and("contain", "Delete all records in this view") + .click(); + + cy.get("#bulkDelete").should("be.visible"); + cy.get('button[name="modal_delete"]').should("be.visible").click(); + + // Check table is empty + cy.get("td.dt-empty") + .should("be.visible") + .and("contain", "There are no records available"); + }); + + it("Should purge all deleted records", () => { + cy.purgeAllDeletedData(table_shortname); + }); + }); +}); diff --git a/cypress/e2e/functionality/10-views.cy.ts b/cypress/e2e/functionality/10-views.cy.ts new file mode 100644 index 000000000..3078f373a --- /dev/null +++ b/cypress/e2e/functionality/10-views.cy.ts @@ -0,0 +1,367 @@ +import { LUA } from "../../../src/frontend/js/lib/util/formatters/lua"; +import { LayoutBuilder } from "../../support/builders/layout/LayoutBuilder"; +import { + ICodeLayoutBuilder, + ICurvalLayoutBuilder, + IDropdownLayoutBuilder, + ILayoutBuilder +} from "../../support/builders/layout/interfaces"; +import { goodPassword, goodUser } from "../../support/constants"; + +describe("View create/edit action tests", () => { + const table_shortname = "table1"; + + const viewDef: ViewDefinition = { + name: "Test view", + filters: [ + { + field: "Text Field", + operator: "equal", + value: "RECORD 5 \\<", + typeahead: false + }, + { + field: "Dropdown Field", + operator: "equal", + value: "Blue", + typeahead: true + }, + { + field: "Dropdown Field", + operator: "equal", + value: "Red", + typeahead: true + }, + { + field: "Number Field", + operator: "equal", + value: "123456789087654321", + typeahead: false + } + ], + fields: ["Text Field", "Date Field", "Dropdown Field", "Number Field"] + }; + + const ErrViewDef: ViewDefinition = { + name: "Erroring view: This view name has over one hundred and twenty nine charecters so therefore should error upon save. Should this view name successfully save then the test will fail and I shall be very sad :(", + filters: [ + { + field: "Date Field", + operator: "equal", + value: "111:111:111", + typeahead: false + }, + { + field: "Number Field", + operator: "equal", + value: "123 aabc", + typeahead: false + }, + { + field: "Dropdown Field", + operator: "equal", + value: "Red", + typeahead: true + } + + ], + fields: ["Text Field", "Date Field", "Dropdown Field", "Serial"] + }; + + before(() => { + cy.log("login").login(goodUser, goodPassword); + cy.log("update user groups").addUserToDefaultGroup("test@example.com", "check"); + cy.log("setup table permissions"); + const permissionObject: Record = {}; + [ + "Bulk import records", + "Purge deleted records", + "Delete records", + "Bulk delete records", + "Manage views" + ].forEach((permissionName) => { + permissionObject[permissionName] = true; + }); + cy.setTablePermissionsByShortName(table_shortname, permissionObject); + // cy.addUserToDefaultGroup('test@example.com'); + cy.log("create layouts"); + cy.populateTableWithLayouts("my_table_shortname"); + cy.clearImports(table_shortname); + cy.bulkImportRecords(); + cy.clearImports(table_shortname); + cy.logout(); + }); + + beforeEach(() => { + cy.login(goodUser, goodPassword); + cy.gotoInstanceByShortName("table1", "data"); + }); + + afterEach(() => { + cy.log("Deleting view"); + cy.gotoInstanceByShortName("table1", "data") + .get("span").contains("Manage views").click() + .get('a[role="menuitem"]').contains("Edit current view").click() + .get(".btn-js-delete").contains("Delete view").click() + .get('button[type="submit"]').contains("Delete").click(); + }); + + after(() => { + cy.deleteAllData("table1"); + cy.purgeAllDeletedData("table1"); + cy.cleanTableOfLayouts("table1"); + cy.clearAllTablePermissions("table1"); + cy.addUserToDefaultGroup("test@example.com", "uncheck"); + }); + + it("Creates a personal view with all fields then edits with no fileds", () => { + cy.log("Creating a view") + .get("span").contains("Manage views").click() + .get('a[role="menuitem"]').contains("Add a view").click() + .get('input[name="name"]').type(viewDef.name) + .get("span").contains("Fields").click() + + .get('#table-view-fields-selected tbody tr').each(($row) => { + cy.wrap($row).should('have.attr', 'data-field-is-toggled', 'false') + cy.wrap($row).find('input[type="checkbox"]').should('not.be.checked'); + }); + + cy.get('button.btn-js-toggle-all-fields').contains('Select all fields').click(); + + + cy.get('#table-view-fields-selected tbody tr').each(($row) => { + cy.wrap($row).should('have.attr', 'data-field-is-toggled', 'true'); + cy.wrap($row).find('input[type="checkbox"]').should('be.checked'); + }); + + cy.get('button[type="submit"]').contains("Save").click(); + cy.contains("span", "Current view: Test view").should("exist"); + cy.get('thead th').contains('Text Field').should('exist'); + cy.get('thead th').contains('Number Field').should('exist'); + cy.get('thead th').contains('Date Field').should('exist'); + cy.get('thead th').contains('Range Field').should('exist'); + cy.get('thead th').contains('Dropdown Field').should('exist'); + + + + cy.get("span").contains("Manage views").click() + .get('a[role="menuitem"]').contains("Edit current view").click() + .get("span").contains("Fields").click() + .get('#table-view-fields-selected tbody tr').each(($row) => { + cy.wrap($row).should('have.attr', 'data-field-is-toggled', 'true'); + cy.wrap($row).find('input[type="checkbox"]').should('be.checked'); + }); + + cy.get('button.btn-js-toggle-all-fields').contains('Remove all fields').click(); + + cy.get('#table-view-fields-selected tbody tr').each(($row) => { + cy.wrap($row).should('have.attr', 'data-field-is-toggled', 'false') + cy.wrap($row).find('input[type="checkbox"]').should('not.be.checked'); + }); + + cy.get('button[type="submit"]').contains("Save").click(); + cy.get('thead th').contains('ID').should('exist'); + cy.get('thead th').contains('Text Field').should('not.exist'); + cy.get('thead th').contains('Number Field').should('not.exist'); + cy.get('thead th').contains('Date Field').should('not.exist'); + cy.get('thead th').contains('Range Field').should('not.exist'); + cy.get('thead th').contains('Dropdown Field').should('not.exist'); + }); + + it("Creates a personal view with dropdown filter from a typeahead", () => { + cy.log("Creating a view") + .get("span").contains("Manage views").click() + .get('a[role="menuitem"]').contains("Add a view").click() + .get('input[name="name"]').type(viewDef.name) + .get("span").contains("Filter").click() + .get("button").contains("Add rule").click() + .get("div.filter-option-inner-inner").click() + .get('a[role="option"]').contains(viewDef.filters[1].field).click() + .get("div.filter-option-inner-inner").contains("equal").click() + .get('a[role="option"]').contains(viewDef.filters[1].operator).click() + .get("input.tt-input").type( + viewDef.filters[1].typeahead + ? viewDef.filters[1].value.slice(0, 2) + : viewDef.filters[1].value + ) + .get("div.tt-suggestion").contains(viewDef.filters[1].value).click() + .get("span").contains("Fields").click(); + + for (const field of viewDef.fields) { + cy.get("#table-view-fields-available").find("td.check").contains(field).click(); + } + + cy.get('button[type="submit"]').contains("Save").click(); + cy.contains("span", "Current view: Test view").should("exist"); + cy.get("td.dt-empty").should("not.exist"); + }); + + it("Creates a personal with text filter, followed by an edit", () => { + cy.log("Creating a view") + .get("span").contains("Manage views").click() + .get('a[role="menuitem"]').contains("Add a view").click() + .get('input[name="name"]').type(viewDef.name) + .get("span").contains("Filter").click() + .get("button").contains("Add rule").click() + .get("div.filter-option-inner-inner").contains("------").click() + .get(".dropdown-menu.show").last() + .find('a[role="option"]').not('[aria-hidden="true"]').contains(viewDef.filters[0].field).click() + .get('input.form-control[type="text"]').last() + .type(viewDef.filters[0].value); + + + cy.get('button[type="submit"]').contains("Save").click(); + cy.contains("span", "Current view: Test view").should("exist"); + cy.get("td.dt-empty").should("not.exist"); + cy.contains("Showing 1 to 1 of 1 entry").should("be.visible"); + + cy.log("Editing the view to add a filter") + .get("span").contains("Manage views").click() + .get('a[role="menuitem"]').contains("Edit current view").click() + .get("span").contains("Filter").click() + .get("button").contains("Add rule").click() + .get("div.filter-option-inner-inner").contains("------").click() + .get(".dropdown-menu.show").last() + .find('a[role="option"]').not('[aria-hidden="true"]').contains(viewDef.filters[1].field).click() + .get('input.tt-input:visible').last() + .type( + viewDef.filters[1].typeahead + ? viewDef.filters[1].value.slice(0, 2) + : viewDef.filters[1].value + ) + .get("div.tt-suggestion").contains(viewDef.filters[1].value).click() + cy.get('button[type="submit"]').contains("Save").click(); + cy.contains("span", "Current view: Test view").should("exist"); + cy.get("td.dt-empty").should("not.exist"); + cy.contains("Showing 1 to 1 of 1 entry").should("be.visible"); + + cy.log("Editing the view again to add a 3rd filter and fields") + .get("span").contains("Manage views").click() + .get('a[role="menuitem"]').contains("Edit current view").click() + .get("span").contains("Filter").click() + .get("button").contains("Add rule").click() + .get("div.filter-option-inner-inner").contains("------").click() + .get(".dropdown-menu.show").last() + .find('a[role="option"]').not('[aria-hidden="true"]').contains(viewDef.filters[2].field).click() + .get('input.tt-input:visible').last() + .type( + viewDef.filters[2].typeahead + ? viewDef.filters[2].value.slice(0, 1) + : viewDef.filters[2].value + ) + .get("div.tt-suggestion").contains(viewDef.filters[2].value).click() + .get("span").contains("Fields").click(); + + for (const field of viewDef.fields) { + cy.get("#table-view-fields-available").find("td.check").contains(field).click(); + } + + cy.get('button[type="submit"]').contains("Save").click(); + cy.contains("span", "Current view: Test view").should("exist"); + cy.get("td.dt-empty").should("exist"); + cy.contains("Showing 0 to 0 of 0 entries").should("be.visible"); + cy.get('thead th').contains('Date Field').should('exist'); + cy.get('thead th').contains('Text Field').should('exist'); + cy.get('thead th').contains('Dropdown Field'); + }); + + it("Creates a personal view with a ASC sort", () => { + cy.log("Creating a view with ASC serial sort") + .get("span").contains("Manage views").click() + .get('a[role="menuitem"]').contains("Add a view").click() + .get('input[name="name"]').type(viewDef.name) + .get("span").contains("Sort/Group").click() + .get('#btn-sortfield').click() + .get(".dropdown-menu.show").last() + .find('li[role="option"]').contains("Serial").click() + + .get("span").contains("Fields").click(); + for (const field of ErrViewDef.fields) { + cy.get("#table-view-fields-available").find("td.check").contains(field).click(); + } + cy.get('button[type="submit"]').contains("Save").click(); + cy.contains("span", "Current view: Test view").should("exist"); + cy.get("td.dt-empty").should("not.exist") + cy.get('thead th').contains('Serial').should('exist'); + + cy.get('td.sorting_1').then($cells => { + const firstFive = [...$cells].slice(0, 5).map(cell => parseInt(cell.innerText.trim(), 10)); + expect(firstFive).to.deep.equal([1, 2, 3, 4, 5]); + }); + + cy.log("Edit view to DESC serial sort") + cy.gotoInstanceByShortName("table1", "data") + .get("span").contains("Manage views").click() + .get('a[role="menuitem"]').contains("Edit current view").click() + .get("span").contains("Sort/Group").click() + .get('#btn-sorttype').click() + .get('li.select__menu-item[role="option"][data-value="desc"]').contains('Descending').click(); + + cy.get('button[type="submit"]').contains("Save").click(); + cy.contains("span", "Current view: Test view").should("exist"); + cy.get("td.dt-empty").should("not.exist") + cy.get('thead th').contains('Serial').should('exist'); + + cy.get('td.sorting_1').then($cells => { + const firstFive = [...$cells].slice(0, 5).map(cell => parseInt(cell.innerText.trim(), 10)); + const sortedDesc = [...firstFive].sort((a, b) => b - a); + expect(firstFive).to.deep.equal(sortedDesc); + }); + }); + +it("Attempts to create views with errors", () => { + + cy.log("Creating a view with blank name") + .get("span").contains("Manage views").click() + .get('a[role="menuitem"]').contains("Add a view").click() + .get('button[type="submit"]').contains("Save").click() + .get('div.alert.alert-danger[role="alert"]').should('contain', 'ERROR:').and('contain', 'Please enter a name') + + .get('input[name="name"]').type(ErrViewDef.name) + .get('button[type="submit"]').contains("Save").click() + .get('div.alert.alert-danger[role="alert"]').should('contain', 'ERROR:').and('contain', 'View name must be less than 128 characters') + + + // checks for invalid date type error. + cy.log("Attempt to save the view with incorrect date value") + .get('input[name="name"]').clear() + .get('input[name="name"]').type(viewDef.name) + .get("span").contains("Filter").click() + .get("button").contains("Add rule").click() + .get("div.filter-option-inner-inner").contains("------").click() + .get(".dropdown-menu.show").last() + .find('a[role="option"]').not('[aria-hidden="true"]') + .contains(ErrViewDef.filters[0].field).click() + .get('input.form-control[type="text"]').last().type(ErrViewDef.filters[0].value) + .get('button[type="submit"]').contains("Save").click() + .get('div.alert.alert-danger[role="alert"]') + .should('contain', 'ERROR:') + .and('contain', 'Invalid date'); + + // checks for invalid int type error. + cy.log("Attempt to save the view with incorrect int value") + .get("span").contains("Filter").click() + .get("div.filter-option-inner-inner").contains(ErrViewDef.filters[0].field).click() + .get(".dropdown-menu.show") + .find('a[role="option"]').not('[aria-hidden="true"]') + .contains(ErrViewDef.filters[1].field).click() + .get('input.form-control[type="text"]').last().type(ErrViewDef.filters[1].value) + .get('button[type="submit"]').contains("Save").click() + .get('div.alert.alert-danger[role="alert"]').should('contain', 'ERROR:').and('contain', 'not a valid integer'); + + // Finally create a working view to end the erroring test. + cy.log("Attempt to resave the view with correct data types") + .get("span").contains("Filter").click() + .get("div.filter-option-inner-inner").contains(ErrViewDef.filters[1].field).click() + .get(".dropdown-menu.show") + .find('a[role="option"]').not('[aria-hidden="true"]') + .contains(viewDef.filters[3].field).click() + .get('input.form-control[type="text"]').last().clear().type(viewDef.filters[3].value) + .get('button[type="submit"]').contains("Save").click(); + + cy.contains("span", "Current view: Test view").should("exist"); + cy.get("td.dt-empty").should("exist"); + cy.contains("Showing 0 to 0 of 0 entries").should("be.visible"); + }); + +}); diff --git a/cypress/e2e/functionality/11-create-record.cy.ts b/cypress/e2e/functionality/11-create-record.cy.ts new file mode 100644 index 000000000..73cb044b0 --- /dev/null +++ b/cypress/e2e/functionality/11-create-record.cy.ts @@ -0,0 +1,320 @@ +import { LUA } from "../../../src/frontend/js/lib/util/formatters/lua"; +import { LayoutBuilder } from "../../support/builders/layout/LayoutBuilder"; +import { + ICodeLayoutBuilder, + ICurvalLayoutBuilder, + IDropdownLayoutBuilder, + ILayoutBuilder +} from "../../support/builders/layout/interfaces"; +import { goodPassword, goodUser } from "../../support/constants"; + +describe("Record create/edit tests", () => { + const table_shortname = "table1"; + + before(() => { + cy.log("login").login(goodUser, goodPassword); + cy.log("update user groups").addUserToDefaultGroup("test@example.com", "check"); + cy.log("setup table permissions"); + + const permissionObject: Record = {}; + [ + "Purge deleted records", + "Delete records", + "Bulk delete records", + "Manage views" + ].forEach((permissionName) => { + permissionObject[permissionName] = true; + }); + cy.setTablePermissionsByShortName(table_shortname, permissionObject); + cy.addUserToDefaultGroup('test@example.com'); + cy.populateTableWithLayouts("my_table_shortname"); + cy.logout(); + }); + + beforeEach(() => { + cy.login(goodUser, goodPassword); + cy.gotoInstanceByShortName("table1", "data"); + }); + + after(() => { + cy.deleteAllData("table1"); + cy.purgeAllDeletedData("table1"); + cy.cleanTableOfLayouts("table1"); + cy.clearAllTablePermissions("table1"); + cy.addUserToDefaultGroup("test@example.com", "uncheck"); + }); + + it("It should create a record", () => { + cy.contains('a', 'Add a record').click(); + //Add a value to all text fields + cy.get('input[type="text"]:not([data-dateformat-datepicker])') + .each(($input) => { + cy.wrap($input).clear().type('Hello Test'); + }); + + //Add a value to all dates and dateranges + const dateStr = '2222-01-30'; + cy.get('input[data-dateformat-datepicker]') + .each(($input) => { + cy.wrap($input) + .focus() + .type(dateStr, { force: true }) + .blur(); + }); + //Select the first available option in all dropdowns field + cy.get('.linkspace-field[data-column-type="enum"]') + .each(($dropdown) => { + cy.wrap($dropdown) + .find('div.select-widget-dropdown > div.form-control > ul.current') + .click({ force: true }); + cy.wrap($dropdown) + .find('ul.available.select__menu.show label').first() + .then(($label) => { + const optionText = $label.text().trim(); + cy.wrap($dropdown) + .find('input.form-control-search').clear() + .type(optionText, { force: true }); + cy.wrap($dropdown) + .find('ul.available.select__menu.show') + .contains('label', optionText) + .click({ force: true }); + }); + }); + //Add a value to all integer fields + cy.get('input[type="number"]').each(($input) => { + cy.wrap($input).clear().type('111'); + }); + cy.get('button#submit').click(); + }); + + it("It should test for manadatory errors followed by a successful create record", () => { + cy.contains('a', 'Add a record').click(); + //Get how many inputs are required on this form? + cy.get('input[required], input[aria-required="true"], textarea[required], textarea[aria-required="true"]') + .then(($required) => { + const requiredCount = $required.length; + cy.log(`Found ${requiredCount} required controls`); + cy.get('button#submit').click(); + //Same number must now be invalid + cy.get('input:invalid[required], input[aria-invalid="true"], textarea:invalid[required], textarea[aria-invalid="true"]') + .should('have.length', requiredCount); + //Every field should error and should mention "required" + cy.get('.form-text--error:visible') + .each(($msg) => { + cy.wrap($msg).should('contain.text', 'required'); + }); + }); + //Add a value to all text fields + cy.get('input[type="text"]:not([data-dateformat-datepicker])') + .each(($input) => { + cy.wrap($input).clear().type('Hello Test'); + }); + //Add a value to all dates and dateranges + const dateStr = '2222-01-30'; + cy.get('input[data-dateformat-datepicker]') + .each(($input) => { + cy.wrap($input) + .focus() + .type(dateStr, { force: true }) + .blur(); + }); + //Select the first available option in all dropdowns fields + cy.get('.linkspace-field[data-column-type="enum"]') + .each(($dropdown) => { + cy.wrap($dropdown) + .find('div.select-widget-dropdown > div.form-control > ul.current') + .click({ force: true }); + cy.wrap($dropdown) + .find('ul.available.select__menu.show label') + .first() + .then(($label) => { + const optionText = $label.text().trim(); + cy.wrap($dropdown) + .find('input.form-control-search') + .clear() + .type(optionText, { force: true }); + cy.wrap($dropdown) + .find('ul.available.select__menu.show') + .contains('label', optionText) + .click({ force: true }); + }); + }); + //Add a value to all integer fields + cy.get('input[type="number"]').each(($input) => { + cy.wrap($input).clear().type('111'); + }); + //Save record + cy.get('button#submit').click(); + cy.get("td.dt-empty").should("not.exist"); + cy.get('div.alert.alert-success[role="alert"]') + .should('be.visible') + .and('contain.text', "Submission has been completed successfully") + }); + + it("Should show datatype errors and then successfully create a record", () => { + cy.contains('a', 'Add a record').click(); + cy.get('input[type="text"]:not([data-dateformat-datepicker])') + .each(($input) => { + cy.wrap($input).clear().type('hello text'); + }); + + //Add invalid values to all date and date range inputs + const invalidDate = '99/99/9999'; + cy.get('input[data-dateformat-datepicker]') + .each(($input) => { + cy.wrap($input) + .focus() + .type(invalidDate, { force: true }) + .blur(); + }); + + //Select the first option in all dropdown fields + cy.get('.linkspace-field[data-column-type="enum"]') + .each(($dropdown) => { + cy.wrap($dropdown) + .find('div.select-widget-dropdown > div.form-control > ul.current') + .click({ force: true }); + + cy.wrap($dropdown) + .find('ul.available.select__menu.show label') + .first() + .then(($label) => { + const optionText = $label.text().trim(); + cy.wrap($dropdown) + .find('input.form-control-search') + .clear() + .type(optionText, { force: true }); + + cy.wrap($dropdown) + .find('ul.available.select__menu.show') + .contains('label', optionText) + .click({ force: true }); + }); + }); + //Change integer field value + cy.get('input[type="number"]') + .each(($input) => { + cy.wrap($input).clear().type('111'); + }); + + cy.get('button#submit').click(); + cy.get('div.alert.alert-danger[role="alert"]') + .should('be.visible') + .and('contain.text', "Invalid date"); + + //Change the date field value + const validDate = '2222-01-30'; + cy.get('input[data-dateformat-datepicker]') + .each(($input) => { + cy.wrap($input) + .clear() + .focus() + .type(validDate, { force: true }) + .blur(); + }); + + cy.get('button#submit').click(); + cy.get("td.dt-empty").should("not.exist"); + cy.get('div.alert.alert-success[role="alert"]').should('be.visible').and('contain.text', "Submission has been completed successfully"); + }); + + it("Should create/edit draft followed by a save", () => { + cy.contains('a', 'Add a record').click(); + //Add a value to all text fields + cy.get('input[type="text"]:not([data-dateformat-datepicker])') + .each(($input) => { + cy.wrap($input).clear().type('Hello Test'); + }); + //Save as draft + cy.get('button#save-draft').click(); + cy.get('div.alert.alert-success[role="alert"]') + .should('be.visible') + .and('contain.text', 'NOTICE:') + .and('contain.text', 'Draft has been saved successfully'); + + cy.contains('a.btn.btn-add', 'Continue draft record').should('be.visible').click(); + + cy.get('input[type="text"][value="Hello Test"]:not([data-dateformat-datepicker])').should('exist'); + cy.get('button#delete_draft').click(); + + cy.get('div.alert.alert-success[role="alert"]') + .should('be.visible').and('contain.text', 'NOTICE:').and('contain.text', 'Draft has been deleted successfully'); + + cy.contains('a', 'Add a record').click(); + //Add a value to all text fields + cy.get('input[type="text"]:not([data-dateformat-datepicker])') + .each(($input) => { + cy.wrap($input).clear().type('Hello Test'); + }); + //Add a value to all dates and dateranges + const dateStr = '2222-01-30'; + cy.get('input[data-dateformat-datepicker]') + .each(($input) => { + cy.wrap($input) + .focus() + .type(dateStr, { force: true }) + .blur(); + }); + //select the first available option in all dropdowns field + cy.get('.linkspace-field[data-column-type="enum"]') + .each(($dropdown) => { + cy.wrap($dropdown) + .find('div.select-widget-dropdown > div.form-control > ul.current') + .click({ force: true }); + cy.wrap($dropdown) + .find('ul.available.select__menu.show label') + .first() + .then(($label) => { + const optionText = $label.text().trim(); + cy.wrap($dropdown) + .find('input.form-control-search') + .clear() + .type(optionText, { force: true }); + cy.wrap($dropdown) + .find('ul.available.select__menu.show') + .contains('label', optionText) + .click({ force: true }); + }); + }); + //Add a value to all integer fields + cy.get('input[type="number"]').each(($input) => { + cy.wrap($input).clear().type('111'); + }); + //Save record as draft + cy.get('button#save-draft').click(); + cy.get('div.alert.alert-success[role="alert"]') + .should('be.visible') + .and('contain.text', 'NOTICE:') + .and('contain.text', 'Draft has been saved successfully'); + + cy.contains('a.btn.btn-add', 'Continue draft record') + .should('be.visible') + .click(); + + //Save draft as record + cy.get('button#submit').click(); + cy.get("td.dt-empty").should("not.exist"); + cy.get('div.alert.alert-success[role="alert"]') + .should('be.visible') + .and('contain.text', "Submission has been completed successfully"); + }); + + it("It should create a record from a duplicate", () => { + + cy.get('table tbody tr').first().click(); + cy.contains('li.list__item a', 'Duplicate record').click(); + + //Ensure the URL includes clone param 'from=' + cy.url().should('include', 'from='); + + //Check for copied values + cy.get('input[type="text"]').should('have.value', 'Hello Test'); + cy.get('input[type="number"]').should('have.value', '111'); + cy.get('input[data-dateformat-datepicker]').should('have.value', '2222-01-30'); + cy.get('button#submit').click(); + cy.get('.alert.alert-success') + .should('be.visible') + .and('contain.text', 'Submission has been completed successfully'); +}); + +}); diff --git a/cypress/e2e/functionality/12-edit-table.cy.ts b/cypress/e2e/functionality/12-edit-table.cy.ts new file mode 100644 index 000000000..d8361006e --- /dev/null +++ b/cypress/e2e/functionality/12-edit-table.cy.ts @@ -0,0 +1,290 @@ +import { LUA } from "../../../src/frontend/js/lib/util/formatters/lua"; +import { goodPassword, goodUser } from "../../support/constants"; +import { LayoutBuilder } from "../../support/builders/layout/LayoutBuilder"; +import { ICodeLayoutBuilder, ICurvalLayoutBuilder, IDropdownLayoutBuilder, ILayoutBuilder } from "../../support/builders/layout/interfaces"; + + +describe('Edit table feature tests', () => { + const table_shortname = "table1"; + before(() => { + cy.log("login").login(goodUser, goodPassword); + cy.log("update user groups").addUserToDefaultGroup("test@example.com", "check"); + cy.log("setup table permissions"); + const permissionObject: Record = {}; + [ + "Bulk import records", + "Purge deleted records", + "Delete records", + "Bulk delete records", + "Manage views" + ].forEach((permissionName) => { + permissionObject[permissionName] = true; + }); + cy.setTablePermissionsByShortName(table_shortname, permissionObject); + cy.addUserToDefaultGroup('test@example.com'); + cy.log("create layouts"); + cy.populateTableWithLayouts("my_table_shortname"); + + const builder: ICodeLayoutBuilder = LayoutBuilder.create("RAG") as ICodeLayoutBuilder; + builder + .withName("test1") + .withShortName("t1") + .withCode(LUA`function evaluate(txt_fd) + return "red"; + end + `); + + cy.createLayout(builder, true); + cy.clearImports(table_shortname); + cy.bulkImportRecords(); + cy.clearImports(table_shortname); + cy.logout(); + }); + + beforeEach(() => { + cy.loginAndGoTo(goodUser, goodPassword, 'http://localhost:3000/table'); + cy.location("pathname").should("include", "/table"); + }); + + after(() => { + cy.deleteAllData("table1"); + cy.purgeAllDeletedData("table1"); + cy.deleteLayoutByShortName("t1", true); + cy.cleanTableOfLayouts("table1"); + cy.clearAllTablePermissions("table1"); + cy.addUserToDefaultGroup("test@example.com", "uncheck"); + }); + + context('Tests editing table shortname', () => { + it('error invalid table shortnames', () => { + cy.visit('http://localhost:3000/table1/edit'); + cy.get('input#name_short').click().clear().type('test/'); + cy.contains('button', 'Save').click(); + cy.location("pathname").should("include", "/table1"); + cy.get('.alert.alert-danger').should('be.visible').and('contain.text', 'Invalid short name') + + cy.get('input#name_short').click().clear().type('test%'); + cy.contains('button', 'Save').click(); + cy.location("pathname").should("include", "/table1"); + cy.get('.alert.alert-danger').should('be.visible').and('contain.text', 'Invalid short name') + + cy.get('input#name_short').click().clear().type('test test'); + cy.contains('button', 'Save').click(); + cy.location("pathname").should("include", "/table1"); + cy.get('.alert.alert-danger').should('be.visible').and('contain.text', 'Invalid short name') + + // Known Issue: shouldn't allow existing keywords but does so test commented out. + //cy.get('input#name_short').click().clear().type('myaccount'); + //cy.contains('button', 'Save').click(); + //cy.location("pathname").should("include", "/table1"); + //cy.get('.alert.alert-danger').should('be.visible').and('contain.text', 'Invalid short name') + + cy.get('input#name_short').click().clear().type('THIS_IS_A_VERY_LONG_SHORTNAME_AND_ALTHOUGH_ON_THE_SURFACE_THIS_IS_PROBABLY_NOT_GOING_TO_CAUSE_ANY_ISSUES_IT_SHOULD_STILL_BE_RESTRICTED_TO_FIXED_SIZE_IN_ORDER_TO_PREVENT_ANY_UNEXPECTED_BEHAVIOIR_IN_THE_FUTURE'); + cy.contains('button', 'Save').click(); + cy.location("pathname").should("include", "/table1"); + //Currently a Panic error. + //cy.get('.alert.alert-danger').should('be.visible').and('contain.text', 'Invalid short name') + }); + + it('Should save a valid shortname', () => { + cy.visit('http://localhost:3000/table1/edit'); + cy.get('input#name_short').click().clear().type('Finally_A_Normal_Name'); + cy.contains('button', 'Save').click(); + cy.location("pathname").should("include", "/Finally_A_Normal_Name"); + cy.get('.alert.alert-success').should('be.visible').and('contain.text', 'The table has been updated successfully') + + cy.get('input#name_short').click().clear(); + cy.contains('button', 'Save').click(); + cy.location("pathname").should("include", "/table1"); + cy.get('.alert.alert-success').should('be.visible').and('contain.text', 'The table has been updated successfully') + }); + }); + + context('Tests editing table sort order', () => { + it('add and edit sorting', () => { + cy.visit('http://localhost:3000/table1/edit'); + cy.get('#btn-sort_type').click() + + cy.get('#btn-sort_layout_id').click(); + cy.get('li.select__menu-item') + .contains('Serial').click() + cy.get('#btn-sort_type').click() + .get('li.select__menu-item[role="option"][data-value="desc"]').contains('Descending').click(); + cy.contains('button', 'Save').click(); + cy.visit('http://localhost:3000/table1/data'); + cy.get('td.sorting_1').then($cells => { + const firstFive = [...$cells].slice(0, 5).map(cell => parseInt(cell.innerText.trim(), 10)); + const sortedDesc = [...firstFive].sort((a, b) => b - a); + expect(firstFive).to.deep.equal(sortedDesc); + }); + + cy.clearLocalStorage(); + cy.visit('http://localhost:3000/table1/edit'); + cy.get('#btn-sort_type').click() + .get('li.select__menu-item[role="option"][data-value="asc"]').contains('Ascending').click(); + cy.contains('button', 'Save').click(); + cy.visit('http://localhost:3000/table1/data'); + cy.get('td.sorting_1').then($cells => { + const firstFive = [...$cells].slice(0, 5).map(cell => parseInt(cell.innerText.trim(), 10)); + const sortedAsc = [...firstFive].sort((a, b) => a - b); + expect(firstFive).to.deep.equal(sortedAsc); + }); + + //Set back to defaults + cy.visit('http://localhost:3000/table1/edit'); + cy.get('#btn-sort_layout_id').click(); + cy.get('li.select__menu-item') + .contains('Select default sort').click() + cy.get('#btn-sort_type').click() + cy.get('li.select__menu-item[role="option"][data-value=""]').contains('Select default sort direction').click(); + cy.contains('button', 'Save').click(); + }); + }); + + context('Tests editing table RAG labels', () => { + it('Should update RAG values', () => { + cy.visit('http://localhost:3000/table1/edit'); + cy.get('[data-target="#ragFieldDefinitions"]').first().click(); + + cy.get('fieldset[data-name="ragFieldDefinitionOptions"] input[type="checkbox"]') + .each(($el) => { + cy.wrap($el).check({ force: true }).should('be.checked'); + }); + + const dangerVal = "!$_ %&*+"; + const warningVal = "