const username = Cypress.env('username') const password = Cypress.env('password') const hostUrl = Cypress.env('hosturl') const appLocation = Cypress.env('appLocation') const longerCommandTimeout = Cypress.env('longerCommandTimeout') const serverType = Cypress.env('serverType') const libraryToOpenIncludes = Cypress.env(`libraryToOpenIncludes_${serverType}`) const fixturePath = 'excels_general/' context('editor tests: ', function () { this.beforeAll(() => { cy.visit(`${hostUrl}/SASLogon/logout`) cy.loginAndUpdateValidKey() }) this.beforeEach(() => { cy.visit(hostUrl + appLocation) visitPage('home') }) it('1 | Submits duplicate primary keys', (done) => { openTableFromTree(libraryToOpenIncludes, 'mpe_datadictionary') attachExcelFile('MPE_DATADICTIONARY_duplicate_keys.xlsx', () => { clickOnUploadPreview(() => { confirmEditPreviewFile(() => { submitTable(() => { cy.get('.modal-body').then((modalBody: any) => { if (modalBody[0].innerText.includes(`Duplicates found:`)) { done() } }) }) }) }) }) }) it('2 | Submits null cells which must not be null', (done) => { openTableFromTree(libraryToOpenIncludes, 'mpe_x_test') clickOnEdit(() => { cy.get('.btn.btn-sm.btn-icon.btn-outline-danger', { timeout: longerCommandTimeout }).then(() => { cy.get('.ht_master tbody tr').then((rows: any) => { cy.get(rows[1].childNodes[2]) .dblclick({ force: true }) .then(() => { cy.focused() .clear() .type('{enter}') .then(() => { submitTable(() => { cy.get('.modal-body').then((modalBody: any) => { if ( modalBody[0].innerHTML .toLowerCase() .includes(`invalid values are present`) ) { done() } }) }) }) }) }) }) }) }) it('3 | Gets basic dynamic cell validation', () => { openTableFromTree(libraryToOpenIncludes, 'mpe_x_test') clickOnEdit(() => { cy.get('.btn.btn-sm.btn-icon.btn-outline-danger', { timeout: longerCommandTimeout }).then(() => { cy.get('.ht_master tbody tr').then((rows: any) => { cy.get(rows[1].childNodes[5]) .click({ force: true }) .then(($td) => { cy.get('.htAutocompleteArrow', { withinSubject: $td }).should( 'exist' ) }) }) }) }) }) it('4 | Gets advanced dynamic cell validation', () => { openTableFromTree(libraryToOpenIncludes, 'mpe_tables') clickOnEdit(() => { cy.get('.btn.btn-sm.btn-icon.btn-outline-danger', { timeout: longerCommandTimeout }).then(() => { cy.get('.ht_master tbody tr').then((rows: any) => { cy.get(rows[1].childNodes[3]) .click({ force: true }) .then(($td) => { cy.get('.htAutocompleteArrow', { withinSubject: $td }).should( 'exist' ) cy.get('.htAutocompleteArrow', { withinSubject: rows[1].childNodes[7] }).should('exist') cy.get('.htAutocompleteArrow', { withinSubject: rows[1].childNodes[8] }).should('exist') }) }) }) }) }) // An invalid cell shouldn't block submission if its row // is marked for delete it('5 | Submits a delete-marked row with an invalid cell', (done) => { openTableFromTree(libraryToOpenIncludes, 'mpe_x_test') clickOnEdit(() => { cy.get('.btn.btn-sm.btn-icon.btn-outline-danger', { timeout: longerCommandTimeout }).then(() => { cy.get('.ht_master tbody tr').then((rows: any) => { // childNodes[5] = SOME_NUM (numeric) — feed it a non-numeric value // to trigger HOT's native invalid mark. cy.get(rows[1].childNodes[5]) .dblclick({ force: true }) .then(() => { cy.focused() .clear() .type('not a number{enter}') .then(() => { // childNodes[1] = _____DELETE__THIS__RECORD_____ setDeleteFlag(rows[1].childNodes[1], 'Yes', () => { submitTable(() => { // Validation passed despite the invalid SOME_NUM cell: // the confirm-submit modal's Submit button is enabled // (validationDone === 1), not the "invalid values" abort. cy.get('#submitBtn', { timeout: longerCommandTimeout }) .should('exist') .should('not.be.disabled') .then(() => done()) }) }) }) }) }) }) }) }) // The delete exemption must not affect the uniqueness (primary key) check. it('6 | Still blocks a duplicate primary key even on a delete-marked row', (done) => { openTableFromTree(libraryToOpenIncludes, 'mpe_x_test') clickOnEdit(() => { cy.get('.btn.btn-sm.btn-icon.btn-outline-danger', { timeout: longerCommandTimeout }).then(() => { cy.get('.ht_master tbody tr').then((rows: any) => { cy.get(rows[0].childNodes[2]).then((firstPk) => { const duplicateValue = firstPk.text() // childNodes[2] = PRIMARY_KEY_FIELD cy.get(rows[1].childNodes[2]) .dblclick({ force: true }) .then(() => { cy.focused() .clear() .type(`${duplicateValue}{enter}`) .then(() => { setDeleteFlag(rows[1].childNodes[1], 'Yes', () => { submitTable() cy.get('.duplicate-keys-modal', { timeout: longerCommandTimeout }) .should('exist') .then(() => done()) }) }) }) }) }) }) }) }) }) // Opens the _____DELETE__THIS__RECORD_____ dropdown editor on the given cell // and picks the given choice ('Yes'/'No') — same technique as // coltype-delete-record.cy.ts (arrow -> autocompleteEditor choice list). const setDeleteFlag = ( deleteCell: any, value: 'Yes' | 'No', callback?: any ) => { cy.get(deleteCell) .click({ force: true }) .then(($td) => { cy.get('.htAutocompleteArrow', { withinSubject: $td }) .should('exist') .click({ force: true }) cy.get('.autocompleteEditor .htCore tbody td') .contains(value) .click({ force: true }) .then(() => { if (callback) callback() }) }) } const clickOnEdit = (callback?: any) => { cy.get('.btnCtrl button.btn-primary', { timeout: longerCommandTimeout }) .click() .then(() => { if (callback) callback() }) } const openTableFromTree = (libNameIncludes: string, tablename: string) => { cy.get('.app-loading', { timeout: longerCommandTimeout }) .should('not.exist') .then(() => { cy.get('.nav-tree clr-tree > clr-tree-node', { timeout: longerCommandTimeout }).then((treeNodes: any) => { let viyaLib for (let node of treeNodes) { if (node.innerText.toLowerCase().includes(libNameIncludes)) { viyaLib = node break } } cy.get(viyaLib).within(() => { cy.get('.clr-tree-node-content-container > button').click() cy.get('.clr-treenode-link').then((innerNodes: any) => { for (let innerNode of innerNodes) { if (innerNode.innerText.toLowerCase().includes(tablename)) { innerNode.click() break } } }) }) }) }) } const attachExcelFile = (excelFilename: string, callback?: any) => { cy.get('.buttonBar button:last-child') .click() .then(() => { cy.get('input[type="file"]#file-upload') .attachFile(`/${fixturePath}/${excelFilename}`) .then(() => { cy.get('.modal-footer .btn.btn-primary').then((modalBtn) => { modalBtn.click() if (callback) callback() }) }) }) } const clickOnUploadPreview = (callback?: any) => { cy.get('.buttonBar button.btn-primary.btn-upload-preview') .click() .then(() => { if (callback) callback() }) } const confirmEditPreviewFile = (callback?: any) => { cy.get('.modal-footer button.btn-success-outline') .click() .then(() => { if (callback) callback() }) } const submitTable = (callback?: any) => { cy.get('.btnCtrl button.btn-primary') .click() .then(() => { if (callback) callback() }) } const submitTableMessage = (callback?: any) => { cy.get('.modal-footer .btn.btn-sm.btn-success-outline') .click() .then(() => { if (callback) callback() }) } const submitExcel = (callback?: any) => { cy.get('.buttonBar button.preview-submit') .click() .then(() => { if (callback) callback() }) } const rejectExcel = (callback?: any) => { cy.get('button', { timeout: longerCommandTimeout }) .should('contain', 'Approve') .then((allButtons: any) => { for (let approvalButton of allButtons) { if (approvalButton.innerText.toLowerCase().includes('approve')) { approvalButton.click() break } } cy.get('button.btn-danger') .should('exist') .should('not.be.disabled') .click() .then(() => { cy.get('.modal-footer button.btn-success-outline') .click() .then(() => { cy.get('app-history') .should('exist') .then(() => { if (callback) callback() }) }) }) }) } const visitPage = (url: string) => { cy.visit(`${hostUrl}${appLocation}/#/${url}`) }