Added front end testing with Cypress.

This commit is contained in:
Douglas Muth 2022-12-11 22:37:26 -05:00
parent ba63743aee
commit c9810be610
12 changed files with 2319 additions and 194 deletions

4
.gitignore vendored
View file

@ -8,3 +8,7 @@ dist/bundle.js
diceware.zip diceware.zip
# Don't check in videos of unit tests
cypress/videos/

View file

@ -55,17 +55,22 @@ A local webserver can be set up by running `npm install http-server -g` to insta
## In summary: ## In summary:
- `npm run clean` - Cleanup after a previous run - Development
- `npm install` - Install NPM packages used by Diceware - `npm run clean` - Cleanup after a previous run
- `npm run dev-build` - Run webpack to pack Javascript files and watch for changes. - `npm install` - Install NPM packages used by Diceware
- `http-server` - `npm run dev-build` - Run webpack to pack Javascript files and watch for changes.
- `vim src/lib.js src/index.js` - `http-server`
- Be sure to check in your changes before the next step! - `vim src/lib.js src/index.js`
- `rm -fv src/index.js && git co src/index.js` - Get the new SHA1 hash that will be displayed in debug messages. - Be sure to check in your changes before the next step!
- The hash can be crosschecked with the results of `git hash-object src/index.js` - Testing
- `npm test` - Make sure you didn't break any of the core logic! - `rm -fv src/index.js && git co src/index.js` - Get the new SHA1 hash that will be displayed in debug messages.
- `npm run build` - Webpack Javscript files in production mode (smaller file but takes longer) - The hash can be crosschecked with the results of `git hash-object src/index.js`
- `./go-sync-to-s3.sh` - Do this if you're me, to upload to S3. If you're not me, you'll need to do something else, or possibly nothing at all. - `npm test` - Make sure you didn't break any of the core logic!
- `npx cypress run` - Run front-end testing
- If the tests break, run `npx cypress open` to run tests interactively.
- Deployment
- `npm run build` - Webpack Javscript files in production mode (smaller file but takes longer)
- `./go-sync-to-s3.sh` - Do this if you're me, to upload to S3. If you're not me, you'll need to do something else, or possibly nothing at all.
## In practice: ## In practice:
@ -81,7 +86,9 @@ A local webserver can be set up by running `npm install http-server -g` to insta
### Releasing a New Build ### Releasing a New Build
- `npm run release-build` to create the ZIP file `diceware.zip` with all assets in it, including `bundle.js` and the contents of `node_modules/`. - `npm run release-build` to create the ZIP file `diceware.zip` with all assets in it, including `bundle.js` and the contents of `node_modules/`.
- `gh release create v1.0.0` to upload a release to https://github.com/dmuth/diceware/releases. Change the tag for the version number accordingly. - `gh release create v1.0.1` to upload a release to https://github.com/dmuth/diceware/releases.
- Change the tag for the version number accordingly.
- `gh release upload v1.0.1 diceware.zip` to upload the ZIP file containing everything
# Who built this? / Contact # Who built this? / Contact

13
cypress.config.js Normal file
View file

@ -0,0 +1,13 @@
module.exports = {
// The rest of the Cypress config options go here...
projectId: "ot9ks7",
defaultCommandTimeout: 10000,
e2e: {
baseUrl: "http://localhost:8081",
setupNodeEvents(on, config) {
// implement node event listeners here
},
},
};

BIN
cypress/.DS_Store vendored Normal file

Binary file not shown.

View file

@ -0,0 +1,37 @@
describe('Diceware', () => {
it('Roll 2 dice and check results', () => {
cy.visit('/');
cy.get('[data-test="button-2"]').click();
cy.get('[data-test="button"]').click();
cy.get('.results > .results_phrase_key').should("exist").contains("passphrase");
cy.get('[data-test-num-dice]')
.should("exist")
.contains(2)
;
})
it('Roll 4 dice and check results', () => {
cy.visit('/');
cy.get('[data-test="button-4"]').click();
cy.get('[data-test="button"]').click();
cy.get('.results > .results_phrase_key').should("exist").contains("passphrase");
cy.get('[data-test-num-dice]')
.should("exist")
.contains(4)
;
})
})

View file

@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}

