Git Product home page Git Product logo

jquery-mockjax's Introduction

jQuery Mockjax: Ajax request mocking

http://github.com/jakerella/jquery-mockjax/

Travis CI Badge

There are some minor breaking changes in v2, so if you need an older version, please check the v1.x branch or the list of releases in Github.

jQuery Mockjax provides request/response mocking for ajax requests using the jQuery API and provides all standard behaviors in the request/response flow.

You may report any issues you may find in the github issue tracking.

Table of Contents

About Mockjax and Its History

Most backend developers are familiar with the concepts of mocking objects or stubbing in methods for unit testing. For those not familiar with mocking, it's the simulation of an interface or API for testing or integration development purposes. Mocking with front-end development though is still quite new. Mockjax gives front end developers the ability to define ajax requests that should be mocked out, as well as how those requests should be responded to. These mocks can be extremely simple or quite complex, representing the entire request-response workflow.

At appendTo we developed a lot of applications which use RESTFUL web services, but much of the time those services are not yet created. We spec out the service contract and data format at the beginning of a project and develop the front-end interface against mock data while the back end team builds the production services.

This plugin was originally developed by appendTo in March 2010 and the team has been using it in many projects since.

Basic Documentation

API Methods

Mockjax consists of just a few methods, each listed below. You'll find plenty of examples in the sections below, but if you're looking for a specific option, checkout this list:

  • Number $.mockjax(/* Object */ options)
    • Sets up a mockjax handler for a matching request
    • Returns that handler's index, can be used to clear individual handlers
    • options: [Object] Defines the settings to use for the mocked request
      • url: [String | RegExp] Specifies the url of the request that the data should be mocked for. If it is a string and contains any asterisks ( * ), they will be treated as a wildcard by translating to a regular expression. Any * will be replaced with .+. If you run into trouble with this shortcut, switch to using a full regular expression instead of a string and asterisk combination
      • data: [Object | Function] In addition to the URL, match parameters
      • type: [String] Specify what HTTP method to match, usually GET or POST. Case-insensitive, so get and post also work
      • headers: [Object] Keys will be simulated as additional headers returned from the server for the request (NOTE: This is NOT used to match request headers!)
      • status: [Number] An integer that specifies a valid server response code. This simulates a server response code
      • statusText: [String] Specifies a valid server response code description. This simulates a server response code description
      • responseTime: [Number] An integer that specifies a simulated network and server latency (in milliseconds). Default is 500. Setting this to 0 will minimize the simulated latency
      • isTimeout: [Boolean] Determines whether or not the mock will force a timeout on the request
      • contentType: [String] Specifies the content type for the response
      • response: [Function] A function that accepts the request settings and allows for the dynamic setting of response settings (including the body of the response) upon each request (see examples below)
      • responseText: [String] Specifies the mocked text, or a mocked object literal, for the request
      • responseXML: [String] Specifies the mocked XML for the request
      • proxy: [String] Specifies a path to a file, from which the contents will be returned for the request
      • lastModified: [String] A date string specifying the mocked last-modified time for the request. This is used by $.ajax to determine if the requested data is new since the last request
      • etag: [String] Specifies a unique identifier referencing a specific version of the requested data. This is used by $.ajax to determine if the requested data is new since the last request. (see HTTP_ETag)
      • onAfterSuccess: [Function] A callback that will be called after the success method has been called, this is useful to check a condition after the call has been completed
      • onAfterError: [Function] A callback that will be called after the error method has been called, this is useful to check a condition after the call has been completed
      • onAfterComplete: [Function] Similar to onAfterSuccess, but will be executed after the complete method has been called
  • Object $.mockjax.handler(/* Number */ id)
    • Returns the mock request settings for the handler with the provided id. Be careful here, you're accessing the inner workings of the plugin, any changes to this object could be bad.
  • Array $.mockjax.handlers()
    • Returns the array of mock handlers. NOTE: This array is NOT modified when a handler is cleared, the cleared handler position is simply set to null. As such, the array length will only change when new mocks are added. Be careful here, you're accessing the inner workings of the plugin, any changes to the array could be very bad.
  • void $.mockjax.clear([/* Number || String */ identifier])
    • If the identifier provided is a Number, the handler with that ID is cleared (that is, requests matching it will no longer do so, the handler is completely removed)
    • If the identifier provided is a String, the handler with that matching URL is cleared.
    • If no identifier is provided, ALL handlers are cleared, resetting Mockjax to its initial state
  • Array<Object> $.mockjax.mockedAjaxCalls()
    • Returns an array of all mocked ajax calls with each entry being the request settings object as passed into the $.mockjax() function
    • If `$.mockjaxSettings.retainAjaxCalls is set to false, this will always be empty
  • Array<Object> $.mockjax.unfiredHandlers()
    • Returns an array of all mock handler settings that have not been used. In other words, if a handler has been used for a $.ajax() call then it will not appear in this array
  • Array<Object> $.mockjax.unmockedAjaxCalls()
    • Returns an array of all unmocked Ajax calls that were made. The array contains the settings object passed into $.ajax({...})
    • If `$.mockjaxSettings.retainAjaxCalls is set to false, this will always be empty
  • void $.mockjax.clearRetainedAjaxCalls()
    • Empties the arrays returned by $.mockjax.mockedAjaxCalls and $.mockjax.unmockedAjaxCalls

