Server

The Mirage server.

Note that this within your routes function refers to the server instance, which is the same instance that server refers to in your tests.

Properties

db: any

Returns the Mirage Db instance.

inflector: any

Mirage needs know the singular and plural versions of certain words for some of its APIs to work.

For example, whenever you define a model

new Server({
  models: {
    post: Model
  }
})

Mirage will pluralize the word "post" and use it to create a db.posts database collection.

To accomplish this, Mirage uses an object called an Inflector. An Inflector is an object with two methods, singularize and pluralize, that Mirage will call whenever it needs to inflect a word.

Mirage has a default inflector, so if you write

new Server()

you'll be using the node inflected package. This can be customized if you have irregular words or need to change the defaults. You can wead more in the guide on customizing inflections.

You typically should be able to make your customizations using the provided inflector. It's good to match any custom inflections your backend uses, as this will keep your Mirage code more consistent and simpler.

You can also override the inflector completely and provide your own pluralize and singularize methods:

new Server({
  inflector: {
    pluralize(word) {
      // your logic
    },
    singularize(word) {
      // your logic
    }
  }
})

logging: any

Set to true or false to explicitly specify logging behavior.

By default, server responses are logged in non-testing environments. Logging is disabled by default in testing, so as not to clutter CI test runner output.

For example, to enable logging in tests, write the following:

test('I can view all users', function() {
  server.logging = true;
  server.create('user');

  visit('/users');
  // ...
});

You can also write a custom log message using the Pretender server's handledRequest hook. (You can access the pretender server from your Mirage server via server.pretender.)

To override,

new Server({
  routes() {
    this.pretender.handledRequest = function(verb, path, request) {
      let { responseText } = request;
      // log request and response data
    }
  }
})

namespace: any

Set the base namespace used for all routes defined with get, post, put or del.

For example,

new Server({
  routes() {
    this.namespace = '/api';

    // this route will handle the URL '/api/contacts'
    this.get('/contacts', 'contacts');
  }
})

Note that only routes defined after this.namespace are affected. This is useful if you have a few one-off routes that you don't want under your namespace:

new Server({
  routes() {

    // this route handles /auth
    this.get('/auth', function() { ...});

    this.namespace = '/api';
    // this route will handle the URL '/api/contacts'
    this.get('/contacts', 'contacts');
  };
})

If your app is loaded from the filesystem vs. a server (e.g. via Cordova or Electron vs. localhost or https://yourhost.com/), you will need to explicitly define a namespace. Likely values are / (if requests are made with relative paths) or https://yourhost.com/api/... (if requests are made to a defined server).

For a sample implementation leveraging a configured API host & namespace, check out this issue comment.

pretender: any

Mirage uses pretender.js as its xhttp interceptor. In your Mirage config, this.pretender refers to the actual Pretender instance, so any config options that work there will work here as well.

new Server({
  routes() {
    this.pretender.handledRequest = (verb, path, request) => {
      console.log(`Your server responded to ${path}`);
    }
  }
})

Refer to Pretender's docs if you want to change any options on your Pretender instance.

schema: any

Returns the Mirage Schema (ORM) instance.

timing: any

Set the number of milliseconds for the the Server's response time.

By default there's a 400ms delay during development, and 0 delay in testing (so your tests run fast).

new Server({
  routes() {
    this.timing = 400; // default
  }
})

To set the timing for individual routes, see the timing option for route handlers.

urlPrefix: any

Sets a string to prefix all route handler URLs with.

Useful if your app makes API requests to a different port.

new Server({
  routes() {
    this.urlPrefix = 'http://localhost:8080'
  }
})

Methods

create(type: any, traitsAndOverrides: any): any

Generates a single model of type type, inserts it into the database (giving it an id), and returns the data that was added.

test("I can view a contact's details", function() {
  let contact = server.create('contact');

  visit('/contacts/' + contact.id);

  andThen(() => {
    equal( find('h1').text(), 'The contact is Link');
  });
});

You can override the attributes from the factory definition with a hash passed in as the second parameter. For example, if we had this factory

export default Factory.extend({
  name: 'Link'
});

we could override the name like this:

test("I can view the contacts", function() {
  server.create('contact', {name: 'Zelda'});

  visit('/');

  andThen(() => {
    equal( find('p').text(), 'Zelda' );
  });
});

createList(type: any, amount: any, traitsAndOverrides: any): any

Creates amount models of type type, optionally overriding the attributes from the factory with attrs.

Returns the array of records that were added to the database.

Here's an example from a test:

test("I can view the contacts", function() {
  server.createList('contact', 5);
  let youngContacts = server.createList('contact', 5, {age: 15});

  visit('/');

  andThen(function() {
    equal(currentRouteName(), 'index');
    equal( find('p').length, 10 );
  });
});

And one from setting up your development database:

new Server({
  seeds(server) {
    let contact = server.create('contact')

    server.createList('address', 5, { contact })
  }
})

loadFixtures(...args: String): any

By default, fixtures will be loaded during testing if you don't have factories defined, and during development if you don't have seeds defined. You can use loadFixtures() to also load fixture files in either of these environments, in addition to using factories to seed your database.

server.loadFixtures() loads all the files, and server.loadFixtures(file1, file2...) loads selective fixture files.

For example, in a test you may want to start out with all your fixture data loaded:

test('I can view the photos', function() {
  server.loadFixtures();
  server.createList('photo', 10);

  visit('/');

  andThen(() => {
    equal( find('img').length, 10 );
  });
});

or in development, you may want to load a few reference fixture files, and use factories to define the rest of your data:

new Server({
  ...,
  seeds(server) {
    server.loadFixtures('countries', 'states');

    let author = server.create('author');
    server.createList('post', 10, {author_id: author.id});
  }
})

passthrough(...paths: String, options: Array): any

By default, if your app makes a request that is not defined in your server config, Mirage will throw an error. You can use passthrough to whitelist requests, and allow them to pass through your Mirage server to the actual network layer.

Note: Put all passthrough config at the bottom of your routes, to give your route handlers precedence.

To ignore paths on your current host (as well as configured namespace), use a leading /:

this.passthrough('/addresses');

You can also pass a list of paths, or call passthrough multiple times:

this.passthrough('/addresses', '/contacts');
this.passthrough('/something');
this.passthrough('/else');

These lines will allow all HTTP verbs to pass through. If you want only certain verbs to pass through, pass an array as the last argument with the specified verbs:

this.passthrough('/addresses', ['post']);
this.passthrough('/contacts', '/photos', ['get']);

You can pass a function to passthrough to do a runtime check on whether or not the request should be handled by Mirage. If the function returns true Mirage will not handle the request and let it pass through.

this.passthrough(request => {
  return request.queryParams.skipMirage;
});

If you want all requests on the current domain to pass through, simply invoke the method with no arguments:

this.passthrough();

Note again that the current namespace (i.e. any namespace property defined above this call) will be applied.

You can also allow other-origin hosts to passthrough. If you use a fully-qualified domain name, the namespace property will be ignored. Use two * wildcards to match all requests under a path:

this.passthrough('http://api.foo.bar/**');
this.passthrough('http://api.twitter.com/v1/cards/**');

In versions of Pretender prior to 0.12, passthrough only worked with jQuery >= 2.x. As long as you're on Pretender@0.12 or higher, you should be all set.

shutdown(): any

Shutdown the server and stop intercepting network requests.