From c04c578d78b3ea1ec1efa16e2dedbc05723a2d5e Mon Sep 17 00:00:00 2001 From: harjaus Date: Tue, 29 Oct 2019 16:51:44 +0000 Subject: [PATCH 1/7] Early stages of development --- .../cucumber/features/add_one.feature | 17 +-- .../features/manage-todo-list.steps.js | 111 -------------- exercises/03_acceptance/cucumber/package.json | 6 +- .../cucumber/steps/manage-todo-list.steps.js | 138 ++++++++++++++++++ 4 files changed, 151 insertions(+), 121 deletions(-) delete mode 100644 exercises/03_acceptance/cucumber/features/manage-todo-list.steps.js create mode 100644 exercises/03_acceptance/cucumber/steps/manage-todo-list.steps.js diff --git a/exercises/03_acceptance/cucumber/features/add_one.feature b/exercises/03_acceptance/cucumber/features/add_one.feature index 756d5f1..b05388d 100644 --- a/exercises/03_acceptance/cucumber/features/add_one.feature +++ b/exercises/03_acceptance/cucumber/features/add_one.feature @@ -1,12 +1,11 @@ - Feature: Adding Items The user should be able to add a single item to the list. -Scenario: add a single item - Given The browser is open on the home page - When I enter "bread" in the "item" field - And I enter "42" in the "qty" field - And I click on the submit button - Then the heading should be "ToDo List" - And the list should contain "1" row - And the item in row "1" should be "bread" + Scenario: add a single item + Given The browser is open on the home page + When I enter "bread" in the "item" field + When I enter "42" in the "qty" field + When I click on the submit button + Then the heading should be "ToDo List" + Then the list should contain "1" row + Then the item in row "1" should be "bread" diff --git a/exercises/03_acceptance/cucumber/features/manage-todo-list.steps.js b/exercises/03_acceptance/cucumber/features/manage-todo-list.steps.js deleted file mode 100644 index a16504a..0000000 --- a/exercises/03_acceptance/cucumber/features/manage-todo-list.steps.js +++ /dev/null @@ -1,111 +0,0 @@ - -'use strict' - -// Given The browser is open on the home page -// When I enter "bread" in the "item" field -// And I enter "42" in the "qty" field -// And I click on the submit button -// Then the heading should be "ToDo List" -// And the list should contain "1" row -// And the item in row "1" should be "bread" - -const { defineFeature, loadFeature } = require('jest-cucumber') -const feature = loadFeature('./features/add_one.feature') - -const PAGE = 'http://localhost:8080' -const ENTER_EVENT = 'Enter' -const INPUT_SELECTOR = 'section input' -const TODO_ITEMS_SELECTOR = 'ul.todo-list li' -const todoItemSelector = index => `ul.todo-list li:nth-child(${index})` -const todoItemLabelSelector = index => `${todoItemSelector(index)} label` -const deleteButtonSelector = index => `${todoItemSelector(index)} button` - -async function addTodoItem(label) { - await expect(page).toFill(INPUT_SELECTOR, label) - const inputElement = await expect(page).toMatchElement(INPUT_SELECTOR) - await inputElement.press(ENTER_EVENT) -} - -async function deleteTodoItem(index) { - const todoItemElement = await expect(page).toMatchElement( - todoItemSelector(index) - ) - await todoItemElement.hover(); - await expect(page).toClick(deleteButtonSelector(index)) -} - -defineFeature(feature, test => { - let todoList - - beforeEach(async () => { - await page.goto(PAGE) - await page.evaluate(() => { - localStorage.clear() - }) - await page.reload() - todoList = [] - }) - - const givenIHaveTheTodoList = given => { - given("I have the todo list", async table => { - todoList = table - for (let index = 0; index < table.length; index++) { - await addTodoItem(table[index].Label) - } - }) - } - - const thenIExpectTheTodoListToHaveNumberOfItems = then => { - then(/^I expect the todo list to have (\d+) items?$/, async number => { - const todoItemCount = await page.$$eval( - TODO_ITEMS_SELECTOR, - items => items.length - ) - expect(todoItemCount).toBe(parseInt(number)) - }) - } - - test("Add todo item", ({ given, when, then }) => { - givenIHaveTheTodoList(given) - - when(/^I write the todo item "(.*)" in the input field$/, async label => { - await expect(page).toFill(INPUT_SELECTOR, label) - }) - - when('I press enter', async () => { - const inputElement = await expect(page).toMatchElement(INPUT_SELECTOR) - inputElement.press(ENTER_EVENT) - }) - - thenIExpectTheTodoListToHaveNumberOfItems(then) - - then( - /^I expect to see the todo item "(.*)" in the todo list$/, - async label => { - await expect(page).toMatchElement(todoItemLabelSelector(2), { - text: label - }) - } - ) - }) - - test("Delete todo item", ({ given, when, then }) => { - givenIHaveTheTodoList(given) - - when(/^I press the delete button of the todo item "(.*)"$/, async label => { - const index = todoList.findIndex(todoItem => todoItem.Label === label) - await deleteTodoItem(index + 1) - }) - - thenIExpectTheTodoListToHaveNumberOfItems(then) - - then( - /^I expect to not see the todo item "(.*)" in the todo list$/, - async label => { - await expect(page).not.toMatchElement(todoItemLabelSelector(1), { - text: label - }) - } - ) - }) -}) diff --git a/exercises/03_acceptance/cucumber/package.json b/exercises/03_acceptance/cucumber/package.json index 0b2234e..a7d790e 100644 --- a/exercises/03_acceptance/cucumber/package.json +++ b/exercises/03_acceptance/cucumber/package.json @@ -4,6 +4,7 @@ "description": "", "main": "index.js", "scripts": { + "cucumber": "cucumber-js ./features -r ./steps", "linter": "node_modules/.bin/eslint .", "test": "node_modules/.bin/jest --coverage --runInBand --detectOpenHandles", "watch": "node_modules/.bin/jest --coverage --watchAll", @@ -16,7 +17,7 @@ "http-status-codes": "^1.3.2", "koa": "^2.8.1", "koa-bodyparser": "^4.2.1", - "koa-handlebars": "^1.0.0", + "koa-handlebars": "^2.0.0", "koa-hbs-renderer": "^1.2.0", "koa-router": "^7.4.0", "koa-static": "^5.0.0", @@ -35,6 +36,9 @@ "projects": [ "/jest-test.config.js" ], + "testMatch": [ + "**/*.steps.js" + ], "preset": "jest-puppeteer" } } diff --git a/exercises/03_acceptance/cucumber/steps/manage-todo-list.steps.js b/exercises/03_acceptance/cucumber/steps/manage-todo-list.steps.js new file mode 100644 index 0000000..e64d096 --- /dev/null +++ b/exercises/03_acceptance/cucumber/steps/manage-todo-list.steps.js @@ -0,0 +1,138 @@ + +'use strict' + +// Given The browser is open on the home page +// When I enter "bread" in the "item" field +// And I enter "42" in the "qty" field +// And I click on the submit button +// Then the heading should be "ToDo List" +// And the list should contain "1" row +// And the item in row "1" should be "bread" + +const { defineSupportCode } = require('cucumber') +const puppeteer = require('puppeteer') + +// const feature = loadFeature('features/add_one.feature') + +const PAGE = 'http://localhost:8080' +const ENTER_EVENT = 'Enter' +const INPUT_SELECTOR = 'section input' +const TODO_ITEMS_SELECTOR = 'ul.todo-list li' +const todoItemSelector = index => `ul.todo-list li:nth-child(${index})` +const todoItemLabelSelector = index => `${todoItemSelector(index)} label` +const deleteButtonSelector = index => `${todoItemSelector(index)} button` + +const width = 800 +const height = 600 +const delayMS = 5 + +let page +let browser + +async function initialize() { + console.log("Launching browser") + browser = await puppeteer.launch({ headless: true, slowMo: delayMS, args: ['--disable-gpu', `--no-sandbox`, '--disable-dev-shm-usage'] }) + page = await browser.newPage() + await page.setViewport({ width, height }) + console.log("Finished browser!") +} +async function addTodoItem(label) { + await expect(page).toFill(INPUT_SELECTOR, label) + const inputElement = await expect(page).toMatchElement(INPUT_SELECTOR) + await inputElement.press(ENTER_EVENT) +} + +async function deleteTodoItem(index) { + const todoItemElement = await expect(page).toMatchElement( + todoItemSelector(index) + ) + await todoItemElement.hover(); + await expect(page).toClick(deleteButtonSelector(index)) +} + +defineSupportCode(function({Before, Given, When, Then}){ + + let todoList + // AfterFeatures( () => browser.close() ) + Before(async function() { + await initialize() + await page.goto(PAGE) + console.log("Went to page.") + await page.evaluate(() => { + localStorage.clear() + }) + console.log("Cleared local storage.") + await page.reload() + console.log("Reloaded page.") + todoList = [] + }) + + + Given('The browser is open on the home page', function () { + // Write code here that turns the phrase above into concrete actions + return 'pending'; + }); + + // const givenIHaveTheTodoList = given => { + // given("I have the todo list", async table => { + // todoList = table + // for (let index = 0; index < table.length; index++) { + // await addTodoItem(table[index].Label) + // } + // }) + // } + + // const thenIExpectTheTodoListToHaveNumberOfItems = then => { + // then(/^I expect the todo list to have (\d+) items?$/, async number => { + // const todoItemCount = await page.$$eval( + // TODO_ITEMS_SELECTOR, + // items => items.length + // ) + // expect(todoItemCount).toBe(parseInt(number)) + // }) + // } + + // test("Add todo item", ({ given, when, then }) => { + // givenIHaveTheTodoList(given) + + // when(/^I write the todo item "(.*)" in the input field$/, async label => { + // await expect(page).toFill(INPUT_SELECTOR, label) + // }) + + When('I click on the submit button', async () => { + const inputElement = await expect(page).toMatchElement(INPUT_SELECTOR) + inputElement.press(ENTER_EVENT) + }) + + // thenIExpectTheTodoListToHaveNumberOfItems(then) + + // then( + // /^I expect to see the todo item "(.*)" in the todo list$/, + // async label => { + // await expect(page).toMatchElement(todoItemLabelSelector(2), { + // text: label + // }) + // } + // ) + // }) + + // test("Delete todo item", ({ given, when, then }) => { + // givenIHaveTheTodoList(given) + + // when(/^I press the delete button of the todo item "(.*)"$/, async label => { + // const index = todoList.findIndex(todoItem => todoItem.Label === label) + // await deleteTodoItem(index + 1) + // }) + + // thenIExpectTheTodoListToHaveNumberOfItems(then) + + // then( + // /^I expect to not see the todo item "(.*)" in the todo list$/, + // async label => { + // await expect(page).not.toMatchElement(todoItemLabelSelector(1), { + // text: label + // }) + // } + // ) + // }) +}) From 5d358b6fb8e6c4afb3e9e837ec558d62438ab057 Mon Sep 17 00:00:00 2001 From: harjaus Date: Tue, 29 Oct 2019 11:52:14 -0700 Subject: [PATCH 2/7] Gherkin/Cucumber are working, need to sort out puppeteer --- .../cucumber/steps/manage-todo-list.steps.js | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/exercises/03_acceptance/cucumber/steps/manage-todo-list.steps.js b/exercises/03_acceptance/cucumber/steps/manage-todo-list.steps.js index e64d096..8104c31 100644 --- a/exercises/03_acceptance/cucumber/steps/manage-todo-list.steps.js +++ b/exercises/03_acceptance/cucumber/steps/manage-todo-list.steps.js @@ -18,6 +18,7 @@ const PAGE = 'http://localhost:8080' const ENTER_EVENT = 'Enter' const INPUT_SELECTOR = 'section input' const TODO_ITEMS_SELECTOR = 'ul.todo-list li' + const todoItemSelector = index => `ul.todo-list li:nth-child(${index})` const todoItemLabelSelector = index => `${todoItemSelector(index)} label` const deleteButtonSelector = index => `${todoItemSelector(index)} button` @@ -50,6 +51,17 @@ async function deleteTodoItem(index) { await expect(page).toClick(deleteButtonSelector(index)) } +async function addToPage(field, value){ + await page.type("#item", value) +} + +async function pressSubmit(){ + await page.keyboard.press("Enter") + await page.waitForNavigation(); + console.log('New Page URL:', page.url()); + await browser.close(); +} + defineSupportCode(function({Before, Given, When, Then}){ let todoList @@ -69,8 +81,11 @@ defineSupportCode(function({Before, Given, When, Then}){ Given('The browser is open on the home page', function () { - // Write code here that turns the phrase above into concrete actions - return 'pending'; + //already here by default + }); + + When('I enter {string} in the {string} field', function (value, field) { + addToPage(field, value); }); // const givenIHaveTheTodoList = given => { @@ -100,8 +115,7 @@ defineSupportCode(function({Before, Given, When, Then}){ // }) When('I click on the submit button', async () => { - const inputElement = await expect(page).toMatchElement(INPUT_SELECTOR) - inputElement.press(ENTER_EVENT) + pressSubmit() }) // thenIExpectTheTodoListToHaveNumberOfItems(then) From e8cec3ec90ba1ccfcc0eaa582f22bd979b0a0cd4 Mon Sep 17 00:00:00 2001 From: harjaus Date: Wed, 30 Oct 2019 05:08:02 -0700 Subject: [PATCH 3/7] Created simple feature to get started with --- .../cucumber/features/add_one.feature | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/exercises/03_acceptance/cucumber/features/add_one.feature b/exercises/03_acceptance/cucumber/features/add_one.feature index b05388d..81684bf 100644 --- a/exercises/03_acceptance/cucumber/features/add_one.feature +++ b/exercises/03_acceptance/cucumber/features/add_one.feature @@ -1,11 +1,9 @@ Feature: Adding Items The user should be able to add a single item to the list. + + Scenario: add item via function + Given I currently have no items + When I add "bread" with the quantity "17" + Then that data exists in memory + - Scenario: add a single item - Given The browser is open on the home page - When I enter "bread" in the "item" field - When I enter "42" in the "qty" field - When I click on the submit button - Then the heading should be "ToDo List" - Then the list should contain "1" row - Then the item in row "1" should be "bread" From f67519d972896c102c34b9cf015e2b75df7c1411 Mon Sep 17 00:00:00 2001 From: harjaus Date: Wed, 30 Oct 2019 05:08:23 -0700 Subject: [PATCH 4/7] Next feature works with puppeteer, to be implemented by students --- .../03_acceptance/cucumber/features/nextFeature.devel | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 exercises/03_acceptance/cucumber/features/nextFeature.devel diff --git a/exercises/03_acceptance/cucumber/features/nextFeature.devel b/exercises/03_acceptance/cucumber/features/nextFeature.devel new file mode 100644 index 0000000..7479c16 --- /dev/null +++ b/exercises/03_acceptance/cucumber/features/nextFeature.devel @@ -0,0 +1,10 @@ +#When ready copy the code below into add_one.feature and implement it into add_one.steps.js. + + Scenario: add item via webpage + Given The browser is open on the home page + When I enter "bread" in the "item" field + When I enter "42" in the "qty" field + When I click on the submit button + Then the heading should be "ToDo List" + Then the list should contain "1" row + Then the item in row "1" should be "bread" \ No newline at end of file From 4e60fb35a16db538b46fa458d53a8ea16c804174 Mon Sep 17 00:00:00 2001 From: harjaus Date: Wed, 30 Oct 2019 05:09:09 -0700 Subject: [PATCH 5/7] Changed file name + added working test for existing feature and support code for students for new feature --- .../cucumber/steps/add_one.steps.js | 96 +++++++++++ .../cucumber/steps/manage-todo-list.steps.js | 152 ------------------ 2 files changed, 96 insertions(+), 152 deletions(-) create mode 100644 exercises/03_acceptance/cucumber/steps/add_one.steps.js delete mode 100644 exercises/03_acceptance/cucumber/steps/manage-todo-list.steps.js diff --git a/exercises/03_acceptance/cucumber/steps/add_one.steps.js b/exercises/03_acceptance/cucumber/steps/add_one.steps.js new file mode 100644 index 0000000..5881e7e --- /dev/null +++ b/exercises/03_acceptance/cucumber/steps/add_one.steps.js @@ -0,0 +1,96 @@ +'use strict' + +const { Given, When, Then } = require('cucumber') +const assert = require('assert'); + +const todo = require('../modules/todo.js') + +// Scenario: add item via function + Given('I currently have no items', function () { + // Write code here that turns the phrase above into concrete actions + todo.clear() + }); + + When('I add {string} with the quantity {string}', function (string, string2) { + // Write code here that turns the phrase above into concrete actions + todo.add(string, string2) + }); + + Then('that data exists in memory', function () { + // Write code here that turns the phrase above into concrete actions + let currentData = todo.getAll()[0] + assert.equal(currentData.item, "bread") + assert.equal(currentData.qty, 17) + }); + +/* +STARTING CODE TO HELP WITH "nextFeature.devel" + +Copy the contents of nextFeature.devel into add_one.feature, then come back to this file and implement the features one by one. + + +const puppeteer = require('puppeteer') + +const PAGE = 'http://localhost:8080' +const ENTER_EVENT = 'Enter' +const INPUT_SELECTOR = 'section input' +const TODO_ITEMS_SELECTOR = 'ul.todo-list li' + +const todoItemSelector = index => `ul.todo-list li:nth-child(${index})` +const todoItemLabelSelector = index => `${todoItemSelector(index)} label` +const deleteButtonSelector = index => `${todoItemSelector(index)} button` + +const width = 800 +const height = 600 +const delayMS = 5 + +let page +let browser + +async function initialize() { + console.log("Launching browser") + browser = await puppeteer.launch({ headless: true, slowMo: delayMS, args: ['--disable-gpu', `--no-sandbox`, '--disable-dev-shm-usage'] }) + page = await browser.newPage() + await page.setViewport({ width, height }) +} + +async function addTodoItem(label) { + await expect(page).toFill(INPUT_SELECTOR, label) + const inputElement = await expect(page).toMatchElement(INPUT_SELECTOR) + await inputElement.press(ENTER_EVENT) +} + +async function deleteTodoItem(index) { + const todoItemElement = await expect(page).toMatchElement( + todoItemSelector(index) + ) + await todoItemElement.hover(); + await expect(page).toClick(deleteButtonSelector(index)) +} + +async function addToPage(field, value){ + // add puppeteer code + console.log("In development!") +} + +async function pressSubmit(){ + // add puppeteer code + console.log("In development!") +} + +// Scenario: add item via webpage + Given('The browser is open on the home page', async function () { + await initialize() + }); + + When('I enter {string} in the {string} field', async function (value, field) { + await addToPage(field, value); + }); + + When('I click on the submit button', async () => { + await pressSubmit() + }) + + +}) +*/ \ No newline at end of file diff --git a/exercises/03_acceptance/cucumber/steps/manage-todo-list.steps.js b/exercises/03_acceptance/cucumber/steps/manage-todo-list.steps.js deleted file mode 100644 index 8104c31..0000000 --- a/exercises/03_acceptance/cucumber/steps/manage-todo-list.steps.js +++ /dev/null @@ -1,152 +0,0 @@ - -'use strict' - -// Given The browser is open on the home page -// When I enter "bread" in the "item" field -// And I enter "42" in the "qty" field -// And I click on the submit button -// Then the heading should be "ToDo List" -// And the list should contain "1" row -// And the item in row "1" should be "bread" - -const { defineSupportCode } = require('cucumber') -const puppeteer = require('puppeteer') - -// const feature = loadFeature('features/add_one.feature') - -const PAGE = 'http://localhost:8080' -const ENTER_EVENT = 'Enter' -const INPUT_SELECTOR = 'section input' -const TODO_ITEMS_SELECTOR = 'ul.todo-list li' - -const todoItemSelector = index => `ul.todo-list li:nth-child(${index})` -const todoItemLabelSelector = index => `${todoItemSelector(index)} label` -const deleteButtonSelector = index => `${todoItemSelector(index)} button` - -const width = 800 -const height = 600 -const delayMS = 5 - -let page -let browser - -async function initialize() { - console.log("Launching browser") - browser = await puppeteer.launch({ headless: true, slowMo: delayMS, args: ['--disable-gpu', `--no-sandbox`, '--disable-dev-shm-usage'] }) - page = await browser.newPage() - await page.setViewport({ width, height }) - console.log("Finished browser!") -} -async function addTodoItem(label) { - await expect(page).toFill(INPUT_SELECTOR, label) - const inputElement = await expect(page).toMatchElement(INPUT_SELECTOR) - await inputElement.press(ENTER_EVENT) -} - -async function deleteTodoItem(index) { - const todoItemElement = await expect(page).toMatchElement( - todoItemSelector(index) - ) - await todoItemElement.hover(); - await expect(page).toClick(deleteButtonSelector(index)) -} - -async function addToPage(field, value){ - await page.type("#item", value) -} - -async function pressSubmit(){ - await page.keyboard.press("Enter") - await page.waitForNavigation(); - console.log('New Page URL:', page.url()); - await browser.close(); -} - -defineSupportCode(function({Before, Given, When, Then}){ - - let todoList - // AfterFeatures( () => browser.close() ) - Before(async function() { - await initialize() - await page.goto(PAGE) - console.log("Went to page.") - await page.evaluate(() => { - localStorage.clear() - }) - console.log("Cleared local storage.") - await page.reload() - console.log("Reloaded page.") - todoList = [] - }) - - - Given('The browser is open on the home page', function () { - //already here by default - }); - - When('I enter {string} in the {string} field', function (value, field) { - addToPage(field, value); - }); - - // const givenIHaveTheTodoList = given => { - // given("I have the todo list", async table => { - // todoList = table - // for (let index = 0; index < table.length; index++) { - // await addTodoItem(table[index].Label) - // } - // }) - // } - - // const thenIExpectTheTodoListToHaveNumberOfItems = then => { - // then(/^I expect the todo list to have (\d+) items?$/, async number => { - // const todoItemCount = await page.$$eval( - // TODO_ITEMS_SELECTOR, - // items => items.length - // ) - // expect(todoItemCount).toBe(parseInt(number)) - // }) - // } - - // test("Add todo item", ({ given, when, then }) => { - // givenIHaveTheTodoList(given) - - // when(/^I write the todo item "(.*)" in the input field$/, async label => { - // await expect(page).toFill(INPUT_SELECTOR, label) - // }) - - When('I click on the submit button', async () => { - pressSubmit() - }) - - // thenIExpectTheTodoListToHaveNumberOfItems(then) - - // then( - // /^I expect to see the todo item "(.*)" in the todo list$/, - // async label => { - // await expect(page).toMatchElement(todoItemLabelSelector(2), { - // text: label - // }) - // } - // ) - // }) - - // test("Delete todo item", ({ given, when, then }) => { - // givenIHaveTheTodoList(given) - - // when(/^I press the delete button of the todo item "(.*)"$/, async label => { - // const index = todoList.findIndex(todoItem => todoItem.Label === label) - // await deleteTodoItem(index + 1) - // }) - - // thenIExpectTheTodoListToHaveNumberOfItems(then) - - // then( - // /^I expect to not see the todo item "(.*)" in the todo list$/, - // async label => { - // await expect(page).not.toMatchElement(todoItemLabelSelector(1), { - // text: label - // }) - // } - // ) - // }) -}) From 98c52d64e619be1bda5e829e17551fef597f9af3 Mon Sep 17 00:00:00 2001 From: harjaus Date: Wed, 30 Oct 2019 05:31:34 -0700 Subject: [PATCH 6/7] Fixed initialize() in support code section --- .../cucumber/steps/add_one.steps.js | 31 ++++++------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/exercises/03_acceptance/cucumber/steps/add_one.steps.js b/exercises/03_acceptance/cucumber/steps/add_one.steps.js index 5881e7e..ddcc60f 100644 --- a/exercises/03_acceptance/cucumber/steps/add_one.steps.js +++ b/exercises/03_acceptance/cucumber/steps/add_one.steps.js @@ -26,19 +26,15 @@ const todo = require('../modules/todo.js') /* STARTING CODE TO HELP WITH "nextFeature.devel" -Copy the contents of nextFeature.devel into add_one.feature, then come back to this file and implement the features one by one. +Copy the contents of nextFeature.devel into add_one.feature, +then come back to this file and implement the features one by one. + +There is already some setup code, so you only need to focus on the tests. const puppeteer = require('puppeteer') const PAGE = 'http://localhost:8080' -const ENTER_EVENT = 'Enter' -const INPUT_SELECTOR = 'section input' -const TODO_ITEMS_SELECTOR = 'ul.todo-list li' - -const todoItemSelector = index => `ul.todo-list li:nth-child(${index})` -const todoItemLabelSelector = index => `${todoItemSelector(index)} label` -const deleteButtonSelector = index => `${todoItemSelector(index)} button` const width = 800 const height = 600 @@ -52,20 +48,11 @@ async function initialize() { browser = await puppeteer.launch({ headless: true, slowMo: delayMS, args: ['--disable-gpu', `--no-sandbox`, '--disable-dev-shm-usage'] }) page = await browser.newPage() await page.setViewport({ width, height }) -} - -async function addTodoItem(label) { - await expect(page).toFill(INPUT_SELECTOR, label) - const inputElement = await expect(page).toMatchElement(INPUT_SELECTOR) - await inputElement.press(ENTER_EVENT) -} - -async function deleteTodoItem(index) { - const todoItemElement = await expect(page).toMatchElement( - todoItemSelector(index) - ) - await todoItemElement.hover(); - await expect(page).toClick(deleteButtonSelector(index)) + await page.goto(PAGE) + await page.evaluate(() => { + localStorage.clear() + }) + await page.reload() } async function addToPage(field, value){ From c8a9c190634f4abde2bb62cfab69bf5242bddcd3 Mon Sep 17 00:00:00 2001 From: harjaus Date: Wed, 30 Oct 2019 05:31:51 -0700 Subject: [PATCH 7/7] Added justifications and a quick guide for newcomers to Cucumber/Gherkin --- exercises/03_acceptance/cucumber/readme.md | 67 +++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/exercises/03_acceptance/cucumber/readme.md b/exercises/03_acceptance/cucumber/readme.md index 915a7e3..7ab4b6f 100644 --- a/exercises/03_acceptance/cucumber/readme.md +++ b/exercises/03_acceptance/cucumber/readme.md @@ -1,6 +1,71 @@ -# ToDo +# Project Description This project is designed to teach you how to write and debug unit tests and employ the Test-Driven Development (TDD) methodology in your software development. You should open this directory directly in VS Code, ensuring that this file is in the root of the file tree. + +# Cucumber and Gherkin + +To demonstrate TDD we will be using Cucumber and Gherkin in order to make our tests readable by any ordinary person. + +Gherkin is a way to write tests, example: + + Given I currently have no items + When I add "bread" with the quantity "17" + Then that data exists in memory + +Whereas Cucumber is a way to integrate them (to ensure they actually compile and run), example: + + Given('I currently have no items', function () { + // Write code here that turns the phrase above into concrete actions + }); + + When('I add {string} with the quantity {string}', function (string, string2) { + // Write code here that turns the phrase above into concrete actions + }); + + Then('that data exists in memory', function () { + // Write code here that turns the phrase above into concrete actions + }); + +To run your tests just use
 npm run cucumber 