Overview: Your First Mock

Our first example will be for a simple REST service for a fortune app with the REST endpoint being /restful/fortune which returns the following JSON message:

{
    "status": "success",
    "fortune" : "Are you a turtle?"
}

To pull the fortune into our page, we'd use the following HTML and jQuery code:

<!DOCTYPE html>
<html>
  <head>
    <title>Fortune App</title>
    <script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
  </head>
<body>
  <div id="fortune"></div>
</body>
</html>
$.getJSON("/restful/fortune", function(response) {
  if ( response.status == "success") {
    $("#fortune").html( "Your fortune is: " + response.fortune );
  } else {
    $("#fortune").html( "Things do not look good, no fortune was told" );
  }
});

At this point if we were to run this code it would fail since the REST service has yet to be implemented. This is where the benefit of the Mockjax plugin starts to pay off. The first step in using Mockjax is to include the plugin by just adding a regular script tag:

<head>
  ...
  <script src="vendor/jquery.mockjax.js"></script>
</head>

Once you have that included, you can start intercepting Ajax requests and mocking the responses. So let's mock out the service by including the following code:

$.mockjax({
  url: "/restful/fortune",
  responseText: {
    status: "success",
    fortune: "Are you a mock turtle?"
  }
});

Defining a JSON string inline requires a JSON.stringify() method to be available. For some browsers you may need to include json2.js, which is included in the lib folder. However, you could also simply provide an already stringified version of your JSON in the responseText property.

If you plan on mocking xml responses, you may also have to include jquery.xmldom.js, which can also be found in the lib folder.

Mockjax in Depth

What Mockjax does at this point is replace the $.ajax() method with a wrapper that transparently checks the URL being requested. If the URL matches one defined by $.mockjax(), it intercepts the request and sets up a mock XMLHttpRequest object before executing the jQuery.ajax() handler. Otherwise, the request is handed back to the native $.ajax() method for normal execution. One benefit in this implementation detail is that by simulating the XMLHttpRequest object, the plugin continues to make use of jQuery's native ajax handling, so there are no concerns with implementing a custom Ajax workflow.

As you write code to mock responses, there's great value in the fact that there are no modifications required to production code. The mocks can be transparently inserted. This provides easy integration into most frameworks by including the plugin and mock definitions through your build framework. It's also possible to include it at run time by listening for a query string flag and injecting the plugin and definitions.

Now let's look at the various approaches to defining mocks as offered by the plugin. The sections below feature an extensive overview of the flexibility in Mockjax and creating responses.

Data Types Available for Mocking

jQuery is able to handle and parse Text, HTML, JSON, JSONP, Script and XML data formats and Mockjax is able to mock any of those formats. Two things to note: depending upon how you mock out JSON and JSONP you may need to include json2.js for the JSON.stringify() method (older browsers only, typically). Additionally if you mock XML inline, you'll need to include the xmlDOM plugin that transforms a string of XML into a DOM object. However, if you use the proxy approach outlined below then there should be no need to include either the JSON or XMLDOM plugins in any case.

Detailed Request and Response Definition

Defining a Request to Match

The first thing you need to do when mocking a request is define the URL end-point to intercept and mock. As with our example above this can be a simple string:

$.mockjax({
  url: "/url/to/rest-service"
});

or contain a * as a wildcard:

$.mockjax({
  // Matches /data/quote, /data/tweet etc.
  url: "/data/*"
});

or a full regular expression:

$.mockjax({
  // Matches /data/quote, /data/tweet but not /data/quotes
  url: /^\/data\/(quote|tweet)$/i
});

You can also match against the data option in addition to url:

$.mockjax({
  url:  "/rest",
  data: { action: "foo" }
});

The data option may be a custom matching function returning true of false whether the data is expected or not:

$.mockjax({
  url: "/rest",
  data: function( data ) {
    return deepEqual( data, expected );
  }
});

The data function is a recommended place for assertions. Return true and let a testing framework of choice do the rest:

$.mockjax({
  url: "/rest",
  data: function ( json ) {
    assert.deepEqual( JSON.parse(json), expected ); // QUnit example.
    return true;
  }
});

To capture URL parameters, use a capturing regular expression for the URL and a urlParams array to indicate, ordinally, the names of the paramters that will be captured:

$.mockjax({
  // matches /author/{any number here}/isbn/{any number with dashes here}
  // for example: "/author/1234/isbn/1234-5678-9012-0"
  url: /^\/author\/([\d]+)\/isbn\/([\d\-]+)$/,
  // names of matching params
  urlParams: ["authorID", "isbnNumber"],
  response: function (settings) {
    var authorID = settings.urlParams.authorID;
    var isbnNumber = settings.urlParams.isbnNumber;
    // etc...
  }
});

Defining Multiple Requests

Since version 2.2 it is allowed to define several requests at once. $.mockjax([...]) returns a array of handlers' indexes. It is possible to reset handler by index. Read more in Removing Mockjax Handlers.

var handlers = $.mockjax([
  {url: '/rest', responseText: 'one'},
  {url: '/rest', responseText: 'two'}
]);

