• Stars
    star
    155
  • Rank 239,444 (Top 5 %)
  • Language
    JavaScript
  • Created almost 12 years ago
  • Updated almost 11 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

An automatic web app tester

walkabout.js

Walkabout.js is an automatic web application tester. It randomly simulates a user.

This code figures out what your application is paying attention to, and does it. It fills in fields with random values. It finds the events you listen for and fires those events. It finds internal links (like <a href="#foo">) and clicks them. It's a little like a fuzz tester for your app.

It has special support for jQuery, and uses source code rewriting to detect what your application is listening for in the absence of jQuery. (jQuery leaves evidence on DOM nodes about what is being listened for.)

You can use it like so (if you are using jQuery):

// This makes something like $('#some-input').val() return random values:
jQuery.fn.val.patch();

// Now, fiddle around, do 100 random things:
Walkabout.runManyActions({
  times: 100
});

You can also give Walkabout hints about what's a valid input; this lets it guess application-progressing values more often.

You can add data-walkabout-disable="1" to any element to suppress activation of that element or any of its children.

You can use data-walkabout-eventname="..." to set attributes on the event that is created, such as data-walkabout-keyup="{which: 13}"

You can use data-walkabout-options="['a', 'b']" to give the valid inputs for a field.

You can use data-walkabout-edit-value="type paste delete move" to have Walkabout do edit operations inside a textarea or input type=text. You give a space-separated list of the things to do: type a key at the cursor (and fire keyup), paste at the cursor (and fire paste), delete the selection or delete before or after the cursor, or move the cursor around.

Bookmarklet

If you want to try walkabout.js on some random jQuery site, you can use the bookmarklet. This will load Walkabout and also start a simple UI to start the runs. In addition to starting a run it'll also track any uncaught errors and any calls to console.warn() or console.error().

Non-jQuery Support

There's some support for working with code that doesn't use jQuery. It might work with other frameworks (by catching their calls to addEventListener), but is more intended to work with code that doesn't use a framework. (Note: if you know equivalent ways to detect what other frameworks are listening for, patches to Walkabout would be welcome, or issues with details and examples that can be tested on.)

This technique uses code rewriting to capture calls to .addEventListener() and .value. The code can't be weirdly tricky, it needs to actually use those literal names -- which is usually fine in "normal" code, but might not be in fancy or optimized code. E.g., el["addEventListener"](...) would not be found, nor would a="addEventListener";el[a](...)

You can use Walkabout.rewriteListeners(code) to rewrite the code.

The code transformation looks like this:

document.getElementById("el").addEventListener("click", function () {}, true);
var value = document.getElementById("textarea").value;

// Becomes:
Walkabout.addEventListener(document.getElementById("el"), "click", function () {}, true);
var value = Walkabout.value(document.getElementById("textarea"));

And to find actions you use Walkabout.findActions(element).

See Proxy Server for an option to use this.

Options

By default Walkabout will only go to links on the current page (i.e., href="#something"). This is because it will lose its context and potentially not load on the next page. But if you want Walkabout to move to other pages you can use Walkabout.options.anyLocalLinks = true

Or set it to something like "/dir/" which will only follow links under /dir/.

If you use Walkabout.options.loadPersistent = true then it will save the state in localStorage and continue where it left of when another page is loaded.

Proxy Server

An application could include walkabout.js on its own, and if it doesn't use jQuery it could also run Walkabout.rewriteListeners() on all its code. But maybe you don't feel like doing that, maybe you want to try it out without all that work. Also, by default Walkabout will try to stay on the current page, but in the proxy mode because it knows Walkabout will load on each page, it will freely move about the site.

There is a proxy server node-proxy.js that makes this easier. As you might guess, you have to install Node.js to use it.

The server expects to receive requests for the website you want to actually access. To do this you have to edit /etc/hosts to point the request locally, e.g.:

127.0.0.1 site-to-test.com

Then when you access http://site-to-test.com it will connect locally, and the proxy server in turn will forward the request to the actual server. Any HTML responses will have the Walkabout Javascript added, and Javascript will be rewritten.

Note that it binds to port 80, and so you must run it as root. This isn't awesome, pull requests to drop root welcome. A tool like authbind also could help.

When you are done you should definitely stop the server, and undo the /etc/hosts entry.

