Skip to content
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

Merged
merged 57 commits into from
Oct 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
ce995b9
Test drive cucumber
kryswisnaskas Oct 8, 2020
f3fec08
Merge branch 'main' of https://github.com/adhocteam/Head-Start-TTADP …
kryswisnaskas Oct 8, 2020
b2154dc
Test drive cucumber
kryswisnaskas Oct 8, 2020
0f7e27f
Test drive cucumber
kryswisnaskas Oct 8, 2020
5e4536d
Test drive cucumber
kryswisnaskas Oct 8, 2020
516a695
Test drive cucumber
kryswisnaskas Oct 8, 2020
14226c7
Test drive cucumber
kryswisnaskas Oct 8, 2020
1f29240
Test drive cucumber
kryswisnaskas Oct 9, 2020
023ddf1
Test drive cucumber
kryswisnaskas Oct 9, 2020
4715975
Test drive cucumber
kryswisnaskas Oct 9, 2020
b0a4e12
Test drive cucumber
kryswisnaskas Oct 9, 2020
3b0686e
Test drive cucumber
kryswisnaskas Oct 9, 2020
0e74548
Test drive cucumber
kryswisnaskas Oct 9, 2020
0e40aaa
Test drive cucumber
kryswisnaskas Oct 9, 2020
2f567fb
Test drive cucumber
kryswisnaskas Oct 9, 2020
3ef375b
Consolidated steps
kryswisnaskas Oct 12, 2020
a476b96
Enable cucumber testing by env
kryswisnaskas Oct 13, 2020
016943b
Enable cucumber testing by env
kryswisnaskas Oct 13, 2020
6bfa089
Enable cucumber testing by env
kryswisnaskas Oct 13, 2020
decab5e
Enable cucumber testing by env
kryswisnaskas Oct 13, 2020
1990ac2
Enable cucumber testing by env
kryswisnaskas Oct 13, 2020
b73f0ca
Enable cucumber testing by env
kryswisnaskas Oct 13, 2020
c9c24ac
Enable cucumber testing by env
kryswisnaskas Oct 13, 2020
2b34469
Enable cucumber testing by env
kryswisnaskas Oct 13, 2020
498831a
Enable cucumber testing by env
kryswisnaskas Oct 13, 2020
f89bbff
Enable cucumber testing by env
kryswisnaskas Oct 13, 2020
75013f0
Enable cucumber testing by env
kryswisnaskas Oct 13, 2020
85aa888
Enable cucumber testing by env
kryswisnaskas Oct 13, 2020
cacaf5c
Debug config.yml
kryswisnaskas Oct 14, 2020
72d38cb
Debug cucumber start
kryswisnaskas Oct 14, 2020
c3cff5d
Debug cucumber start
kryswisnaskas Oct 14, 2020
80dcbcc
Debug cucumber start
kryswisnaskas Oct 14, 2020
720a129
Debug cucumber start
kryswisnaskas Oct 14, 2020
f57bf58
Debug cucumber start
kryswisnaskas Oct 14, 2020
7d172cb
Debug cucumber start
kryswisnaskas Oct 14, 2020
300f776
Debug cucumber start
kryswisnaskas Oct 15, 2020
4c94b7c
Debug cucumber start
kryswisnaskas Oct 15, 2020
998174e
Debug cucumber start
kryswisnaskas Oct 15, 2020
2774588
Merge branch 'kw-cucumber-js' of https://github.com/adhocteam/Head-St…
kryswisnaskas Oct 15, 2020
8e80cca
Add tests for the activity report stepper
kryswisnaskas Oct 22, 2020
7e19ddc
Merge branch 'main' of https://github.com/adhocteam/Head-Start-TTADP …
kryswisnaskas Oct 22, 2020
47497a2
Add auth bypass
kryswisnaskas Oct 23, 2020
8f2cc8e
Remove debugging stmt
kryswisnaskas Oct 23, 2020
c8b0993
Add env variables to cucumber job
kryswisnaskas Oct 23, 2020
844818c
Set redirect variable for cucumber
kryswisnaskas Oct 23, 2020
071148d
Merge branch 'main' into kw-cucumber-test-js
kryswisnaskas Oct 23, 2020
f2ba925
Set redirect variable for cucumber
kryswisnaskas Oct 23, 2020
8e26a95
Merge branch 'kw-cucumber-test-js' of https://github.com/adhocteam/He…
kryswisnaskas Oct 23, 2020
3cbc3b0
Add screenshots, add tests
kryswisnaskas Oct 23, 2020
3fecdb9
Merge branch 'main' into kw-cucumber-test-js
kryswisnaskas Oct 26, 2020
27cfca7
Add ADR for BDD testing
kryswisnaskas Oct 26, 2020
6ee8e14
Merge branch 'kw-cucumber-test-js' of https://github.com/adhocteam/He…
kryswisnaskas Oct 26, 2020
473da97
Update Readme
kryswisnaskas Oct 26, 2020
5e4b0fd
Adjust the ADR; remove dead code
kryswisnaskas Oct 26, 2020
58fa06e
Merge branch 'main' into kw-cucumber-test-js
kryswisnaskas Oct 27, 2020
df625f5
Add a prod env check
kryswisnaskas Oct 27, 2020
647da9b
Merge branch 'kw-cucumber-test-js' of https://github.com/adhocteam/He…
kryswisnaskas Oct 27, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ jobs:
command: |
mkdir reports
sleep 5
yarn cucumber
yarn cucumber:ci
- store_artifacts:
path: reports/
test_frontend:
Expand Down
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ TTA_SMART_HUB_URI=http://localhost:3000
AUTH_BASE=https://uat.hsesinfo.org
# This env variable should go away soon in favor of TTA_SMART_HUB_URI
REDIRECT_URI_HOST=http://localhost:8080
CUCUMBER_USER_ID=999999;
CUCUMBER_USER=this_is_secret
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ You may run into some issues running the docker commands on Windows:
| | Run the linter for the the backend with results output to xml files | `yarn lint:ci`| |
| | Run `yarn lint:ci` for both the frontend and backend | `yarn lint:all`| |
| | Host the open api 3 spec using [redoc](https://github.com/Redocly/redoc) at `localhost:5000` | `yarn docs:serve` | |
| | Run cucumber tests | `yarn cucumber` | |

## Infrastructure

Expand Down
28 changes: 28 additions & 0 deletions cucumber/features/activityReportStepper.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
Feature: Activity Report Stepper
Copy link

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


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
9 changes: 0 additions & 9 deletions cucumber/features/devLoginPup.feature

This file was deleted.

11 changes: 11 additions & 0 deletions cucumber/features/homePage.feature
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
Copy link

Choose a reason for hiding this comment

The 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.

152 changes: 152 additions & 0 deletions cucumber/features/steps/activityReportStepperSteps.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
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 buttonPrevious = await page.$(buttonOneSelector);

assertTrue(buttonPrevious);

const value = await page.evaluate((el) => el.textContent, buttonPrevious);
assert.equal(value, string);
});

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
Copy link

Choose a reason for hiding this comment

The 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;
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));
});
35 changes: 0 additions & 35 deletions cucumber/features/steps/devLoginPupSteps.js

This file was deleted.

76 changes: 76 additions & 0 deletions cucumber/features/steps/homePageSteps.js
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);
Copy link

Choose a reason for hiding this comment

The 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 activity-reports link.

});
19 changes: 19 additions & 0 deletions docs/adr/0010-bdd-testing.md
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 or in our case cucumber-js is a top tool to provide a friendly language for all team members. To implement cucumber-js, additional tools are needed to provide a way to run automated browser tests. Here, Puppeteer as well as selenium webdriver both of which are popular tools to enable browser automation were evalueated.

## Decision

To go along with cucumber-js Puppeteer was selected. Puppeteer offers more control over Chromium based browsers, very fast, headless by default, run mode, 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.

## 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.
Loading