Integration testing helper for web
Tasty helps test fully assembled web applications in nearly-production environment on real clients as real users.
npm install -g tasty
Tasty supports both multiple and single page applications (with server rendering too) and code coverage. It respects Content Security Policy and SSL/TLS.
Tasty server controls Tasty clients to run your tests against your application: navigate, fill forms, perform checks.
tasty.jsmodule to your assembly or markup.
However, you can use Selenium-driven clients to run your tests using Tasty.
The main purpose is to emulate real user experience. Interact with text and graphics, not with heartless HTML elements.
Tasty provides you only high-level tools to help treat your application as a black box, just like real user does. Don't use knowledge of your application's markup, assume you're helping a real person to achieve some goals.
Serve your application.
Write a test (this one uses Mocha).
Run Tasty server.
tasty --runner mocha --include test.js --pass secret
Open your application in your client. Tasty will run the test, print all output and exit.
Tasty server is a bridge between the clients and the test runner, it controls each client and runs tests written using Tasty tools.
--url flag to configre server's own URL.
Tasty client is a small extendable UMD module that connects to the server and executes its commands.
Tasty supports any test frameworks that support asynchronous tests.
--watch flag to watch for changes or run on several clients. See
tasty --help for more information.
You can run built-in static server on the same URL by passing
--static <path/to/root> flag.
For Tasty server running on
localhost:8765/path you should add the following CSP directives for Tasty client to work properly:
connect-src localhost:8765/path ws://localhost:8765/path wss://localhost:8765/pathscript-src localhost:8765/path/*.js
Remember, CSP allows consequently applied directives to only restrict the resulting set, i.e. meta tags can't expand/loose header directives and vice versa.
Check out a great tool for generating and validating CSP directives.
Each tool adds corresponding action to the runner queue instead of performing that action immediately. This allows to write tests in synchronous manner.
Queue is executed after
queue() call without arguments, which returns
Your testing framework may prefer callback for async tests.
For testing SPA (or rich MPA) you can provide a method for Tasty to ensure that client is ready for the next action.
Note that built-in methods cannot be combined. Call
client.ready(...) to register persistent method or use
page.ready(...) for temporary methods.
The simpliest way is to just wait after using some tools.
You may override the list of tools to wait after.
You always can manually add a delay into queue.
There could be enough to just check if DOM is ready...
client; // 'DOMContentLoaded' aka 'interactive' readyStateclient; // 'load' aka 'complete' readyState
...and maybe wait a little bit.
Another way is to provide some application-specific code.
Some tools could be called without arguments to get data from client.
queue(...) call with function allows you to add some custom logic into test, but you should use
queue.* namespace for tools.
queue.namespace.tool is the same as
namespace.tool, but runs immediately. You should use
queue.* tools only inside
queue(...) call if you don't want to break execution order.
To be described.
page.font(family: string, selector?: string): voidpage.loaded(): booleanpage.loaded(src?: string): voidpage.read(what?: string | RegExp, selector?: string): stringpage.ready(method: string, value: number | function, filter?: string): voidpage.text(what?: string | RegExp, selector?: string): voidpage.title(what?: string | RegExp): stringclient.location(): stringclient.location(what?: string | RegExp): voidclient.navigate(url: string): voidclient.ready(method: string, value: number | function, filter?: string): voidclient.reload(): voidinput.click(what?: string | RegExp, selector?: string, reachable = true): voidinput.hover(what?: string | RegExp, selector?: string, reachable = true): voidinput.paste(text: string): voidinput.type(text: string): voidrunner.get(key: string): anyrunner.pop(): anyrunner.push(value: any): voidrunner.set(key: string, value: any): voidrunner.until(tool: function, ...args: any): voidrunner.while(tool: function, ...args: any): void
On staging or other near-production environment, Tasty can't pass (re)CAPTCHA or two-factor authentication for you.
Store passwords in CIS and pass credentials into command line. All arguments will be available in
Get two-factor nonces from backdoor or use paid services to mock real mobile phones.
Use reCAPTCHA testing
secret for testing environment.
Instead of trying to click on iframed content, simply fake reCAPTCHA response with some suitable string, e.g.
secret, reCAPTCHA server should accept the same
g-recaptcha-response unlimited number of times.
If example above doesn't work (e.g. response format is changed), get new fake
<textarea name="g-recaptcha-response" />on the page.
For other CAPTCHA implementations, get answers from backdoor.
Use Let's encrypt or self-signed certificates.
npm run prepublish
Everything works fine, yay!