diff --git a/cypress/e2e/list.feature b/cypress/e2e/list.feature index e079700..a9318e5 100644 --- a/cypress/e2e/list.feature +++ b/cypress/e2e/list.feature @@ -1,5 +1,6 @@ @logged_in Feature: List management + Scenario: I can create a list When I create a list called 'test list' Then I should see list 'test list' diff --git a/cypress/e2e/reminder.feature b/cypress/e2e/reminder.feature index 79dd904..c1e0ce9 100644 --- a/cypress/e2e/reminder.feature +++ b/cypress/e2e/reminder.feature @@ -1,19 +1,25 @@ -@logged_in +@logged_in @has_list_with_reminders Feature: Reminders management - Scenario: I can check reminder - When I create a list called 'test list' - Then I should see list 'test list' - And I should see reminders for 'test list' + Scenario: I can check a reminder + Given I select the list with reminders + When I check the reminder number 2 + Then I should see the reminder number 2 checked - Scenario: I can rename a list - Given I have a list called 'test list' - When I rename the list to 'test list with new name' - Then I should see list 'test list with new name' - And I should see reminders for 'test list with new name' - And I should not see list 'test list' + When I check the reminder number 3 + Then I should see the reminder number 3 checked - Scenario: I can delete a list - Given I have a list called 'test list' - When I delete the list 'test list' - Then I should not see list 'test list' - And I should not see reminders for 'test list' \ No newline at end of file + When I check the reminder number 2 + Then I should see the reminder number 2 unchecked + + Scenario: I can create a reminder + When I create a reminder called 'test list' + Then I should see the reminder 'test list' + + Scenario: I can rename a reminder + When I rename the reminder number 1 to 'test reminder with new name' + Then I should see the reminder 'test reminder with new name' + And I should not see reminder with old name + + Scenario: I can delete a reminder + When I delete the reminder number 1 + Then I should not see reminder number 1 diff --git a/cypress/support/step_definitions/hooks.ts b/cypress/support/step_definitions/hooks.ts index 2ff9db3..01d4281 100644 --- a/cypress/support/step_definitions/hooks.ts +++ b/cypress/support/step_definitions/hooks.ts @@ -1,39 +1,49 @@ import { After, Before, Step } from '@badeball/cypress-cucumber-preprocessor'; -Before({ tags: "@logged_in" }, function() { + +Before({ tags: '@logged_in'}, function() { Step(this, "I should be logged in as 'pythonista'"); }); +Before({ tags: '@has_list_with_reminders' }, function() { + Step(this, 'I have 1 lists with 3 reminders'); + cy.then(() => this.listWithReminders = this.lists[0]); + Step(this, 'I select the list number 1'); + +}); + // Note: this is not working after failed scenarios // https://github.com/badeball/cypress-cucumber-preprocessor/issues/824#issuecomment-1561492281 -After({ tags: "@logged_in" }, function() { - const lists = []; +After({ tags: '@logged_in' }, function() { + const listsForDeletion = []; if(this.listName) { - lists.push(this.listName); + listsForDeletion.push(this.listName); } if(this.newListName) { - lists.push(this.newListName); + listsForDeletion.push(this.newListName); } if(this.oldListName) { - lists.push(this.oldListName); + listsForDeletion.push(this.oldListName); } if(this.lists) { - lists.push(...this.lists.map(list => list.name)); + listsForDeletion.push(...this.lists.map(list => list.name)); } - cy.request('/api/reminders').then((response) => { - expect(response.status).to.be.ok; - return response.body - .filter(list => lists.includes(list['name'])) - .map(list => list['id']) - }) - .each((listId) => { - cy.request('DELETE', `/api/reminders/${listId}`).then((response) => { + if(listsForDeletion.length > 0) { + cy.request('/api/reminders').then((response) => { expect(response.status).to.be.ok; + return response.body + .filter(list => listsForDeletion.includes(list['name'])) + .map(list => list['id']) + }) + .each((listId) => { + cy.request('DELETE', `/api/reminders/${listId}`).then((response) => { + expect(response.status).to.be.ok; + }); }); - }); + } }); \ No newline at end of file diff --git a/cypress/support/step_definitions/list.ts b/cypress/support/step_definitions/list.ts index e955d48..1e41e60 100644 --- a/cypress/support/step_definitions/list.ts +++ b/cypress/support/step_definitions/list.ts @@ -3,11 +3,20 @@ import { suffix } from '../utils/stringUtils'; const reminderRow = 'div.reminder-row'; const reminderRowWithInput = 'div.reminder-row-with-input'; + +// Input component should be extracted to a separate class +// to prevent code duplication with reminder.ts const reminderInput = 'input[type="text"]'; const reminderButton = 'img'; const newReminderRow = '[data-id="new-reminder-row"]'; +const _selectList = (listName: string) => { + cy.get(reminderRow).contains(listName).parent().as('list'); + cy.get('@list').click(); + cy.get('@list').should('have.class', 'selected-list'); +}; + When('I create a list called {string}', function(name: string) { name = name + suffix(); cy.get(newReminderRow).as('root'); @@ -18,14 +27,12 @@ When('I create a list called {string}', function(name: string) { }); Then('I should see list {string}', function (name: string) { - expect(this.listName).to.not.be.undefined; - expect(this.listName).to.contain(name); + expect(this.listName).to.be.ok.and.to.contain(name); cy.get(reminderRow).contains(this.listName).should('be.visible'); }); Then('I should not see list {string}', function (name: string) { - expect(this.oldListName).to.not.be.undefined; - expect(this.oldListName).to.contain(name); + expect(this.oldListName).to.be.ok.and.to.contain(name); cy.get(reminderRow).contains(this.oldListName).should('not.exist'); }); @@ -47,10 +54,8 @@ Then('I rename the list to {string}', function (newName: string) { this.listName = this.newListName; }); - Then('I delete the list {string}', function (name: string) { - expect(this.listName).to.not.be.undefined; - expect(this.listName).to.contain(name); + expect(this.listName).to.be.ok.and.to.contain(name); // Click Delete button cy.get(reminderRow).contains(this.listName).parent().find(reminderButton).last().click(); @@ -58,7 +63,10 @@ Then('I delete the list {string}', function (name: string) { Then('I select the list number {int}', function (index: number) { expect(this.lists).to.be.ok.and.to.have.length.of.at.least(index - 1); - cy.get(reminderRow).contains(this.lists[index -1].name).parent().as('list'); - cy.get('@list').click(); - cy.get('@list').should('have.class', 'selected-list'); + _selectList(this.lists[index - 1].name); +}); + +Then('I select the list with reminders', function () { + expect(this.listWithReminders).to.be.ok; + _selectList(this.listWithReminders.name); }); \ No newline at end of file diff --git a/cypress/support/step_definitions/reminder.ts b/cypress/support/step_definitions/reminder.ts index f19cbd2..4ca656c 100644 --- a/cypress/support/step_definitions/reminder.ts +++ b/cypress/support/step_definitions/reminder.ts @@ -1,18 +1,34 @@ -import { Then } from '@badeball/cypress-cucumber-preprocessor'; +import { When, Then } from '@badeball/cypress-cucumber-preprocessor'; +import { suffix } from '../utils/stringUtils'; const remindersCardTitle = 'h3.reminders-card-title'; const newReminderItemRow = '[data-id="new-reminder-item-row"]'; const reminderItemRow = '.reminders-item-list .reminder-row'; +const reminderItemRowWithInput = '.reminders-item-list .reminder-row-with-input'; -const shouldDisplayRemindersForList = (listName: string) => { +const reminderInput = 'input[type="text"]'; +const reminderButton = 'img'; + +const _shouldDisplayRemindersForList = (listName: string) => { cy.get(remindersCardTitle).contains(listName).parent().as('reminders'); cy.get('@reminders').should('be.visible'); cy.get('@reminders').find(newReminderItemRow).should('be.visible'); }; +const _checkRemindersInList = (reminders: Array) => { + for(const reminder of reminders) { + cy.get(reminderItemRow).contains(reminder).should('be.visible'); + } +}; + +const _validateListData = (context, index: number) => { + expect(context.listWithReminders).to.be.ok.and.to.have.property('reminders'); + expect(context.listWithReminders.reminders).to.have.length.of.at.least(index - 1); +}; + Then('I should see reminders for {string}', function (listName: string) { expect(this.listName).to.be.ok.and.to.contain(listName); - shouldDisplayRemindersForList(listName); + _shouldDisplayRemindersForList(listName); }); Then('I should not see reminders for {string}', function (listName: string) { @@ -23,9 +39,70 @@ Then('I should not see reminders for {string}', function (listName: string) { Then('I should see reminders for the list number {int}', function (index: number) { expect(this.lists).to.be.ok.and.to.have.length.of.at.least(index - 1); const list = this.lists[index - 1]; - shouldDisplayRemindersForList(list.name); + _shouldDisplayRemindersForList(list.name); + _checkRemindersInList(list.reminders); +}); - for(const reminder of list.reminders) { - cy.get(reminderItemRow).contains(reminder).should('be.visible'); - } -}); \ No newline at end of file +When('I check the reminder number {int}', function (index: number) { + _validateListData(this, index); + cy.get(reminderItemRow).contains(this.listWithReminders.reminders[index - 1]).click(); +}); + +Then('I should see the reminder number {int} checked', function (index: number) { + _validateListData(this, index); + cy.get(reminderItemRow).contains(this.listWithReminders.reminders[index - 1]).parent().should('have.class', 'completed'); +}); + +Then('I should see the reminder number {int} unchecked', function (index: number) { + _validateListData(this, index); + cy.get(reminderItemRow).contains(this.listWithReminders.reminders[index - 1]).parent().should('not.have.class', 'completed'); +}); + +When('I create a reminder called {string}', function(name: string) { + name = name + suffix(); + cy.get(newReminderItemRow).as('root'); + cy.get('@root').click(); + cy.get('@root').find(reminderInput).type(name); + cy.get('@root').find(reminderButton).first().click(); // There's no proper way to select this button + this.reminderName = name; +}); + +Then('I should see the reminder {string}', function (name: string) { + expect(this.reminderName).to.be.ok.and.to.contain(name); + cy.get(reminderItemRow).contains(this.reminderName).should('be.visible'); +}); + +When('I rename the reminder number {int} to {string}', function (index: number, newName: string) { + _validateListData(this, index); + this.reminderName = newName + suffix(); + const oldReminderName = this.listWithReminders.reminders[index - 1]; + + // Click Edit button + cy.get(reminderItemRow).contains(oldReminderName).parent().find(reminderButton).first().click(); + + cy.get(reminderItemRowWithInput).should('be.visible') + .find(reminderInput).as('input'); + + cy.get('@input').should('be.visible').and('have.value', oldReminderName); + cy.get('@input').type(this.reminderName); + cy.get('@input').parent().find(reminderButton).first().click(); + + this.oldReminderName = oldReminderName; + this.listWithReminders.reminders[index - 1] = this.newReminderName; +}); + +Then('I delete the reminder number {int}', function (index: number) { + _validateListData(this, index); + // Click Delete button + cy.get(reminderItemRow).contains(this.listWithReminders.reminders[index - 1]).parent().find(reminderButton).last().click(); +}); + +Then('I should not see reminder number {int}', function (index: number) { + _validateListData(this, index); + cy.get(reminderItemRow).contains(this.listWithReminders.reminders[index - 1]).should('not.exist'); +}); + +Then('I should not see reminder with old name', function () { + expect(this.oldReminderName).to.be.ok; + cy.get(reminderItemRow).contains(this.oldReminderName).should('not.exist'); +});