node-fest
v2.0.44
Published
The best productive test framework
Readme
node-fest
The fastest, code-free E2E framework for black-box testing — from the command line.
node-fest lets you write high-quality end-to-end automation tests for APIs, the Web, and WebSockets without writing any code. You describe a test as a single line of plain text, and node-fest runs it.
- Extremely productive — write hundreds of E2E tests per hour.
- Compact — every test case is a single line in a plain text file.
- No code required — just follow a small, consistent syntax.
- Uniform — the same file format and CLI work across API, Web, and WebSocket testing.
Installation
Install globally from npm
sudo npm install -g node-festThis installs three CLI binaries onto your PATH:
| Binary | Purpose |
| ---------- | ----------------------------- |
| fest_api | Run API test files |
| fest_web | Run Web (browser) test files |
| fest_ws | Run WebSocket test files |
Verify the install:
fest_api --help
which fest_api fest_web fest_wsfest_web drives a real browser via Selenium and requires Chrome (default) or Firefox to be installed.
Install globally from source (local development)
If you are working from a clone of this repo, build it and link it so the same three commands are available globally and stay pointed at your local build:
git clone https://github.com/dipankar08/simplewebtest.git
cd simplewebtest
npm install
npm run build # compiles TypeScript to lib/ (produces the binaries)
npm link # exposes fest_api / fest_web / fest_ws globallyRe-run npm run build after any code change. To remove the global link later:
npm unlink -g node-festQuick start
- Create a test file, e.g.
testcase.txt. - Write one test case per line.
- Run it:
fest_api -f ./testcase.txt # run an API test file
fest_web -f ./testcase.txt # run a Web test file
fest_ws -f ./ws.txt # run a WebSocket test file-f is optional. If you omit it, node-fest looks for ./testcase.txt in the
current directory — so from a folder that contains testcase.txt you can simply run:
fest_apiAt the end you get a pass/fail summary and, on failure, a per-test report with Expected, Observed, and a howToFix hint (e.g. the equivalent curl command).
How to write a test case
- A test file contains one test case per line.
- Each line is a sequence of events separated by
=>.event1 => event2 => event3 - Each event is a command followed by its arguments, also separated by
=>.open => https://example.com
Comments
Use ## for comments (a single # also works). Because # appears inside CSS selectors (IDs), escape it as \# inside a selector, or comment with ##:
=> verifyText => \#c => IdC ## '#c' is an element id, escaped as \#cTemplating & context
Values can be stored in a context and reused later with {{name}} (Mustache syntax):
=> context => server => simplestore.dipankar.co.in
=> get => http://{{server}}/api/test/find => successAPI responses can also be captured into the context using named regex groups:
=> !POST => http://{{server}}/api/test/create => {"name":"dip"} => "_id":"(?<id1>.*?)"
=> GET => http://{{server}}/api/test/find?id={{id1}} => successSetup steps
Prefix a command with ! to mark it as a setup/prep step. Setup steps still execute (and can capture context) but are not counted in the pass/fail totals:
=> !POST => http://{{server}}/api/test/create => {"name":"dip"} => "_id":"(?<id>.*?)"Command-line options
All flags are optional. These work for every runner:
| Flag | Description |
| ----------------------- | ------------------------------------------------------ |
| -f, --file <path> | Path to the test file (default: ./testcase.txt) |
| -s, --server <url> | Default server endpoint |
| -l, --line <n> | Run starting from this line number |
| -sl, --start_line <n> | Start line of the range to run |
| -el, --end_line <n> | End line of the range to run |
| -lm, --limit <n> | Run at most this many test cases |
| -o, --output <path> | Path to write the JSON result (default: system temp) |
| -d, --debug <bool> | Enable debug mode (true / false) |
| -v, --version | Print the installed node-fest version and exit |
| -h, --help | Show usage help and exit |
Additional flags for fest_web only:
| Flag | Description |
| ------------------------ | ---------------------------------------------- |
| -hl, --headless <bool> | Run headless (default true) |
| -q, --quit <bool> | Quit the browser at the end (default true) |
| -b, --browser <name> | chrome (default) or firefox |
Example:
fest_web -f ./web.txt -b chrome -hl false -q false
fest_api -f ./api.txt -sl 2 -el 5 -o ./result.jsonCommon commands
Available in every runner:
| Command | Arguments | Description |
| ---------- | ------------------------ | -------------------------------------------- |
| context | key => value | Set a context variable |
| sleep | seconds | Pause for N seconds |
| sleep_ms | milliseconds | Pause for N milliseconds |
| get | url => expected | HTTP GET, match response against expected |
| post | url => json => expected| HTTP POST JSON, match response |
| BASH | <any shell command> | Run a shell command; passes on exit code 0 |
expected is treated as a regular expression, so you can assert on substrings or capture groups.
Running shell commands
BASH runs any command through /bin/bash. The test passes when the command exits 0 and fails otherwise (captured stdout/stderr become the observed output). This is handy for setup/teardown — resetting a database, seeding fixtures, or checking a service is up — right inside a test file.
Everything after BASH => is taken verbatim, so the command may freely contain => (e.g. JavaScript arrow functions) even though => is normally the argument delimiter:
=> BASH => mongosh --quiet --eval 'db.getMongo().getDBNames().forEach(n=>db.getMongo().getDB(n).dropDatabase())'Context templating still applies, so {{vars}} are interpolated before the command runs:
=> context => db => testdb
=> BASH => mongosh --quiet --eval 'db.getSiblingDB("{{db}}").dropDatabase()'Combine with ! to make it a setup step that is not counted in the pass/fail totals:
=> !BASH => ./scripts/seed.shNote:
#still starts a comment (escape as\#), so avoid a literal#inside aBASHcommand or escape it. Only exit status is asserted —BASHdoes not match anexpectedregex.
Testing APIs
Use fest_api. Commands: GET, POST (plus the common commands above).
## api.txt
=> context => server => simplestore.dipankar.co.in
## GET: url => expected (regex)
=> GET => http://{{server}}/api/test0/test => 404 - We have not yet support this api
## POST: url => jsonBody => expected (regex)
=> POST => http://{{server}}/api/test0/create => {"name":"dip","count":1} => success
=> sleep => 2
## Capture an id from the response, then reuse it
=> !POST => http://{{server}}/api/test0/create => {"name":"dip"} => "_id":"(?<id1>.*?)"
=> GET => http://{{server}}/api/test0/find?id={{id1}} => successRun:
fest_api -f ./api.txt -o ./result.jsonTesting Web
Use fest_web. It drives a real browser via Selenium.
Supported commands:
| Command | Arguments | Description |
| ----------------- | -------------------------------------- | --------------------------------------------- |
| open | url [=> window] | Open a URL (optionally in a named window) |
| verifyBodyText | text | Assert the page body contains text |
| verifyNoBodyText| text | Assert the page body does not contain text |
| verifyText | selector => text | Assert an element's text |
| verifyTitle | title | Assert the page title |
| verifyAttr | selector => attr => value | Assert an element attribute |
| setAttr | selector => attr => value | Set an element attribute |
| click | selector | Click an element |
| clickWaitVerify | selector => ms => text | Click, wait, then assert body text |
| input | selector => text | Type text into an input |
| inputWithEnter | selector => text | Type text and press Enter |
| alert | ok | cancel | Accept or dismiss a browser alert |
| cookie | verify\|set\|delete => name [=> value] | Manage cookies |
| switch | window | Switch to a named window (main = default) |
| reset | — | Reset the browser state |
Example:
## web.txt — remember to escape '#' in selectors as '\#'
=> open => http://127.0.0.1:5500/src/web/sample.html
## Validate text
=> verifyBodyText => Welcome
=> verifyText => .a => classA
=> verifyText => \#c => IdC
=> sleep_ms => 500
## Actions
=> click => \#act1 button
=> verifyBodyText => Button clicked 1
=> clickWaitVerify => \#act1 button => 10 => Button clicked 3
## Inputs
=> input => \#inp1 input => hello
=> inputWithEnter => \#inp1 input => hello3
=> verifyBodyText => input is hello3
## Attributes
=> verifyAttr => \#atr1 a => href => https://google.com/
=> setAttr => \#atr1 a => href => https://yahoo.com/
## Alerts
=> click => \#alert button
=> alert => ok
=> verifyBodyText => alert return ok
## Cookies
=> cookie => set => name => dipankar
=> cookie => verify => name => dipankar
=> cookie => delete => name
## Multiple windows
=> open => http://google.com => Window1
=> open => http://yahoo.com => Window2
=> switch => Window1
=> verifyTitle => Google
=> switch => mainRun:
fest_web -f ./web.txtTip: arguments are split on
=>, so avoid literal=>inside a value. For JSON bodies with commas this is fine — commas are not delimiters.
Testing WebSockets
If you run a WebSocket server, you can test message flow across multiple clients.
Supported commands: connect, disconnect, send, check_recv, debug (plus context).
| Command | Arguments | Description |
| ------------ | ---------------------------------- | --------------------------------------------- |
| connect | url => id [=> expected] | Open a connection and bind it to id |
| send | id => payload [=> expected] | Send a message; optionally assert a reply |
| check_recv | id => expected [=> expected...] | Assert the next received message(s) for id |
| disconnect | id [=> expected] | Close a connection |
| debug | — | Dump all connections and queued messages |
## ws.txt — three clients on one server
=> context => server => wss://echo.websocket.org
=> connect => {{server}} => id1
=> connect => {{server}} => id2
=> connect => {{server}} => id3
=> send => {{id1}} => payload-A1
=> send => {{id2}} => payload-B1
=> check_recv => {{id1}} => payload-A1
=> check_recv => {{id2}} => payload-B1
=> disconnect => {{id1}}
=> disconnect => {{id2}}
=> disconnect => {{id3}}Run:
fest_ws -f ./ws.txtOutput & results
- A live log shows each test as it executes (
[PASS]/[FAIL]). - A summary prints pass count, fail count, and pass percentage.
- Failed tests are listed with
Expected,Observed, and ahowToFixhint. - The full run is written as JSON to the
-opath (or the system temp directory by default).
Roadmap
- Android — under development, not yet supported.
- iOS — under development, not yet supported.
Development
For contributing to node-fest itself, see HOW_TO_USE.md.
npm run build # compile TypeScript to lib/
npm test # run the jest suite
npm run format # prettier
npm run lint # tslint