I have chosen to write the tests in Cypress because it includes all the dependencies required to write, run and report the tests.
In addition, Cypress automatically handles timing and asserts that elements are present without needing to write specific test cases.
Note that I have made comments under "First Impressions" that assume this is a production site, not a mock-up. These may be over the top for this exercise.
Install node.js and npm
Clone this repo
cd amplyadvantaged
npm install cypress --save-dev
npx cypress open
Run the aa-web.spec.js
test from the Cypress interface
The web application allows users to add politicians to a database through a web form.
The following fields are mandatory:
- name
- country (country code or full name)
- date of birth (mm/dd/yyyy)
- position (string)
- url (where the info was extracted from, can be a fake url in valid format)
- risk level (list selection).
The data format is also validated.
If data was successfully added, a popup will confirm it, showing the name of the politician.
This process is asynchronous, it might take a few seconds.
- https should be used for sensitive data entry
- The form is missing basic HTTP security headers:
-
- Strict Transport Policy
-
- X Content Type
-
- X Frame Options
-
- Content Security Policy
-
- X XSS Protection
- Are we sanitising text input server-side to prevent DB injection attacks?
Field needs labelling to indicate:
- which country is relevant in this context
- what format the information can be entered in (code/name)
We should use a pre-populated drop-down for country entry to eliminate typos. This could show both the full name (localised for the user) and country code - and be sortable/filterable by either. This would also drastically reduce the possible scope of possible tests compared to free-form text input
- Should be "Date of birth" to prevent confusion
- Format should be "mm/dd/yyyy" to meet spec but is "dd/mm/yyyy" - perhaps date format should be localised rather than mandated.
- Input element is missing an id property that could be used for a selector in testing
Wrongly typed as a password field, so will be invisible to the user
Pedantically, the success message should be "Valid URL format." - validity of URLs is not a solvable problem.
This field will need sanitising to prevent javascript URLs being used to seed unexpected behaviour when the data is presented.
Each option element is missing a value.
The user should be forced to enter a value here - defaulting to "Low" risks accidental form completion (e.g. by tabbing or hitting space or enter, unintended swipe/tap on mobile, etc.) with the wrong risk level.
It should be possible to render this form using vanilla HTML and CSS - with server-side validation.
Expires headers are set at 12 hours - they should have much larger values to take advantage of browser caching.
Connections are not persistent - resulting in repeated reconnection attempts to the same domain.
Assets should be gzipped to improve transfer speeds.
Assets should be served from other domains/CDN to improve parallelisation.
CSS and JS assets are largely redundant given the functionality of the page. If they are needed in subsequent parts of the app, then there is an argument for bundling and delivering them early to improve the overall performance of the app. If they are just cruft, then the bundling needs to be more targetted.
All the test scripts are inside the aa-web.spec.js
file.
Checks that the form cannot be submitted without adding content
immediately submits the form without inputting any data. This should trigger multiple validation errors on the front-end and prevent the form from being saved. This assumes that there is a pop-up for invalid form submissions and that it should not contain the words "You added".
The succeeding tests are all written in a data-driven way using the VALID_ENTRY
and INVALID_ENTRIES
objects.
Completes a form with valid values
Takes a single valid input object, submits the form and checks that the name matches in the save dialog. This test can be extended to input multiple valid values to test edge cases (see next test for an example). It includes a check that all the non-date input fields are of a text type.Checks that wrong input values are rejected
Takes the valid input and loops around the invalid values in theINVALID_ENTRIES
object, resubmitting the form each time and checking that the save dialog is not shown and that the correct Source info URL validation is applied. Note that Cypress does not allow you to input invalid dates, so an alternative test would be required to check date validation. For fields that take unstructured free-form text input, I am assuming that at least one alpha character is necessary. I am also assuming that country names should be real.Should validate missing entries
Takes the valid input and removes one value at a time, resubmitting the form each time and checking that the save dialog is not shown and that the correct Source info URL validation is applied.Checks for input sanitation
Attempts to submit an injection attack in the name field (the test can be extended to repeat for all text fields). The name value should be sanitised/deleted and the form NOT submitted.
cypress/support/commands.js
adds 3 functions to the cy
object that input complete and incomplete form entries and check the URL validation. They are kept in this file to keep the main script file free of confusing detail.
Completing the form always fails because:
- "John Doe" is hard-coded into the submit dialog text
- the name value that was input is deleted, resulting in errors in every test, plus a false positive in the
Checks for input sanitation
test. - Cypress cannot set a value for the Risk level field because the option elements are not correctly specified.
Cypress reports false positives when checking the Position field value - the value is correct but the text is not because it is declared as a password input. There is an extra check in the Completes a form with valid values
test to catch this.
Other than the URL field, there is no validation of acceptable values, so each test fails because no error message appears (I have assumed here that an element with a class of "error" should appear for invalid inputs).