$.mockjax.clear(handlers[0]);

Defining a Response

The second step is to define the type and content of the response. The two main properties you will be dealing with are either responseText or responseXML. These properties mirror the native XMLHttpRequest object properties that are set during a live response. There are three different patterns for specifying the responses: Inline, Proxy, and Callback.

Inline Responses

A simple text response would be:

$.mockjax({
  url: "/restful/api",
  responseText: "A text response from the server"
});

A simple JSON response would be:

$.mockjax({
  url: "/restful/api",
  // You may need to include the [json2.js](https://raw.github.com/douglascrockford/JSON-js/master/json2.js) library for older browsers
  responseText: { "foo": "bar" }
});

Also note that a JSON response is really just a text response that jQuery will parse as JSON for you (and return a JSON object to the success and complete callbacks).

A simple XML response would be:

$.mockjax({
  url: "/restful/api",
  // Need to include the xmlDOM plugin to have this translated into a DOM object
  responseXML: "<document><quote>Hello world!</quote></document>"
});

As you can see, if you have a significant amount of data being mocked this becomes unwieldy. So that brings us to the next pattern: the proxy.

Proxy

In this example below, the Mockjax plugin will intercept requests for /restful/api and redirect them to /mocks/data.json:

$.mockjax({
  url: "/restful/api",
  proxy: "/mocks/data.json"
});

The /mocks/data.json file can have any valid JSON content you want, and allows you to maintain that mock data in its own file for maintainability.

Note: If you're testing your code with a poxy, it is best to run an actual web server for the tests. Simply loading test/index.html from the file system may result in the proxy file not being loaded correctly. We recommend using something like the http-server npm module.

Callback

In the final response pattern, we can define a callback function on the response property and have it set responseText or responseXML as needed:

$.mockjax({
  url: "/restful/api",
  response: function(settings) {
    // Investigate the `settings` to determine the response...

    this.responseText = "Hello world!";
  }
});

The default version of this callback is synchronous. If you provide both parameters to the callback function, you can use asynchronous code to set the dynamic response.

$.mockjax({
  url: '/restful/api',
  response: function(settings, done) {
    var self = this;
    someAsyncMethod(function(data){
      self.responseText = data;
      done();
    });
  }
});

Note that the callback is given the settings provided to the $.mockjax({...}) method merged with any Ajax settings defined by jQuery or your application. This allows you to thoroughly investigate the request before setting the response body (or headers).

Advanced Mocking Techniques

At this point we've looked at a series of basic mocking techniques with Mockjax and will now unpack some of the additional functionality contained in the plugin.

Simulating Response Time and Latency

Simulating network and server latency for a mock is as simple as adding a responseTime property to your mock definition:

$.mockjax({
  url: "/restful/api",
  // Simulate a network latency of 750ms
  responseTime: 750,
  responseText: "A text response from the server"
});

You can also use an interval for responseTime to randomize latency:

$.mockjax({
  url: "/restful/api",
  // Use a random value between 250ms and 750ms
  responseTime: [250, 750],
  responseText: "A text response from the server"
});

Simulating HTTP Response Statuses

It's also possible to simulate response statuses other than 200 (default for Mockjax) by simply adding a status property.

$.mockjax({
  url: "/restful/api",
  // Server 500 error occurred
  status: 500,
  responseText: "A text response from the server"
});

The ability to provide an array of possible response statuses (from which the response for a given request will be randomly picked from):

// Randomly fail
$.mockjax({
  url: "/restful/api",
  status: [200,400,500]
});

// Randomly fail (with a preference towards success)
$.mockjax({
  url: "/restful/api",
  status: [200,400,200,500,200]
});

These forced error status codes will be handled just as if the server had returned the error: the error callback will get executed with the proper arguments.

Setting the Content-Type

You can set the content type to associate with the mock response, in the example below, we're setting a JSON content type.

$.mockjax({
  url: "/restful/api",
  contentType: "application/json",
  responseText: {
    hello: "World!"
  }
});

Setting Additional HTTP Response Headers

Additional HTTP Response Headers may be provided by setting a key in the headers object literal:

$.mockjax({
  url: "/restful/api",
  contentType: "application/json",
  responseText: {
    hello: "World!"
  },
  headers: {
    etag: "xyz123"
  }
});

Dynamically Generating Mock Definitions

In some situations, all of your REST calls are based upon a URL schema. Mockjax has the ability for you to specify a callback function that is handed the $.ajax request settings. The callback function may then either return false to allow the request to be handled natively, or return an object literal with relevant Mockjax parameters set. Below is an example that rewrites all Ajax requests to proxy to static mocks:

$.mockjax(function(settings) {

  // settings.url might be: "/restful/<service>" such as "/restful/user"

  var service = settings.url.match(/\/restful\/(.*)$/);
  if ( service ) {
    return {
      proxy: "/mocks/" + service[1] + ".json"
    };
  }
  // If you get here, there was no url match
  return;
});

Accessing Request Headers

In some situations, you may need access to the request headers to determine matching or response bodies. To do this, you will need to specify a callback function that is handed the $.ajax request settings:

