Talks

Front-end Testing for Skeptics

Paul Graham once quipped that "Web 2.0" really meant "JavaScript now works". Nearly ten years later, more and more functionality of our web applications is written in JavaScript. But for those of us who came of age when JavaScript was unreliable, it's been preferable to test the server-side, while leaving the UI a thin-as-possible shell. Testing the front-end was error prone and brittle.
However, when you're delivering a JavaScript widget hundreds of thousands of times a day on diverse third party websites, it needs to work. So: we need to test it, and those tests need to be as painless as possible to write and maintain.
This is a session for front-end testing skeptics (like me): It is possible to create tests that drive your web UI (JavaScript and all) that are automated, fast, reliable, headless -- no browser required -- and written in pure Ruby instead of some obtuse syntax. We'll explore the challenges and gotchas of testing the front-end and walk through an example that meets the above goals.

Help us caption & translate this video!

http://amara.org/v/FGau/

RailsConf 2013

00:00:16.400 so hello welcome my name is luke fransel and i am a front-end testing
00:00:22.000 skeptic so this is the story of how i learned to
00:00:27.119 love okay tolerate front-end testing and uh so you can follow along with my
00:00:33.120 journey now what do i mean when i'm talking about front-end testing i'm talking about full-stack integration testing including
00:00:40.399 running the javascript um that you're that's probably part of your application so by the end of this talk um you'll be
00:00:48.079 able to set up pure ruby uh front-end tests that are um fast and reliable
00:00:55.680 most of the time and can become a valuable part of your and the truth hurts sometimes they can
00:01:02.320 become a valuable part of your workflow so when i started doing front-end
00:01:07.840 development uh testing javascript looked a little bit like this
00:01:14.159 so naturally we tried to avoid doing javascript as much as possible we try to
00:01:20.880 push as much as we could onto the server and test it there where you know we could be confident that our code would
00:01:27.040 actually work and this had a kind of a corollary in
00:01:32.079 developing native gui applications where you would have your models and your views and your controllers and you
00:01:38.400 would try to keep your view as a thin as possible layer on the top of your application
00:01:44.159 because um with most native toolkits that was just pixels right it was very hard to automate this part
00:01:50.960 in a reliable way when i was researching this talk i went back to the c2 wiki and i was looking up you know what they said
00:01:57.360 about about gui testing and you go through pages and pages of stuff and it's like there's nothing that's really
00:02:03.360 satisfactory but below that level you could have system tests that test the whole rest of the application and unit
00:02:08.959 tests that test your models and those were reliable and those could be repeatable and automated
00:02:16.319 and when we started developing web applications we had the same sort of situation where you've got your models and your controllers on the
00:02:22.160 server side and you control that and then up at the top you've got your html and your css and your javascript
00:02:28.400 and that is hard to test but in between them we have this wonderful abstraction
00:02:34.000 of http and so you could do full stack tests um using http pretending to be
00:02:41.360 a web browser basically because the web browser is just talking at that level too but the other nice
00:02:48.080 thing about this as opposed to a classical gui application is that html css
00:02:56.640 and javascript are all just text so we can actually examine them we can look at them and see
00:03:02.560 if they are matching uh what what we were looking for but
00:03:08.080 since i came from this background of trying to avoid javascript as much as possible i never really saw the cost-benefit
00:03:13.680 analysis being there for for testing for for doing this kind of front-end testing so i wanted to keep
00:03:18.959 it at the http level and below but things have changed as paul graham
00:03:26.319 put it when he was talking about uh ajax and web 2.0 javascript works now
00:03:31.920 javascript has become in the last five or six years like a huge part of our applications to the
00:03:37.360 point where entire applications are written basically in javascript and this is pretty amazing and it's
00:03:42.959 allowing us to do some incredible things with our applications but this old way of testing needs to
00:03:49.840 catch up so for me there were two things that caused me to sort of rethink my
00:03:57.840 position and come to grips with a good coming up with a good way of testing this front
00:04:03.200 end the first was that i started working at a startup called swift type
00:04:08.400 so swift type provides a search as a service and in addition to our developer api
00:04:14.560 that lets uh lets you index and search for content with uh with a rest api
00:04:19.600 we also have a consumer type of product where we give you a javascript embed and you can just put this into your
00:04:26.320 template of your of your code of your website and it will enhance your search box and give you a full featured
00:04:32.479 modern search experience and the way we do that is by injecting javascript into your page
00:04:37.600 here's a demo of how that works from my blog so you can see here you type into the
00:04:44.000 uh to the search box you get auto complete results if you click on one of those you'll
00:04:49.040 go directly to it but you can also get the search results uh in a list as a traditional search
00:04:54.720 results and this is all done through client-side javascript third-party javascript
00:05:01.120 if you are interested in doing third-party javascript i definitely recommend checking out this book written by two
00:05:08.000 two of the engineers who wrote disqus which is a commenting system you may be familiar with
00:05:14.080 um so this will give you some of the tips about how to do this in a reliable way
00:05:19.440 but the trouble with doing third party javascript is that your executing in an environment that
00:05:24.960 you don't control so the page that you're in can be uh you know setting variables that you
00:05:31.120 need to make sure aren't interfering with your variables you need to make sure you're not exporting global variables and screwing up their content
00:05:38.080 it's a it's a very constrained environment that that makes it hard to develop for and so we wanted to make sure as we
00:05:45.039 develop this product that we're not uh going to break things
00:05:50.800 so um we've been growing a lot and we as you can see from this graph with no
00:05:56.240 y-axis uh we've been growing a lot and so we're putting
00:06:01.840 we're putting this javascript onto tens of thousands of web pages hundreds of thousands of times a day
00:06:07.120 and so it really needs to work but uh this graph is really not the one that scares me this is the one that
00:06:13.680 scares me uh total number of search engines now not all of these people use the third party javascript but a lot of them
00:06:20.000 do and i have to help answer the support requests for this so if we break this javascript
00:06:26.720 we're going to hear about it and it's going to be really painful for me so i want to make sure that it works and
00:06:32.479 doesn't break now the specific problem project that um
00:06:37.680 that uh led us to come up with this uh solution was that we as swift i wanted
00:06:43.680 to improve our mobile experience so we came up with this design where if you're on an iphone or an android phone
00:06:50.000 and you're using our javascript embed we give a mobile optimized search results so we had to add this to our existing
00:06:56.639 code and in the meanwhile we also wanted to remove some duplication and
00:07:02.080 make the code smaller and nicer and refactor it but oh yeah it needed to continue
00:07:08.319 working so if you're not running javascript this is really hard to test
00:07:14.000 to the point of being impossible you're going to be you know loading it up like we used to you're going to be every time you do a
00:07:19.599 deploy it's like load it up in all the important sites and make sure it's still working and that's no fun so the second thing
00:07:27.520 that led me to kind of rethink this client-side javascript testing thing
00:07:32.880 is that the tools are so much better now when i started looking at javascript
00:07:38.479 automation the state of the art was selenium and it would record your your clicks and then replay them by
00:07:44.879 launching firefox and going through it and it was really slow and painful and prone to
00:07:50.639 breaking because anytime you change something on your web page all your scripts break
00:07:56.080 so i'm going to be talking today about three tools the first one is copybara which is a
00:08:01.680 framework for front-end accepting acceptance testing so it gives you a dsl for interacting with the dom
00:08:08.639 the second tool is phantomjs which is a headless webkit browser so unlike
00:08:15.840 old version selenium it doesn't start up a browser and click through things while you're watching
00:08:21.120 it and it doesn't require a frame buffer so it starts really quickly and it's super easy to
00:08:26.960 install including on your ci servers and then the third tool is poltergeist
00:08:33.039 so poltergeist has the phantom js driver for copy bara it's the ruby code that ties the two
00:08:38.839 together one thing i'm not going to be talking about is cucumber
00:08:45.200 i don't really understand cucumber if you like cucumber and you're you're
00:08:50.399 being successful using cucumber more power to you but i i
00:08:55.680 as i said i don't really understand it and it's not necessary to test front and code uh a lot of examples you see it's like
00:09:01.839 we're gonna test some javascript first step set up cucumber and that's totally uh not necessary
00:09:07.519 but if you find it useful you certainly can use it so in order to demonstrate this uh these
00:09:15.120 techniques i decided to write a sample app which you'll be able to download from github um so what it does is uh lets you type
00:09:22.640 ahead uh the names of a country so and and uh get a list and it uses twitter's type
00:09:28.560 ahead js library which is a really cool library for autocomplete so here's how that works you just start
00:09:34.240 typing countries and it auto-completes them you can click on one of them to go to it and then when you do that
00:09:40.320 you'll end up on the page for that country so this is the example we'll be using as i go through these tests
00:09:46.880 so first step install phantomjs uh super easy if you use homebrew brew
00:09:52.160 install phantomjs it's done in a few seconds next up you'll need to add copy bar and
00:09:59.360 poltergeist to your gem file in this example i'll be using r-spec but
00:10:04.880 obviously if you prefer mini-test or something else you can use those instead and down at the bottom here is the url
00:10:11.839 for this this github repo repo
00:10:18.720 finally uh you need to tell capibara to use poltergeist and so here's how you do that what i'm
00:10:26.079 doing is i'm registering the driver name poltergeist and there's a couple things that i'm doing here that are not the defaults for
00:10:32.480 this one is that i'm i have this js errors true option set and the second one is the web
00:10:39.839 inspector or inspector true so what jazz errors true does is it will fail your tests
00:10:45.200 if there's a javascript error and the other one is a web inspector so you can actually connect to it and and debug your tests
00:10:53.200 live as they're running which is super cool and then the final uh thing i'm doing down here is i'm setting
00:10:59.360 the javascript driver to poltergeist now the reason it's just setting the javascript driver is that
00:11:05.120 copybara's default behavior is not to run javascript it uses racktest and so it's a lot faster if you don't
00:11:11.519 need to run javascript but if you do then you uh then you will use the javascript driver
00:11:18.160 so what's the simplest possible test that will demonstrate value for you in in
00:11:24.399 your application i think it's this right here so what this is doing is it's visiting a path on
00:11:29.680 your website and it's filling in something on the page and all this is doing
00:11:34.800 is that it will throw an error if the test if it it will fail the test if the
00:11:40.959 javascript error occurs so you can imagine there's probably times you have deployed to production
00:11:46.880 and missed some page on your on your site maybe some important page on your site
00:11:52.160 and there was a javascript error on there maybe you left a console log in there or something like that right this will catch that and
00:11:59.200 that is a really cool really cool feature one thing to note about this is that i
00:12:04.240 am setting js true here as i was saying on the left side
00:12:09.279 we've registered poltergeist as the javascript driver so anytime i want to use javascript i have to pass this jstru
00:12:18.880 before we go deeper let's look a little bit at the copybara dsl some of the things you can do
00:12:24.959 so first of all you can visit a page in your application you can either use a string url or you
00:12:31.120 can use your rails routes which is really handy then you can click on things you can click on links or buttons
00:12:37.519 and you can do that by the name or the the text on the on the element or by the id
00:12:45.200 i think long term using the id is better because it's less prone to change this test here
00:12:51.200 would fail if you change login to login here but if you're using the
00:12:56.399 you know the id of the button then it's not going to break you can fill in forms so i can in this
00:13:03.120 example i'm filling in the form field with the label username with the text
00:13:08.639 railsconf the next two lines are interesting because i'm i can assert that the page
00:13:15.120 has uh elements with a css selector and i can find elements with a css selector and do
00:13:21.120 something with them and the reason this is interesting is one of the things that makes copybar a really useful tool
00:13:26.800 what this is doing is actually retrying over and over again until this becomes
00:13:33.279 true or a certain timeout is is reached and the reason that's important is because
00:13:38.560 if you're using asynchronous javascript your dom is changing out from underneath you
00:13:43.920 right so it may not be true the instant your test runs something
00:13:49.440 you're you're clicking a link and then something is going to your server and then it's changing in the page and so this allows
00:13:55.120 you to test that kind of behavior the final line i think is also really interesting you can evaluate javascript
00:14:03.440 inside phantomjs and then return the result to ruby so here i'm testing whether or not the
00:14:09.760 javascript expression the number one is equal to the string one which although one of javascript's stupider
00:14:16.399 features is true so this can this can return
00:14:21.440 uh simple values like you can't just return a javascript object and like have it like you know marshalled to a ruby class or
00:14:27.839 something but if you've got arrays or strings or numbers uh it can it can do that and can be a
00:14:35.199 really powerful thing for your tests all right so the next couple tests
00:14:42.160 i'm going to talk about um are for the example app i showed you and i'd like to
00:14:47.199 look at how the dom for that page is so that we'll have a context for understanding the tests
00:14:53.839 so the this input country line here that you can see that is the base html of the page like that's
00:15:00.880 what i started with and then by adding the twitter type ahead library the rest all the rest of this stuff got added so
00:15:07.199 it it includes everything in this twitter type ahead span and then underneath the input there's
00:15:13.519 the tt drop down menu and the tt data set countries which is the name of the the data
00:15:19.199 and then on inside that there's tt suggestions and the individual suggestions so if i'm
00:15:24.800 typing af you know afghanistan is going to be one of the tt suggestions
00:15:30.160 and if i type something that doesn't match any countries the tt suggestions isn't going to have
00:15:35.440 any children so that that's uh just try to keep that in mind as we look at these next tests
00:15:41.120 so this is a slightly more complicated test what we're doing is we're visiting the home page
00:15:46.320 we're filling in the country field with norw which is short for norway this next line
00:15:52.959 is a hack and i'll talk about that in a second but after we click on the body
00:15:58.800 uh i'm finding the tt suggestion so this just finds the first one and then i'm
00:16:04.000 clicking on it and if you remember from the video what that does is takes you to the page for
00:16:09.839 that country so i'm asserting that the current path should equal the country path for norway
00:16:17.519 now let's talk about this hack this is actually interesting because as i was developing the sample app i ran
00:16:23.680 into this test failure and so it's saying that the element wasn't found tt suggestion
00:16:28.880 because there were no suggestions i was typing in norway with phantom js and i wasn't finding anything
00:16:35.199 well debugging is never fun especially with javascript tests but poltergeist and
00:16:40.720 phantomjs make it a lot easier it has this amazing feature called
00:16:48.120 page.driver.debug and what this does is it launches the web inspector
00:16:53.199 remember that how i said inspector true so this will launch the web inspector and allow you to navigate through the dom
00:17:00.079 of the actual running test it's just like doing debug in your tests in ruby you know
00:17:05.679 that launches you into a you know a irb console and you can check out the local variables and stuff
00:17:11.360 like that so here's a video of how that works this shows how i figured out what was wrong with that test
00:17:16.799 so you can see this is just like chrome or safari's web inspector you can look at the dom there's the form
00:17:24.720 i'm digging into it inside it you can see the twitter type head span and then down here at the bottom
00:17:32.400 there's the tt drop down menu and there's something wrong with it it's display none why is that
00:17:39.360 well it's probably because the way that twitter the twitter type ahead library decides
00:17:45.440 to show the results is probably based on some sort of uh you know on click or
00:17:51.679 on uh on key up event from the browser and the way that i'm filling in that
00:17:56.880 field isn't actually triggering that so i added that hack to actually click
00:18:02.000 on the body and that caused it to um to display so that's this is like a super powerful
00:18:08.799 tool for debugging your tests and sometimes you know it since it isn't exactly like a browser you may have to
00:18:14.640 make some adjustments like that another thing i think is really
00:18:19.760 important is testing the negative case so a lot of times people just test sort of the happy path like you're not
00:18:26.240 you test that oh yeah i typed in norway and i found norway but you need to make sure that you're also
00:18:32.240 testing negative cases like in this case i'm typing in zzz which should not match any
00:18:37.840 countries and in order to test that there were no suggestions for this
00:18:43.760 i'm going to take advantage of this evaluate script feature and so what i'm doing is i've got this
00:18:48.880 string of javascript and all it's saying is that i'm using jquery here
00:18:53.919 tt suggestions has no children and so if i evaluate script that should
00:18:59.039 be true and it is which shows you the power of being
00:19:04.400 able to just use javascript in your tests
00:19:09.600 another thing that's really important to us at swift type is to make sure that we're not leaking global variables so this is an example of an r spec
00:19:16.400 matcher that we wrote uh to to test for that so you can imagine you're you're clicking on some
00:19:22.240 sort of ajax thing and then it's doing something right and it's running a function
00:19:29.200 well what if somebody forgot to declare their variable in that function this kind of test will catch that and
00:19:35.600 here's how it works so this is a sort of simplified example
00:19:41.360 from our code base what it does is we have this this string globals.js
00:19:47.280 and that's really a string containing a javascript function and that function is pretty simple it
00:19:53.200 just iterates over uh window to see what properties it has
00:19:58.320 and so i capture that array of names uh variable names in before globals then
00:20:04.480 i call the proc.call so the proc is the block that was passed in to expect and then in
00:20:12.320 after globals i run it again and i subtract them to get the difference and this
00:20:17.360 uh this matcher also has an argument called allowed and what aloud does is allows you to say oh well i'm i i'm
00:20:24.240 going to add this property to the window and that's expected so i take those out of there as well
00:20:30.080 and then the test will fail unless that difference is empty so this is going to catch any kind of
00:20:35.360 situation where a programmer is leaking global variables and i think that's a really interesting
00:20:41.760 thing that you know this may not break your application but it's really it's bad style to do so
00:20:48.320 this is a simple thing that you can do in your application today to ensure that you have good javascript
00:20:53.919 style another thing that i think is uh really interesting
00:20:59.600 with testing this approach is testing cross-site scripting so you know we hopefully all follow best
00:21:04.799 practices uh you know we're we're using rails is now secure by default for cross-site scripting
00:21:10.559 but there are cases where you want to display html from the users right um and so this will make sure
00:21:18.080 that those cases don't allow cross-site scripting to be um to be used so what i'm doing is i'm
00:21:24.559 creating a document and i've intentionally added some script tag to it my test on the other hand visits that
00:21:31.760 document and then make sure that the content of the title i imagine you have a template that's
00:21:38.240 outputting this right uh it ensures that the content of the title is exactly equal to
00:21:46.240 what i have set in this in this let block and what that means is that this script tag was escaped
00:21:52.080 because if the script tag wasn't escaped it would be evaluated and it wouldn't be there anymore and so that wouldn't match and then the second
00:21:58.720 line also does that it evaluates a script to check the value of
00:22:04.039 window.xss so that's what the attack is doing right so that should not
00:22:09.520 be true because it shouldn't be set so this is something that's really
00:22:15.200 important to get right you need to have secure applications and just because you are following best practices and your co-working
00:22:21.600 workers are following best practices doesn't necessarily mean that you know two two three months four months six months
00:22:27.360 down the line somebody isn't going to add a problem like this and if you have a test like this it will catch it and
00:22:33.520 unlike testing uh through the rail stack you're you're actually evaluating these
00:22:39.919 cross-cut scripting attacks and to to see if they are working or not
00:22:45.520 so uh just to sum up this part you may not be injecting third-party
00:22:50.720 javascript in hundreds of thousands of sites or whatever but you probably have a flow in your
00:22:57.360 application that's using javascript right like maybe your login when you when you log into your app or
00:23:02.720 sign up to your app you have a a username checker right and it's it's it's checking to see
00:23:08.000 if your username is available and you may not be testing that all the time because you already have an account and so you're not you're not on that page a
00:23:14.400 lot unless you're running your javascript tests you can break that really easily
00:23:19.919 and get that deployed to production i mean has anybody deployed broken javascript to production yeah i mean i think we all have right so
00:23:27.280 if you test your most important flows you won't be sitting at looking at your growth graph and being like
00:23:33.760 oh is it dead my projector died uh so you won't be sitting there looking
00:23:40.320 at your at your growth graph wondering geez why isn't anybody signing up for my app
00:23:46.000 uh so uh
00:23:54.640 so therefore you should you should test those important flows i mean i'm not saying that you should be testing javascript on
00:24:00.080 every single aspect of all your pages but uh but the important parts of your
00:24:05.600 app i think uh really deserve that testing so i think we see now why the uh screen
00:24:10.720 was going orange but uh i was at a conference in portland
00:24:16.400 uh earlier this month and uh this guy's presentation totally died like his computer crashed or something
00:24:22.480 and it was amazing because he just gave the best talk i have ever seen and the
00:24:28.320 best part was he just got his laser pointer out and he's like up here i'd be showing you what's going on
00:24:34.320 so i'm going to soldier on all right so the next thing i was going to talk about is kind of the gotchas about this
00:24:41.200 so you you've heard the good parts right but
00:24:46.559 it's not all roses like they're these these technologies have problems
00:24:51.679 uh so i'll talk about three three problems that we ran into the
00:24:57.039 first problem was waiting for stuff so as i was saying capibara
00:25:02.400 uh will wait for things to change on the page and uh
00:25:10.080 that works a lot better now than it used to in copper barrel one uh so before in copy borrow one we would
00:25:16.880 uh you know we'd be loading up our javascript in bed and we'd have a lot of things going on on the page
00:25:23.919 but in our test we'd have to be like okay wait for this to happen okay wait for this to happen okay wait
00:25:29.120 until this happens and then click on this okay screw it i'm just gonna sleep i'm gonna wait
00:25:35.360 uh and that has gotten a lot better in copy borrow two those problems are
00:25:40.960 almost entirely uh resolved the only problem that sort of still remains is if you're you're
00:25:47.120 waiting for some sort of javascript thing to become true like if you're evaluating a script
00:25:53.120 because that isn't uh that doesn't work the same way with the with the finder waiting until the
00:25:59.200 timeout is uh is expired um and there's a guy named
00:26:04.480 uh kyle van der beek who wrote a good blog post about this um talking about how he he wrote some
00:26:11.520 helpers for copybara that synchronized javascript um and synchronized jquery so what they
00:26:17.360 those do are they they apply this um well copybro now has this method called
00:26:22.799 synchro synchronize which will um apply this this retry logic and so what his his code does is it
00:26:30.640 synchronizes and then it evaluates a script over and over again until it becomes true or the timeout is expired uh the second
00:26:39.520 big problem that we've run into is phantom js crashes um so can can a ghost die like does that
00:26:46.240 even make sense i don't know but it does happen um and if it's repeatable well then you can file a bug report but
00:26:53.039 if it's not repeatable you just sort of like forget about it so i would say maybe like one percent of
00:26:58.080 the time our tests will fail and uh it'll be because of a phantom js crash
00:27:03.600 so it hasn't been uh a deal breaker for us it's just something that's like oh the build failed oh it's it's
00:27:10.960 phantom.js again okay whatever so you just you know you just kind of live with that
00:27:16.400 the third problem uh is about transactions and database setup and if you could see my slides you would
00:27:21.760 see that i have a quote from the readme manual which
00:27:28.399 we probably should have read so we actually use mongodb and uh
00:27:35.360 mongodb is not really transactional right uh and so the problem with transactions
00:27:41.039 in copybara is and uh phantom or sorry the the problem with transactions in
00:27:49.360 pretty the problem with transactions is usually that
00:27:55.200 oh yeah awesome so the problem with transactions is that
00:28:00.840 uh copy borrow when you run a javascript driver actually starts up a
00:28:06.640 copy of your rails app in the tess and so it's in another thread or yeah in another thread
00:28:12.320 and so your your the browser is running the fake browser is running connecting to that real version of your rails app
00:28:18.320 that's connected to your real test database and so the problem with a relational database is usually that
00:28:24.000 uh the way that rails uh you know fixture loading works is that it rolls back after every test
00:28:30.720 completes and so in this in with copy bar it'll roll back
00:28:35.760 before it has a chance to actually see the data but with us what was happening is that we use database cleaner and it just
00:28:41.760 wipes out the database in between every test run and so the test would be running and our spec
00:28:47.200 randomizes test order right so depending on where in our test run our copy borrow test started
00:28:52.720 running all of a sudden tess would start failing and it was really weird fortunately uh with rspec you get a seed
00:28:59.760 you know of the random order and you can go back and recreate that and after after a bit of digging i was able to
00:29:05.760 figure out that the problem was actually this copybara starting up a server and talking to the same test database at the
00:29:10.960 same time and the fix once we knew that was really pretty simple what we do is we run all our tests that
00:29:17.760 don't require javascript so our standard rails unit tests our standard rails controller tests and
00:29:23.120 any copy borrow tests we have that use the rack driver those all run first in our normal test run and the
00:29:30.399 um everything else that's using javascript runs second like as part of another process and so
00:29:35.919 they don't interfere with each other all right so that covers the gotchas and
00:29:41.120 i've talked about how we're using it now i'd like to talk about what we are looking at next
00:29:46.320 these aren't things that we're doing yet but i think they're super interesting so one of the next things i'd like to
00:29:52.080 look at is javascript unit testing we're not actually doing any of this yet
00:29:57.520 but there's a couple frameworks out there that look pretty nice this example is jasmine which was created by pivotal
00:30:03.520 labs there's also q unit which is a jquery project that they use for testing jquery
00:30:09.600 and another one called mocha so the downside to these tools is that you need to
00:30:14.799 load them in a browser to run the tests this is a jasmine test runner example what it is
00:30:21.840 doing is uh you know running the tests and the way that you do that is you
00:30:27.600 reload the page but we have this great headless web browser so can we get it working
00:30:34.240 in our regular tests in an automated repeatable way so i don't have to load up my web browser to run my javascript
00:30:40.159 tests yes and uh this uh gentleman matthew o'riordan uh wrote one of the
00:30:46.640 most epic blog posts of all time describing how he got all of this working and i'm just gonna i'm just gonna have it up here and scrolling as i
00:30:53.440 talk about it because this page is huge but what's great about this is he went through a
00:30:59.440 lot of the stuff that i've talked about here today and i i relied on this post a lot when i was setting this up he went through all
00:31:05.120 this and he talked about what worked and what didn't and the problems he ran into um and at the end of it he gets all this
00:31:12.559 stuff working and then he adds uh automated running of his javascript unit tests
00:31:18.080 and the way he did it i thought was really clever he has a a controller with an action that's only
00:31:23.679 hit in his tests and the way that that works is that the action is a javascript file
00:31:30.559 basically and so he loads that action with each javascript test file that he has
00:31:36.640 and so he can get like individual test failures for all his javascript which is awesome and i thought you know
00:31:42.399 i should set this up in my test app for this talk but then i found out about uh
00:31:47.840 mode sets uh teabag gem great name guys thanks
00:31:52.880 um so this does all that stuff except you just do gem install teabag
00:31:58.640 and you're done it's really cool and it's really cleverly thought out too because he uses
00:32:04.559 the asset pipeline as a way to or all these tests run through the asset pipeline
00:32:10.320 so in your javascript unit test you can actually include files with sprockets uh that you're
00:32:15.600 testing which i thought was cool so this is how it works um this is uh an
00:32:20.799 example of running some tests with teabag and what it does is it starts up a server and then it
00:32:26.240 uses phantomjs to hit that server uh one at a time like uh like matthew's
00:32:32.480 example and so you get individual test failure messages and you can you can debug them you can
00:32:39.600 run just one file or all or everything it's it's it's actually really nice and since we're not actually using this
00:32:46.480 yet uh i just added it a couple examples of it into the example
00:32:51.919 app that you can find on github so i definitely recommend that you check that out
00:32:58.159 uh one of the other things i'm really interested in is perceptual diffs uh can can anybody tell me what the
00:33:04.480 difference between these two rectangles is can anybody tell
00:33:12.480 yes one of them is slightly bigger and i believe it's the one on the
00:33:19.679 right so this is the perceptual diff generated with the program called pdiff that shows the difference that red part
00:33:26.320 is the difference and i can prove it by overlaying them so you can see that part
00:33:32.880 is just a little bit bigger on the one that went on the bottom uh so i got this from uh brett slatkin
00:33:40.159 who works at google at the uh on the google uh consumer surveys team
00:33:48.399 so he their team is using perceptual diffs for automated testing and continuous
00:33:53.679 deployment and he says that for them perceptual diffs are the thing that makes
00:33:58.720 continuous deployment work so here's another quiz who can tell me what is wrong with this web page like what what is not
00:34:05.679 working here well besides the pink uh the answer is actually the exp
00:34:14.159 this this this chart you can see the the actual result over here the axis is all screwed up and
00:34:21.679 on the right the access is how it's supposed to look and that's really hard to tell you if
00:34:27.359 you look closely down at the bottom you can kind of see it right so you can imagine like you're just
00:34:32.639 you're just doing a once-over on your app real quick before you deploy you push it out um you you don't notice it but the
00:34:40.079 computer notices this right away and so they get this perceptual diff of the in the middle and they get those results
00:34:47.280 emailed to them and uh are able to look at look through them and be like oh yes i meant to change that or hey
00:34:53.760 what is that and i think that's really powerful and for us specifically at swift type it
00:34:59.119 would be amazing if we could load up a new like the the expected
00:35:05.200 version of our jquery of our javascript third party javascript onto a site
00:35:10.400 do a search and c and screenshot the results and then load up the new version do the
00:35:15.599 same search screenshot the results and compare them and make sure that they're actually the same
00:35:21.119 that would be a very powerful tool for us and would save us a lot of time what i've talked about so far you know
00:35:26.640 is kind of assures us like a baseline of functionality doesn't isn't breaking but what this would allow
00:35:31.680 us to do is be a lot more aggressive with pushing out changes to the javascript and not having to test them manually so
00:35:37.440 much so i think that that's really cool i'm brett slatkins working on an open source
00:35:42.880 project to make this possible for um for for any project and i'm i'm really
00:35:48.240 curious to see how that develops all right so to to review um we've seen
00:35:54.800 why front-end testing has become a necessity because more and more of our applications are written in
00:36:00.320 javascript more logic is moved to the front end and we've looked at how capybara phantom
00:36:05.359 js and poltergeist can be used to make front-end testing if not enjoyable at least less painful
00:36:13.839 and we've introduced an example app that you can take home and you can adapt to your your purposes your own projects and
00:36:20.880 we've shown how to debug test failures in that in that app
00:36:26.240 so uh have i convinced you i don't think i'm ever going to love
00:36:31.280 front-end testing but with these tools it's become a really valuable part of my workflow
00:36:36.880 and it's really helped to keep swift types javascript code running smoothly thank you
00:37:20.160 you