Git Product home page Git Product logo

ember-cli-mirage's Introduction

Ember CLI Mirage

Build Status npm version Ember Observer Score

A client-side server to develop, test and prototype your Ember CLI app.

View the docs here.


Compatibility

  • Ember.js v3.12 or above
  • Ember CLI v3.12 or above
  • Node.js v14 or above

Installation

ember install ember-cli-mirage

Has a peer dependency on MirageJS which is added to your projects package.json during installation.

Feature requests

Please open an issue and add a ๐Ÿ‘ emoji reaction. We will use the number of reactions as votes to indicate community interest, which will in turn help us prioritize feature development.

You can view the most-upvoted feature requests with this link.

Support

Having trouble?

Contributing

Have a look at our Contributing guidelines.

About

This library is developed and maintained by EmberMap. We have a Mirage tips and tricks video series if you're looking to learn how to get the most out of Mirage.

Thanks to all our amazing contributors!

ember-cli-mirage's People

Contributors

2468ben avatar asantos00 avatar azdaroth avatar bantic avatar bekzod avatar bendemboski avatar blimmer avatar cah-brian-gantzler avatar cibernox avatar dependabot-preview[bot] avatar dependabot-support avatar dependabot[bot] avatar dfreeman avatar ef4 avatar geekygrappler avatar jelhan avatar jherdman avatar jrjohnson avatar lazybensch avatar lolmaus avatar lukemelia avatar mupkoo avatar offirgolan avatar rjschie avatar rwjblue avatar samselikoff avatar sergeastapov avatar simonihmig avatar turbo87 avatar willrax 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

ember-cli-mirage's Issues

Models

Follow progress in #82

[notes to clarify my thoughts and for posterity, but anyone feel free to jump in]

I think we need to add collections to mirage - essentially, a model layer - because of associations. Here's why.

If you're just using fixtures, fine, you can manage related IDs yourself and return whatever you want. But this becomes a hassle, couples your tests to external files, etc. Lots of people want something simpler.

So, we have factories. But, factories are supposed to define the minimum attributes necessary to make your model valid, as well as attributes for other common scenarios.

So you go to define a contact factory and an address factory, and you say "for a contact to be valid, it also needs an address". You specify this in your factory:

// factories/contact.js
export default Mirage.Factory.extend({
  name: 'Sam',
  address: Mirage.association()
});

The thing is, when you go to .create() a contact, you need to create the associated address. This means building the attrs from the factory, as well as relating the two models via some id within Mirage's database. Essentially, we need to know where the foreign key lives, so in your route handlers you can fetch the related models.

Okay, so let's say a contact hasOne address. We could specify this in the factory...

