A client-side server to develop, test and prototype your JavaScript app.
Visit miragejs.com to read the docs.
An Ember Addon to easily add Mirage JS to your Ember app.
Home Page: http://ember-cli-mirage.com
License: MIT License
A client-side server to develop, test and prototype your JavaScript app.
Visit miragejs.com to read the docs.
if run ember server, get below error, but it works once I remove http://localhost:8000/tools application adapter.
Error: Pretender will not respond to requests for URLs. It is not possible to accurately simluate the browser's CSP. Remove the http://localhost from http://localhost:8000/tools and try again
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.
changed expect.to.include
to expect.not.to.include
and tests still pass ๐ต
didn't catch a bug when I renamed to mirage
something like store.findQuery('contact', {count: 10}, {only: ['id', 'name', 'count']});
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.
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.
find(type, id)
, findAll(type)
, findQuery(type, {query})
remove the string/number check from
https://github.com/samselikoff/ember-cli-mirage/blob/master/addon/factory.js#L12-L16
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 [
];
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
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();
});
});
whichever you prefer. shouldn't be too difficult.
Update usingProxy to check for proxies generated with files that live in /server/proxies
(generated from ember g http-proxy
).
Should be an easy one.
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
};
});
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.
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})
should be able to pass in a timing parameter to individual routes
Shouldn't return data under a root
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');
Probably [ ] or { }
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.
somehow
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.
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)
For some background info on why treating IDs as strings instead of numbers is a good ideas, this is a good read: https://dev.twitter.com/overview/api/twitter-ids-json-and-snowflake
From an implementation perspective in mirage, we should coerce ids to strings when adding to db, and convert ids to strings when calling db[collection].find(someId)
This is no longer really about Pretender, it's
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.
I essentially need to test the initializer in dev
environment, to check if data was actually loaded from /fixtures
. How do I do this?
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');
};
Serializer layer for
what should this be? Right now push, when it creates, finds new id by adding 1 to max id of existing records.
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?
and return an array of items with those ids (a la ActiveRecord::Base#find)
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 */
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.
e.g. lesson has many questions, questions has many answers
Is this possible?
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?
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?
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?
https://github.com/samselikoff/ember-cli-mirage/blob/master/addon/controllers/delete.js#L20
I just do console.error
right now, should I be doing throws
or something like it? When I tried that in a few places, the error didn't really show up in the log, Ember kind of took over.
Being built in the add-factory branch.
Factory
create, createList
additional features
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.