Note many live sites seem to notice the proxy, though I don't know how. My IP got blocked for a week from news.ycombinator.com after using it in my own testing. Any ideas welcome.

You can control the proxy with environmental variables: $PORT for the port to bind to (default 80), $BIND for the interface to bind to (default 127.0.0.1; 0.0.0.0 means all interfaces), and $PORT_ALIASES which looks like domain1:8088;domain2:8080 which lets you proxy from one port to another (helpful sometimes when you need to proxy to a server running locally).

License

This is available under the Mozilla Public License or the GPL.

To Do

Lots of stuff, of course. But:

  • Sometimes the validation options (like data-walkabout-options) should be obeyed, and sometimes they should be ignored. Obeying them progresses you through the site, disobeying them does some fuzz testing.

  • Not all form controls get triggered, I think. E.g., checkboxes don't get checked.

  • .val() should figure out better what's a reasonable return value. E.g., a textarea returns multi-line strings, a checkbox returns true/false.

  • Probably .val() hacking should just go away, and only do "real" editing of the fields.

  • The generator could have smarts about what scripts (i.e., action sequences) are successful and which are not. Starting with a successful script (that progresses you through the application), and then tweaking that script and increasing randomness at the end of the script.

  • We could look at code coverage as a score. Or we could even just look at event coverage - hidden elements often have events bound, but we know they have to be visible to be triggered. We'd like to explore paths where they are visible.

  • Something more Gaussian with the values generated. Like, sometimes you should make a 100 character input. But maybe not as often as a 10 character input. And sometimes a 1 character input. The values should be biased towards "fencepost" values. E.g., a bug that isn't triggered when you enter 43 is unlike to be triggered by 42, but more likely with 0, -1, or 1000000.

  • data-walkabout-options should be treated more as additional suggestions instead of the only suggestions. They represent valid inputs that will keep the application going, but invalid inputs are still sometimes interesting. Still the given options should be generally preferred when picking random options.

  • Once a path has shown itself to get us to "new" code (via code coverage or that we see new action options) we might want to explore that specific code path further. Maybe instead of a single random number seed, we could have a sequence of seeds: [[30491, 10], 50492] meaning use seed 30491 for 10 numbers, then reseed, exploring a different path but with the same start as a known-successful path.

  • A corollary of the above: we should have a signature for a set of actions, so we can quickly see if a set is unique.

  • Configuration should be possible externally, not just on attributes on the DOM. This would be fairly simple stuff, like:

    Walkabout.options.elements = {
      "#name": {
        suggest: "Bob"
      },
    };
    
  • Some way of indicating a bug-detector. Like, you know in some circumstances some element doesn't show when it should or something. These would be functions that would be run in-between actions. Simple assertions might work okay, but some tests are expensive or tricky. But in cases when you don't get an "error" but have noticed that invalid things can happen (without an exception) a detector might help create a reproducable case. This could also be a kind of "pause when" detector.

  • QuickCheck has this notion of making a test as small as possible -- basically seeing if you can get to the same error case with a smaller set of actions. This could be pretty straight forward for Walkabout as well. Though in cases like "do something, cancel something, do something again, do error thing" it might be tricky: we want to trim the first two actions, but trimming either one alone won't make the path possible. So we have to look for chunks we can pull out. With action signatures it might be easier to determine such chunks.

  • With code coverage it would be interesting to see which scripts had "changed" by seeing if any of the code they touch "changed". Then those scripts could be re-run.

  • Making "screencaps" at various points would be interesting. These would be a freeze of the visible DOM (BrowserMirror-style). We could do them only when we've determined a path that is "interesting" (i.e., maybe shows an error), by rerunning from the start.

  • Having a "reset app" hook would be good, so we can truly rerun.

  • Combining signatures, we could try to determine if the app wasn't deterministic despite our efforts.

  • We should patch Math.random()

  • We could consider timeouts an actionable thing. We could keep our own fake internal clock (mocking Date and setTimeout/setInterval), and moving it ahead in a predictable way. We could simulate conditions like a computer going to sleep this way.

  • Simulate pagehide and pageview.

  • Simulate WebAPIs, at least the non-deterministic ones. This involves mocking each one out (except event ones, which work kind of like other events).

  • Maybe hook up to WebDriver so we can issue events that we aren't generally allowed to issue. .dispatchEvent() doesn't work with keyboard events, for instance. OTOH, we could also reimplement the event dispatch process.

  • Put in touch events on mobile, and suppress hover events.