View file

@ -0,0 +1,25 @@
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add('login', (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })

20
cypress/support/e2e.js Normal file
View file

@ -0,0 +1,20 @@
// ***********************************************************
// This example support/e2e.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands'
// Alternatively you can use CommonJS syntax:
// require('./commands')

View file

@ -95,12 +95,13 @@
<div class="dice_word dice_element" style="float: left; padding-left: 20px; padding-top: 25px; "> <div class="dice_word dice_element" style="float: left; padding-left: 20px; padding-top: 25px; ">
</div> </div>
<div id="results-num-dice" data-test-num-dice="" >0</div>
<div class="results_words_key" >Your words are: </div> <div class="results_words_key" >Your words are: </div>
<div class="results_words_value" ></div> <div class="results_words_value" data-test="results-words" ></div>
<div class="results_phrase_key" >Your passphrase is: </div> <div class="results_phrase_key" >Your passphrase is: </div>
<div class="results_phrase_value" ></div> <div class="results_phrase_value" data-test="results-phrase" ></div>
<div class="results_num_possible_key" ># of possible passwords: </div> <div class="results_num_possible_key" ># of possible passwords: </div>
<div class="results_num_possible_value" ></div> <div class="results_num_possible_value" ></div>
@ -127,19 +128,19 @@
</h2> </h2>
<div class="btn-group-lg" role="group" aria-label="..."> <div class="btn-group-lg" role="group" aria-label="...">
<button id="button-dice-2" type="button" class="btn btn-default dice_button">2</button> <button id="button-dice-2" type="button" class="btn btn-default dice_button" data-test="button-2">2</button>
<button id="button-dice-3" type="button" class="btn btn-default dice_button">3</button> <button id="button-dice-3" type="button" class="btn btn-default dice_button" data-test="button-3">3</button>
<button id="button-dice-4" type="button" class="btn btn-default dice_button">4</button> <button id="button-dice-4" type="button" class="btn btn-default dice_button active" data-test="button-4">4</button>
<button id="button-dice-5" type="button" class="btn btn-default dice_button">5</button> <button id="button-dice-5" type="button" class="btn btn-default dice_button" data-test="button-5">5</button>
<button id="button-dice-6" type="button" class="btn btn-default dice_button active">6</button> <button id="button-dice-6" type="button" class="btn btn-default dice_button" data-test="button-6">6</button>
<button id="button-dice-7" type="button" class="btn btn-default dice_button">7</button> <button id="button-dice-7" type="button" class="btn btn-default dice_button" data-test="button-7">7</button>
<button id="button-dice-8" type="button" class="btn btn-default dice_button">8</button> <button id="button-dice-8" type="button" class="btn btn-default dice_button" data-test="button-8">8</button>
</div> </div>
<br/> <br/>
<a name="roll_dice_button" ></a> <a name="roll_dice_button" ></a>
<button type="button" class="btn btn-default btn-lg btn-primary" id="roll_dice"> <button type="button" class="btn btn-default btn-lg btn-primary" id="roll_dice" data-test="button">
<span class="glyphicon glyphicon-play" aria-hidden="true" ></span> Roll Dice! <span class="glyphicon glyphicon-play" aria-hidden="true" ></span> Roll Dice!
</button> </button>

2349
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -33,6 +33,7 @@
"dependencies": { "dependencies": {
"buffer": "^6.0.3", "buffer": "^6.0.3",
"crypto-browserify": "^3.12.0", "crypto-browserify": "^3.12.0",
"cypress": "^12.0.2",
"process": "^0.11.10", "process": "^0.11.10",
"random-number-csprng": "^1.0.2", "random-number-csprng": "^1.0.2",
"stream-browserify": "^3.0.0", "stream-browserify": "^3.0.0",

View file

@ -255,6 +255,13 @@ Diceware.rollDiceHandler = function(e) {
}); });
//
// Store the number of dice rolled in a data attribute for
// inspection by Cypress or another test.
//
var results_num_dice = jQuery("#results-num-dice");
results_num_dice.text(num_dice);
Diceware.rollDiceHandlerPost(rolls, passphrase, num_passwords); Diceware.rollDiceHandlerPost(rolls, passphrase, num_passwords);
}); });