Transcript from the "Unit & E2E Testing" Lesson
>> So I'm gonna make a statement here, and that's the fact that, while unit tests are great, I would argue that they're often not the 20% of tests that we really should be focusing on. Back to the Pareto principle, like a lot of us are introduced to unit tests as our entry point into testing because, oftentimes, it's sort of the simplest one to wrap your mind around.
[00:00:20] So, the proverbial example is like function at AB, test that A plus B equals, if A is one and B is one, make sure it's two, this is like the proverbial unit test. But as we know, while this gives the developer the sense of comfort and safety that their utility function works correctly, or their component may work correctly, at the end of the day, the person that really decides whether or not our app actually works is the user.
[00:00:45] There's a saying where if you can only have two tests for your entire application, especially when it comes to these enterprise level applications, there are two that I always basically demand that they create. And one is that, can the user login? and two, can the user pay us?
[00:01:07] Now, this might seem a little tongue and cheek, but if you think about it, these two functionalities often represent the core piece of the entire business. If either of these features break, there is no business, right? There there's a real measurable dollar impact on your applications at the end of the day, if the user can't log out great, that's a bug, we can figure that out.
[00:01:31] And, if certain functionality doesn't work, we can figure that out, but if users can't log in and they can't pay, you don't have a business and you won't have an app to write for. And so it's a little tongue and cheek, but the truth is, is that it's funny how very often, when it comes to these applications, they don't test for this, there is no test that reliably checks these things every time.
[00:01:51] But there might be a lot of unit tests, but there's nothing checking this thing that is so critical to the actual application itself. And so this is why it's important to what we were talking about earlier regarding that Pareto principle. Is that we spend all this time on these unit tests, which again are useful for shoring up our code and making it safe over time for longevity purposes.
[00:02:13] But the real bugs that we need to at least make sure we cover are the ones that could really tank the business, and oftentimes those are the ones we're not paying attention to. And so these two tests or that 20%, they represent 80% of the value that testing would provide in enterprise level application.
[00:02:29] And so if you're thinking like, well, my application doesn't receive payment, what I'm basically trying to emphasize here is what is that critical path that if I took down that one feature and it broke, chaos would break loose, everyone will need to hop on, there would need to be a hotfix.
[00:02:47] If you can figure out those critical paths, make sure those things are being tested. And so as a result rather than entering at the unit level, I actually represent [LAUGH] I'm recommending flipping that on its head and actually starting with end-to-end tests. Now, this is a little bit controversial because most teams are most applications avoid E2Es entirely, there are a couple of reasons for this.
[00:03:13] And that's one, well, traditionally, when most people have experienced with end to end tests, they take a long time to run. And in the testing where they call, they're often flaky, which is another term for being unreliable. And that complexity often leads to the fact that here are no E2E tests at all, or if there are, people ignore it.
[00:03:34] They'll be like, the E2E test pipeline's broken, yeah, but we need to push it out, let's just ship it. I think the moment you're ignoring broken tests and that they're failing, that's definitely an indication that something is wrong, and either those tests need to get straight up deleted or we need to reconsider things.
[00:03:51] Now, in my opinion, one of the reasons end to end tests are typically considered a behemoth for people to approach on an enterprise level is that we want to be called perfectionist about everything. We want to cover every scenario with end to end tests, meaning we got to cover every single breakpoint, right?
[00:04:07] Whether it's mobile, tablet, laptop, widescreen, let's cover it all, we gotta make sure it works everywhere. And let's not forget about cross browser testing, right? Chrome, Firefox, Safari, IE, IE11, Opera and any older browsers that we think, our users are using, we need coverage on everything and our one tool must do it all.
[00:04:27] And then on top of that, then it's like, we have to make sure we're covering everything, right? Code coverage, we wanna make sure we see those green bars lit up all the way, we want that 100%. And it's no wonder that at the end, everyone's just like, this is way too much work.
[00:04:42] Right? This is terrifying, because ,you put all this work, you tried to do all of these things, and then it just breaks and then you're just like, what was that for? And so what I wanna propose to you here is when you're thinking about your test for your enterprise applications, again, this is the 100% method, you want everything to be perfect.
[00:04:58] So I say, move back from that, we don't need 100%, and arguably, you don't need all the browsers, either. Yes, you might have some users that are on older versions of IE, but at this point we need to focus on that Pareto principle, what is our 20% gain that 80%, and oftentimes it boils down to one, maybe two browsers.
[00:05:18] And so your end-to-end test suite might be as simple as we have a ton of desktop users on Chrome, and we know that a lot of our mobile users are on Safari. So these are our two critical paths to test, this is what we optimize for. Yes, we might have some things fall through on the other browsers and devices, but at the same time, if you don't have end to end tests at all, or ones that you can trust and rely upon, you basically have no tests at all.
[00:05:42] And so it's funny seeing how some people will argue they want it all, but if you have nothing, this is monumentally better. And so, when it comes to running end to end tests, also, tooling in particular in the past like with things like selenium, for example have also been notoriously difficult to work with.
[00:06:02] But there's been a lot of advancements in the field, so the two frameworks that are very popular in the view ecosystem are Cypress and TestCafe. And so, for those who haven't used either, definitely check them out as end to end tools. Cypress in particular, I have personal experience with that and I know a lot of people really love Cypress.
[00:06:21] Is that, when you're running the test, it actually shows you what's happening in the browser, so, you can debug your end to end tests, seeing your app running, which is in my opinion, pretty huge. So you can basically time travel and skip, but again, I could do a whole workshop on testing.
[00:06:39] So, as you think about in E2E, try give Cypress a try, give TestCafe a try, that is I would say the best place to start. And actually the one thing I will plug about Cypress which I've heard a lot of people say is that Cypress makes testing fun.
[00:06:56] The way that especially as front end developers, we love building things that we love front end is because, that visual feedback is very immediate from if you run or something on the page, you see it immediately and you get to that feedback loop is so quick. Well Cypress basically does the same thing with end-to-end test as far as creating a fast.
[00:07:14] Feedback loop that allows you to see tests and then actually interact with it in the way that doesn't make you dig through terminal logs and try to figure out which line is broken. So, yes, can't plug Cypress enough, they do a fantastic job. So, in terms of writing our end to end tests, first thing first that most people make the traditional mistake of is that they try to maintain state between tests.
[00:07:38] Meaning you create dependency of like, first I want you to on this test, I want you to click a button, and that button will generate a token, and then in this test, I'm gonna take that token, and then I'm gonna do something with it. This is probably the biggest mistake that people make when it comes to end to end tests because in the event one breaks, basically you have this whole chain effect where something's flaky.
[00:07:59] Because integration tests can be tricky when it comes to databases going down or connections going out for example. And so if you need a token for a test, just have that test independently, generate its own token or figure out some sort of stub or mock for dealing with that.
[00:08:16] But that way the more you can decouple your end to end test, the more reliable they will be, and you won't be like well, the reason this test failed is because, three chains down the line, this test really needed to do this thing. Make sure everything tests accordingly and then that way it'll be easy instead of a line of red across everything that's breaking, you know exactly what's breaking.
[00:08:36] So, in this regard thinking of our end-to-end test a little bit like unit tests where we're trying to achieve one thing without the dependency of everything else, is a really important way to be successful at writing those end-to-end tests. And the other thing, I will call is more of a pro tip less of a best practice, but in general, I would recommend when you're doing element selectors is to avoid using them with CSS classes.
[00:09:01] And the reason for this is because, it's an extremely brittle way to keep track of what element is doing what, as we know, eventually code changes, CSS changes. And if you attach it to a CSS class, you're basically attaching your testing hook to the styling, which context wise has nothing to do with it.
[00:09:19] Whether the button uses a red property to color it red or is blue, doesn't matter the test, the test cares that it's a button, the test cares that the user clicks the button and this thing happens. And so similarly, this is why the advice here, is to really think from the user's perspective, and really think about the intent.
[00:09:38] And so, a popular alternative to CSS classes is the data test attribute, so you might be like data test ID equals submit payment button. And so that's pretty good, because, what you've done now is you've extracted this attribute that can theoretically then be attached to any element that even if it's not actually a button, for example, it would still click on the right thing.
[00:10:05] And so this is a perfectly valid way to do it, but I would recommend think one step further. Because, at this point, we're still thinking from the perspective of developers, right? We're thinking of how we can swap things out and make it abstract. But it's the end to end test, if the real impact that we're looking for is to make sure that things work for users, then, actually selecting a button element that has a text submit payment, is if you think about it, this is actually the correct the optimum selector you're looking for.
[00:10:36] In this case, then you're actually replicating the user's intent, and if you think about it from another way, this has an added benefit of basically creating test accessibility to some extent as well. Because now, if you have DIV that's attached to submit payment, that's not gonna work from a screen reader's perspective, you could do roll button.
[00:10:59] But we wanna try and think from the user's perspective, and so as a result, selecting elements from an accessible perspective in a way that they're looking for a link that does, that has this text, that does this thing. This is probably the better route to approach when it comes to ensuring that things work from the users perspective and not just from our perspective.