$.mockjax(function( requestSettings ) {
  // Here is our manual URL matching...
  if ( requestSettings.url === "/restful/user" ) {
    // We have a match, so we return a response callback...
    return {
      response: function( origSettings ) {

      	// now we check the request headers, which may be set directly
      	// on the xhr object through an ajaxSetup() call or otherwise:

      	if ( requestSettings.headers["Authentication"] === "some-token" ) {
      	  this.responseText = { user: { id: 13 } };
      	} else {
  		  this.status = 403;
  		  this.responseText = "You are not authorized";
        }
      }
    };
  }
  // If you get here, there was no url match
  return;
});

Forced Simulation of Server Timeouts

Because of the way Mockjax was implemented, it takes advantage of jQuery's internal timeout handling for requests. But if you'd like to force a timeout for a request you can do so by setting the isTimeout property to true:

$.mockjax({
  url: '/restful/api',
  responseTime: 1000,
  isTimeout: true
});

Dynamically Generating Mock Responses

It's also possible to dynamically generate the response text upon each request by implementing a callback function on the response parameter:

$.mockjax({
  url: "/restful/webservice",
  dataType: "json",
  response: function(settings) {
    this.responseText = {
      randomText: "random " + Math.random()
    };
  }
});

Data Types

Many of the examples above mock a json response. You can also mock xml:

$.mockjax({
  url: "/some/xml",
  dataType: "xml",
  responseXML: "<document><say>Hello world XML</say></document>"
});

(Don't forget that it's likely you'll need the xmlDOM library as well!)

And html:

$.mockjax({
  url: "/some/webservice",
  dataType: "html",
  responseText: "<div>Hello there</div>"
});

Performing Actions After Request Completion

If you need to perform some actions after a call has completed you can use one of the onAfter{Xxxxx} options. For example, to fire a method when a request completes (either successfully or not):

$.mockjax({
  url: "/api/end/point",
  onAfterComplete: function() {
    // do any required cleanup
  }
});

Globally Defining Mockjax Settings

It is also possible to define the global defaults for all Mockjax requests by overwriting the $.mockjaxSettings object. By default the settings are as follows:

{
  log:             null,  // DEPRECATED, use $.mockjaxSettings.logger instead
  logger:          window.console,
  logging:         2,
  logLevelMethods: ['error', 'warn', 'info', 'log', 'debug'],
  namespace:       null,
  status:          200,
  statusText:      "OK",
  responseTime:    500,
  isTimeout:       false,
  throwUnmocked:   false,
  retainAjaxCalls: true,
  contentType:     "text/plain",
  response:        "",
  responseText:    "",
  responseXML:     "",
  proxy:           "",
  proxyType:       "GET",
  lastModified:    null,
  etag:            "",
  headers: {
    etag: "IJF@H#@923uf8023hFO@I#H#",
    "content-type" : "text/plain"
  }
}

To overwrite a particular settings such as the default content-type, you would do the following:

$.mockjaxSettings.contentType = "application/json";

Setting a Global URL Namespace

The namespace option in $.mockjaxSettings allows you to apply a prefix to all of your mocked urls, such as /api/v1.

$.mockjaxSettings.namespace = "/api/v1";

Then the following mock will match /api/v1/rest:

$.mockjax({
    url: "/rest"
})

Asย willย theย followingย RegExpย pattern:

$.mockjax({
    url:ย /^\/rest$/
})

The global namespace option can also be overwritten on a particular mock.

$.mockjax({
    url: "/rest-2",
    namespace: null
})

Note that the namespace prefix does not apply to proxies.

Globally defining match order

By default, Mockjax matches requests in registration order (mockjax considers the handlers registered first before handlers registered last). To reverse this behavior:

$.mockjaxSettings.matchInRegistrationOrder = false;

Setting matchInRegistrationOrder to false lets you override previously defined handlers. Suppose you had:

$.mockjax({
    url: "/rest",
    responseText: "hello"
});
$.mockjax({
    url: "/rest",
    responseText: "byebye"
});

The default behavior is that Mockjax returns "hello", but with matchInRegistrationOrder set to false, Mockjax would return "byebye".

This behavior allows you to override older handlers after they are initially set.

Removing Mockjax Handlers

If you need to reset the Mockjax handlers you've added, just call $.mockjax.clear(). This will NOT reset the $.mockjaxSettings!

$.mockjax.clear();

You can also clear individual mock handlers using their ID:

var id = $.mockjax({
   ...
});

$.mockjax.clear(id);

Or you can clear a handler by the URL that it matches with either a String or RegExp:

$.mockjax({
   url: "/api/foo",
   ...
});

$.mockjax.clear("/api/foo");
// or
$.mockjax.clear(/foo/);

Miscellaneous Information

jQuery Version Support

We strive to ensure that Mockjax is tested on the furthest patch version of all minor versions of jQuery (1.x.y through 3.x.y). In other words, we don't test 1.12.1, but rather 1.12.4 (the furthest patch version on the 1.x line). The QUnit tests in the /test directory include links to each version of jQuery tested in the header.

Browsers Tested

We use BrowserStack's awesome open source collaboration to test Mockjax in real browsers using VMs on their platform. We run all of our tests on the current versions of the major browsers below, plus the specific versions of Internet Explorer specified.

  • Edge
  • Firefox
  • Chrome
  • Safari

Each PR will run these tests using TravisCI for continuous integration before code is merged into master to ensure we do not introduce regressions.

Using Mockjax in Other Ways

You can use Mockjax as a Node module or with Browserify... and presumably in other ways as well. We have tests for each of the methods above.

When using Mockjax as a Node module (including with Browserify), you must provide the module with the jQuery library and a window. Here is an example using a module intended for use as a "browserified" module:

var jquery = require('jquery');
var mockjax = require('jquery-mockjax')(jquery, window);
// Note that we expect `window` to be defined once this file is browserified and
// used in a browser. If it isn't Mockjax will have a problem!

mockjax({
    url: '/resource',
    responseText: 'content'
});

function getResource(cb) {
    jquery.ajax({
        url: '/resource',
        success: cb,
        error: cb
    });
}

Logging

Mockjax logs various pieces of information to the console (on window) in browsers, or to stdout in Node). You can customize various aspects of the logging to suit your needs. By default, only 'error', 'warn' or 'info' messages will be shown, but detailed information may be available in debug logs. Below are some common things you might need to do to get better logging information.

