 So thanks for coming to this session everyone. It's called test all the things, getting productive with automated testing in Drupal 8. So a little bit about me, I'm Sam on 5.2 on Drupal.org, I'm a back-end developer for previous Next, we're a dev shop based in Australia. I've done a little bit of core contribution, but I also maintain a bunch of contributor projects. So who are you guys? So this talk is really going to be a broad overview of the kind of testing that we do in Contrib Core and take and apply that to your own bespoke Drupal builds. So if you've done a lot of testing before, you've written different types of tests and sort of maintained Contrib modules, that sort of thing. This talk may not be super relevant to you, because it is quite a gentle introduction. But if you do want to find out that information, by all means, stick around. So I'm going to start right at the beginning. That's first principles, and that is what is a test. And at a basic level, a test is really just code that we write as part of our project that asserts a set of constraints on the other code that we've written in the project. And for any type of complex software, testing is really essential. But the thing about testing is there's lots of different forms of testing as well. It comes in very many different flavors. And we're going to explore a few of those different flavors in this session. So here is the simplest example I could conjure of a test. And this is testing the UUID generator in core. It doesn't use any kind of framework. It's just a straight PHP file. And there's two constraints that are being concerted here. And the first one is that the return value of that generate method is going to be a string. And the next one is the length of characters is going to be 36 from that method. You can see here you can actually run this test. And if I go introduce a bug into my code and rerun that test, it's going to tell me exactly what broke. So that's fundamentally what an automated test is. But of course, in the real world and applications are a lot more complex than this, we use frameworks to help us do this kind of thing. So why do we do this? First and foremost, it is to catch bugs, fewer issues in production. We want stable code. We want happy stakeholders. We don't want to break things all the time. But it's also confidence to refactor. So if we write tests correctly, we should be able to refactor the underlying code and still use those tests. I've definitely worked on projects where there weren't test suites. And the general vibe of those kind of projects is touch the absolute bare minimum to get by and get your job done. But with a really kind of solid test suite, it really changes that whole mindset. And you're always kind of looking at projects and ways to improve them. So it's definitely a valuable thing for projects you might be working on. When you're working in core and contrary as well, a test in a patch is really essential because it proves to the reviewer that something works in a particular way, which is really important. So if you're a maintainer and you're stretched pretty thin across a lot of different projects, when you're reviewing patches, if they come with a test, there's a huge, huge increase chance of that just getting committed straightaway if it has a test case associated with it. So that's another benefit of working in the Drupal community and getting productive with testing. I'm going to talk about PHP unit now. And this is really at the core of all the testing we do in core and contrary. And it's a framework that's trusted by a bunch of other platforms and CMSs and projects. So any skills you learn that are kind of in the sphere of PHP unit are going to be translatable to a whole different other set of projects, which is great. The other benefit is lots of tools and extensions out there integrate and support PHP unit. So by learning that and using that in Drupal core, we get things like integration with our IDEs and all sorts of other tools that we can use around our core tests. So this is the basic anatomy of a PHP unit test. I told you we're going to start gentle. This is it. It's a class. And at the top of the class, we have some annotations, which specifies some metadata about that particular test. Might be the group the test is in or the kind of code coverage that that particular test class is associated with. All test classes in the Drupal sphere will generally extend some test-based class from Drupal core. And these different test bases are used for different purposes. So you kind of have to be really conscious of the class you're extending and be mindful of that when you're kind of picking the scenario and what you're testing. There's also a property on these test classes, which are the modules to set up during the test. So typically tests start from scratch, an empty database, a clean slate, and you sort of build up the environment around the test case for what particular scenario you might want to test. And then finally, you have a test method. And any method in one of these classes, which is prefixed with the word test, will get executed as a test case. So that is really all you need to know about the kind of skeleton where you need to kind of get going writing a test. Data providers are good syntax. I'm going to talk about this because it's so widely used in Core and Contrib. And this essentially is another piece of metadata you put on top of a test method. And what that allows you to do is reuse one test method for lots of different test cases. So we have a method under here, which is returning an array of arrays. And the outer array is all of the test cases that will be passed into that test method. And then each element inside that sub array is the arguments in order for that test method. So here we're testing some URL parsing. We're saying that if we're given this string, we can extract some ID from it. But to actually increase the test coverage of the module, we don't have to increase the complexity of the test method. We can just insert test cases into this data provider, which really encourages us to kind of flesh out and extend the test coverage whenever we can. That's kind of the most I'm going to go into specific PHP unit concepts. On Thursday, there is a session by the maintainer of PHP unit. So he's going to be very well equipped to get everyone up to speed on PHP units specifically. Let's step back into a bit of a recent history. And in Drupal 6, there was a contrary module called simple test that integrated a testing framework into Drupal, which allowed us to write tests. And it gained some traction and it was introduced in Drupal 7 for testing Drupal core. But the problem with this testing framework was it didn't really gain much widespread adoption. So PHP unit kind of won the race and it superseded that testing framework in Drupal 8. But if you are writing Drupal 7 contributor projects, it's still kind of the go-to tool. So it's worth knowing about in case you step back in time into Drupal 7 land for an afternoon. But yeah, this has been superseded. But the problem is there's still a lot of simple tests in Drupal 8 core today. So there's an initiative around porting these tests as well. So if you're interested in testing and you wanna sort of see those legacy tests get upgraded, there's a tag you can search and find issues to help out there. And really the benefit of that is gonna be consistency. So if you're working on a Drupal 8 core issue, you don't have to sort of context switch between, you know, what kind of test run am I gonna use to test this class? So the kind of tests I'm gonna look at today from a really high level are kind of differentiated by the level of abstraction which they kind of interact with your application. So on one end of the spectrum, we have unit testing and that's really the lowest level of abstraction kind of tested, right? It's interacting directly with the units in your application, instantiating classes. It has a lot of knowledge about the kind of implementation of your application as a whole. Then you kind of move into that middle level of abstraction with integration testing. And that's working within a Drupal bootstrap. So we actually have a functioning website. We can do assertions inside the Drupal API. And the highest level of abstraction is functional UI testing. And that's black box testing because it has no understanding of the application. It doesn't matter how the implementation is done. It's really just asserting the constraints of the system from a really high level of abstraction and that's a web browser. So there's these three different kind of broad categories of testing that we apply to Drupal. The test pyramid is a concept that broadly describes how many of these kind of tests you should be writing as well. So the thesis is that really at the lowest level you should have the most number of unit tests in an application. So where possible you should interact directly with your units and provide this foundation level of coverage. And then as you move up you should have fewer integration tests and some UI tests. And I wanna illustrate this point with a scenario. This is a fictional scenario but the thing that we wanna test here is are shipping prices correct on an e-commerce store? So if we were to do this with a UI test we need all of these different components to be able to actually run this test. So we need a user who can access checkout, we need a product, we need them to be able to navigate through the checkout. And then finally when we land on the shipping page we can actually assert that the price is correct. And this would be a perfectly valid test but it does have a few issues. One of them is that it's incredibly slow. So any kind of UI testing is slow by nature because there's a browser in the background going and performing actions on your website. The other thing is it's a really brittle test. So anytime any one of those systems change there's a good chance that it's gonna break your test which isn't really concerned with any of those other things, right? We just care about shipping prices. So why we're changing a product page break our shipping prices test. When you compare that to a unit test you're working directly with the unit in the application that's calculating those prices. So you might instantiate a instance of the shipping price calculator. And then you're calling a method and inserting a return value. And again the benefit of this is it's super fast runs in 10 milliseconds. Any changes outside of that unit aren't gonna affect that test. And again it encourages you to test lots and lots of different scenarios. Because it's so easy to set up the preconditions for that one thing completely in isolation versus creating all of these entities and clicking through these UIs. For this particular scenario we definitely wanna unit test. On the other end of the spectrum there's another scenario which is can the user check out, right? So this is on the other end of the spectrum because we can't unit test this scenario because there's no one particular unit in the application which is actually responsible for all of check out. So this is the kind of test that you definitely would wanna create a high level of abstraction UI test to go and perform all of these actions. But realistically you probably only have one or two of those for a complex website. And the foundation would be those hundreds of units in your application that are individually tested for optimal coverage. So that's really the testing period. It describes the optimal number of tests you should write. Drupal definitely kind of tends this on its head a little bit with site building and a few other concepts. There generally are a lot more UI tests on Drupal projects than there are unit tests. In some cases, kind of depends on the scenario as well. So the first actual concrete test class we're gonna be looking at is JavaScript test base. And this is the highest level of abstraction we have. And it's UI testing with a browser. And this browser is actually executing JavaScript on the page as you go and perform actions and navigate around and do things. This is a new capability in Drupal 8. We didn't have this in Drupal 7. But the caveat of this kind of test is, again, it is incredibly slow. So you wanna be kind of selective about using this particular tool. You wanna be using it when it's appropriate and not trying to test too many scenarios that are really outside the realm of specifically UI testing. The reason we have a browser at all is from another framework called Mink. And Mink is all about pluggable drivers. So Mink provides this API for doing things on the page, right? So visiting URLs, clicking links, submitting forms, any kind of action you would do as a user in a web browser. Mink is the API that we leverage to actually provide that. And in this little example, we're visiting a node page. We're gonna find an image, click on it, wait a little bit, and make sure that a color box launches. So since it's a real browser executing JavaScript, we can do these kind of actions. To get productive with this kind of test, there's a couple of things you wanna know. There's methods on this class that you're gonna wanna call to do different things. And the first one is get session. And this behaves a little bit like window does in JavaScript. So it's kind of controlling the meta of the page, doing things like forwards back, change URL, that kind of thing. Inside that object, there's another method called get page. And this is a bit like document in JavaScript. You can interact with the DOM, basically. So that might be doing things like filling in form fields, finding elements, any kind of manipulation of the page that you might wanna do inside a test. You'd use get session, get page. And the final one is assert session. And this is really about enforcing those constraints on the particular page. So you might assert that a certain element exists or that some text appears on the page. And that's kind of the test part of the whole scenario. The rest of it's really about sort of navigating and setting up preconditions for actually testing some particular scenario. There's also a few Drupal helpers for doing common things, posting forms, visiting a page, logging in a user. Those are all handy to know. So this little snippet is actually from a real test in Contra. It's testing the ColourBox module. And we're testing the gallery here. So we're creating a user, logging them in, visiting a page, clicking on the first image we find on the page. And then we're gonna assert a whole bunch of things. And that is that there's an element on the page with a particular caption in it. So this is testing that whole end-to-end integration of installing the module, creating the configuration, actually doing the actions as if you were a user. And since it is a real browser, this is the kind of output you can get from these tests. You can take screenshots during these tests and see what's going on under the hood. This is really handy for debugging. If you're not sure why a test is failing, you can pop a screenshot in there and find out what's going on under the hood. One of the issues that does come up with JavaScript Test Base is non-determinism. And in the queues, that's kind of known as the random fail. And that's really about this, the fact that we do have this browser doing stuff in the background. And it behaves like a browser with respect to things like asynchronous JavaScript. So the repeat offender is Ajax. If you go and fire some Ajax request, the response that comes back and even things that happen after that, you sort of have to make sure that you're waiting for those things to happen. And there's a bunch of helpers shown here where you can wait for some precondition on the page to have completed before continuing on with the test. You can have scenarios where something passes nine out of 10 times and it fails on the 10th time. And that's actually a pretty ugly thing for a test suite because if it happens enough and you have enough tests that are in that sort of non-deterministic bucket, people sort of lose confidence in the test suite as a whole. They don't treat like a red test runners as really this bad circumstance, which is what it's really designed to be. So fixing non-determinism is really important in automated testing. Browser Test Base is kind of like the cousin of JavaScript Test Base and the good news is it's the exact same API. You don't have to worry about learning any kind of new tools. It's the assert session, get session, get page, that kind of stuff. But the difference is this test class doesn't execute any JavaScript whatsoever. And it's a lot faster. It's less prone to random fails and it has no external dependency. So to actually run that JavaScript browser, you have to go and download PhantomJS, which is a separate binary. This thing's written in PHP, so you can just kick off Composer Install and run the test. And again, you should use this for any test that doesn't require JavaScript. For all of these kind of tests, I think I mentioned earlier, but you're setting up the whole universe of the test from scratch. So you start from a blank canvas. In the background, the test goes and installs Drupal. You have to install the modules that you need for the test. You have to create all the configuration. You might enable test modules, that sort of thing. And the reason we do that in core and contrary is really to isolate each test run. We don't want to be testing on the same sort of Drupal instance for different tests, because obviously, state can bleed between those two test runs. But there's this whole class of other tools out there, like Behats or there's a few others, that really just work over the top of a pre-provisioned instance. We don't have to worry about setting up the state of our site before we're testing it. We might do something like sync a database or do a site install. And there is a concept, people are working on this in the core queues, for being able to use these exact same set of tools on completely pre-provisioned websites. So you don't have to start from scratch. You can do something like set up the site as you would on a CI system, and then use JavaScript test base, browse test base, and go and perform all of those actions on that existing fully set up site. And this kind of test is really handy whenever you're testing things which are heavily interdependent, right? So if you've got a custom site build, and everything that goes into that website is a combination of site building, things from a theme, custom code, tweak templates, your own custom modules, and contrived things interacting. It would be kind of crazy to try and set all of that stuff up in a setup method to try and replicate production, when you can just sort of bring production to you and test over the top of it. So this is a patch in progress. We have been running this patch our previous next since about 8.1, so it's definitely had some battle testing. So yeah, like I said, we do this because we wanna create production and test that. But the cons of this is it can be a little bit brittle. So between test runs, the state leaks onto this production site that we have provisioned. And as a result, it's kind of harder to maintain these tests. There's a lot more reason for them to go wrong. But again, as part of that pyramid, that's like the highest level of abstraction of end-to-end testing. You don't want too many of those. You sort of wanna isolate things where possible in a test suite anyway. This is really that full level of confidence for end-to-end testing. Let's talk about kernel test base. And this is the first test class that we use which completely drops the notion of a web browser. So we're not interested in doing things as a user would. We're really interested in testing things as a developer might interact with an API. So kernel test base creates a bootstrap of Drupal with a real Drupal installation and a Drupal database. And you go and write your test code inside this Drupal bootstrap. It's really fast compared to the other types of tests. So this is an example of the speed of one of these kernel tests. And each one of those green ticks is actually like a fully fresh version of Drupal, completely from scratch. There's no state leaking between those two things. But you do have to set these things up. And the reason it is so fast is because it's not doing a full end-to-end installation of Drupal. You actually instruct the test class what parts of Drupal you want installed before actually running your test code. So there's only three methods that do that, three you have to know about. And that's install entity schema, install schema and install config. And the first one basically instructs the test class that you plan on creating an entity or using an entity during your test. The next one's install schema. That's if a module provides a table that you need to use as part of the test. In this case, it's sequences table from the system module. And the last one is install configuration. So any config in that config install directory, if you need to actually use that config as part of your test, you have to specify that as well. And it's kind of a small trade-off to make just based on how fast these tests actually run. Here is an example of a kernel test. It's a simple field formatter. It's not doing anything too crazy. It's just formatting the output of a field with a theme wrapper. But there's a couple of subsystems which are really kind of contributing to this test, right? So we're actually just testing one class which is our formatter, but to actually arrive at that outcome, we're using Entity and Field API for storage. We're saving an entity. We're using the plugin system because field formatters are plugins. And we're also kind of using the module system because we're actually installing our custom module. So this really sits in that middle level of abstraction where you're not kind of right down into the details of the implementation of something, but you're not so far away that you're in a web browser. And this is called integration testing because it's testing the integration of your particular unit in your application with these other subsystems. It's where the name comes from. So the last one is unit test case. And this is incredibly fast, right? It's the lowest level of abstraction in testing that you'll encounter. And it does away with the concept of a Drupal database. You don't have any of that kind of context. You've got no web browser. It's super fast. And you instantiate the classes and the units that you're testing directly inside the test, right? So you know about the implementation of your particular unit. You're gonna do things like pass the dependencies, call methods. And here's an example from Drupal Commas, actually. And this is testing one of the units in Drupal Commas which is the rounding system. And this creates an instance of the roundup and it passes it a few of its dependencies. So when you're unit testing, since you don't have access to things like a database, if you actually interact with, say, an entity in your particular unit, you actually have to create a test double which is basically a representation of your dependency which behaves in a really specific fashion. So in this case, we're creating three dependencies. We're creating an entity for currency, US dollars. And we're setting up some preconditions to say that this dependency, when the ID method is called, is gonna return US dollars. Then we're creating entity storage and entity type manager and we're passing all of that into the roundup. So the roundup doesn't need that extra level of database and abstraction to actually do its thing. So design of your code actually kind of ties into this concept of unit testing. For a couple of reasons, these are just a few of them. And the first one is it clearly reveals all the dependencies of a particular unit in your application. So with that roundup example, we know exactly what the roundup has access to because we actually had to go and create those test doubles as part of the test. So it kind of encourages information hiding, right? So did we really need access to the entire entity type manager? Maybe not. Could we have just injected some entity storage for doing things like loading? So it kind of forces you to have that discussion with yourself because you are like manually going and creating these test doubles. It's also a great reference for your public interface or your public API of the particular things you're writing in your application. So if you've ever written a service or something like that and to actually use it in all the different ways you intended, you have to go and do these crazy things from the UI. If you're actually interacting with it in a test, you can sort of exactly see like the different scenarios where you might use that particular service or unit. So I was talking a little bit about test doubles. So this is the notion of creating a dependency for your unit in a test class. And there's a lot of different types of them. These are a few. The first one is a dummy. And on the left-hand side, that kind of correlates to the text on the right-hand side. So the first one is a dummy and that basically will return null for every call of the method, right? So if you've got a dependency on something and for your particular test case, you don't need that dependency to do anything special. You can create a dummy and just pass that in and it'll be satisfied. The next one's a stub. And stubs are a little bit special because as the person writing the test, you're programming in the behavior of your dependency. So here I am stubbing the mail manager and whenever the mail method is called, I will return true. And that's a version of the mail manager that my test can now use and will behave in that very specific fashion. And the last one is mox. And mox go one level beyond that. They don't just create behaviors, but they actually assert that that dependency will be used in a particular way. So in this case, this is a mock and it's saying if at some point during the test, the mail method isn't exactly called with the argument's test mail and food example, then the test will fail. So that's really essential. Anytime you have a particular thing in your application that has to utilize one of these dependencies in a really specific fashion, otherwise you consider it a test fail. And the framework doing all of this is prophecy. There's a few different frameworks in PHP unit which are designed to actually assist with mocking. But this is kind of, I guess, emerged as the go-to standard because it is just quite a nice representation of how methods would be called. When you're creating your test doubles, you literally just call methods on them as if you were the particular unit in your application. So unit tests can also indicate code smells in your application. The first one, again, is if you have hundreds of test doubles, that could be a sign that your particular class is way too complex. Maybe you can split it up into a few different units. Maybe they can all have different responsibilities where they don't need these large amount of dependencies. The other trap you can fall into is actually testing the implementation of something. So again, when you're writing a test, you want the freedom to be able to refactor the code that's underneath it. So if you pre-program in a bunch of really specific requirements into your dependencies, you run the risk of kind of testing how you're arriving at some outcome instead of actually just testing the outcome itself. The other thing you can do is actually stub out the thing you're testing. So if there's a particular method on the class that you're testing that you want to behave in a very specific fashion, you can stub that. But again, that's a code smell because really, you shouldn't find it too difficult to set up the state of your units in a way that are actually gonna behave in that fashion anyway. Could be a sign again that your particular class is way too complex. So I'm gonna go over some tools and runners. And once you've written these glorious test suites, you're gonna want to run them in some way. And really the only one I'm gonna talk about is PHP Storm because it's absolutely essential when you get this set up. Being able to sort of write a test and write code in your application and just right click on it and run it is so invaluable. Means you don't have to do all this crazy context switching between command lines and graphical runners. Integrating that directly into your ID is just a really good thing to do. So there's some docs. You do need to do some setup to do this. But once it's set up, it usually works. With all of these kind of test classes though, there are some limitations. And that is when you're writing JavaScript, we obviously have JavaScript test base which is executing that JavaScript, allowing us to write assertions about it. But we don't currently have any JavaScript unit testing framework in core. So that's being discussed in an issue. But in the meantime, we're sort of left to kind of decide and integrate JavaScript unit testing as we see appropriate in our applications. And one possible solution that I've been sort of looking at and playing with is Jest. And Jest is a framework out of Facebook. It's used a lot with testing React applications which we've done a little bit of at previous Next. But you can also use Jest to test completely vanilla, Drupal kind of modules and integrations. And to do that, there is some setup though. You need to follow these steps. So first of all, you actually need to draw boundaries in your JavaScript code, right? So you need to actually recognize that something could be this individually testable unit. You need to split that out into a JavaScript module. Then you can test those units in isolation and then you need to integrate them back into your Drupal code. Webpack is a tool which allows you to do that. I realize that sounds really complicated, but it's not, I've got an example. And here it is. So this is a JavaScript unit test from a Drupal 7 contributor project called Webform Date Restrictions. And the idea is in the administration, if you're creating a date component, you can say, I don't want to use it to be able to select the date on Thursday or some particular set of dates. And it's a bit of a complicated JavaScript module. It does some funky things with dates. So this is the thing that we've split out into its own particular unit. At the bottom, we're exporting that function for consumption by application. But on the right-hand side, we've actually got the test for this particular unit. So we're creating an instance of it. We're passing it a bunch of dates and then we're saying the return value from this method is gonna be true, false, true, true, false depending on the scenario. And now that we have a tested unit in our JavaScript application, we can integrate this into Drupal through any kind of way you like. In this instance, we're using a Drupal behavior, which I'm sure a lot of you are familiar with. And here I'm creating my Date Restrictions module. I'm using it in my application. And on the right-hand side, this is the outcome, right? So some of those dates are grayed out. But now when I'm thinking about the testing of this module as a whole, I no longer have to think about a UI test, which is actually gonna run these different scenarios, which is testing different days of the week so different days because that's kind of been delegated to the JavaScript unit test. So I'm sort of filling that gap of JS unit testing. One of the other great features of Jest is snapshot testing. And this is all about not hard coding any kind of assumptions into your test class. So here is an example of another test which is testing this module, which generates a big complicated link based on some other parameters. And right at the bottom here, I've just called to match snapshot. And what that essentially means is every time I run that test, it's gonna assert that the thing that that method returns just matches the last time the test ran, right? So I'm gonna introduce a change here. And even though there's no URL in my test case, it's gonna blow up and say something changed. And the advantage of this as well is it's really low maintenance because if I as a developer now kind of acknowledge that this is the correct scenario for that particular test case, I can just pass this minus U flag to it. And it's gonna go update all of my project snapshots to match the new behavior. So that's a really great capability of jest. So again, if you wanna get involved with the JavaScript unit testing discussion, you can see this core issue. We're discussing which ones to integrate and to leverage. So again, bringing it all together once you've got a test suite for an application or a Drupal website in this instance. Continuous integration is really the process of running these things in regular intervals, right? So there's no good writing them all and not actually getting visibility on when they're passing or failing. So continuous integration is really, really that process. So if you're using a pull request workflow, it might run your test suite every time you submit a pull request. Other workflows that might run them every time you merge into a branch or something like that. If you don't have a lot of time to invest in continuous integration infrastructure, there's these platforms like GitLab and CircleCI which have great free tiers, really easy to set up to run all of these different types of tests. Great, so that's it. Thanks, guys. If there are any questions, that'd be cool. Otherwise, all good, right? So when discussing code smells, you mentioned that when prophesizing the things you need, that might indicate that you're asking for too much, that the class you're testing or unit testing in that case, isn't well-written, it's probably too complex doing too many things at once. Problem is, I've encountered in Drupal 8 that whenever you're working with entities, as soon as you need the entity manager, that smells enormously like... Yeah, it's a big dependency in the test, right? The whole entity manager. Because it's got the storage handler to load the entities. So for something very simple, we're encouraged to properly inject our dependencies and the entity type manager is one of those. But injecting the entity type manager does mean that your tests will suddenly blow up, like they will become huge, because you need to prophesize all the things. Yeah, I'm sure. I mean, it depends what you're using on that. I think in my example, we were only calling getStorage, right? So we could start out every other method and essentially just say that that particular getStorage method is gonna return the entity storage that's being marked. Yeah, and this is perhaps the problem I'm having with Drupal when it comes to that, is that in order to get the storage, we need to inject the entity type manager. Right, right. We can't inject the storage. It's definitely encouraged, right? There's other ways of kind of like using factories and crazy things in the service container to like just pull specific parts out of different services to inject to them. But it's kind of just hard enough that no one really does it. And that's definitely like a unique problem to like writing services, right? And unit testing services because you inject whole other services, right? You don't inject like method calls off the other, like back of other services. But that isn't necessarily true for like all classes you might have in the application, right? Most have like vanilla PHP classes that don't really need to like feel those same constraints of like having their dependencies injected with the service container, right? Could be created with some other factory. So it's a code smell we just have to live with. In this case, yeah, it definitely is. But I mean, in this example, I would say that's completely reasonable. But if we had like eight other services that all needed some crazy other preconditions to make this rounder work, then that's the kind of touch point to say that this thing knows about too much, right? So you're right, it's not perfect and that's a huge dependency, but it's something you kind of have to deal with a lot in the reality of Drupalite for sure. I was just curious whether you had a solution or something. No, there are a few different techniques, but again, they're so non-standard that you wouldn't really encounter them. All right, cheers. Typically, right? Okay. Anyone else? Don't be shy. All good? Oh. You mentioned some examples of bad tests in Drupal core. Oh right, bad tests. Yeah, I don't know if I have any bad ones in here specifically, but I could dig some out for you and show you. I've got hundreds of examples of terrible testing contrary, which I've written, so I can point you towards those. Okay, thank you. Yeah, no problem. Great, okay. Thank you, everyone. I think maybe we finished a bit early, but that's okay, great. Let's go to Vasta, I was going to ask you some questions. Yeah, yeah, yeah. There was a URL, but it didn't... Oh, there's wasn't a URL for Drupal. Sure, that's fine. Mm-hmm. Thank you so much. Hi, yeah. Yeah, I think it's a good result. Yeah, not a fatal error. Yeah, yeah, yeah, yeah. Yeah, so you've got to go to community integration. You've got to go to preferences, how to get to here, and then ask them to target your proposal or whatever. You've got to ask them. That's great. Yeah, so I knew that you would have been something with the auto-novel. Yeah, it needs some good docs, I don't know if there's good docs out there, but if you fix it, you can't find the docs. You should write the docs. Yeah. I don't know.