 Hi, so my name is Will, I'm Will Rax on GitHub and Twitter if you're interested, recently moved to London from Australia. So I work for a company called AlphaSites and you can find us there at engineering.alphasites.com. So we use Ember, we use Ruby, we have a little bit of React, we have some Elixir, so we have a whole wide range of technologies that we use. We kind of operate on the similar to Netflix, so you can kind of choose the technology as long as you are ready to own that technology and kind of, you know, vouch for it and convince other people to use it. So we're a pretty fun and interesting company to work for. Of course we're hiring and we have cookies literally and we have apples and things like that as well if you're into that. So I wanted to talk to you today about Ember CLI Mirage. So I wanted to kind of cover what Ember CLI Mirage is, why it exists and how you can use it. So what is Ember CLI trying to solve? Well basically with most Ember applications you're going to need some sort of data that feeds into that application. So whether you're using Ember data or something else to fetch that data, you usually have like a Rails API or an Elixir API or a Node.js application that's serving data to that. And this is kind of like a typical setup for an application. So you have your client and then you have your API on the back end. But this kind of poses a little bit of a problem for development or at least initial development. So one of these, or both of these things kind of have to exist for the other to exist. So it's very hard to build a front end application without an API running on the back end. And again, it's very hard to kind of work with your API when it's hard to see those details kind of happening and happening, occurring on the front end of your client. So we kind of have these two options for, well we have three options for kind of dealing with this issue of how, well where do we start? It's like a chicken or the egg type of thing. So the first one is we build out our API but then we have to spend weeks building out this API or a week or so, building out this API before we can jump into our client. And that doesn't kind of lend itself to parallel working. So if you have a team of people working, you kind of leave your front end developers, your amber developers sitting there doing nothing while they wait for your API to be built. So the two options from there are kind of server mocking and client mocking. So by server mocking I mean you build your API but you don't worry about any of the implementation details of your business logic or anything like that. You just have it serve these kind of dummy objects. They're just objects that are representative of the data that you will eventually provide to your front end. But this kind of has some issues, right? It kind of doesn't, it's not portable for one. It's not shareable easily across teams. It also means that data gets out of sync quite quickly. So if you're not keeping your objects up to date on your back end, then they're not up to date on the front end either and what you're expecting. And it also means as your team is building out the functionality in the back end, the objects may fall out of sync there. But as I said, the kind of big issue about that one is it's not portable at all. So you may have your front end people working on that and then they have to get this whole Rails application running or Node application running. They have to keep that in sync, they have to run this whole server infrastructure, which doesn't lend itself to quick iteration in the beginning, which leaves us with client mocking. So what do I mean by that? You might use fixtures, for example. But this, again, has some kind of issues. Data gets out of sync quite quickly. It's not very portable across apps. So both of these options, while they have their pros, they also have their cons which carry them. So what is the ideal situation for this? So what is the ideal solution that we would expect to kind of solve here? Or solve this issue with? Well, in an ideal world, we would want conventions. So we would want a convention that we can say to our team, to our developers. This is how we do our testing. This is how we build out and mock our objects. And this is the library that we use. These are the type of tools that we use as well. And this means you have consistency across your entire development team. You'd also want some sort of fixtures or even factories would be ideal as well. So you'd want to be able to recreate data on the fly. You don't want to concern yourself with generating these objects every time. So say you need 10 of one thing. You don't want to go and then spin off like 10 different objects, trying to look after the IDs are different. You might want different names because you have presence validation or uniqueness validations rather. So we would also want routes. So we'd want to say this is what our application gets and this is what we want to serve back to it. So something like pretender and then all of these things put into pretender. And we also want like a database. So we want to be able to manipulate this data in some way and then send it back into our ember data or into our application. So this is our pipe dream. So this is basically what Ember CLI Mirage provides us with. So it was created by Sam Selikoff. He works at TED and he started Ember CLI Mirage and it's up on GitHub and you can find it under his account there. So what does Ember CLI provide us? Well, you saw the list before, so really it gives us these things. It gives us a set of conventions that we can pass down to our users or to our developers rather. It gives us fixtures and fixtures, that should say factories. So it gives us fixtures and factories that we can use in development and test environments. So they're easily portable, they're set in one file, easily reusable across the whole app. You create them once and you can use them in a variety of routes. So it also gives us a configuration file where we can actually say, like these are the endpoints that our server is going to hit. This is the data manipulation I want to do. And then that feeds it back into the Ember data or whatever thing that you're using. And I'll kind of go into a little bit more detail on how that works, because it's a little bit of a concept to get your head around. But it also gives us a database to use. So it has its own internal store where we can store data, reuse data and manipulate data as well. So this is kind of what our front end development thing begins to look like now. So we have our client and we have our API that exists within our client as well. And with Ember CLI Mirage you can opt to use it in development and test or you can just use it in your testing environment. So for our application, for example, in the beginning we used it for development because it was very easy to get up and running. And we could kind of build out what the Ember application was using. And then we switched that off when we used our, or when we got onto our Rails API and now we just use it for our test environment, which is very good. So I've built a bit of an example application that I kind of wanted to walk through and just show you how we've used or how we've implemented some features of Ember CLI Mirage in this very basic application. I'm assuming zero knowledge of Ember CLI Mirage, sorry. So these are very basic examples and there's a lot more that you can do with it. So is that way too small? Okay, so the application itself- I'm not full screen, wait, I'll turn on all this. I can't go any longer. So the basic premise of this app is that it displays a list of movies. It's really simple. It's nothing like IMDB. Basically it's just a page, you have a list of movies. There's an input form and you can fill it in and things like that. You might notice I'm not using the new input things as shown before. So this is our main page. It's only a one page or a one template application. This is the model for the movies themselves. So each movie has a name, a rating, and a trailer link and that can be YouTube or whatever. And the two things that I'm going to do with these movies, so the two actions that I'm going to hit on them, I want to get a list of movies and I also want to post back to movies to create a new movie. So if I was to run Ember server, which I've done here, so it's running, and then load up the application, can you see that? You might notice an error down the bottom here saying Mirage. You remember app tried to get my API awesome company slash movies, but there was no route defined to handle this request. So straight away, Mirage is kind of guiding us in what to do. So what's happened here is the app is loaded. It's gone through the normal Ember stuff. There is a fetch to fetch the actual movies in my movies route. So I've gone store find movie and then that's gone and Mirage has kicked in, or pretender through Mirage has kicked in and it's discovered that there is nothing to return or there's no actual mock for that endpoint. So this is an example of Mirage working in development mode, which is the default setting. So what I can do is when you generate a new Ember CLI Mirage setup, it generates a config file for you. And this is where you set up what the routes for your application are. And this is kind of where you have to touch on this separation of the client and what Ember CLI Mirage is actually providing. I'm going to call it Mirage from now on. So Mirage is really, it's very agnostic towards what you're using for your data store, so it doesn't care if you're using Ember data. It doesn't care if you're using anything else like that other one that exists. But I can't remember the name of, because it's separate from all that. It doesn't insert directly into Ember data or anything like that. All it does is mock what your RAIL server or your node server may look like. And that becomes evident when you look at the factories that are created for this particular movie. So you'll notice here the trailer link in particular, it's not the camel case that normal JavaScript would be. And that's because in my adapter, I'm using the active model adapter, right? So that, by default, from RAILs will send a key that looks like trailer underscore link in the usual snake case. So there's that difference between, or once you kind of get the concept that the data store within Mirage and the data store within your Ember app is different, then it kind of becomes a lot easier and it makes a lot more sense in how it fits into your development and test workflow, which is one of the reasons why Mirage is. So portable across different apps. So if you have different apps that use different APIs, it's quite easy to just bundle this kind of Mirage configuration into a separate node module or a separate set of files where you can just import into your application, get up and running straight away. So if I wanted to get rid of that error, I would just need to comment this line out, the app will rebuild. And what I'm saying here is Mirage will read in this config file and it'll actually evaluate that get slash movies into a mock, sort of interpret and send it through to pretender. And what it's actually going to do is it's going to say when I hit my API, so at the moment Mirage is acting as my API. When I hit my API with slash movies, I want to return the movies from my data store. So in development mode, this is going to spin off and create some movies. And you can see here that it's done just that. And these are all the movies, so it's just Lorem Ipsum. So some things to note that Mirage comes with in regards to these factories. So what it's doing is it's creating a list of factory of movies. It's putting that into Mirage's data store and then it's sending it to my application through the API request, which is then populating it at Ember data. So Mirage comes with Faker as well. So you can use Lorem Ipsum, you can make up company jargon. You can do all types of anything really that Faker can do. If you're not familiar with Faker, I'd definitely check it out because it's extremely useful for creating unique records. The other thing you can do, you can just assign straight values so you can go five or you can say 10 or you can do 50 or whatever these can be strings or anything. The other thing you can do is you can use this kind of sequencing. So if you're familiar with Factor-Go, with Rails, they have a sequence method. So this is a very similar thing. So it passes in I, which will be the sequence of the list. And then you can actually tag that onto the end here. So you're making unique records. So you can either use Faker or you can do this. So I think before I had something like like that to make a unique name before I switched to Faker. And I'll just revert all of this. So now if I load my application, we have the movies there as well and they're all listed neatly. So now the next step would be to create a movie, right? So I can go Jurassic World. I'd give it a rating of 10. Oh, great. We'll just ignore that for now, I must have. But then if I hit save, we're going to get that a very similar error to before. So my Ember app tried to hit post movies, but there was no route defined to do this request. So what I can do is I can uncomment this. And now I've set up a route or I've mocked a route that will take that post to movies. It will manipulate that data. So when you do this, you get access to the DB. So Mirage's internal store. And you also get access to the request that was sent from Ember to your API. And you can pass this request and get out the attributes of that request. Then what I do is you create a movie. So you create an instance of the movie in Mirage's store. So in Mirage's database. And this is so I can reuse it later if I need to. Say you're doing relationships or something like that. You can kind of get as tricky as you want in there because remember this isn't Ember data's internal store. It's Mirage's internal store. So in here you would do things that your server implementation would do. So say you in your like ideal API, you would create a new movie. It would go off and like aggregate scores from different websites. It would actually try and get the trailer link. It might do some fancy stuff. Well here you can implement that same logic and then just return what your Ember app expects to get returned. Does that make sense to everyone? Cool. And then I just need to return. I need to return the movie and then the movie object as well. So far this is just exactly what my API return in the active model serializes fashion. I believe that there is actually an option for Mirage to supply this stuff by default. But I kind of wanted to demonstrate that you can get in to the gritty details of how you want your server and you can do a deep data manipulation and things like that. So with that now if I save my movie, now it gets added there to the end of the list. Just ignore the fact that the name's not showing up. It does work in reality. So what this also allows us to do is use Mirage in a test environment. These tests may fail now because stuff's broken everywhere. But if I show you a quick example of a test, so this is a test for movies. So we do a couple of tests. We're testing that the first test we'll do is test that the current path is movies and everything loads. That's just a basic test. But here we're gonna actually fill in a movie into the input form that you saw earlier. So you can see here that I am just filling in each input with different kind of information. So with the rating, the trailer, the name, I'm clicking the button. Then I wait and then what happens is that actually goes back to Mirage which carries out the exact same API manipulator or API response that we were doing for development and then sends that back to our test environment and the test passes, yes. So then, and if you want proof, I can make it fail as well. I hope it fails, yeah. So CLI Mirage makes it really easy to kind of create this development environment that you can use in your test environment straight away as well. So you're kind of killing two birds with one stone. So kind of like more, or another test here is that we wanna test that each movie is, or if we load the default page that the movies that already exist in the database are populated onto the page. So there's an example of this here where you see in a test Mirage will actually give you access to this server object which is direct access to Mirage's internal data store. So you can actually manipulate that and set it up from your test. So here what I'm doing is I'm creating a movie object generated from the factory. So I could create a list of movies and create 10 of them. I believe that's how that particular thing works. And then that would go off and spin off 10 unique movies which would then be used in our test. And one of them fails now because it was the first one. So I'm gonna do that. And then we just do a normal test there to check it. Oh, I have to change this one back. And then we should be green again. So yeah, this is just a very simple example of what Mirage can be used for. I would really highly suggest checking it out even if you're not using it for like development just for testing alone. It saves a ton of time in being able to create the factories for one, the configuration file and just having it all tie in neatly. It makes it a ton easier. Does anyone have any questions about Mirage or my application? How did you solve Mirage? How many pictures to generate? In development? Yeah. Yeah, I knew that would come up. I can't remember. Yes, that's it, the scenario. Whoops, I knew I forgot something. So Ember and Mirage has this idea of scenarios. So at the moment you can only load in one scenario which is this default scenario. But in the future you'll be able to create a scenario for say in the instance that we have 100 movies and we wanna paginate, then you could easily run that. Then yeah, you can just set up your factories and your store from there. So I could change this to one. And then kill that Ember server. And then it will load in that scenario, create one factory for me in my Mirage server. When my Ember app goes and hits that Mirage API, it'll return that one object. Do you choose audience? No, so the moment there's only support for one. So it'll only load the default one. But in future the plan is to have multiple scenarios. So you can easily just spin up like different situations for your app. Any other questions? You should have started off with the element, but Mirage, do you stop now that you've got the API you're knocking anymore, does that... Sorry, so... Well, because it's done now, why do you stop once you... So we just use it for tests now. We stopped using it on the development side. Is that the question? Why did we stop using it on development? Yeah, so the complexity of the app itself was the way the app works but actually uses another app and then talks to that and then sucks in data and then sends it back. The complexity of that, it's things like RabbitMQ and then there's all this other data that gets populated from the other side and it just became testing it. We needed to test that the flow kind of worked right through to the app. So it was more an application-specific thing where it was just like we made the decision to go, okay, now we need to start using the app in development with the full suite of tools of other applications. In an ideal world, it'd be awesome to use Mirage the whole time but yeah, it wasn't just a simple case of serving this API, unfortunately. Yeah. Can I run my tests to get to each of the old versions? I... With fixtures. Sorry? With fixtures you can do whatever you want. Yeah, fixtures, yeah, you're fixtures, because you could create... Yeah, you could create a fixture that represents a different version of that object from a different API endpoint. You can use this, you can use this, yeah, yeah. How far off is that, does it look like at the moment? I'm not sure. Yeah. Like, so one thing about Sam is he's been actively like, this thing is, he's been adding more and more as he goes and is actively developing it. So I think he uses it at work, well, I would assume he uses it at work quite often. He has a ton of ideas so he wants to do more things on relationships so at the moment, relationships are quite difficult. Well, they're not difficult, they're just a bit, yeah. They, yeah, they're manual, that's the word. So you have to create each object and then assign the IDs to it when you create it in your test. So you saw before how a server create movie. So if that had like comments then I would create my comments first and then I would assign those comments to the movie internally. But he has this whole idea of being able to do that in the factory. So very similar to factory girl. The next step in your task, Sam told me, was creating a small R&M. So the factories are closer to what factory girl does and knows how to create associated records. So having quite small factories will lead to maybe less typing, you know, if you can create user or create movies with comments like a trait in a factory girl and create, it espouses 10 comments for each movie. Yeah, it's been really good. The other thing that you don't have to do is you don't have to, so in another application that we have at work they have to manually build their objects in their tests each time, which they no longer have to do. So they were able to like rip out a whole bunch of test code. So yeah, any other questions about Mirage? Yeah, I was wondering, does it ship with any test helpers for like asserting that the right thing goes over the wire in a particular test? Because it looks like in Mirage itself you could check that the parameters that came through were the expected things or like fit criteria. But sometimes it's quite nice in a test to be able to say, you know, I took this button I expect to see exactly this payload go over the wire. Is there anything to help that with that? Yeah, I see, like to check. So that it actually calls the API you mean or? Just like something that could say, I know, hook into Mirage and say, when you're processing this request, give it to me so I can run these assertions first. Right, right, right. Not that I've used. Yeah, you can. You can? Okay. Because inside your test you can define groups. Groups, like you do on your profile. Oh, and Mirage? Yes, so basically the same thing you have on your profile, you specify a small server dot, I think server dot map or something like that. And inside you do this dot get and post the thing and you expand the function. Inside this function, you can use the assertions because it's your type of data. So the server object that you get access to is kind of like the God object in Mirage. You can get access to the adding routes, the database and all types of things. And it's up to you to spin it up and set it down again in your test. It's not something you need to spin up. It's just there. It's just, am I supposed to put it in there? How do you make sure that it's not carrying any state from test to test? No, no, no. How does it make sure that it's, maybe you have been in a new server on before its test, okay? This is wiping everything. Nice. Cool. All right, thank you very much. No problem.