-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Activity Report Stepper cucumber tests #53
Changes from 53 commits
ce995b9
f3fec08
b2154dc
0f7e27f
5e4536d
516a695
14226c7
1f29240
023ddf1
4715975
b0a4e12
3b0686e
0e74548
0e40aaa
2f567fb
3ef375b
a476b96
016943b
6bfa089
decab5e
1990ac2
b73f0ca
c9c24ac
2b34469
498831a
f89bbff
75013f0
85aa888
cacaf5c
72d38cb
c3cff5d
80dcbcc
720a129
f57bf58
7d172cb
300f776
4c94b7c
998174e
2774588
8e80cca
7e19ddc
47497a2
8f2cc8e
c8b0993
844818c
071148d
f2ba925
8e26a95
3cbc3b0
3fecdb9
27cfca7
6ee8e14
473da97
5e4b0fd
58fa06e
df625f5
647da9b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
Feature: Activity Report Stepper | ||
|
||
Scenario: Activity Summary | ||
Given I am logged in | ||
And I am on the activity reports page | ||
Then I see the Stepper | ||
And the first step is the Activity Summary | ||
Scenario: Navigation buttons | ||
Given I am logged in | ||
And I am on the activity reports page | ||
Then I see two navigation buttons | ||
And the "Previous" button is disabled | ||
When I click the "Next" button | ||
Then the "Previous" button is no longer disabled | ||
Scenario: Progress | ||
Given I am logged in | ||
And I am on the activity reports page | ||
When I click the "Next" button | ||
Then I moved past the "Activity Summary" step | ||
And I am on the "Participants" step | ||
When I click the "Next" button again | ||
Then the "Participants" step is still current, but I am on page 2 | ||
And I have not advanced to the "Goals & Objectives" step yet | ||
When I click the "Previous" button | ||
Then the "Participants" step is still current, but I am on page 1 | ||
When I click the "Previous" button again | ||
Then I am no longer on the "Participants" step | ||
And I am on the "Activity Summary" step |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
Feature: TTA Smarthub Home Page | ||
|
||
Scenario: Welcome page is displayed | ||
Given I am logged in | ||
And I am on the Smart Hub home page | ||
Then I see "Welcome to the TTA Smart Hub" message | ||
And I see "Activity Reports" link | ||
# Scenario: Login is redirected to HSES | ||
# Given the home page of tta-smarthub | ||
# When pressing login | ||
# Then we should see "Head Start Enterprise System" page | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd prefer this test was deleted instead of being commented out. Please do that when the stepper steps are removed. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
const { | ||
Given, When, Then, | ||
} = require('@cucumber/cucumber'); | ||
const assertTrue = require('assert'); | ||
const assert = require('assert'); | ||
const select = require('puppeteer-select'); | ||
const scope = require('../support/scope'); | ||
|
||
Given('I am on the activity reports page', async () => { | ||
const page = scope.context.currentPage; | ||
const selector = 'a[href$="activity-reports"]'; | ||
await Promise.all([ | ||
page.waitForNavigation(), | ||
page.click(selector), | ||
]); | ||
await page.screenshot({ path: 'reports/givenOnTheActivityReports.png' }); | ||
}); | ||
|
||
Then('I see the Stepper', async () => { | ||
const page = scope.context.currentPage; | ||
const selector = '[aria-label="progress"]'; | ||
|
||
const value = await page.$eval(selector, (el) => el.textContent); | ||
|
||
assertTrue(value); | ||
assertTrue(value.startsWith('Activity Summary')); | ||
}); | ||
|
||
Then('the first step is the Activity Summary', async () => { | ||
const page = scope.context.currentPage; | ||
const selector = '[aria-label="progress"] ol li span[aria-current="true"]'; | ||
|
||
const value = await page.$eval(selector, (el) => el.textContent); | ||
|
||
assert.equal(value, 'Activity Summary'); | ||
}); | ||
|
||
Then('I see two navigation buttons', async () => { | ||
const page = scope.context.currentPage; | ||
|
||
const buttonOne = await select(page).getElement('button:contains("Previous")'); | ||
const buttonTwo = await select(page).getElement('button:contains("Next")'); | ||
|
||
assertTrue(buttonOne); | ||
assertTrue(buttonTwo); | ||
|
||
let value = await page.evaluate((el) => el.textContent, buttonOne); | ||
assert.equal(value, 'Previous'); | ||
|
||
value = await page.evaluate((el) => el.textContent, buttonTwo); | ||
assert.equal(value, 'Next'); | ||
}); | ||
|
||
Then('the {string} button is disabled', async (string) => { | ||
const page = scope.context.currentPage; | ||
const buttonOneSelector = 'button[disabled]'; | ||
// const buttonOne = await select(page).getElement('button:contains("Previous")'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can remove some dead code |
||
// const buttonTwo = await select(page).getElement('button:contains("Next")'); | ||
const buttonPrevious = await page.$(buttonOneSelector); | ||
|
||
assertTrue(buttonPrevious); | ||
// assertTrue(buttonTwo); | ||
|
||
const value = await page.evaluate((el) => el.textContent, buttonPrevious); | ||
assert.equal(value, string); | ||
|
||
// value = await page.evaluate((el) => el.disabled, buttonTwo); | ||
// assert.equal(value, 'Next'); | ||
}); | ||
|
||
When('I click the {string} button', async (string) => { | ||
const page = scope.context.currentPage; | ||
const buttonTwo = await select(page).getElement(`button:contains(${string})`); | ||
await buttonTwo.click(); | ||
}); | ||
|
||
Then('the {string} button is no longer disabled', async (string) => { | ||
const page = scope.context.currentPage; | ||
const buttonOneSelector = 'button[disabled]'; | ||
|
||
const buttonPrevious = await page.$(buttonOneSelector); | ||
|
||
const value = await page.evaluate((el) => el, buttonPrevious); | ||
assert.equal(value, null); | ||
}); | ||
|
||
Then('I moved past the {string} step', async (string) => { | ||
const page = scope.context.currentPage; | ||
assert.equal(string, 'Activity Summary'); | ||
jasalisbury marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This line will lock down this step to only work with "Activity Summary". If that's desired, we should hard-code that in the test definition instead of using the parameter. If we want it to work with other strings then this line should be removed. I also think a lot of these steps could be combined down to a single "Then I am on the {string} step". It would result in slightly worse readability in the feature file, but I think that is worth reducing duplicated code here. Another option is extracting the test steps into a function and calling that from each version of the step, or getting creative with regexes to match more versions of the feature file to a single step definition. No need to change these steps at this time though. |
||
const selector = `[data-testid="${string}"] > [aria-current="false"]`; | ||
|
||
const value = await page.$eval(selector, (el) => el.textContent); | ||
|
||
assertTrue(value); | ||
assertTrue(value.startsWith(string)); | ||
}); | ||
|
||
Then('I am on the {string} step', async (string) => { | ||
const page = scope.context.currentPage; | ||
// assert.equal(string, 'Participants'); | ||
const selector = `[data-testid="${string}"] > [aria-current="true"]`; | ||
|
||
const value = await page.$eval(selector, (el) => el.textContent); | ||
|
||
assertTrue(value); | ||
assert.equal(value, string); | ||
}); | ||
|
||
When('I click the {string} button again', async (string) => { | ||
jasalisbury marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const page = scope.context.currentPage; | ||
const buttonTwo = await select(page).getElement(`button:contains(${string})`); | ||
await buttonTwo.click(); | ||
}); | ||
|
||
Then('the {string} step is still current, but I am on page 2', async (string) => { | ||
const page = scope.context.currentPage; | ||
assert.equal(string, 'Participants'); | ||
const selector = '[data-testid="form"] > h1'; | ||
|
||
const value = await page.$eval(selector, (el) => el.textContent); | ||
|
||
assertTrue(value); | ||
assert.equal(value, `${string} - Page 2`); | ||
}); | ||
|
||
Then('I have not advanced to the {string} step yet', async (string) => { | ||
const page = scope.context.currentPage; | ||
assert.equal(string, 'Goals & Objectives'); | ||
const selector = `[data-testid="${string}"] > [aria-current="false"]`; | ||
|
||
const value = await page.$eval(selector, (el) => el.textContent); | ||
|
||
assertTrue(value); | ||
assertTrue(value.startsWith(string)); | ||
await page.screenshot({ path: 'reports/notOnGoalsYet.png' }); | ||
}); | ||
|
||
Then('the {string} step is still current, but I am on page 1', async (string) => { | ||
const page = scope.context.currentPage; | ||
assert.equal(string, 'Participants'); | ||
const selector = '[data-testid="form"] > h1'; | ||
|
||
const value = await page.$eval(selector, (el) => el.textContent); | ||
|
||
assertTrue(value); | ||
assert.equal(value, `${string} - Page 1`); | ||
}); | ||
|
||
Then('I am no longer on the {string} step', async (string) => { | ||
const page = scope.context.currentPage; | ||
assert.equal(string, 'Participants'); | ||
const selector = `[data-testid="${string}"] > [aria-current="false"]`; | ||
|
||
const value = await page.$eval(selector, (el) => el.textContent); | ||
|
||
assertTrue(value); | ||
assertTrue(value.startsWith(string)); | ||
}); |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
require('dotenv').config(); | ||
const { | ||
Given, Then, | ||
} = require('@cucumber/cucumber'); | ||
const assertTrue = require('assert'); | ||
const assert = require('assert'); | ||
const scope = require('../support/scope'); | ||
|
||
Given('I am logged in', async () => { | ||
if (!scope.browser) { | ||
const width = 1024; | ||
const height = 1600; | ||
|
||
scope.browser = await scope.driver.launch({ | ||
defaultViewport: { width, height }, | ||
headless: true, | ||
// slowMo: 250, // can be used in conjunction with headless: false to slow down the browser | ||
}); | ||
} | ||
scope.context.currentPage = await scope.browser.newPage(); | ||
const page = scope.context.currentPage; | ||
|
||
const domain = process.env.TTA_SMART_HUB_URI.split('//')[1]; | ||
|
||
const cookies = [{ | ||
name: 'CUCUMBER_USER', | ||
value: `${process.env.CUCUMBER_USER}`, | ||
domain, | ||
path: '/', | ||
httpOnly: true, | ||
secure: false, | ||
session: true, | ||
sameSite: 'Strict', | ||
}]; | ||
|
||
await page.setCookie(...cookies); | ||
|
||
const loginLinkSelector = 'a[href$="api/login"]'; | ||
// const homeLinkSelector = 'a[href$="/"]'; | ||
const activityReportsSelector = 'a[href$="activity-reports"]'; | ||
|
||
await page.goto(scope.uri); | ||
await page.waitForSelector('em'); // Page title | ||
const name = await page.$eval('em', (el) => el.innerText); | ||
|
||
assert.equal(name, 'TTA Smart Hub'); | ||
// Check if actually logged in. If not login | ||
const result = await page.$(loginLinkSelector); | ||
|
||
if (result) { | ||
await page.click(loginLinkSelector); | ||
await page.waitForSelector(activityReportsSelector); // Activity Reports link | ||
await page.screenshot({ path: 'reports/givenLoggedIn.png' }); | ||
} | ||
}); | ||
|
||
Given('I am on the Smart Hub home page', async () => { | ||
await scope.context.currentPage.waitForSelector('h1'); | ||
}); | ||
|
||
Then('I see {string} message', async (string) => { | ||
const page = scope.context.currentPage; | ||
const value = await page.$eval('h1', (el) => el.textContent); | ||
|
||
assertTrue(value.includes(string)); | ||
}); | ||
|
||
Then('I see {string} link', async (string) => { | ||
const page = scope.context.currentPage; | ||
const selector = 'a[href$="activity-reports"]'; | ||
|
||
await page.waitForSelector(selector); | ||
const value = await page.$eval(selector, (el) => el.textContent); | ||
|
||
assert.equal(value, string); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the next time someone tries to use this step: this test should try to find a link by the text and then assert that it found anything. Or the name should be updated to pass in the href or other way to select more general links than only the |
||
}); |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,19 @@ | ||||||
# 10. BDD testing | ||||||
|
||||||
Date: 2020-10-25 | ||||||
|
||||||
## Status | ||||||
|
||||||
Pending | ||||||
|
||||||
## Context | ||||||
|
||||||
Behavior-driven development (BDD) allows for a broader team to collaborate on software development. The business stakeholders have insight into how well the software meets the requirements. Through automated tests they have a way to validate the functionality in a user friendly way. Cucumber, and it particular cucumber-js was selected as the tool of choice to accomplish this. To go along with cucumber-js, puppeteer as well as selenium webdriver were looked at to provide a full solution for BDD testing. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Feels like this should be in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point. The idea was to present why we chose Puppeteer, since it was compared to some extent with the selenium webdriver. I didn't look at alternatives to Cucumber itself. I did reorganize the sections though to hopefully make it clearer. Hope it makes more sense now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
## Decision | ||||||
|
||||||
Puppeteer as well as selenium webdriver provide a way to run automated browser tests. Both of these are popular tools to enable browser automation. Puppeteer offers more control over Chromium based browsers, very fast, headless by default, run modej, and it can take screenshots of the pages, both in an image and PDF formats. Additionally, it measures rendering and load times by Chrome Performance Analysis tool and it is easier to set up than selenium webdriver. The drawback to using Puppeteer is it's lack of full cross-browser support, which is offered by the selenium webdriver, since Puppeteer is specialized for Chromium. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This paragraph feels like it should be in the context section. Also this talks about Puppeteer and Selenium but not cucumber. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Should it be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks. It's |
||||||
|
||||||
## Consequences | ||||||
|
||||||
Investing time into enabling BDD with cucumber-js will have a positive impact on collaboration with the business stakeholders and provide a way to validate application's functionality. This was viewed as a worthwile investment considering that schedules might be affected. By using Puppeteer with cucumber-js we will have a solution that is fast and easier to set up with a limitation of not providing a full cross-browser support (Microsoft Edge, which is a default on Windows 10, is based on Chromium). Since the browsers to support include Chrome and IE this poses somewhat of a limitation, however the bulk of the benefits from using BDD comes from validating the application's behavior against the requirements. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The format of these steps is perfect. Good job