Show different levels of log messages

$.mockjaxSettings.logging = 4;  // very verbose debug messages
$.mockjaxSettings.logging = 3;  // verbose log messages
$.mockjaxSettings.logging = 2;  // informational messages
$.mockjaxSettings.logging = 1;  // warning messages
$.mockjaxSettings.logging = 0;  // only critical error messages

(Note that each level enables that level plus any lower number... thus setting logging to 2 also enables warnings and errors.)

Implement a custom logger

If you don't want to use the console object, you can pass in your own logging implementation with the logger setting. Note that your logger must either implement the debug, log, info, warn, and error methods, or you must also provide what methods map to the 5 levels (0 through 4).

$.mockjaxSettings.logger = {
  debug: function() { ... },
  log: function() { ... },
  // ...
};

Your logger methods may receive any number of arguments to log out, either as strings or objects, similar to how the window.console object methods work.

If you have a logger that uses different methods names, specify them in this array:

$.mockjaxSettings.logLevelMethods = ['critical', 'bad', 'stuff', 'log', 'verbose'];

Note that the first entry in this array (index 0) will be errors while the last entry will be verbose output. Anything beyond index 4 will be ignored.

What about the old log setting?

This was an undocumented feature whereby you could provide a log method using $.mockjaxSettings, however, it is no longer used internally. This undocumented option is now deprecated, and while it will work, log messages of ALL levels will be sent to it.

If you have no idea what we're talking about... good! Don't worry about it. The proper way to implement your own logger is via $.mockjaxSettings.logger.

Release History

Please read the CHANGELOG for a list of changes per release.

Note that all releases are tagged in Github for easy reference, the master branch should not be considered a stable release!

License

Copyright (c) 2014-2024 Jordan Kasper, formerly appendTo

NOTE: This repository was taken over by Jordan Kasper (@jakerella) October, 2014

Licensed under the MIT license: http://opensource.org/licenses/MIT

Troubleshooting

If mockjax appears to be behaving unexpectedly, be sure to check the console logs for warnings.

Contributing

We welcome any contributions by the community, whether in the form of a Pull Request, issue submission and comments, or just sharing on social media!

If you want to contribute code to the project, please read our Contribution guidelines to see what you need to do to get your Pull Request ready for merging.

jquery-mockjax's People

Contributors

addepar-andy avatar bdusell avatar danpaz avatar dcneiner avatar elijahmanor avatar gregid avatar ifandelse avatar jakerella avatar jcreamer898 avatar jdsharp avatar johnkpaul avatar jonspalmer avatar jzaefferer avatar kkirsche avatar koorgoo avatar kumar303 avatar manuelzs avatar mattmcla avatar michaelbrooks avatar mlynch avatar nicholascloud avatar prantlf avatar reinrl avatar rniemeyer avatar shellscape avatar stas-vilchik avatar suchipi avatar udnisap avatar weswedding avatar wfortin 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  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

jquery-mockjax's Issues

Overhaul codebase

The current codebase has some serious problems: Lots of single-character variable names, heavy nesting, a single function that does most of the work instead of delegating to small methods.

Cleaning that up would probably break most or all open pull requests, so those should be merged first...

jsre, rquery, jsc not defined

I've been trying to mock out jsonp requests. It seems that the jsre, rquery, and jsc variables are missing/out-of-scope.

Move documentation to GitHub

They blog post isn't editable, the comments aren't reflected in it. There are tools for converting html to markdown, so the first step should be easy enough. Afterwards, people can contribute to docs directly via pull requests, making the repo the project home, instead of the blog post.

Console check needs to be modified

The check for the console needs to be modified to:

if ( window.console && window.console.log ) {
    window.console.log('MOCK GET: ' + s.url);
}

Bug in IE9

It seems that some of test is failed or you don't test mockjax under IE9. I've just run mockjax under IE9 with Jasmine and I've got the error "SCRIPT438: Object doesn't support property or method 'apply'"

mockjax-error

mockjax GET with jQuery 2.0 JSON result doesn't work

