 I hope you're ready. So last year, I don't know how many of you were here last year, but I gave a lightning talk with 24 hours of notice after much peer pressure from Leia on the topic of testing in Ember. At the time, I had three months of experience as a professional developer. I had freshly graduated from the Flatiron School. I didn't really know that much about testing at all. And I found that there were not that many great resources. So hence, I felt much like our friend ChemistryDog here. I had no idea what I was doing. So I gave this talk on, like, you know, your testing resources suck. So I'm back now. And I'm here to share with you all the things that I wish that I had known last year. Basically, going back in time, so travel with me, I'm going to talk to my past self, because now I have some idea of what I'm doing. So first of all, what do I wish I knew a year ago? First of all, what do I have access to with Ember right out of the box without even thinking about it, what am I getting? How do I use Ember's built-in test helpers that Ember gives us right out of the box? What's the difference between unit acceptance and integration tests? At the time, I think that Ember Guide's kind of conflated acceptance and integration a little bit. It was very confusing for me. I think it's since been remedied. But what's the deal with all these other frameworks in libraries? I kept hearing people whenever I would go into, like, you know, a testing room or whatever, everyone would be like, oh, Jasmine, Jai, QUnit, and all this stuff. And I was like, well, do I need that stuff? Is that important? I have no idea. What are mock, stubs, and spies? Do I need them? How can I mock API responses? Obviously, you don't want to be hitting your API live all the time. In your testing environment, that's terrible. So how can I mock those API responses for my tests? How do I deal with async behavior? And finally, what are some best practices when it comes to testing? So what do I get without even trying? I can roll out a bed, and there's QUnit ready for me. So QUnit is a JavaScript testing framework. It's not specific to Ember. It's a JavaScript testing framework. You can use it with any JavaScript project. But Ember gives it to you right out of the box. It's a default testing framework. And it includes, so when you have an Ember app, it includes everything that QUnit has. So if you go to the QUnit documentation, you'll see all the assertions they give you, and all the cool helpers, and all that stuff. And you have all of that. Ember test helpers. These are built-in methods to automate common tasks in acceptance tests, like visiting a page, clicking a button, all that fun stuff. Test them. Very simply, test runner runs your tests. So the Ember acceptance test helpers. There's three groups. The first is Async. These are helpers that are aware of, and they wait for your Async behavior. They are run in order. And they are click, fill in, key event, trigger event, and visit. They're fairly self-explanatory. But if you want super detail, you can look in the Ember guides. So the sync test helpers. The sync test helpers are performed immediately when triggered. Some of those are current path, current route name, current URL, find. And finally, the wait helpers, which is really just one helper. And then waits for all the preceding Async helpers to finish before executing the code wrapped within. So here is an example. This is a test that is, we're just testing that if I visit a certain URL and I click on a certain selector, then I'm not going to be redirected. And I'm going to see this warning message. So you see on line two how many assertions are expected. You see on line four an Async helper in action. That's visit. More Async on six, click. So those happen in order. And then waits for those guys to finish. We have our Q unit assertions. We're asserting that the current URL is not equal to settings slash billings. And that the warning message selector text is an account already exists for shared at example.com. So that's some examples of those helpers in action. What's the difference between the different kinds of tests? We have unit tests, integration tests, and acceptance tests. Unit integration acceptance, like the stages of grief. Nailed it. So unit tests, first of all, are self-contained tests. You're only testing the code itself with unit tests. You're not testing user interaction. You're testing only a particular function or another unit of code. This is not clicking, visiting, whatever. So to give you an example, we have this super basic computer property, full name. Just takes first name, last name, concatenates them with a nice space in the middle. Super basic. So we're just gonna write in a little unit test for that. That full name returns first name and last name. So we're just making a user, setting the first and last name properties to Bob Smith. And then we're asserting that when we call user get full name that we get Bob Smith as expected. So that's an example of a unit test. Integration or component tests. Component tests are integration tests, but integration tests might not be component tests. When you generate a component using Ember CLI, it comes with a little component test out of the box, which is an integration test. Basically, you're testing how one layer of your application interacts with another. In the case of components, it's usually how components interact with each other or with other templates. So we have this little component. It's just a list of dudes. Joe Bob, Bob Joe, Joe Bobby, Joseph Robert. For some reason, these guys are really important and we want their names all over our app. So we made this little component called list display. And then we're just testing that when it renders that they are there. So it's pretty simple. This.render list display and then you see the assertion that when we trim all the text that we get what we expect. Acceptance tests. So acceptance tests and integration tests can be tricky to pull apart, but acceptance tests, the way I remember it, is that I accept that my app has actual users who will actually interact with it. So I had better well test for that. Cause they're gonna click that button that you don't want them to click and you gotta be ready for that. So again, we have Joe Bob, Bob Joe, Joe Bobby, et cetera. This is just a plain template. And so we have two acceptance tests. The first is that when we visit the homepage, it results in the current URL of the homepage. So we see again the async helper visit and then waiting assert equal current URL. That's one of our sync helpers is equal to slash. Simple enough. And then that the correct number of users are displayed. So again, we visit the homepage and we check that the number of users that we expect are there. Mox, Spies and Stubs. Mox, Spies and Stubs, they help you write unit tests in isolation. They probably won't come up very often in Ember, but they're good to be aware of. I was only made aware of them because I was working on like a plain JavaScript project at my last job and they had all these things. So that's how I became aware of them. But they're really more for unit tests and you should mostly be writing acceptance tests and unit tests you should write the least of. So it's not gonna come up that much. SignOn.js is a great library that provides Mox, Stubs, Spies and more. There are also two highly rated Ember SignOn add-ons called Ember SignOn and Ember SignOn Queue Unit that you can look into if you wanna use these things. And there's also a link to a blog post that I found about using SignOn in Ember projects. So Mox are also known as test doubles. These are fake methods with pre-programmed behavior and pre-programmed expectations. Spies, a spy is a function that records arguments, returns the value as well as the value of this and any exceptions that might be thrown for all its calls. It's good for seeing how many times a particular function was called or how a function is handling a specific callback. And Stubs, Stubs are spies. So you get everything that you get with spies with Stubs. They kind of help you force your code down a specific path. So if you wanna throw an error or you have a specific sort of path you wanna go down, they're good for that. In the case of SignOn.js, there's a lot to explore. Stubs, like I said, they support the full spy API. So if you look at the documentation, you can find tons of information. Mocking API responses. So this is pretty important because you don't wanna be hitting your live API, obviously, you want your test to be running in isolation. A great solution that I love for it and I think a lot of people love for it is Mirage. Mirage is awesome, super popular solution. Not just for testing. It can be used in development as well as in test environments. They offer factories that you can use for tests. You can seed your test database ahead of time. You can mock one off responses in individual tests. SignOn also offers mock API responses, but Mirage just offers so much more that it's definitely worth looking into. And like I said, you can use it in development. So if you don't have an API that's ready yet and you just want a mock API to work with in development, you can use it for that as well. It's awesome. So here's an example of where you might use Mirage. So we're just testing that someone who's entering, they're changing their password and they enter an incorrect password and we wanna make sure that this error is gonna get thrown. But we need to get that response from the API that old password is not correct. So you can see from lines four to eight how Mirage works there, just like server.patch and you say what you want and then you throw whatever the response is. Framework FOMO. So if you're anything like me last year, a year ago, you might be seeing everyone talk about all these different testing frameworks and libraries and stuff and you're thinking like, God, do I need this? Like, how do I know which one I should be using? So I looked into a couple of the ones that I heard a lot about and kind of compiled a bunch of the different, whatever I could tell was slightly different about them. So Jasmine is the first one. It's a behavior-driven testing framework. Doesn't require a DOM. Doesn't depend on any other frameworks. It's similar in syntax to RSpec, which I think is the biggest selling point if you're a developer coming from Rails background. I've heard that Jasmine is a little easier to pick up but I also came from a Rails background, so I really didn't find QUnit difficult at all to pick up. So, you know, to each their own. Chai is an assertion library, not a framework. People seem to really like having a ton of different assertions. It's a personal choice. I find QUnit to be more than enough but if you really want to have that, then Chai could be a good solution for you. I've heard that it's difficult to implement an Ember with QUnit. There's a few add-ons out there but I couldn't find one that seemed to be like a distinct solution. However, there's Mocha, which is another testing framework, so you would probably use this in place of QUnit. You can use any assertion library, so if you really like Chai, you can always just use Mocha instead of QUnit. I read that you can't use the ES6 fat arrow syntax. I don't know if that's true, but it seems weird. Apparently the reason for this is that their lexical binding of this value makes them unable to access the Mocha context, so statements like this.timeout1000, it won't work inside an arrow function. I don't know why. So, Selayam, another one I've never used but I've heard a lot about. It's mostly for end-to-end testing, clicking and all that. It drives your browser in your application environment rather than test environment. I've heard it's difficult to hook up to Ember and that it's much slower than using QUnit. So, what's the verdict? As far as I'm concerned, QUnit is great. I have yet to come upon a situation in which I felt like QUnit was lacking, so I think everything that comes out of the box is awesome, except for you should add Mirage, because that's great. Okay, TDD, so if you're a beginner, like I was a year ago, you might hear this term thrown around, what's TDD? TDD is test-driven development. It means that, basically, first you write a failing test for something that doesn't exist yet, then you build the thing to make the test pass, you write another test for another thing that doesn't exist yet, and you rinse, repeat. This is a great way to ensure as complete test coverage as possible, but a lot of beginners find it very difficult if you're trying to do this without any guidance because all the time, as beginners, you'll find that you are just kind of hacking something together and you don't really know what it's gonna be when you're done, and so it's impossible to know what it's gonna be ahead of time to test for it, so it's okay if you try to do TDD and you're a beginner and you have a hard time, you know, there's nothing wrong with you. Page objects, okay. So UI changes can make your tests really brittle if they're frequently dependent on specifically named selectors. You might find that you make a lot of changes to a bunch of classes, and all of a sudden you have all these tests failing because you're depending on all these classes and all your acceptance tests, so that's annoying, but page objects are a great solution for that. Basically just you encapsulate the structure of your page within an object, so it helps keep your tests dry as well as keeping the intention of your tests clear. There's a well-supported ember add-on that looks awesome, called Ember CLI page object, and there's also this famous blog post by Martin Fowler on the topic of page objects if you wanna read more about them in general. So here's an example of where we might use page objects. We have that same test again, we're using Mirage, and we've got all these, there's a ton of selectors here. You've got the change password, select your new password, input, whatever. So let's make a page object for the account settings page and let's just encapsulate all that stuff. So when we're visiting, let's just make a visit function, let's just make a click change password so it's very obvious what's going on. And then when we go back to the test, you can see it's very obvious the flow, like if you just hired a new developer and they come in and they look at this test, they know exactly what's going on. You visit the page, you click change password, you enter incorrect current password, enter the new password, update the password, and then you wanna see that the password error text is equal to that text, so it makes it a lot easier. Some best testing practices that I have come upon. Keep your test code dry by writing test helpers. So if you find yourself repeating your code over and over in your tests, Ember allows you to write custom test helpers and there's a lot of information about that in the Ember guides. So if you find yourself doing that, start writing some test helpers. It'll make everything happy. Protect your tests from UI changes and keep their intention clear with page objects as I just talked about. Keep each test discreet in its function. So you don't wanna be testing five different interactions in one test. You wanna make sure that you're keeping everything very discreet and isolated as you can. Most tests should be acceptance, some integration, least of all unit. This is my opinion. Katie Gangler gave a talk a while ago where she had like a pyramid, I think. I think it was her. And it was a little bit of unit at the top. In the middle was integration and the bottom was acceptance. And since Ember is a front end framework, it makes sense that you wanna mostly test your user interaction and clicking around and stuff like that. But if you have like a really complex computed property, then obviously you might wanna unit test for that. Testing styles like TDD. They're a matter of personal preference. Not any better or worse than anything. They're worth looking into. I think TDD is super interesting. I just haven't been able to use it very much myself. Some resources. Ember Guide link to the test helpers, QUnit docs. I also gave a talk at the Global Ember Meetup like a few months ago called Intro to Testing. And that's just like a step by step, like nitty gritty, how do you actually run your tests? What's the difference between all the test environments? So if you're interested in that, that can give you more information about that. And some more links to all the different things and a great blog post I found about the differences between Mox, Stubbs, and Spies. Finally, I would love to thank my former coworkers at Simple Reach who are on the front row. They were my, thank you, Hayjin. They were my coworkers a year ago. I came here with most of them a year ago and they were very, Simple Reach was very supportive of me as I was trying to learn testing on the job and basically they were like, we don't have any tests in this app. Why don't you learn testing and write all the tests for this app? So I wouldn't have learned all this stuff without Simple Reach. And also I just moved here two months ago from New York working at Simple Reach and now I work at Tilda, which is amazing and awesome. And I would also like to thank my current coworkers and team members at Tilda. That's it, thank you very much. Hi, I have a question about coverage tools and I've been trying to integrate Blanket, for example, and with the CLI, it's kind of a hassle. So any suggestions would be appreciated. I actually didn't, we, at my last job, I think we did implement Ember CLI Blanket, but I didn't do it, Andre did it. Because I think I tried and I just couldn't, it was so hard. But Andre Milan can help you a lot with that. Anyone else? Oh, thank God. Thank you very much. Thank you.