export default Mirage.Factory.extend({
  name: 'Sam',
- address: Mirage.association()
+ address: Mirage.hasOne()

but then, users would need to ensure all their relationship metadata is in their factories. What if this doesn't match up with their business requirements regarding what makes their models valid? For example, what if a contact didn't need an address to be valid, and so the factory didn't have the association in its definition? In this case, we still want the user to be able to do

var contact = server.create('contact');
var address = server.create('address', {contact: contact});

in their tests. But if the association information isn't in the factory, how will Mirage know to store the foreign key on the addresses collection (i.e., to add a contact_id field to each address in the database), rather than on the contacts collection? It won't.

So, factories aren't a good place to encode relationship information.

Another possibility is in the upcoming serializer layer. We need serializers because, we want users to be able to say from a route handler, "respond with this contact", and then for that contact to go through a serializer, where they decide which attrs to expose, whether to include a root key, what relationships to include etc. (similar to ActiveModelSerializers).

So, we could require users to add the relationship metadata to the serializers. But, this is an unnecessary coupling as well. What if you don't want to include related addresses in your default ContactSerializer. You shouldn't have to, just to let Mirage know about your relationships. Users will also want to be able to specify multiple serializers for different scenarios - for example, to show a small subset of attrs for a summary overview route, and then all attrs + related models for a detail route. Deciphering the relationship metadata from these various serializers seems intractable.

In factory_girl, you specify an associated factory by referencing its name. The thing is, factory_girl is building ActiveRecord objects. The association information is encoded in your ActiveRecord model definitions - has_many, belongs_to, etc. In Mirage, we don't have a model layer. So, I think the solution is, create one.

It's going to be very simple, where you essentially declare what your Mirage collections are, and you specify where the foreign keys are:

// mirage/collections.js
export default function() {
  this.collection('contacts');
  this.collection('addresses', {belongsTo: 'contacts'});
}

Not sure what the API will be, but anyway, something like this.

With this information, we can give users a consistent answer about where they expect to find related models in the db object in their route handlers, as well as make serializers + factories much simpler to work with.

Is store confusing?

Since mirage's store has nothing to do with Ember Data's store, should it be renamed to something like db instead to reduce confusion? Or ds for data store?


We're renaming store to db, with new API:

db.contacts;  // [{id: 1, name: 'Sam'}, ... ]
db.contacts.insert({name: 'Jane'});
db.contacts.find(1);  // return single record
db.contacts.where({registered: true}); // return array
db.contacts.update({some: attr});
db.contacts.update(id, {some: attr});
db.contacts.update({some: query}, {some: attr});
db.contacts.remove()
db.contacts.remove(1)
db.contacts.remove({some: query})

Return data on put, delete?

Ran into a bug where, because I returned data + PUT had a 200 response code, triggered change events in Ember Data.

Changed it to 204, but should we even return data?

Factories error: myapp/tests/factories/school.jshint must export a factory

I can't make factories work, I get this weird error. Someone thinks that I am not exporting a factory.

The factory in tests/factories/school.js

import EP from 'ember-pretenderify';

export default EP.Factory.extend({
  name: function(i) {
    return "School " + i;
  },

  subdomain: function(i) {
    return this.name.replace(' ', '-');
  },
  school_type: 'expensive',
  address: '2 Some Street, London',
  teacher_ids: []
});

The acceptance in tests/acceptance/schools/show-test.js

import Ember from 'ember';
import { module, test } from 'qunit';
import startApp from '../../helpers/start-app';

var application;
var school;

module('Acceptance: School Show', {
  beforeEach: function() {
    application = startApp();
    school = server.create('school');
  },
  afterEach: function() {
    Ember.run(application, 'destroy');
  }
});

/* Some tests */

Is 'server' injected or should I import it?

The docs seem to indicate that 'server' will be available and that I should use it and tell jshint about it. However it doesn't seem to be set on my tests??

If I run import Server from 'ember-cli-mirage/server'; that works, is that the correct way? Or is there some kind of global 'server' variable getting created that I should use?

option to configure pretenderify data path

One could place all the pretenderify data in a separate repo for a backend team to use for testing, or otherwise put it in a folder at the same level as the frontend and backend (/frontend, /json-data, /backend)

Add option to run Mirage in test environment only

Even if someone isn't using --proxy they may want to disable Mirage in development. Let's add an option that lets them do this.

// config/environment.js
ENV['ember-pretenderify'] = {
  enableInTestingOnly: true
}

We'll need to modify index.js here as well as the initializer here.

As a side note, is there a way to ignore that initializer based on something in the index.js? Seems like we're duplicating some logic.

Refactor store

  • make it an ember object/service, inject
  • add tests
  • ids can be strings (der)
  • update find api to match new ED api: find(type, id), findAll(type), findQuery(type, {query})

Cross origin requests

Pretender doesn't support cross origin requests (see #39). We either need to come up with a solution and submit upstream to Pretender, or use something like jquery-mockjax.

Simulate websocket data

I wonder if we simulate websocket responses with this lib, with something like long polling. That would be amazing. You could return an array from the route, and specify some settings for throttling the responses.

Discordance when POST url is undesrcored and resource is hypheneated

I have a model named StaffMember, whose normalize name following ember-cli convections would be staff-member. I use rails as a backend, so my urls have to use snake case (staff_member)

My app/pretender/config.js contains this:

  this.get('/staff_members', 'staff-members');
  this.post('/staff_members', 'staff-member');
  this.get('/staff_members/:id', 'staff-member');
  this.del('/staff_members/:id', 'staff-member');
  this.put('/staff_members/:id', 'staff-member');

The problem comes when I save a record, performing a POST request to /api/staff_members with a type string of staff-members. The data doesn't match in this line and therefore breaks in this other line.

To make it easier, I created this little project to demonstrate the problem: https://github.com/cibernox/bug_demo

Install dependencies, run ember serve and go to http://localhost:4200/tests to see only one test failing.

Allow stub handler function to influence the HTTP response code

It would be great to write tests that emulate how the client responds to a unsuccessful server response (where the HTTP response code is not a successful response, e.g. 406).

this.stub('get', '/contacts/:id', function(store, request) {
  var contactId = +request.params.id;
  var contact = store.find('contact', contactId);
  // Test record not being found
  var responseCode = contact ? 200 : 404;
  return {
    contact: contact,
    responseCode: responseCode   // where the front.js file is looking at this specific field and returning this code if it is present
  };
});

Factories

Being built in the add-factory branch.

Factory

  • Factory.define
  • work with basic numbers, strings
  • work with functions that have access to sequence
  • basic inheritance

create, createList

  • basic functionality
  • allow override of attrs

additional features

  • traits
  • relationships
  • fake data via Faker.js

add test for loading fixture data

I essentially need to test the initializer in dev environment, to check if data was actually loaded from /fixtures. How do I do this?

Add resource generator

When generating a fixture blueprint, a get route entry should be added to app/mirage/config.js.

For instance, when generating:
ember g fixture contacts

the following would be added to the config:

// app/mirage/config.js
export default function() {

  this.get('/api/contacts', 'contacts');

};

It should be optional to generate additional route entries, for post, put and del, by passing additional options through flags.

ember g fixture contacts -post -put -del

would add the following to the config:

// app/mirage/config.js
export default function() {

  this.get('/api/contacts', 'contacts');
  this.post('/api/contacts');
  this.put('/api/contacts/:id');
  this.del('/api/contacts/:id');

};

Generators for factories and fixtures

Factory would be

ember g mirage-factory contact

which creates

//app/mirage/factories/contact.js
import Mirage from 'ember-cli-mirage';

export default Mirage.Factory.extend({
});

and fixture would be

ember g mirage-fixture contact

which creates

//app/mirage/fixtures/contact.js
export default [
];

New name?

This is no longer really about Pretender, it's

  • an XHR interceptor (currently Pretender, possibly mockjax in the future if we can't solve #19)
  • a clientside datastore
  • soon, a clientside factory system

It's really a fake clientside server. Any good name ideas?

I want to extract the main part into a separate non-Ember lib, and keep this lib the ember addon that ties it all together. That way it could be used elsewhere, e.g. in a React app.

QueryParams not recognized (e.g. on store.filter)

Hi,
i am having issues when using query params (such as using this.store.filter('someModel', {some: "param"}); for example.

The error reported is:

Mirage: The route handler for /api/v1/languages?isDefault=true is requesting data from the languages?isDefault=trues collection, but that collection doesn't exist. To create it, create an empty fixture file or factory.

Defining this route in config.js or overriding the server.get(...) in a test does not solve it.

Is there a way to handle these request / defining these routes?

Factory sequences, traits, lazy

The API for sequences is changing to be consistent with upcoming traits, dynamic attrs and associations.

// factories/post.js
import Mirage from 'ember-cli-mirage';

export default Factory.extend({
  title: 'ABC',
  date: new Date(),

  likes: Mirage.seq(i => i),

  approved: Mirage.trait({
    approved_at: new Date(),
  }),

  views: Mirage.lazy(() => {
    return Math.random() * 1000;
  }),

  link: Mirage.lazy('title', 'date', (title, date) => {
    return moment(date).format('MM/DD') + '/' + title;
  }),

});


// tests/acceptance/index-test.js
...
server.create('user');
server.create('user', 'approved');

Serializer layer

Serializer layer for

  • whitelist which attrs to show
  • including vs. not including a root key
  • embedding vs. sideloading related models
  • camelCasing vs hyphenated

Add factory properties when generating blueprint

We should add the ability to generate factory properties through params like so:
ember g factory contact name:Joe age:20 email:=> admin:function
would generate:

// app/mirage/factories/contact.js
import Mirage from 'ember-cli-mirage';

export default Mirage.Factory.extend({
  name: 'Joe',
  age: 20,
  email: (i) => i,
  admin: function(i) {
  }
});

The options for the property format are as follows:
<property-name>:<property-value>

with the following property types available:
String: any value that does not parse to a number or is not a reserved word ('function' for instance)

Number: any value that parses into a number will be converted to a number

Function: a value with the reserved keyword 'function' will generate an empty function with 'i' as the only parameter. We would also provide => as a keyword to generate an arrow function instead.

Cannot get record in tests

I'm not sure of that's going on, but I can't get individial records in tests.

The exact error is:

Pretender intercepted GET /api/schools/1 but encountered an error: Cannot read property 'findBy' of undefined

that references to this line: https://github.com/samselikoff/ember-pretenderify/blob/ab7f70d0073e14a047ac753152d39573743212e7/addon/store.js#L27

My config.js:

export default function() {
  this.namespace = 'api';
  this.timing = 100;

  this.get('/schools/:id');
  this.get('/schools');
  this.get('/teachers/:id');
  this.get('/teachers');
}

and my fixtures in app/pretender/data/schools.js

export default [
  {
    id: 1,
    name: "Copley High School",
    subdomain: "copley",
    school_type: 'secondary_school',
    address: '11 Test Road',
    teachers: [1, 2]
  }, {
    id: 2,
    name: "Tendring Tech",
    subdomain: "tendringtech",
    school_type: 'secondary_school',
    address: '11 Test Road',
    teachers: [3]
  }, 
  /* and a few more */
];

Everything seems to be by the book, but in my acceptance tests it fails. The only special bit is that I'm using ember-cli-simple-auth and ember-cli-simple-auth-oauth2, but I don't see why it would affect this.

I'm open to pairing to fix this is that helps

[Feature request] Pass default handler to customHandlers

I'll expose my use case to see if you see this as something it might worth to add.

I have some index routes where I need to perform pagination (and also filtering if a filter=abc query param is received) but also they need to handle coalescedRequests like /posts?ids=1,3,5.

I've defined a custom hander like this one:

this.get('/posts', function(store, request) {
  if (request.queryParams.ids) {
    // mimic default behavior
  } else {
    let results = store.findAll('post');
    let payload = {};
    if (request.queryParams.filter) {
      // do filter
    }
    // bla bla construct meta 
    return payload
  }
});

I thought that a situation where you want to use the default behavior or a slightly modified version of the default behavior, receiving the default handler as a third parameter in that function could be useful.

P.e:

this.get('/posts', function(store, request, defaultHandler) {
  if (request.queryParams.ids) {
    return defaultHandler(store, request);
  } else {
    return myCustomPayload;
  }
});

or

this.get('/posts', function(store, request, defaultHandler) {
  var payload = defaultHandler(store, request);
  payload.meta = { page: 1, timestamp: (new Date()).toString() };
  return payload;
});

Thoughts? I've located the part of the code that has to be changed and seems fairly minimal.

Exclude data from production build

Right now, the server doesn't run in production (unless force is specified), but all the data + route definitions end up in app.js. Is it possible to exclude these files?

Partial models

something like store.findQuery('contact', {count: 10}, {only: ['id', 'name', 'count']});

Remove console.log's

It'd be great if you could remove the console.log calls. That will make our Travis logs much easier to read. (also it looks like there is a memory leak in test'em where if you log a lot of objects it really bogs testem down).
screen shot 2015-02-12 at 1 33 25 pm

Support for an error response

Is there a way to handle testing and error response from the server.

Adding an api that could be used in a test that returns an error for an api resource would be helpful.

I see that you are have this as a todo.

it('should have heading', function(done) {
  pretenderify.stub('get', '/contact/:id', 'error');
  visit('/contact/jack');
  andThen(function() {
    assert.equal(find('.container h2').text(), Ember.I18n.t('title'));
    done();
  });
});

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.