If you put some code like this:

    $.mockjax({
        type: "GET",
        url: "*",
        responseTime: 50,
        response: function (settings) {
            // Return the data to verify against.
            var responseData = JSON.parse(JSON.stringify(someObject));
            this.responseText = responseData; // i am sure this is not null
        }
    });

var def = someGetCall();
def.done(function (msg)) {
// msg is null
});

Only seems to happen with jQuery 2.0, GET and JSON scenario.

Intercept ALL XMLHttpRequests

Can Mockjax be modified to intercept ALL XMLHttpRequests, not just ones that attempt to use jQuery to do so?

Thanks!

Mockjax doesn't work with $.ajax(url, settings)

jQuery 1.5.2 (and possibly earlier versions) allows you to call $.ajax in two ways: $.ajax(url, settings) or $.ajax(settingsIncludingURL). When mockjax overrides the ajax method here, it assumes it's just getting a single settings hash, which breaks requests made in the other format.

Seems like it should be easy to fix; if I have time next week I can put together a pull request with tests.

Thanks for the library!

Mockjax only capture the first request (AMD)

Hi,

I have a strange bug with Mockjax.

When I load it, it will capture the first mocked request made and respond accordingly. But on the second call, the request isn't captured and it goes on the server (returning 404).

I'm not sure where this come from, but I'm using it in an AMD environnement (with require.js), could this be an issue?

Handle multiple * in url

I was trying to mock a url similar to
"/my_api/action_summary?token=&aggregated=daily&action=1" but only the first * gets replaced to ".+".

The fix is easy, just need to change the replace("_",".+") to replace(/_/g,".+") [line 107]

