<commit_before># Pretender

Pretender is a mock server library in the style of Sinon (but built from microlibs. Because javascript)
that comes with an express/sinatra style syntax for defining routes and their handlers.

Pretender will temporarily replace the native XMLHttpRequest object, intercept all requests, and direct them
to little pretend service you've defined.

```javascript
var PHOTOS = {
  "10": {
    id: 10,
    src: 'http://media.giphy.com/media/UdqUo8xvEcvgA/giphy.gif'
  },
  "42": {
    id: 42,
    src: 'http://media0.giphy.com/media/Ko2pyD26RdYRi/giphy.gif'
  }
};

var server = new Pretender(function(){
  this.get('/photos', function(request){
    var all =  JSON.stringify(Object.keys(PHOTOS).map(function(k){return PHOTOS[k]}))
    return [200, {"Content-Type": "application/json"}, all]
  });

  this.get('/photos/:id', function(request){
    return [200, {"Content-Type": "application/json"}, JSON.stringify(PHOTOS[request.params.id])]
  });
});

$.get('/photos/12', {success: function(){ ... }})
```


## The Server DSL
The server DSL is inspired by express/sinatra. Pass a function to the Pretender constructor
that will be invoked with the Pretender instance as its context. Available methods are
`get`, `put`, `post`, `'delete'`, `patch`, and `head`. Each of these methods takes a path pattern
and a callback. The callback will be invoked with a single argument (the XMLHttpRequest instance that
triggered this request) and must return an array containing the HTTP status code, headers object, and body as a string.

```javascript
var server = new Pretender(function(){
  this.put('/api/songs/99', function(request){
    return [404, {}, ""];
  });
});

```

### Paths
Paths can either be hard-coded (`this.get('/api/songs/12')`) or contain dynamic segments
(`this.get('/api/songs/:song_id'`). If there were dynamic segments of the path,
these well be attached to the request object as a `params` property with keys matching
the dynamic portion and values with the matching value from the path.

```javascript
var server = new Pretender(function(){
  this.get('/api/songs/:song_id', function(request){
    request.params.song_id;
  });
});

$.get('/api/songs/871') // params.song_id will be '871'

```