+ +# Installation + +This repository should already be setup to be ready to go, but if you ever want to replicate it in one of your projects here is what you need to do. + +1. Create your own node project (should know how to by now) +2. Install cucumber: +
 npm install --save-dev cucumber 
+3. You can run tests manually as such: +
 node_modules/.bin/cucumber-js ./features -r ./steps
+4. If you want to run them when you type "npm run cucumber", add this to your package.json: +
 "scripts": {
+    "cucumber": "cucumber-js ./features -r ./steps" } 
+5. Put your gherkin files (.feature) in /features and cucumber files (.steps) in /steps. + + +# Activity + +After you've wrapped your head around existing tests try giving "features/nextFeature.devel" a try. It accomplishes the same thing as our unit test, but instead checks the functionality at a higher level (acceptance/integration testing). + +There are some instructions and support code already available in "steps/add_one.steps.js", you just need to implement the tests in the same way we did with our first Scenario. + +Remember to have your website running in a different terminal if you want puppeteer to be able to access it. + +# Notes + +If you want to develop a new Scenario, or even a new Feature, just write the Gherkin tests first (the human readable tests), then try running them. They will obviously not pass, but the terminal will help you write them. + +Example: +
+1) Scenario: add item via function # features/add_one.feature:4
+   ? Given I currently have no items
+       Undefined. Implement with the following snippet:
+
+         Given('I currently have no items', function () {
+           // Write code here that turns the phrase above into concrete actions
+           return 'pending';
+         });
+