// Look for a simple wildcard '*' or a direct URL match
var star = handler.url.indexOf('*');
if (handler.url !== requestSettings.url && star === -1 || 
    !new RegExp(handler.url.replace(/[-[\]{}()+?.,\\^$|#\s]/g, "\\$&").replace(/\*/g, '.+')).test(requestSettings.url)) 
{
  return null;
}

Can the type be 'PUT'?

I found that it can not mock a request with 'PUT' method.
Could this type be supported?

Support global async setting for tests that don't work well with setTimeout

I have a few projects that don't work well with async mocking and I'd like to extend the conditional below to include a global setting that would allow me to avoid the setTimeout issue (and invoke process directly instead).

if ( requestSettings.async === false || mockHandler.async === false ) {
    process();
} else {
    this.responseTimer = setTimeout(process, mockHandler.responseTime || 50);
}

I could work up a PR but I wanted to see if this was something that would be pulled into core first

Data empty on a GET route after calling a POST route

Hi,

I have a weird issue: I declared two routes, one on GET and another on POST, and the GET route works well until I call the POST route at least once. Then it always return null data.

Here is the test case: http://jsfiddle.net/2V3DD/3/

Here is the thing:

  • If I click the "Get" button, it works:
    [server] GET: Response: { "property":"not posted..!" }
    [client] GET: Success! { "property":"not posted..." }
  • Now, if I click the "Post" button, it also works:
    [server] POST: Response: { "property":"Posted!" }
    [client] POST: Success! { "property":"Posted!" }
  • But now, when I click the "Get" button, it crashes:
    [server] GET: Response: { "property":"Posted!" }
    [client] GET: Success! null
    Error: Uncaught [client] GET: Data is null
  • Even weirder: If I click again "Post", it still works:
    [server] POST: Response: { "property":"Posted!" }
    [client] POST: Success! { "property":"Posted!" }

I tried this use case and it is indeed broken with jQuery 1.8.2 and 1.7.2 at least, on Chromium and Firefox.

Alexis

Support for async/deferred responses

Just what the title says.
Right now it's impossible to "resolve" the request at a later stage (don't read timeout).

Shouldn't you return a $.Deferred object instead?

Eg. I want to hook up into an ajax call and perform 3 other ajax calls "invisibly", concatenate the payloads and return one single payload

Logging is hardcoded to be on, and log option is ignored

So peeking into the source shows me that there is a log option on line 527 that is completely ignored.

And there is a logMock(...) function that actually performs the console.log calls, but it is hard coded to always run on line 449.

But it has a comment on line 127 that says "// If logging is enabled, log the mock to the console".

Adding as an issue because of that comment, and the apparently vestigial log option. Would fix myself and make a pull request but I think the decision of moving logMock or setting log in default options to it, as well as the most ideal conditional check, would best be left to the repo maintainers.

Thanks for the awesome plugin! <3 Works great on our actual pages and in our Jasmine unit tests.

Failed unit test in Chrome

jQuery version: 1.5 (test/jquery-1.5.html).

Output follows (bold text means failed 'red' tests).

Mockjax
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1
Core: Return XMLHttpRequest object from $.ajax (0, 1, 1)
Core: Intercept and proxy (sub-ajax request) (1, 0, 1)
Proxy request succeeded
Core: Dynamic response callback (0, 1, 1)
Core: Remove mockjax definition by id (0, 3, 3)
Core: Intercept log messages (0, 1, 1)
Core: Disable console logging (0, 1, 1)
URL Matching: Exact string (0, 1, 1)
URL Matching: Wildcard match (0, 1, 1)
URL Matching: RegEx match (0, 1, 1)
Data Types: Response returns text (0, 1, 1)
Data Types: Response returns html (0, 2, 2)
Data Types: Response returns json (0, 2, 2)
Data Types: Response returns jsonp (1, 1, 2)
Error callback executed
Content type of text/json
Expected:
"text/json"
Data Types: Response executes script (1, 1, 2)
Script executed
Expected:
1
Result:
0
Diff:
1 0
Source:
at Object.complete (file:///C:/appendto-jquery-mockjax-v1.4.0-5-g96a2a52/appendto-jquery-mockjax-96a2a52/test/test.js:304:4)
Content type of text/plain
Expected:
"text/plain"

Data Types: Response returns parsed XML (0, 3, 3)
Connection Simulation: Async test (0, 2, 2)
Connection Simulation: Sync test (0, 2, 2)
Connection Simulation: Response time simulation and latency (0, 3, 3)
Tests completed in 1109 milliseconds.
27 tests of 30 passed, 3 failed.

proxy approach does not seem to work for xml files

It seems like xml files do not work for the proxy approach. Tested with both json and xml proxy files and the latter would'nt work. Could you please fix that? Used

<script src="../lib/jquery-1.10.2.min.js"></script>
<script src="../lib/jquery-migrate-1.2.1.min.js"></script>
<script src="../lib/jquery.mockjax.js"></script>

as libraries. responseXML worked like a charm. However, for more complex xml files, the proxy approach would be of great help.

abort() is not supported

Once I call abort() in an asynchroneous way, the fail() callback is called.
But the setTimeout in MockJax will call the done. It should not

Mockjax is cloning the whole settings.context

Hi

Mockjax is cloning the whole settings.context when it is using $.extend. There are two issues here -

  1. It clones the whole object structure (Maybe a whole DOM tree).

  2. We need to have some references to update after getting the response (like updating knoclout observables or UI based on the response). In this case we are not able to identify the object back as we are getting a new object structure.

JQuery also had similar issues that was fixed. See here http://bugs.jquery.com/ticket/9887.

We will need to stop making deep copies if it specified in jQuery.ajaxSettings.flatOptions. Below is the fn added by jquery to fix this.

// A special extend for ajax options
// that takes "flat" options (not to be deep extended)
// Fixes #9887
function ajaxExtend(target, src) {
    var key, deep,
    flatOptions = jQuery.ajaxSettings.flatOptions || {};
    for (key in src) {
        if (src[key] !== undefined) {
            (flatOptions[key] ? target : (deep || (deep = {})))[key] = src[key];
        }
    }
    if (deep) {
        jQuery.extend(true, target, deep);
    }
    return target;
}

We need to the same logic and call it at the two places where we do $.extend. Can also send in the changes. Or should I fork and commit?

Better fuzzy matching

url: "offset=" should match only urls containing that 'offset=' substring, currently they match all URLs.

The problem basically is: Everything before an asterisk is ignored. Instead the asterisk should behave as an actual wildcard.

Mocking remote JSONP fails

the modified test code fails with jQuery 1.5 once 'calling' the remote server:

https://gist.github.com/1024911

asyncTest('Response returns jsonp', function() {
    $.mockjax({
        url: 'http://example.com/jsonp*',
        contentType: 'text/json',
        proxy: 'test_jsonp.js'
    });
    window.abcdef123456 = function(json) {
        ok( true, 'JSONP Callback executed');
        deepEqual(json, { "data" : "JSONP is cool" });
    };

    $.ajax({
        url: 'http://example.com/jsonp?callback=?',
        jsonpCallback: 'abcdef123456',
        dataType: 'jsonp',
        error: noErrorCallbackExpected,
        complete: function(xhr) {
            equals(xhr.getResponseHeader('Content-Type'), 'text/json', 'Content type of text/json');
            start();
        }
    });
    $.mockjaxClear();
});

Support expectations and verification

Today, mockjax is more of a stub than a mock. It would be a great improvement (at least in testing) if you could also set expectations on the mock within a test and then verify that the expectations were fulfilled. This allows testing of the behavior (calling the proper service, passing the proper values) rather than just testing the resulting state assuming that the stub is set up to return the proper data needed for the particular test.

isTimeout with jQuery Deferred callbacks doesn't work

I had an error using isTimeout in mockjax with jQuery's Deferred callbacks (http://api.jquery.com/category/deferred-object/).

I'm using jQuery version 1.7.2, but there were errors with earlier versions as well. I created a test demonstrating the problem in this repo: https://github.com/michaelbrooks/jquery-mockjax

The error was on line 181 of jquery.mockjax.js, where it attempts to call requestSettings.error(), but no such function exists.

I have no idea how to fix this, but hopefully this is helpful. I see there have been earlier changes to make mockjax work with deferred callbacks (#37) but this problem seems to be particular to the case of using isTimeout.

More control over handlers

Using mockjax within an application to test certain error handlers. In case of a scrolling pager, I want the request for the second page to fail, then pass when clicking the retry button. For that it would be nice if I could either define a mock to run only once (remove itself), or get a callback to remove it with some other method. Currently not really feasible at all as only $.mockjaxClear exists to delete things.

* in the url regular expression is getting replaced with .+ instead of .*

In our tests, some ajax urls have parameter in some cases and not in the other. So we want to give an expression that would with our gateway with or without parameters (Something like gatewayURL*).

But in the code, * is getting replaced with .+, and so it doesnt work when there are no parameters.

So, is it possible to change the .+ in the line below (line no:107) to a .*

!new RegExp(handler.url.replace(/[-[\]{}()+?.,\\^$|#\s]/g, "\\$&").replace('*', '.+')).test(requestSettings.url)) {

Regards
sharbel

When we have two or more mocks on same run

Imagine you have a mock to the request A and another to the request B. Both use wildcard.

In this case, the mockHandlers iteraction will fail in first run of request B because the variable m will get null value. The reason is the true value returned to the conditional m.url.substr(0, star) != s.url.substr(0, star) in the wildcard verification.

So, once the m is null, m.data and m.type will throws an exception.

Simple wrap lines in:

if (m) {
// lines 52-86
}

More verbose console information for mockjax requests

Hi,

I really enjoyed using mockjax in my latest project, but I found the console.log information for the requests a bit incomplete. MOCK POST: /mockUrl doesn't tell me anything about the data posted, the delivered response, the server response code,...

When working with real AJAX requests, I always have the network panel open to spot the data that is sent "over the wire". This allows me to spot errors much faster than by manually setting breakpoints. It would be nice if mockjax offered a similar experience.

Origin null is not allowed by Access-Control-Allow-Origin.

I get this error when I use :

$(function() {
$.mockjax({
url: '/app/',
proxy:'apps.json'
});
});

With : http://code.jquery.com/jquery-1.7.1rc1.min.js
and Chrome : 15.0.874.121 m

I grab the jquery-mockjax from the Github repo.

I tried to run chrome like that : chrome.exe --allow-file-access-from-files but always get the same error.

Inside the apps.json :

[
{title : "fwefwewef", description : "fweweffwefwe"},
{title : "fwefwejoijwef", description : "fwejijweffwefwe"}
]

Any idea ?

Pass settings parameters to response callback

Hi, the response callback currently has no access to the data that is passed to the original ajax call.

Would it be an idea to replace the:
m.Response()
with:
m.Response(s)

in the send function? This would allow my response callback to create responses based on the data passed in.

m is null Line 84

I'm getting an error "m is null" on line 84. Looks like it happens when we don't get a match on the mockHandlers.

83 // Inspect the request type
84 if ( m.type && m.type != s.type ) {

bower install jquery-mockjax throws error

Installing mackjax via bower fails;

$ bower install jquery-mockjax  
bower cloning git://github.com/appendto/jquery-mockjax
bower cached git://github.com/appendto/jquery-mockjax
bower fetching jquery-mockjax
bower checking out jquery-mockjax#v1.5.1
bower copying /Users/aqb99/.bower/jquery-mockjax

/usr/local/lib/node_modules/bower/node_modules/semver/semver.js:117
  return stars.trim().replace(starExpression, starReplace)
               ^
TypeError: Object 1.3.2,1.4.4,1.5.2,1.6.4,1.7 has no method 'trim'
    at replaceStars (/usr/local/lib/node_modules/bower/node_modules/semver/semver.js:117:16)
    at Object.validRange (/usr/local/lib/node_modules/bower/node_modules/semver/semver.js:187:11)
    at new Package (/usr/local/lib/node_modules/bower/lib/core/package.js:68:23)
    at Package.addDependencies (/usr/local/lib/node_modules/bower/lib/core/package.js:273:33)
    at async.parallel.results (/usr/local/lib/node_modules/bower/node_modules/async/lib/async.js:454:21)
    at _asyncMap (/usr/local/lib/node_modules/bower/node_modules/async/lib/async.js:185:13)
    at async.forEach (/usr/local/lib/node_modules/bower/node_modules/async/lib/async.js:86:13)
    at Array.forEach (native)
    at _forEach (/usr/local/lib/node_modules/bower/node_modules/async/lib/async.js:26:24)
    at async.forEach (/usr/local/lib/node_modules/bower/node_modules/async/lib/async.js:85:9)

Probably this is nothing to do with mockjax and is a bower bug, but other packages install fine.

Keep the mocking data object intact

It seems the data object gets replaced in the mock object after calling matching an ajax call.
This seems the right thing to do when you are trying to match an exact object, but it doesn't work if you want to match subsequent ajax calls with a "wildcard".

This is the problem:

            $.mockjax({
                url: "/path/to/validate",
                data: { remote: { test: function(data) {
                    return data !== "hello";
                }
                }
                },
                responseTime: 1000,
                responseText: "false"
            });

            $.mockjax({
                url: "/path/to/validate",
                data: { remote: "hello" },
                responseTime: 1000,
                responseText: "true"
            });

In this case, after calling ajax once, the first mockjax gets replaced and will not behave like it should afterwards...

Is there a way to achieve this problem?
Basically, any ajax calls that are not equal to "hello" should fail.

it doesn't skip the path doesn't exist

When I include mockjax whenever request is made it submit the request to the current file not the actual path specified. Is it bug or there is some option that I can specified?

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.