Pretender will *only* handle requests to paths (`/some/kind/of/path`) and not fully qualified URLs
(`https://mydomain.tld/some/kind/of/path`). There are many
[CSP](http://www.html5rocks.com/en/tutorials/security/content-security-policy/) behaviors that cannot
be consistenly simulated when using full URLs (calls to `http` from an `https` page, requests to
external domains which may not implement CORS, etc).

### Query Parameters
If there were query parameters in the request, these well be attached to the request object as a `queryParams`
property.

```javascript
var server = new Pretender(function(){
  this.get('/api/songs', function(request){
    request.queryParams.sortOrder;
  });
});

// typical jQuery-style uses you've probably seen.
// queryParams.sortOrder will be 'asc' for both styles.
$.get({url: '/api/songs', data: {sortOrder: 'asc'});
$.get('/api/songs?sortOrder=asc');

```


### Responding
You must return an array from this handler that includes the HTTP status code, an object literal
of response headers, and a string body.

```javascript
var server = new Pretender(function(){
  this.get('/api/songs', function(request){
    return [
      200,
      {'content-type': 'application/javascript'},
      '[{"id": 12}, {"id": 14}]'
    ];
  });
});
```

### Pass-Through
You can specify paths that should be ignored by pretender and made as real XHR requests.
Enable these by specifying pass-through routes with `pretender.passthrough`:

```javascript
var server = new Pretender(function(){
  this.get('/photos/:id', this.passthrough);
});
```

## Hooks
### Handled Requests
In addition to responding to the request, your server will call a `handledRequest` method with
the HTTP `verb`, `path`, and original `request`. By default this method does nothing. You can
override this method to supply your own behavior like logging or test framework integration:

```javascript
var server = new Pretender(function(){
  this.put('/api/songs/:song_id', function(request){
    return [202, {"Content-Type": "application/json"}, "{}"]
  });
});

server.handledRequest = function(verb, path, request) {
  console.log("a request was responded to");
}

$.getJSON("/api/songs/12");
```

### Unhandled Requests
Your server will call a `unhandledRequest` method with the HTTP `verb`, `path`, and original `request`,
object if your server receives a request for a route that doesn't have a handler. By default, this method
will throw an error. You can override this method to supply your own behavior:

```javascript
var server = new Pretender(function(){
  // no routes
});
<commit_msg>Update README to explain the async features<commit_after># Pretender

Pretender is a mock server library in the style of Sinon (but built from microlibs. Because javascript)
that comes with an express/sinatra style syntax for defining routes and their handlers.

Pretender will temporarily replace the native XMLHttpRequest object, intercept all requests, and direct them
to little pretend service you've defined.

```javascript
var PHOTOS = {
  "10": {
    id: 10,
    src: 'http://media.giphy.com/media/UdqUo8xvEcvgA/giphy.gif'
  },
  "42": {
    id: 42,
    src: 'http://media0.giphy.com/media/Ko2pyD26RdYRi/giphy.gif'
  }
};

var server = new Pretender(function(){
  this.get('/photos', function(request){
    var all =  JSON.stringify(Object.keys(PHOTOS).map(function(k){return PHOTOS[k]}))
    return [200, {"Content-Type": "application/json"}, all]
  });

  this.get('/photos/:id', function(request){
    return [200, {"Content-Type": "application/json"}, JSON.stringify(PHOTOS[request.params.id])]
  });
});

$.get('/photos/12', {success: function(){ ... }})
```


## The Server DSL
The server DSL is inspired by express/sinatra. Pass a function to the Pretender constructor
that will be invoked with the Pretender instance as its context. Available methods are
`get`, `put`, `post`, `'delete'`, `patch`, and `head`. Each of these methods takes a path pattern,
a callback, and an optional [timing parameter](#timing-parameter). The callback will be invoked with a
single argument (the XMLHttpRequest instance that triggered this request) and must return an array
containing the HTTP status code, headers object, and body as a string.

```javascript
var server = new Pretender(function(){
  this.put('/api/songs/99', function(request){
    return [404, {}, ""];
  });
});

```

### Paths
Paths can either be hard-coded (`this.get('/api/songs/12')`) or contain dynamic segments
(`this.get('/api/songs/:song_id'`). If there were dynamic segments of the path,
these well be attached to the request object as a `params` property with keys matching
the dynamic portion and values with the matching value from the path.

```javascript
var server = new Pretender(function(){
  this.get('/api/songs/:song_id', function(request){
    request.params.song_id;
  });
});

$.get('/api/songs/871') // params.song_id will be '871'

```

Pretender will *only* handle requests to paths (`/some/kind/of/path`) and not fully qualified URLs
(`https://mydomain.tld/some/kind/of/path`). There are many
[CSP](http://www.html5rocks.com/en/tutorials/security/content-security-policy/) behaviors that cannot
be consistenly simulated when using full URLs (calls to `http` from an `https` page, requests to
external domains which may not implement CORS, etc).

### Query Parameters
If there were query parameters in the request, these well be attached to the request object as a `queryParams`
property.

```javascript
var server = new Pretender(function(){
  this.get('/api/songs', function(request){
    request.queryParams.sortOrder;
  });
});

// typical jQuery-style uses you've probably seen.
// queryParams.sortOrder will be 'asc' for both styles.
$.get({url: '/api/songs', data: {sortOrder: 'asc'});
$.get('/api/songs?sortOrder=asc');

```


### Responding
You must return an array from this handler that includes the HTTP status code, an object literal
of response headers, and a string body.

```javascript
var server = new Pretender(function(){
  this.get('/api/songs', function(request){
    return [
      200,
      {'content-type': 'application/javascript'},
      '[{"id": 12}, {"id": 14}]'
    ];
  });
});
```

### Pass-Through
You can specify paths that should be ignored by pretender and made as real XHR requests.
Enable these by specifying pass-through routes with `pretender.passthrough`:

```javascript
var server = new Pretender(function(){
  this.get('/photos/:id', this.passthrough);
});
```

### Timing Parameter
The timing parameter is used to control *how* a request responds. By default, a request responds
asynchronously on the next frame of the event loop. A request can also be configured to respond
synchronously, after a set amount of time, or never, (i.e., it needs to be manually resolved).

**Default**
```javascript
var server = new Pretender(function(){
  // songHandler will execute the frame after receiving a request (async)
  this.get('/api/songs', songHandler);
});
```

**Synchronous**
```javascript
var server = new Pretender(function(){
  // songHandler will execute immediately after receiving a request (sync)
  this.get('/api/songs', songHandler, false);
});
```

**Delay**
```javascript
var server = new Pretender(function(){
  // songHandler will execute two seconds after receiving a request (async)
  this.get('/api/songs', songHandler, 2000);
});
```

**Manual**
```javascript
var server = new Pretender(function(){
  // songHandler will only execute once you manually resolve the request
  this.get('/api/songs', songHandler, true);
});

// resolve a request like this
server.resolve(theXMLHttpRequestThatRequestedTheSongsRoute);
```

Pretender is a standalone library, and as such, offers no convenience methods for capturing
XHRs that another library makes.

#### Using functions for the timing parameter
You may want the timing behavior of a response to change from request to request. This can be
done by using a function for the timing parameter.

```javascript
var externalState = 'idle';

function throttler() {
  if (externalState === 'OH NO DOS ATTACK') {
    return 15000;
  }
}

var server = new Pretender(function(){
  // songHandler will only execute based on the result of throttler
  this.get('/api/songs', songHandler, throttler);
});
```

Now whenever the songs route is requested, its timing behavior will be determined by the result
of the call to `throttler`. When `externalState` is idle, `throttler` returns `undefined`, which
means the route will use the default behavior.

When the time is right, you can set `externalState` to `"OH NO DOS ATTACK"` which will make all
future requests take 15 seconds to respond.

## Hooks
### Handled Requests
In addition to responding to the request, your server will call a `handledRequest` method with
the HTTP `verb`, `path`, and original `request`. By default this method does nothing. You can
override this method to supply your own behavior like logging or test framework integration:

```javascript
var server = new Pretender(function(){
  this.put('/api/songs/:song_id', function(request){
    return [202, {"Content-Type": "application/json"}, "{}"]
  });
});

server.handledRequest = function(verb, path, request) {
  console.log("a request was responded to");
}

$.getJSON("/api/songs/12");
```

### Unhandled Requests
Your server will call a `unhandledRequest` method with the HTTP `verb`, `path`, and original `request`,
object if your server receives a request for a route that doesn't have a handler. By default, this method
will throw an error. You can override this method to supply your own behavior:

```javascript
var server = new Pretender(function(){
  // no routes
});

{'fraction_non_alphanumeric': 0.12907015777106412, 'fraction_numerical': 0.008811681772406849, 'mean_word_length': 4.494236975564776, 'pattern_counts': {'":': 14, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1128850', 'n_tokens_mistral': 3607, 'n_tokens_neox': 3388, 'n_words': 1352}