Every user input is a potential thread to the web application. When handling forms, there are several things, that should be tested to guarantee flawless functionality. The servers security, immutability of variables, error handling, correct processing of user requests and the correct communication of all the above.
On the other hand, a user should not be discouraged when trying to fill out the form. Take care on how he or she might approach your form.
This will be a general post to list the types of tests that should be considered when using web forms. If possible I will try to follow with some more specific posts, using specific frameworks for implementation.
I found “A Checklist for Web Form Testing (by Pooja Potghan) that takes care about testing with a browser, by hand and using simple, build-in tools.
Then there is this “Form Submission Test Checklist” with abstract but very good entries to consider, when testing web forms.
Then there is a “Checklist for Better Web Forms” (by Mert TOL), that looks on specific form inputs and how to correctly code them.
There will be resources for whichever specific framework you use, so watch out for them.
And as always, I will happily expand this list.
Yes, this deserves a heading on it’s own. When constructing your application and your web form, take a good amount of time and brain to think about testing. Consider TDD (Test Driven Development), establish guidelines for unit tests and PR (pull requests), as well as free resources to proceed manual testing and even to use test devices.
On another note, web forms will have to work in different browsers on different platforms. As it is nearly impossible to implement them for ALL the browsers, create a browser and device matrix for testing. This is especially true when working for a steakholder. You might want as much detail as specific devices with their os version and browsers with their version or “current version”.
Every feature and every form step should receive a unit test. When building your own forms templates, test the single controls exzessively, as well as conditions that you want to apply. Then there are tests that still make sense when using an established framework to check, whether user input is handled correctly.
In the post about designing web forms, validators were already mentioned. Test whether they work by feeding your inputs values with empty, unexpected and strange characters, as well as asking for edge cases. Depending on the input type and the information it should gather, consider additional tests.
For names of peoples and places, did you allow special characters, that might be crucial? (á, ö, …) Do you limit the length and will this prevent a user from filling their rather long name? Did you trim the text from white spaces?
When using selects, is there a default value? Will the default be valid and is it transferd through the form?
Date inputs are a challenge on their own. Besides from good usability, how does your application react to different date inputs? Today? In the future? In the past? Birth dates that make the user 2 or 200 years old?
Only valid forms should be submitted. Therefore…
- Test that an empty form can not be submitted and does not send a request to the backend.
- Test that a partially filled form (with empty required fields) can not be submitted and does not send a request to the backend.
- A fully filled form should only be submitted and send a request to the backend, if it is valid. Forms with errors should not.
- Test that a correctly filled form is submitted and sends a request to the backend.
Remember that there is more than one way to fill a form – valid or invalid.
If your framework uses MVC as a pattern, consider implementing MVP (Model View Presenter). This might be only viable for larger projects, but then it makes modular testing much easier.
If in the design stage you choose to make your form complicated, keep an eye on optionally visible form elements, conditions between fields and dynamic validators. In your tests, implement positive and negative cases to check if they work properly.
This involves tester, that are different from the developers. The thing is, that as a developer you are only sensible to the working paths through your forms and it takes a fresh view to break it.
The form should be easy accessible. Required and optional fields must be easyly spotted. A user should be able to navigate the form with the keyboard only. Texts should be of high contrast and readable. Also no unrequired information should be shown.
When entering an invalid value or characters, does the form correctly show an error? Does the form make clear, which input causes the error? Is the error message truely a message, and explains what the user has to do, to fix it?
Testing in a browser comes with additional tools. Use the browsers functionalities, like buttons to navigate the pages (back, reload), delete cookies mid form, close the browser, copy and paste the url on a step within the form. Try to use the form in another order.
On mobile, try phone features. Move the browser to the background, get a phone call mid form or shut down the device and see what happens.
Another nice test is with the internet connection. Browsers may slow the date rate down and on a device, you should be able to fully deactivate the connection. The form should react accordingly.
Use the defined browser matrix to do all of the above in all the browsers on all the devices that are meant to work for this form. Maybe try a clearly excluded browser to check some error messages.
More on this topic under pentests. But it’s easy to enter clearly wrong symbols or values and see how the form reacts.
The real magic happens in the backend. At least the stuff that involves work that should or could not be done by the browser. Get data, load images, post changes and forms.
The frontend framework uses http requests to talk to the backend. They have a specific format, parameters and headers. A change at either end must be reflected in the other. Think about renaming a parameter in the backend when requesting user data, but the old version in the frontend lets the whole request fail.
Cover the functionality around requests, by writing api tests. For me this is a collection of possible request, that can be send by the frontend and reflects its workflow. Running these tests helps detecting changes, that have only been made at one end.
Type of requests
The address of an API call is meant to react to GET… or POST…, but there are more types of request. There is PUT, and DELETE for example. They have to be explicitly blocked, to disallow these kind of requests. Therefore, wrong types of request should fail.
Additionally, valid requests should be send with another type. Use POST instead of PUT and so on.
And changes might also be made on the requests type.
HTTP calls have different types of parameters. Headers attached to the requests, url paramters to specify the request and data, send in the content.
Additionally, a session token or cookie might be in use to autorize the user. The autorization is a very sensible use case to take care of. Unautorized calls should fail, tokens must be refreshed and it should be impossible to create them without valid user credentials.
When testing forms, send the forms data in different variations. Ignore the implemented validators on the frontend, they must always be repeated on the backend. Invalid request should be declined and correct ones should succeed.
Also – although we are touching the pentest area here – sensible data should never be send in plain text. Never. Ever.
This is a list of tools that I know and have used to comfortable test a list of api calls.
- Postman: Use as app or browser plugin to create collections of api calls for differend use cases, like login, data update and so on.
- JMeter: With an older UI, but also able to run load tests and distribute the tests amoung devices.
Pentests are necessary, whenever the secrecy of data or the availability of a website is crucial. So, most of the time. Penetration tests will emulate attacks on page, service and backend. There is a huge variety of test that can be executed, the scope should fit the application.
I will give a hint on larger tests but concentrate on those, that apply specifically to forms.
Yes, there is wrong input, broken conditions, missing characters or numbers in a textfield. But there also is malicious input. Nowadays, there are frameworks used to prevent dependency injection, nonetheless – don’t skip the test.
Dependency injection wants to start right after the input value. Start with quotation marks, slashes, semicolons and see, how the requests reacts.
Wrong values might succeed, when the validator didn’t catch them. I.e. negative numbers, special characters or the words “null” or “undefined”.
This evolves mostly around login, logout and session persistance. In case of forms, how long will you hold the session data – the forms input – before deleting? A user might want to return to his half filled form after a short break, but you don’t want to expose his sensible data by storing it too long. Also, a link to the session should never include the inserted data, this must be local and temporary (delete after submit).
This one is easy: let your small children or cat hit the keyboard.
The application should be able to handle unexpected input – of any key or klick or touch. At least it should not crash or leak sensible information.
(Distributed) Denial of Service.
This scenario actually happends every day. Not only could the servers shut down under a malicious attack, but it should also be able to handle a huge amoungt of requests. As the developer it is neccessary to estimate the number of users that may use the form at the same time. At a release, deadline, or when a page gets viral, this number might explode and not only beats the servers, but also demotivates all the potential users.
In the field of pentesting, there is a lot more to attack a website. Half of it attacks the server. Even when creating the frontend, one should be familiar with cross side scripting, spoofing and the art of spam emails.
I will add to this list, if I stumple across something fitting.