Testing and Modular Front-End Testing in the Browser
Transcript from the "Testing in the Browser" Lesson
>> So next, we can get into how to run these tests in a web browser. The neat thing about what we've been doing so far with Tape is that, if we have tests that don't use things like HTTP servers or any of that kind of stuff, then it's pretty simple to get it running in the browser.
[00:00:19] Tape internally uses console.log to print its messages, which works just as well in the browser as it does in Node. So you don't really have to do very much to get it all working. So I'm gonna make a second test now, just something real simple to get started.
[00:00:35] So gonna require tape, and have a bit of code here. And I'll do just some simple statements, I don't know, then t.end. All right, so give it a name if we like, so here's an extremely simple test that's just testing arithmetic, doesn't really test anything. If I run that in Node, it works.
[00:01:06] If I wanna run this in the browser, there's a few different ways we can do that, so, Call this browser-test so that we can, Differentiate some things a little bit. All right, so one way that I can do this is, I can run, if you npm install this command browserify, then you can use browserify to compile your test into some code that the browsers can understand.
[00:01:37] So it's gonna walk all of the require statements in the code recursively every time it sees a file. And it's just gonna kind of intelligently concatenate all of the files that you need to run the program, if you've written it in sort of this Node.js CommonJS style, like we've been doing.
[00:01:57] So if we wanted to put this in a browser, you can redirect that output to a file, like this. And then you can make just some scaffold HTML that has a script tag in it, like so. And if I go to this location in a web browser, and I open up the index.js, it's gonna be an empty page.
[00:02:28] But if I open up the debugger, I can see that hey, look, TAP version 13. And we see all of the messages that we were seeing on the command line, and the test worked. It's a bit of an awkward way to run your tests, so of course, there's some better options.
[00:02:42] But this is sort of a really barebones way to do this kind of stuff. Just to show you how you could build your own test runner, for example. Some other ways that we could run this are, could use a tool called budo, which I'll be using a bit after lunch.
[00:02:59] So you could either do it for a single file, or you can run it for a whole directory of tests. If you have a test directory, you can run budo like this. Now I go to that URL that it tells me to go to. It's blank, but that's what I expect.
[00:03:17] I go into the debugger, and we have all of these messages. So there's some useful tools that you can use if you want to, for example, copy all of these messages that are being written with console.log into the debugger into your terminal. Or into whatever you like, some sort of continuous integration system or whatever.
[00:04:02] And every time you do console.log in the browser, it's just gonna copy that to your standard out. So it uses a WebSocket connection or an XHR connection, depending. So if I wanna, for example, run this test suite, I can just do browserify *.js, can pipe it to browser-run, and you can specify the browser that you wanna run it in with -b.
[00:04:25] So if I run this command, here, browser-run is gonna open a real browser. But if you look on the command line, I see all of the data that's written to standard out. So if I open up the debugger, I see all of the same stuff that I see on the command line.
[00:04:43] And just to prove to you that yes, in fact, we're really running in the browser, I can do something like, what can you only do in the browser? I'll console.log the window.navigator., I don't actually remember. What are some things, navigator.appName, I think, yeah, appVersion? Yeah, the appVersion, that's a fun thing to do.
[00:05:13] Or maybe we wanna write a test out of this now, so that should have Linux in it cuz i'm on Linux. Or maybe I'll search for Chrome, so t.equal, or t.ok, I'll just use a regex, chrome.test that. So if I run this test in Firefox, it's gonna fail, probably.
[00:05:31] But if I run that in Chrome, Then yep, first assertion now is what we expect, so it's really running in a browser. This is pretty much all that you need to run your tests in a browser. So you do have to write your code in a way that can be digestible with CommonJS.
[00:05:57] And it's usually better, if you wanna test your browser code, to build modules whenever you can. Instead of like just building a big, hairy application that has a lot of pieces that are kinda tightly coupled, whenever you can, it's best to sorta break those out into separate pieces that are easy to test.
[00:06:17] So some ways of doing that are to, if you can help it, to not use any kind of global state. Because you're gonna have to set up that global state when you write a test. Also, if your code is really difficult to set up generally, that makes testing a lot harder.
[00:06:38] So one thing that I like to do, I can show you an example of this, is, So here I have a bunch of projects. So a lot of the time, when I write a piece of code, I'll have an example directory, and this is one of the first things that I write.
[00:06:55] So here's an example file. What you can do is, if you write an example file, then you can just take that example file and copy it into your test directory. So I'm gonna copy that example to my test directory, call it cool-test.js so I know which one I'm dealing with.
[00:07:18] I already have a lot of tests in here, but the basic idea is, all right, we have an example file. I can run this on the command line, I can see what it should print. And then I can just kinda copy-paste that output, and then require a testing library like tape, and just sorta make a test out of it, so, Really simple way to get started with testing is to do it this way.
[00:07:48] So I can do now t.equal(tree.outerHTML, and then I'm gonna use backticks to paste in that bit of code. Actually, gonna use, Gonna paste it correctly first. So just cuz I want my test to be formatted a little more nicely, and I don't really care about the whitespace, I'm just gonna get rid of all of the whitespace.
[00:08:19] So I'll just have a little trim function for doing this comparison, incidental to what we're doing here. And then I can call t.end, cuz in this case, we're not doing anything asynchronous, so it's usually fine to do to t.end. I have a trim function, and all that that's gonna do is, it's gonna replace all of the whitespace with just nothing.
[00:08:45] Okay, so now if I run that test, passes on the command line. I ought to be able to browserify this test as well, and run it with browser-run, so I'll just do that. Now when I run it in the browser, there's actually some subtle differences. Like an attribute isn't getting set for some reason, so I think that there might even be a bug in this module that I use all the time, so I should really go and look at that.
[00:09:16] But I think this at least gives you a basic idea of kinda how you can just take something that you already have, ideally, like an example file, which is good to have anyways. And turn it into something that's more like a test. If you wanna do things that look more like end-to-end or integration style tests, that can get so much harder.
[00:09:41] So what I recommend is, if you can not have that problem, don't have that problem in the first place. Not always practical, but if you can kind of move everything that you're doing out into small, reusable pieces as much as possible, it's so much easier to test that kinda stuff.
[00:10:00] So I'll copy the cool-test into the workshop directory real quick, and I'll add it. Okay, so git add this file, And all the files.