From 32ef3753b2cf004598a464ad465a49f693607be3 Mon Sep 17 00:00:00 2001 From: br0kenpixel <23280129+br0kenpixel@users.noreply.github.com> Date: Mon, 17 Nov 2025 17:07:58 +0100 Subject: [PATCH] feat: add custom command to validate table columns in e2e tests --- .../cypress/e2e/admin/students/list.cy.ts | 68 +++++-------------- frontend/cypress/support/commands.ts | 24 ++++--- frontend/cypress/support/index.d.ts | 13 ++++ 3 files changed, 42 insertions(+), 63 deletions(-) create mode 100644 frontend/cypress/support/index.d.ts diff --git a/frontend/cypress/e2e/admin/students/list.cy.ts b/frontend/cypress/e2e/admin/students/list.cy.ts index a01641d..2a76d6e 100644 --- a/frontend/cypress/e2e/admin/students/list.cy.ts +++ b/frontend/cypress/e2e/admin/students/list.cy.ts @@ -16,68 +16,32 @@ describe('Admin Student CRUD', () => { it('should load the list of students in a proper format', () => { cy.get('table').within(() => { - cy.contains('th', 'Meno').parent('tr').then(($headerRow) => { - const nameColumnIndex = $headerRow.find('th').index(cy.$$('th:contains("Meno")')[0]) - - cy.get('tbody tr').each(($row) => { - cy.wrap($row).find('td').eq(nameColumnIndex).invoke('text').then((name) => { - const nameParts = name.trim().split(' ') - expect(nameParts).to.have.length.at.least(2) - expect(nameParts[0]).to.not.be.empty - expect(nameParts[1]).to.not.be.empty - }) - }) + cy.validateColumn('Meno', (name) => { + const nameParts = name.trim().split(' ') + expect(nameParts).to.have.length.at.least(2) + expect(nameParts[0]).to.not.be.empty + expect(nameParts[1]).to.not.be.empty }) - cy.contains('th', 'E-mail').parent('tr').then(($headerRow) => { - const nameColumnIndex = $headerRow.find('th').index(cy.$$('th:contains("E-mail")')[0]) - - cy.get('tbody tr').each(($row) => { - cy.wrap($row).find('td').eq(nameColumnIndex).invoke('text').then((email) => { - expect(email).to.include("@student.ukf.sk") - }) - }) + cy.validateColumn('E-mail', (email) => { + expect(email).to.include("@student.ukf.sk") }) - cy.contains('th', 'Telefón').parent('tr').then(($headerRow) => { - const phoneColumnIndex = $headerRow.find('th').index(cy.$$('th:contains("Telefón")')[0]) - - cy.get('tbody tr').each(($row) => { - cy.wrap($row).find('td').eq(phoneColumnIndex).invoke('text').then((phone) => { - expect(phone.trim()).to.not.be.empty - }) - }) + cy.validateColumn('Telefón', (phone) => { + expect(phone.trim()).to.not.be.empty }) - cy.contains('th', 'Študijný program').parent('tr').then(($headerRow) => { - const programColumnIndex = $headerRow.find('th').index(cy.$$('th:contains("Študijný program")')[0]) - - cy.get('tbody tr').each(($row) => { - cy.wrap($row).find('td').eq(programColumnIndex).invoke('text').then((program) => { - expect(program.trim()).to.not.be.empty - }) - }) + cy.validateColumn('Študijný program', (program) => { + expect(program.trim()).to.not.be.empty }) - cy.contains('th', 'Osobný e-mail').parent('tr').then(($headerRow) => { - const personalEmailColumnIndex = $headerRow.find('th').index(cy.$$('th:contains("Osobný e-mail")')[0]) - - cy.get('tbody tr').each(($row) => { - cy.wrap($row).find('td').eq(personalEmailColumnIndex).invoke('text').then((personalEmail) => { - expect(personalEmail.trim()).to.not.be.empty - expect(personalEmail.trim()).to.include("@") - }) - }) + cy.validateColumn('Osobný e-mail', (personalEmail) => { + expect(personalEmail.trim()).to.not.be.empty + expect(personalEmail.trim()).to.include("@") }) - cy.contains('th', 'Adresa').parent('tr').then(($headerRow) => { - const addressColumnIndex = $headerRow.find('th').index(cy.$$('th:contains("Adresa")')[0]) - - cy.get('tbody tr').each(($row) => { - cy.wrap($row).find('td').eq(addressColumnIndex).invoke('text').then((address) => { - expect(address.trim()).to.not.be.empty - }) - }) + cy.validateColumn('Adresa', (address) => { + expect(address.trim()).to.not.be.empty }) }) }) diff --git a/frontend/cypress/support/commands.ts b/frontend/cypress/support/commands.ts index 698b01a..af644e1 100644 --- a/frontend/cypress/support/commands.ts +++ b/frontend/cypress/support/commands.ts @@ -24,14 +24,16 @@ // // -- This will overwrite an existing command -- // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) -// -// declare global { -// namespace Cypress { -// interface Chainable { -// login(email: string, password: string): Chainable -// drag(subject: string, options?: Partial): Chainable -// dismiss(subject: string, options?: Partial): Chainable -// visit(originalFn: CommandOriginalFn, url: string, options: Partial): Chainable -// } -// } -// } \ No newline at end of file + +// Custom command to validate table columns +Cypress.Commands.add('validateColumn', (columnName: string, validator: (value: string) => void) => { + cy.contains('th', columnName).parent('tr').then(($headerRow) => { + const colIndex = $headerRow.find('th').index(cy.$$(`th:contains("${columnName}")`)[0]) + + cy.get('tbody tr').each(($row) => { + cy.wrap($row).find('td').eq(colIndex).invoke('text').then((cellText) => { + validator(cellText as string) + }) + }) + }) +}) \ No newline at end of file diff --git a/frontend/cypress/support/index.d.ts b/frontend/cypress/support/index.d.ts new file mode 100644 index 0000000..496adf3 --- /dev/null +++ b/frontend/cypress/support/index.d.ts @@ -0,0 +1,13 @@ +/// + +declare namespace Cypress { + interface Chainable { + /** + * Custom command to validate all cells in a table column + * @param columnName - The name of the column header to validate + * @param validator - A function that receives the cell text and performs assertions + * @example cy.validateColumn('Email', (email) => { expect(email).to.include('@') }) + */ + validateColumn(columnName: string, validator: (value: string) => void): Chainable + } +}