More Repositories

1

infinite-ai-array

Do you worry that you'll get to the end of a good list and have nothing more, leaving you sad and starved of data? Worry no more!
Python
167
star
2

git-sync

Use git as a sync tool, without munging your source and sync VCS operations
Shell
160
star
3

doctestjs

Javascript testing made easy and explicit
JavaScript
145
star
4

llm-garden

A number of experiments using GPT-3, delivered in a web app
JavaScript
48
star
5

jsshell

Shell (ala bash) written in Javascript for the browser and Node.js (incomplete prototype!)
JavaScript
47
star
6

personal-history-archive

An experiment in creating a dump of your personal browser history for analysis
Jupyter Notebook
33
star
7

neighborly

Neighbor-to-neighbor communication tool
Python
28
star
8

pywebapp

Support library for Python Web Applications
Python
19
star
9

sticky-reader-mode

A browser extension to turn on Reader Mode automatically per your preference
JavaScript
18
star
10

seeitsaveit

A Firefox Addon to extract and route information from web pages using ad hoc user scripts
JavaScript
16
star
11

whrandom

A port of Python's pseudo-random generator, whrandom
JavaScript
13
star
12

thecutout

A data storage and synchronozation system for client/browser-based applications
Python
11
star
13

wsgibrowserid

Stand-alone app to implement relying-party browserid.org support
Python
8
star
14

copy-keeper

An experimental add-on for saving everything you copy
JavaScript
7
star
15

webannotate

Annotate (add comments to) web pages
JavaScript
6
star
16

blog

My blog
HTML
6
star
17

find-plus-one

An experimental browser extension for search in pages linked from the current page
JavaScript
6
star
18

tab-switchr

Experimental super-simple tab switching add-on
JavaScript
5
star
19

wsgi-access-control

Access-Control-Allow-Origin etc middleware for WSGI
Python
4
star
20

apppkg

Application Package, a format for executable introspectable stuff
Python
4
star
21

fatfingers

A Javascript library to turn inaccurate touches into a modal selection to disambiguate
JavaScript
3
star
22

python-dc311

Python API for the Washington DC 311 API
Python
3
star
23

copy-url-extension

Small Firefox extension to make it easy to copy the page URL with the title
JavaScript
3
star
24

emailit

A very little Python app to email web pages to people
JavaScript
3
star
25

statusnet-firefoxshare

A Status.net plugin for Firefox Share (F1) support
PHP
2
star
26

alexa-sites

Whitelist of common sites, using Alexa as a basis
Shell
2
star
27

browsercommander

A browser-based shell and general system commander
JavaScript
2
star
28

thrive-ai

Implementation of the game Thrive, with some basic AI
Python
2
star
29

cmdutils

Python
2
star
30

phrase-matcher

JavaScript library to pattern-match English phrases
JavaScript
2
star
31

bitplanning

Playing around with Logic Planning, as described in Artificial Intelligence: A Modern Approach
Jupyter Notebook
2
star
32

app1.ianbicking.org

Test app
HTML
2
star
33

xmasapp

Little (open)webapp for Christmas Lyrics
Python
2
star
34

aitc-html

Apps In The Cloud HTML implementation
JavaScript
1
star
35

partial-language

An experiment with a partially-evaluated language: https://www.ianbicking.org/blog/2020/09/project-ideas-2020.html#partial-evaluation
JavaScript
1
star
36

intent-experiment

Just playing around with intent parsing
Shell
1
star
37

fungpt

Code for a presentation on coding with GPT
JavaScript
1
star
38

silverlining

(deprecated) A system to make easily deployable applications
Python
1
star
39

soul-faith

Open Soul named "Faith"
TypeScript
1
star
40

logdb-app

App structure for logdb
1
star
41

wphp

(deprecated) WSGI wrapper for PHP
Python
1
star
42

sheets

Experimenting with a Jupyter Notebook-style Python interface
Python
1
star
43

memebot

Messing around with meBot programming
Python
1
star
44

misc-recipes

These are old bits of code I kept on my once-SVN server
Python
1
star
45

crossnav

An experimental add-on to offer different ways to navigate from a page (besides in-page hyperlinks)
1
star