Giter VIP home page Giter VIP logo

pretender's Introduction

Pretender

npm version Build Status Coverage Status Dependency Status devDependency Status Code Climate

Pretender is a mock server library for XMLHttpRequest and Fetch, that comes with an express/sinatra style syntax for defining routes and their handlers.

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

โš ๏ธ Pretender only works in the browser!

const 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'
  }
};

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

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

$.get('/photos/12', {success() => { ... }})

Usage

yarn add -D pretender
# or
npm install --save-dev pretender

You can load Pretender directly in the browser.

<script src="node_modules/pretender/dist/pretender.bundle.js"></script>

Or as a module:

import Pretender from 'pretender';
const server = new Pretender(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. 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.

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

a Pretender constructor can take multiple maps:

import adminMaps from "testing/maps/admin";
import photoMaps from "testing/maps/photos";

const server = new Pretender(photoMaps, adminMaps);
// testing/maps/photos

const PHOTOS = {
  "58": {
    id: 58,
    src: 'https://media.giphy.com/media/65TpAhHZ7A9nuf3GIu/giphy.gif'
  },
  "99": {
    id: 99,
    src: 'https://media.giphy.com/media/4Zd5qAcFv759xnegdo/giphy.gif'
  }
};

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

The HTTP verb methods can also be called on an instance individually:

const server = new Pretender();
server.put('/api/songs/99', request => [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 will 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.

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

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

Query Parameters

If there were query parameters in the request, these will be attached to the request object as a queryParams property.

const server = new Pretender(function() {
  this.get('/api/songs', 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.

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

Or, optionally, return a Promise.

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

      resolve(response);
    });
  });
});

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:

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

In some cases, you will need to force pretender to passthough, just start your server with the forcePassthrough option.

const server = new Pretender({ forcePassthrough: true })

Other times, you may want to decide whether or not to passthrough when the call is made. In that case you can use the .passthrough() function on the fake request itself. (The unhandledRequest property is discussed below.)

server.unhandledRequest = function(verb, path, request) {
  if (myIgnoreRequestChecker(path)) {
    console.warn(`Ignoring request) ${verb.toUpperCase()} : ${path}`);
  } else {
    console.warn(
      `Unhandled ${verb.toUpperCase()} : ${path} >> Passing along. See eventual response below.`
    )
  
    const xhr = request.passthrough(); // <-- A native, sent xhr is returned
  
    xhr.onloadend = (ev) => {
        console.warn(`Response for ${path}`, {
          verb,
          path,
          request,
          responseEvent: ev,
        })
      };
  }
};

The .passthrough() function will immediately create, send, and return a native XMLHttpRequest.

Timing Parameter

The timing parameter is used to control when a request responds. By default, a request responds asynchronously on the next frame of the browser's event loop. A request can also be configured to respond synchronously, after a defined amount of time, or never (i.e., it needs to be manually resolved).

Default

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

Synchronous

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

Delay

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

Manual

const 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);

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 providing a function as the timing parameter.

const externalState = 'idle';

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

const 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.

Scheduling ProgressEvent

If the timing parameter is resolved as async, then a ProgressEvent will be scheduled every 50ms until the request has a response or is aborted.

To listen to the progress, you can define onprogress on the XMLHttpRequest object or its upload attribute.

let xhr = new window.XMLHttpRequest();
xhr.open('POST', '/uploads');
// https://fetch.spec.whatwg.org/#concept-request-body
// https://xhr.spec.whatwg.org/#the-send()-method
let postBody = new ArrayBuffer(8);
xhr.upload.onprogress = function(event) {
  // event.lengthComputable === true
  // event.total === 8
  // event.loaded will be incremented every ~50ms
};
xhr.onprogress = function(event) {
  // xhr onprogress will also be triggered
};
xhr.send(postBody);

Sharing routes

You can call map multiple times on a Pretender instance. This is a great way to share and reuse sets of routes between tests:

export function authenticationRoutes() {
  this.post('/authenticate',() => { ... });
  this.post('/signout', () => { ... });
}

export function songsRoutes() {
  this.get('/api/songs',() => { ... });
}
// a test

import {authenticationRoutes, songsRoutes} from "../shared/routes";
import Pretender from "pretender";

let p = new Pretender();
p.map(authenticationRoutes);
p.map(songsRoutes);

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:

const server = new Pretender(function() {
  this.put('/api/songs/:song_id', 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:

const server = new Pretender(function() {
  // no routes
});

server.unhandledRequest = function(verb, path, request) {
  console.log("what is this I don't even...");
}

$.getJSON("/these/arent/the/droids");

Pass-through Requests

Requests set to be handled by pass-through will trigger the passthroughRequest hook:

const server = new Pretender(function() {
  this.get('/some/path', this.passthrough);
});

server.passthroughRequest = function(verb, path, request) {
  console.log('request ' + path + ' successfully sent for passthrough');
}

Error Requests

Your server will call a erroredRequest method with the HTTP verb, path, original request, and the original error object if your handler code causes an error.

By default, this will augment the error message with some information about which handler caused the error and then throw the error again. You can override this method to supply your own behavior:

const server = new Pretender(function() {
  this.get('/api/songs', request => {
    undefinedWAT("this is no function!");
  });
});

server.erroredRequest = function(verb, path, request, error) {
  SomeTestFramework.failTest();
  console.warn("There was an error", error);
}

Mutating the body

Pretender is response format neutral, so you normally need to supply a string body as the third part of a response:

this.get('/api/songs', request => {
  return [200, {}, "{'id': 12}"];
});

This can become tiresome if you know, for example, that all your responses are going to be JSON. The body of a response will be passed through a prepareBody hook before being passed to the fake response object. prepareBody defaults to an empty function, but can be overridden:

const server = new Pretender(function() {
  this.get('/api/songs', request => {
    return [200, {}, {id: 12}];
  });
});

server.prepareBody = function(body){
  return body ? JSON.stringify(body) : '{"error": "not found"}';
}

Mutating the headers

Response headers can be mutated for the entire service instance by implementing a prepareHeaders method:

const server = new Pretender(function() {
  this.get('/api/songs', request => {
    return [200, {}, '{"id": 12}'];
  });
});

server.prepareHeaders = function(headers){
  headers['content-type'] = 'application/javascript';
  return headers;
};

Tracking Requests

Your pretender instance will track handlers and requests on a few array properties. All handlers are stored on handlers property and incoming requests will be tracked in one of three properties: handledRequests, unhandledRequests and passthroughRequests. The handler is also returned from any verb function. This is useful if you want to build testing infrastructure on top of pretender and need to fail tests that have handlers without requests. You can disable tracking requests by passing trackRequests: false to pretender options.

const server = new Pretender({ trackRequests: false });

Each handler keeps a count of the number of requests is successfully served.

server.get(/* ... */);
const handler = server.handlers[0];

// or

const handler = server.get(/* ... */);

// then

const numberOfCalls = handler.numberOfCalls;

Clean up

When you're done mocking, be sure to call shutdown() to restore the native XMLHttpRequest object:

const server = new Pretender(function() {
 ... routing ...
});

server.shutdown(); // all done.

Development of Pretender

Running tests

  • yarn build builds pretender
  • yarn test runs tests once
  • yarn test:server runs and reruns on changes

Code of Conduct

In order to have a more open and welcoming community this project adheres to a code of conduct adapted from the contributor covenant.

Please adhere to this code of conduct in any interactions you have with this project's community. If you encounter someone violating these terms, please let a maintainer (@trek) know and we will address it as soon as possible.

pretender's People

Contributors

adamjmcgrath avatar bantic avatar bekzod avatar bombillazo avatar cibernox avatar dependabot[bot] avatar dingoeatingfuzz avatar dschmidt avatar eluciano11 avatar givanse avatar guybedford avatar happycollision avatar ledleds avatar machty avatar mattrothenberg avatar mfeckie avatar mike-north avatar ming-codes avatar mrijke avatar nathanhammond avatar raido avatar riklaunim avatar rwjblue avatar ryanto avatar samselikoff avatar stefanpenner avatar trek avatar tricknotes avatar xg-wang avatar zglagola avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pretender's Issues

How can I use posted data?

How can I access the data passed via a post request?

Based on the evil trout video on pretender I'd like to do something like this:

this.post('/api/v1/token', function(request){
    console.log(request);
    var data = parsePostData(request.requestBody); // doesn't work
   // check username and password and if okay
    var response = {
        "access_token": "myaccesstoken==",
        "token_type": "bearer"
    };
    return [200, {}, response];

Pretender doesn't recognize routes with query params

Failing test:

test("can register queryParam urls", function(){
  var queryCalled  = false;
  var noQueryCalled = false;
  pretender.get('/some/path?a=1&b=2', function(request){
    queryCalled = true;
  });
  pretender.get('/some/path', function(request){
    noQueryCalled = true;
  });

  $.ajax({url: '/some/path?a=1&b=2'});
  ok(!noQueryCalled, 'should be false');
  ok(queryCalled, 'should be true');
});

I have tracked the problem down to RouteRecognizer: https://github.com/tildeio/route-recognizer/blob/master/lib/route-recognizer.js#L475-L523

It appears that RotueRecognizer will register the original path along with the queryParams. However in the linked function above the queryParams are striped from the path and no handler is found for the truncated path.

My use-case is https://github.com/dockyard/ember-cli-proxy-fixtures. This module is recording request responses during the test suite for faster playback via Pretender on future runs.

How can I use request headers?

I would also like to be able to access the headers and get to the authorization bearer token for simulating oauth, how can I get to these fields in the request object?

Response data in handledRequest?

Is there any way to get/log the response data in handledRequest, or some other callback? I'd like to log the verb/path + response each time one is made, similar to how the network tab shows actual XHR requests.

preprocessing requests

Hello,

sometimes urls requests are performed by 3rd party libraries and they use an absolute url, like http://localhost:4200/api/v1/s3_mock, when initial path was only /api/v1/s3_mock.

For that case it will be good to have some request pre-processing hook(s), which will allow altering request url, something analogues to the server.prepareBody and server.prepareHeaders hooks.

latest releases not on npm

This may be intentional, though I don't understand why: the latest release on npm is behind the latest release on github.

npm install fails - route-recognizer version

Seems NPM still things you're asking for route-recognizer 0.1.1?

$ npm install pretender
npm http GET https://registry.npmjs.org/pretender
npm http 304 https://registry.npmjs.org/pretender
npm http GET https://registry.npmjs.org/fake-xml-http-request
npm http GET https://registry.npmjs.org/route-recognizer
npm http 304 https://registry.npmjs.org/fake-xml-http-request
npm http 304 https://registry.npmjs.org/route-recognizer
npm ERR! notarget No compatible version found: route-recognizer@'>=0.1.1-0 <0.2.0-0'
npm ERR! notarget Valid install targets:
npm ERR! notarget ["0.1.0"]
npm ERR! notarget
npm ERR! notarget This is most likely not a problem with npm itself.
npm ERR! notarget In most cases you or one of your dependencies are requesting
npm ERR! notarget a package version that doesn't exist.

Tests fail on master

To reproduce:

  • Check out 3bec2d1 (currently master, or release 0.7.0)
  • clear node_modules and bower_components, and npm i; bower i if you like
  • run npm test

screen shot 2015-07-29 at 2 46 28 pm

How to use this with Karma and Mocha?

I have a similar question to this issue but not for Ember, just for a simple project not using any MVC framework.

Using Karma, Mocha, and RequireJS, where would the pretender server code go? And does it need to run beforeEach test or should it only run once at the beginning of the test suite?

Progress events

According to the XHR2 specification (https://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#make-progress-notifications):

while the download is progressing, queue a task to fire a progress event named progress about every 50ms or for every byte received, whichever is least frequent.

How do you feel about pretender triggering that event each 50ms by default? If nobody is listening, it's ok. Alternatively you can trigger only if there is an "onprogress" handler attached to the relevan object.

FakeXMLHttpRequest.prototype.send's that happen after `shutdown` should error

https://github.com/trek/pretender/blob/master/pretender.js#L36-L50

adding this.alive = true here https://github.com/trek/pretender/blob/master/pretender.js#L33
adding this.alive = false here https://github.com/trek/pretender/blob/master/pretender.js#L136

and checking pretender.alive here https://github.com/trek/pretender/blob/master/pretender.js#L44 will allow pretender to assert.

How can this happen?

var server = new Pretender();

var myRequest = new XMLHttpRequest();
// setup stuff
// some async
setTimeout(function(){
  myRequest.send();
}, 0);

server.shutdown();

sync case.

var server = new Pretender();

var myRequest = new XMLHttpRequest();
// setup stuff
// some async
server.shutdown();
myRequest.send();

Server Inheritance / Easier map sharing

Ideally, we'd like to have new Pretender instances be created from existing instances. This would allow you to re-use a set of routes in tests. I think this would be especially useful for nested tests. You can get this behavior today by sharing route maps, but it's a little manual and limited to a depth of 1.

This will likely require pretty major internal refactoring?

Support for passthrough by default

Currently, there doesn't seem to be a way to only use Pretender for only a couple of specific paths, while allowing everything else to behave normally.

I'm trying to use Pretender to stub out data for one or two endpoints that aren't built out yet on the server. Since I do have a whole lot of other endpoints that are built out, I'd like to tell it to go ahead and treat all unhandled requests as passthroughs. Essentially, if I didn't tell it what to do for a path, let my server handle it.

Testing file uploads

Just thought of doing this through pretender in one of my projects and was wondering if anyone had experience?

allow to bypass if passthrough is specified

Hello, there should be a way to interact with the 3rd party API, like S3 for example.

Right now even taking in account that passthrough is defined Pretender still throw an error:

this.post('https://bucket.s3.amazonaws.com', this.passthrough);

Error: Pretender will not respond to requests for URLs. It is not possible to accurately simluate the browser's CSP. Remove the https://bucket.s3.amazonaws.com from https://bucket.s3.amazonaws.com/ and try again

jQuery 1.x with passthrough

I can't get passthrough to work with jQuery 1.x. The requests are sent using $.ajax('/path').then(...) but the then callbacks are never fired.

Seems like the onload event is detected on the browser xhr but is not supported by the 1.x jQuery xhr module, so it is not dispatched when the response is received.

I was able to get the events to fire by removing the check for onload and just adding both events.

There is a chance that both events could be fired I'm guessing. Any other concerns I should check into before getting a PR ready?

Question about using/implementing a front controller

I'm wondering if it's possible to dynamically register request handlers at time of request, i.e. look up a handler when the actual request is made. I'd like to do this so that my addon can respond to requests by looking up a handler if it exists at, say, /app/pretender/routes/some-route.js.

Is this possible now? I was thinking about doing it in the unhandledRequest, but I'm not sure I can invoke handleRequest from there? Any suggestions about how to approach this/work a possible PR?

Add to npm

Could you publish to npm? pretender package name is still available.

support for promises

Example:

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

Feature Request: api namespace

Would you be open to a PR adding options to the Pretender constructor that allowed passing in a namespace, similar to Ember Data's namespace property?

Example usage:

server = new Pretender(function(){
   this.get('users/:user_id', function() { ... });
}, {namespace: 'api/v1'});

This will intercept a GET request to /api/v1/users/:user_id.

pretender doesn't work with jspm

I just tried pretender with the jspm package manager, but there are some internals it tries that defeats jspm, in particular this line:

var FakeXMLHttpRequest = isNode ? require('./bower_components/FakeXMLHttpRequest/fake_xml_http_request') : window.FakeXMLHttpRequest;

in a jspm environment pretender thinks it's in node, but then tries to do a require directly from a bower_components directory which isn't there in a jspm setup. Since jspm is actually not in node the whole detection of node might also be somewhat fragile.

Remove the bower install postinstall script

Is there a reason that the bower install needs to be run on postinstall? It requires bower to be installed for projects using pretender as an npm dependency.

"scripts": {
    "postinstall": "bower install"
  }

unable to npm install with pretender as dependency

I get the following error whenever i run 'npm install'. Looks like bower dependency was not installed before running the postinstall step?

npm install
npm WARN package.json [email protected] assert is also the name of a node core module.
|

[email protected] postinstall /Users/jlidder/Documents/repos/temp3/fba/node_modules/pretender
bower install

sh: bower: command not found
npm ERR! Darwin 13.4.0
npm ERR! argv "node" "/usr/local/bin/npm" "install"
npm ERR! node v0.12.0
npm ERR! npm v2.5.1
npm ERR! code ELIFECYCLE

npm ERR! [email protected] postinstall: bower install
npm ERR! Exit status 127
npm ERR!
npm ERR! Failed at the [email protected] postinstall script 'bower install'.
npm ERR! This is most likely a problem with the pretender package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR! bower install
npm ERR! You can get their info via:
npm ERR! npm owner ls pretender
npm ERR! There is likely additional logging output above.

npm ERR! Please include the following file with any support request:
npm ERR! /Users/jlidder/Documents/repos/temp3/wtvproject/npm-debug.log

Passthrough loses request Content-Type

I'm using

var server = new Pretender(function(){
  this.post('/ubus', this.passthrough);
});

This changes the requests' Content-Type header from

Content-Type:application/json

to

Content-Type:text/plain;charset=UTF-8

so that I get a 500 error back from the server.

Binary files are converted to strings

We use pretender to stub an Ember application, we have some sounds that are loaded and played while using the application. Loading and playing sounds fails because the pretender doesn't handle the xhr.responseType. We use Howler to load and play sounds, Howler sets the xhr.responseType to 'arraybuffer'. Pretender doesn't handle 'arraybuffer' which results in an error because Howler expects an arraybuffer. I've been trying all day to fix this in Pretender but without success so far.

This is how Howler loads an audiofile
https://github.com/goldfire/howler.js/blob/master/howler.js#L1230

Transparently follow redirects

Ran into an interesting thing today where I simulated a 302 response from an API using pretender and TDD'd some app functionality. However, when I integrated the actual API, I found that the 302 was never seen by jQuery, leading my feature to be broken with the real API despite working with pretender.

After some research, it turns out that part of the XMLHttpRequest spec says that redirects should be followed, transparently to the client:

If the origin of the URL conveyed by the Location header is same origin
with the XMLHttpRequest origin and the redirect does not violate infinite
loop precautions, transparently follow the redirect while observing the
same-origin request event rules.

Ideally, pretender would exhibit this behavior, too.

Passing off certain requests to real endpoints

Is there any way to let Pretender know that for specified paths to continue using the actual request route? I would like to be able to fake out certain routes that are not handled by my application but have some go through to the real endpoints. I can't see an easy way to do this currently but I'm hoping you could point me in the right direction.

[Proposal] - `all` Route Registerer

When working with routes (specifically passthrough) it would be helpful to have an all route registration to allow handling of any HTTP verb.

For instance if an API has gone from needing mocks to needing passthrough, the code now becomes:

this.get('user', this.passthrough);
this.post('user', this.passthrough);
this.put('user', this.passthrough);
this.delete('user', this.passthrough);

Async response

Is it possible in pretender to create a route that returns a promise? I have a need to communicate via postMessage to a parent window before I can return the correct response. Is there any built in way to respond to a request asynchronously?

Aysnc Responses

Currently responses occur synchronously. This can create subtle self-trolls where your code assumes responses will occur immediately in testing but the don't in production.

Stubbing out urls (as opposed to paths)

Currently it is not possible to register handlers for URLs, only paths. When looking for a handler for the upcoming request, Pretender checks if the first char of the path is a '/', and if not, adds the slash.

Thus a handler registered for e.g http://api.twitter.com will never be "recognized". I think the reason is probably using the RouteRecognizer for finding the handler so I'm not sure if this could be remedied but I think it's a common enough use case to see what can be done about it or how others dealt with this.

I ended up transforming the URL for the request only in testing (so e.g https://api.twitter.com/endpoint would become /twitter-api/endpoint) so that I could stub it out with Pretender. Not a big fan of this, though, since I had to add non-testing code to facilitate testing.

Using Pretender with `fetch`.

It would be nice to be able to use fetch instead of XMLHttpRequest. When using the non-native fetch polyfil Pretender would likely still work (because the polyfill uses XMLHttpRequest to implement fetch), but it doesn't seem that native fetch requests would be handled by Pretender.

Spec: https://fetch.spec.whatwg.org

This issue is mostly to lay out a path forward.

/cc @cowboyd @toranb

Unscoped for-loop counter

// trigger the route map DSL.
  for(i=0; i < arguments.length; i++){
    this.map(arguments[i]);
  }

Is there a reason why the counter is added to the window object?

Pretender intercepts PUT but thinks there are no handlers

When trying to use Pretender in my tests, I keep getting an error that a PUT request is being unhandled.

"Pretender intercepted PUT http://api.lvh.me:3000/passwords/4615efd359fb8d96804a1d77efea78e528667d62
but no handler was defined for this type of request"

But from the test below, it seems to be pretty clearly handled.

`import { test, moduleFor } from 'ember-qunit'`
`import startApp from '../helpers/start-app'`

App = undefined
server = undefined

module "Integration: Reset Password",
  setup: ->
    App = startApp()
    response = 
      user:
        email: "[email protected]"
    server = new Pretender(->
      @put "/passwords/4615efd359fb8d96804a1d77efea78e528667d62", (request)->
        return [201, {"Content-Type": "application/json"}, JSON.stringify(response)]
    )
  teardown: ->
    Ember.run App, App.destroy
    server.shutdown()

test "Resets the password", ->
  expect 1
  visit("/passwords/4615efd359fb8d96804a1d77efea78e528667d62").then ->
    fillIn "#password", "newpassword"
    click("form button").then ->
      equal find(".alert-success p").text(), "You can now login with your new password.", "The password reset success notice renders"

I'm expecting this is a user error, but I'm really stumped at the moment.

cannot get my request to be handled and I have no way of knowing what my handler truly is set to handle

pretender intercepts my requests successfully, but no matter what I do, pretender won't recognize my requests, and when I log the pretender object, my requests go to unhandled, my handler is in the handlers array, but in that object, there is no real indication in that object of what the handler is set to handle

i have no way of troubleshooting...

my current set up is this:

export default Ember.Route.extend({
    beforeModel: function() {
        server = new Pretender(function() {
            console.log('this part runs');
            this.get('/node/api/inbox', function(request) {
                console.log('y u no run', request);
                return [200, {"Content-Type": "application/json"}, messages];
            });
        });
        console.log(server);
    },
    model: function() {
        console.log(this.store.find('inbox'));
        // return this.store.find('inbox');
    },
    afterModel: function() {
        server.shutdown();
    }
});

and it tells me:

Pretender intercepted GET http://mydomain/node/api/inbox  but no handler was defined for this type of request

(real domain not shown to not expose it publicly)

Pretender mock in Ember.js

Hi, I'm trying to use Pretender to mock my server requests, but I always get this error:

Setup failed on something: undefined is not a function
    at Object.Pretender (http://localhost:9876/base/app/assets/vendor/components/pretender/pretender.js:12:10)
    at Object.singleModule.setup (http://localhost:9876/base/tests/specs/integration/a_routes_test.js:4:24)
    at Object.Test.setup (http://localhost:9876/base/node_modules/qunitjs/qunit/qunit.js:1276:31)
    at http://localhost:9876/base/node_modules/qunitjs/qunit/qunit.js:1460:10
    at process (http://localhost:9876/base/node_modules/qunitjs/qunit/qunit.js:1016:24)
    at http://localhost:9876/base/node_modules/qunitjs/qunit/qunit.js:186:5
 debug.html:31window.__karma__.result debug.html:31(anonymous function) adapter.js:66runLoggingCallbacks qunit.js:1167Test.finish qunit.js:1434(anonymous function) qunit.js:1469process qunit.js:1016(anonymous function)

After trying with my specific tests, I've tryed to do a simple test to reproduce this so I have this code:

(code in coffeescript)

singleModule "Posts",
  setup: ->
    pretender = new Pretender () ->
      @get "/posts", (request) ->
        [
          200
          {
            "Content-Type": "application/json"
          }
        ]
    return

test "something", ->
  $.get "/posts", (data) ->
    console.log data

The problem comes from inside of pretender.js in Pretender(maps) function,

the maps.call(this); or maps() is always returning undefined.

Do someone have a idea of what could be happening here?

Best Regards,

Marius

Middleware or filters

it would be very handy to have some sort of filtering functionality where a function would be executed before a request handler and if that function returned a value, that value should be sent back as the request response.

server.post('api/orderhistory',{ before: 'authFilter' } , function(request){
  var ORDERS = some data;
  return [200, "Content-Type": "application/json" , ORDERS];
});

server.filter('authFilter', function( request) {
 //chech request headers to see if access token exists otherwise return 
    return [403,{"Content-Type": "application/json"},JSON.stringify({status:'failed',message:'access denied'})];
});

this way you can define a filter once and enforce it on multiple routes. the key is treating a possible response from the filter as response for the request.

What files do the server mock calls go in?

I know this seems simplistic but I don't see in the README where we are supposed to put our mock server code. Basically, where do we put the code below in an Ember-cli app?

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])]
  });
});

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.