diff --git a/e2e/helpers/extensions.js b/e2e/helpers/extensions.js index b02bff31c..2b53d88b2 100644 --- a/e2e/helpers/extensions.js +++ b/e2e/helpers/extensions.js @@ -93,8 +93,11 @@ let actions = { }, selectModule: function(moduleName, done) { + let snakeName = moduleName.replace(/[\w]([A-Z])/g, m => { + return m[0] + '-' + m[1]; + }).toLowerCase(); this.waitToClick(`vn-home a[ui-sref="${moduleName}.index"]`) - .waitForURL(moduleName) + .waitForURL(snakeName) .then(done) .catch(done); }, diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index 45b1e0398..908c22d68 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -7,6 +7,7 @@ export default { clientsButton: 'vn-main-menu [vn-id="apps-menu"] ul > li[ui-sref="client.index"]', itemsButton: 'vn-main-menu [vn-id="apps-menu"] ul > li[ui-sref="item.index"]', ticketsButton: 'vn-main-menu [vn-id="apps-menu"] ul > li[ui-sref="ticket.index"]', + invoiceOutButton: 'vn-main-menu [vn-id="apps-menu"] ul > li[ui-sref="invoiceOut.index"]', claimsButton: 'vn-main-menu [vn-id="apps-menu"] ul > li[ui-sref="claim.index"]', returnToModuleIndexButton: `a[translate-attr="{title: 'Return to module index'}"]`, userMenuButton: 'vn-topbar #user', @@ -304,10 +305,13 @@ export default { invoiceOutRef: 'vn-ticket-summary > vn-card > div > vn-horizontal > vn-one:nth-child(1) > vn-label-value:nth-child(6) > section > span' }, ticketsIndex: { + openAdvancedSearchButton: 'vn-ticket-index vn-searchbar t-right-icons > vn-icon[icon="keyboard_arrow_down"]', + advancedSearchInvoiceOut: 'vn-ticket-index vn-searchbar vn-ticket-search-panel vn-textfield[model="filter.refFk"] input', newTicketButton: 'vn-ticket-index > a', searchResult: 'vn-ticket-index vn-card > div > vn-table > div > vn-tbody > a.vn-tr', searchResultDate: 'vn-ticket-index vn-table vn-tbody > a:nth-child(1) > vn-td:nth-child(5)', searchTicketInput: `vn-ticket-index ${components.vnTextfield}`, + advancedSearchButton: 'vn-ticket-index vn-searchbar > vn-popover vn-ticket-search-panel vn-submit[label="Search"] input', searchButton: 'vn-ticket-index vn-searchbar vn-icon[icon="search"]', moreMenu: 'vn-ticket-index vn-icon-menu[vn-id="more-button"] > div > vn-icon', moreMenuTurns: 'vn-ticket-index vn-icon-menu vn-drop-down > vn-popover li:nth-child(2)', @@ -641,5 +645,21 @@ export default { weekWorkedHours: 'vn-worker-time-control > div > vn-side-menu > div > vn-vertical > vn-vertical > vn-label-value > section > span', nextMonthButton: 'vn-worker-time-control > div > vn-side-menu > div > vn-calendar > div > vn-horizontal > vn-auto:nth-child(3) > vn-icon', navigateBackToIndex: 'vn-worker-descriptor vn-icon[icon="chevron_left"]' + }, + invoiceOutIndex: { + searchInvoiceOutInput: `vn-invoice-out-index ${components.vnTextfield}`, + searchButton: 'vn-invoice-out-index vn-searchbar vn-icon[icon="search"]', + searchResult: 'vn-invoice-out-index vn-card > div > vn-table > div > vn-tbody > a.vn-tr', + }, + invoiceOutDescriptor: { + moreMenu: 'vn-invoice-out-descriptor vn-icon-menu[vn-id="more-button"]', + moreMenuDeleteInvoiceOut: 'vn-invoice-out-descriptor vn-popover li[name="Delete Invoice"]', + moreMenuBookInvoiceOut: 'vn-invoice-out-descriptor vn-popover li[name="Book invoice"]', + moreMenuShowInvoiceOutPdf: 'vn-invoice-out-descriptor vn-popover li[name="Show invoice PDF"]', + acceptDeleteButton: 'vn-invoice-out-descriptor > vn-confirm[vn-id="deleteConfirmation"] button[response="ACCEPT"]', + acceptBookingButton: 'vn-invoice-out-descriptor > vn-confirm[vn-id="bookConfirmation"] button[response="ACCEPT"]' + }, + invoiceOutSummary: { + bookedLabel: 'vn-invoice-out-summary > vn-card > div > vn-horizontal > vn-one > vn-label-value:nth-child(4) > section > span' } }; diff --git a/e2e/paths/09-invoice-out-module/01_descriptor.spec.js b/e2e/paths/09-invoice-out-module/01_descriptor.spec.js new file mode 100644 index 000000000..fd3e4b24e --- /dev/null +++ b/e2e/paths/09-invoice-out-module/01_descriptor.spec.js @@ -0,0 +1,183 @@ +import selectors from '../../helpers/selectors.js'; +import createNightmare from '../../helpers/nightmare'; + +describe('InvoiceOut descriptor path', () => { + const nightmare = createNightmare(); + + describe('as Administrative', () => { + beforeAll(() => { + nightmare + .loginAndModule('administrative', 'ticket'); + }); + + it('should search for tickets with an specific invoiceOut', async() => { + const result = await nightmare + .waitToClick(selectors.ticketsIndex.openAdvancedSearchButton) + .write(selectors.ticketsIndex.advancedSearchInvoiceOut, 'T2222222') + .waitToClick(selectors.ticketsIndex.advancedSearchButton) + .waitForNumberOfElements(selectors.ticketsIndex.searchResult, 2) + .countElement(selectors.ticketsIndex.searchResult); + + expect(result).toEqual(2); + }); + + it('should navigate to the invoiceOut index', async() => { + const url = await nightmare + .waitToClick(selectors.globalItems.applicationsMenuButton) + .wait(selectors.globalItems.applicationsMenuVisible) + .waitToClick(selectors.globalItems.invoiceOutButton) + .wait(selectors.invoiceOutIndex.searchInvoiceOutInput) + .parsedUrl(); + + expect(url.hash).toEqual('#!/invoice-out/index'); + }); + + it('should search for the target invoiceOut', async() => { + const result = await nightmare + .write(selectors.invoiceOutIndex.searchInvoiceOutInput, 'T2222222') + .waitToClick(selectors.invoiceOutIndex.searchButton) + .waitForNumberOfElements(selectors.invoiceOutIndex.searchResult, 1) + .countElement(selectors.invoiceOutIndex.searchResult); + + expect(result).toEqual(1); + }); + + it(`should click on the search result to access to the invoiceOut summary`, async() => { + const url = await nightmare + .waitForTextInElement(selectors.invoiceOutIndex.searchResult, 'T2222222') + .waitToClick(selectors.invoiceOutIndex.searchResult) + .waitForURL('/summary') + .parsedUrl(); + + expect(url.hash).toContain('/summary'); + }); + + it('should delete the invoiceOut using the descriptor more menu', async() => { + const result = await nightmare + .waitToClick(selectors.invoiceOutDescriptor.moreMenu) + .waitToClick(selectors.invoiceOutDescriptor.moreMenuDeleteInvoiceOut) + .waitToClick(selectors.invoiceOutDescriptor.acceptDeleteButton) + .waitForLastSnackbar(); + + expect(result).toEqual('InvoiceOut deleted'); + }); + + it('should have been relocated to the invoiceOut index', async() => { + const url = await nightmare + .parsedUrl(); + + expect(url.hash).toEqual('#!/invoice-out/index'); + }); + + it(`should search for the deleted invouceOut to find no results`, async() => { + const result = await nightmare + .write(selectors.invoiceOutIndex.searchInvoiceOutInput, 'T2222222') + .waitToClick(selectors.invoiceOutIndex.searchButton) + .waitForNumberOfElements(selectors.invoiceOutIndex.searchResult, 0) + .countElement(selectors.invoiceOutIndex.searchResult); + + expect(result).toEqual(0); + }); + + it('should navigate to the ticket index', async() => { + const url = await nightmare + .waitToClick(selectors.globalItems.applicationsMenuButton) + .wait(selectors.globalItems.applicationsMenuVisible) + .waitToClick(selectors.globalItems.ticketsButton) + .wait(selectors.ticketsIndex.searchTicketInput) + .parsedUrl(); + + expect(url.hash).toEqual('#!/ticket/index'); + }); + + it('should search for tickets with an specific invoiceOut to find no results', async() => { + const result = await nightmare + .waitToClick(selectors.ticketsIndex.openAdvancedSearchButton) + .write(selectors.ticketsIndex.advancedSearchInvoiceOut, 'T2222222') + .waitToClick(selectors.ticketsIndex.advancedSearchButton) + .waitForNumberOfElements(selectors.ticketsIndex.searchResult, 0) + .countElement(selectors.ticketsIndex.searchResult); + + expect(result).toEqual(0); + }); + + it('should now navigate to the invoiceOut index', async() => { + const url = await nightmare + .waitToClick(selectors.globalItems.applicationsMenuButton) + .wait(selectors.globalItems.applicationsMenuVisible) + .waitToClick(selectors.globalItems.invoiceOutButton) + .wait(selectors.invoiceOutIndex.searchInvoiceOutInput) + .parsedUrl(); + + expect(url.hash).toEqual('#!/invoice-out/index'); + }); + + it('should search for a new target invoiceOut', async() => { + const result = await nightmare + .write(selectors.invoiceOutIndex.searchInvoiceOutInput, 'A1111111') + .waitToClick(selectors.invoiceOutIndex.searchButton) + .waitForNumberOfElements(selectors.invoiceOutIndex.searchResult, 1) + .countElement(selectors.invoiceOutIndex.searchResult); + + expect(result).toEqual(1); + }); + + it(`should now click on the search result to access to the invoiceOut summary`, async() => { + const url = await nightmare + .waitForTextInElement(selectors.invoiceOutIndex.searchResult, 'A1111111') + .waitToClick(selectors.invoiceOutIndex.searchResult) + .waitForURL('/summary') + .parsedUrl(); + + expect(url.hash).toContain('/summary'); + }); + + it(`should check the invoiceOut isn't booked yet in the summary data`, async() => { + const result = await nightmare + .waitToGetProperty(selectors.invoiceOutSummary.bookedLabel, 'innerText'); + + expect(result).toEqual('-'); + }); + + it('should book the invoiceOut using the descriptor more menu', async() => { + const result = await nightmare + .waitToClick(selectors.invoiceOutDescriptor.moreMenu) + .waitToClick(selectors.invoiceOutDescriptor.moreMenuBookInvoiceOut) + .waitToClick(selectors.invoiceOutDescriptor.acceptBookingButton) + .waitForLastSnackbar(); + + expect(result).toEqual('InvoiceOut booked'); + }); + + it(`should check the invoiceOut booked in the summary data`, async() => { + const result = await nightmare + .waitToGetProperty(selectors.invoiceOutSummary.bookedLabel, 'innerText'); + + expect(result.length).toBeGreaterThan(1); + }); + }); + + describe('as salesPerson', () => { + beforeAll(() => { + nightmare + .loginAndModule('salesPerson', 'invoiceOut') + .accessToSearchResult('A1111111'); + }); + + it(`should check the salesPerson role doens't see the book option in the more menu`, async() => { + const result = await nightmare + .waitToClick(selectors.invoiceOutDescriptor.moreMenu) + .wait(selectors.invoiceOutDescriptor.moreMenuShowInvoiceOutPdf) + .exists(selectors.invoiceOutDescriptor.moreMenuBookInvoiceOut); + + expect(result).toBeFalsy(); + }); + + it(`should check the salesPerson role doens't see the delete option in the more menu`, async() => { + const result = await nightmare + .exists(selectors.invoiceOutDescriptor.moreMenuDeleteInvoiceOut); + + expect(result).toBeFalsy(); + }); + }); +});