 About two minutes, a little bit of housekeeping. Is the audio okay in the back? Are you screaming in the back? Okay. Also, I'd like to point out, as the program says, this is an introduction to behavior-driven development with VHAP. We are starting literally from scratch, and it's a great couple of tests, both non-Java Stream and Java Stream enabled. If you are expecting an advanced session, it is not advanced, it is from the very basic, till you get something working, and I will not feel offended if you decide to leave. And the last thing is that I am not a deep English speaker, so if I speak too fast, or you don't understand, by all means raise your hand, and I will try to figure out how to convey the message. I speak Spanish as my native language, and I also learn a little bit of French, and I am kind of making signs, so we will figure it out. So we're about one minute away. As I said before, the slideshow are very available, but it's basically a live demo. There is a link to a guest in GitHub where you can find the code, but that's like the final version of the code along the way, during the session, and I will be creating from scratch. First time that I do a 30-minute session, so I will start on time. Now, welcome everyone, thank you very much for being here. This is behavior-driven development in Drupal with GitHub. You can follow along the slides. My name is Mauricio Dinarte. You can find me as dinarcon on drupal.org, Twitter and pretty much anywhere on the internet. If you want to shoot me an email, that's my address. I am from Nicaragua, beautiful country, pretty warm. If you want to escape the cold winter, we are like 70, 80 degrees all year round, so I'm pretty nice. I work with a company called Agaric. We are based in Boston, but we're actually distributed. I work from Nicaragua, other people from Mexico, Germany, and some here in the States. And I am very passionate about teaching. I have started a project called Understand Drupal, which I want to teach both in text and video format, Drupal Basics in three languages. It's English, Spanish, and French. There are some stickers on the table if you'd like some cool stickers. And let's dive in. So we're going to write some VHAP tests today and to test some real content, we're going to use the umami demo that comes with Drupal Core. There are some tools that we're going to use and because they take time to download and install, I have already done that, but I will tell you which are they. We're going to use a tool called Drupal Extension for VHAP by requiring this tool in our Drupal project. It already has other dependencies which we'll get installed automatically. Those are VHAP, MIM, extension, good driver, Selenion driver, and Drupal drivers. Along the way, I will be explaining what each of these things are for. In addition to this, I will also be using other libraries that will be useful for different purposes and again, I'm going to explain along the way why they are needed. As I said before, we're going to use the umami demo. The first example is trying to submit the contact form. We're going to do it as anonymous user and as registered users. And the second example is writing, excuse me, creating articles. And in this particular one, what I want to test is the JavaScript functionality of the node creation process. So, nothing can go wrong, of course. As I said before, that is the link to the final repository, but we're going to start from scratch. So let's begin. I hope that's been enough. So, just for you to know, I wanted to use a few tools as possible. So I use just Drupal core and the quickest start script that comes with it. So you basically just need PHP and it will work. I don't have any lamb server installed, so it's easy to follow along if you want to do it later. I need to start the website. Basically, this is a regular Drupal installation and I just have to do PHP, core, scripts, Drupal, and quickest start. Because I have already installed Drupal, it doesn't ask me to install it again. Otherwise, it would ask me which install store profile I want to use. I already said umami, so it just opens up. I'm going to have that there. And as I said before, the tools are already installed. So let's begin. VHAT was installed via Composer, so it will be available in vendor being VHAT. So far, I have nothing other than Drupal core installed and if I execute a command, I get an error. It is, by default, this command is going to look in certain directories for both test and context. I'm going to explain what context is in a moment, but basically, because we don't have anything, I simply get an error. How do I get it started? I need to initialize VHAT. So I simply pass the dash dash init flag and this is going to do three things. It is going to create a features folder, inside that one, a bootstrap folder, and inside that one, a file core feature context. Those are the directories where VHAT is going to look by default. All of this can be overridden by configuration, but by default, that's what VHAT is going to do and what it's going to look for things. If I run that VHAT command again without any parameters, this time I don't get an error, but nothing happens. Basically, it says no scenarios, no steps, no nothing. In VHAT, we're going to write test using a language called Gerkin, which is basically like a human language given that I am on the contact page. As an anonymous user, I want to be able to send a message. It's basically plain English. So by default, VHAT is going to look in the features folder for files that are going to define test. So I'm going to go to my IDE. I have the features folder there. This is what the command created before. The tests are going to be in the same level as the bootstrap folder. So in here, I put the name. This is going to be contact form, a test for the code platform, and the file extension need to be featured. Okay, now that I have that, I'm going to copy-paste some code and I'm going to explain what it does. As I said before, VHAT is going to use this very English-like language and I can basically read sentences and VHAT is going to execute them. In this case, the organization of the file is I have a feature, something that is called a feature. A feature is going to contain one or multiple scenarios and each scenario is one specific thing that I want to test. For example, in this feature, I want to test two things. Being able to submit the form as an anonymous user and being able to submit the form as an authenticated user. But I will go one at a time. In the scenario that I already have here, I say giving I am at some page in the Drupal website and I can see what is that. So this is the page. And because I am logged in in this browser, I don't have the option to enter my name and my email address, but if I were to be anonymous as what I want to try to test at the moment, I will have the option. So this is what I'm going to test now. So I basically say given that I am on this specific page, I will fill in all these different fields. There are four fields with some values. Then I press a button and I should see a message on the screen that says that the email was sent. So let's see what happens if I try to execute this test. I get an error. We had this very magical in many senses, but at least I need to provide some guidance. So each of these things, given when and then and so on, those are called steps. And these steps are going to eventually become PHP code that is going to be executed and replicate user behavior on the browser. But in order to do that, I need to provide more information to be helped. And this is where the tools that we installed before start to be useful. I'm going to create now a configuration file for BHAD. This is going to mean in my home directory. And it is called BHAD.YML. If you have worked with Jamel files in Drupal 8, you will know that they are very sensitive to water spaces. So you need to be very, very careful. If you have one extra water space on one viewer, it will break. So what we're doing here is that we are telling BHAD to take into account some context that are provided by the Drupal extension. Context contains the PHP code that will transfer those lines that we saw before into the actual code that is going to execute and simulate user behavior in the browser. We have a list of five contexts. It is not necessary to put them all, just an idea of what you can do. You can, for example, if you want to check that a message appeared on the screen, like an error, a warning, or a success message, you can use the message context for that. If you want to test some drush behavior, there is a drush context for that. And so on. The main context is the one that we're going to use in this example for the most part. And that is basically saying, fill this form element with somebody. The feature context was created by BHAD out of the box. It is an empty class, just with a constructor within itself is empty. So I include it because I will use it later, but if not, you can simply delete it. These contexts are provided by the Drupal extension. And in addition to defining that, I also define some configuration in general. BHAD itself is a test runner. It's a program that will read these lines and execute some PHP code. Another tool that we're using under the hood is called Mink. Mink is a API that will allow me to control different browsers using the same method. So it's like one way to control different browsers. And that bridge between BHAD and Mink, it's called Mink extension, which is what I am configuring here. I am going to come back to this good configuration in a moment, but the important one to put attention at the moment is the URL. This is the URL where I am loading the site. As you can see, it's a local installation. So I basically put the address. And now I also configure the Drupal extension. This is the one that is going to give me this context for later use. And we're going to talk about drivers in a moment, but basically this is this black box driver is saying that I want to use this good driver. It's just like a reference to it. That being said, now I run again the command. And something happened. You can see that it is color coded a little bit. The first three ones are green, but then I have a red one and I have a message saying that value cannot be found. So it already started to do something. It didn't complete it, but at least the three first steps already passed. That means it actually visited the page and for the name and the email field, there was some value entered, but it failed on the subject. Why? Again, we had this magic, but it did some help. The information that I pass in these steps, when I say I fill in something with some other value, the first part in quotes, those are going to be variables that are going to be replaced dynamically later. They have to be the name argument of the HTML tag, the input tag, it has to be the name attribute. So if I come to my browser and I check with the depth tools, I will see that for the name, the name attribute is name. For the address, the name attribute is mail and that matches what I had in my code, name and mail. But if I look, for example, in the subject, the name attribute is actually different. It says subject, square brackets, zero square dotted value. So it might seem ugly, but if I copy paste this into my browser, I, excuse me, into my editor, and I know for a fact that the message is similar. If I do that and run the command again, now everything passes. So the thing to remember is in these steps that are provided by the Drupal extension, you can use for the most part the name attribute. You can also use the ID and you can also use like the label of the form element. It is better to use the name in my opinion, but all three are possible. So we already got something in a couple of minutes. We have our first VHAP test and it is already doing something useful. What we're going to do next is we're going to do something similar, but for anonymous users. Actually, one, something before that. I don't know what you think, but to me, this subject zero value doesn't make a lot of sense. And in fact, it is a recommendation when you write VHAP tests that you write them from the perspective of the end user. Remember that VHAP and me, what they are emulating is user behavior on a real browser. And regular people doesn't think like this subject zero value. They just say the subject field, the message field, and so on. So it is possible if I can have, I can have a look at the code under the hood. And this is what we saw before. This is called a step. And the PHP code that executes is called a step definition. So this is the PHP code that is being executed under the hood. I can create my own steps and my own step definition to make the commands here more sensible. So let's try to do that. I will say I fill in the subject field with some value. If you have an IDE, in this case, PHPStorm, it will already give you some error message. But let's assume that we don't have this capability. And we're trying to run the command again. Something similar to what happened before, VHAP recognizes that there are some steps that doesn't have a corresponding definition. And it gives me the option to create that definition. And it is even smart enough to detect all the contexts that are already available. And it asks, like, if you are going to create this step definition, where do you want to place it? In this case, I select number one for the feature context. This is the class where I am supposed to put my custom code. And it even gives me a code snippet that I can copy-paste into the class so I can use it. So I'm going to copy-paste this into my class. And to save some time, I am going to cover some text that I already prepared. So the code that I have here is very similar to what comes by default in the Drupal extension. And there is no need to reinvent the wheel. I can simply use it. So how this works, how this works is I can come up with my own steps. And whatever I put in quotes, they are going to be pass as parameter to the function. So I have one quote here and another element in quote here. So they become the first and the second argument, respectively. The first one is the name. The second one is the value. What I'm going to do is I'm going to transform this name subject into the CSS selector that I was using before. That's a function that I have here below. Like if I type email address, for example, or subject or message, I am going to get the proper name tags as it is used in the contact form. I do some sanitization of the input values because they come with quotes. And I can have quotes inside them. It's just like a sanitization step down below. And once I have that value, it's basically the same code that Drupal extension provides. I call a method called fill fill and I pass the values and it will work. So if I do that, it fails. So why it is failing? You need to be very careful with how you declare the steps. This is the function and what we have here is something called annotation. And this needs to match what we have here. So in this case, I say I fill in a placeholder, then fill with another placeholder. So this needs to match. And one way to do it is simply copy, paste it. And replacing the placeholders with colon and then the name of the variable. Usually, it is not needed. When you copy, paste the code snippet that was generated, that is enough. But in this case, because I was copying from another example and in another example, I did it differently to demonstrate that they need to match. That's why it failed. If I do this again, now it passes. So I now have a custom command that is more sensible for the end user to execute. Because I already have that one, I can do the same for all the others. Remember that I say email address, this point name and this one message. And it is important that these things match by regular expression. So the button of the step needs to match. So by doing this, now I have something that works and doesn't have these crazy zero value things out of the box. What I'm going to do now is an example for authenticated users. So let's see what happens just by running that. It detects that there are now two scenarios in the code. The first one passes, but the second one fails. And it gives me some error. I can verify if I have proper, if I click here and it takes me to a real function, that means that the text is correct. And now I get an error saying you should put API. What's happening here is it is possible using the tools that we already have at our disposal to do all that user creation process, like go to the user registration page, fill out the form and everything, assign the roles and so on. But it will be time consuming. The Drupal extension provides an API that I can simply tag my scenario with our API and it will do that automatically for me. So in this case, just by doing this, let's see what happened. It gives me an error. It detects that I am trying to use the API, but that error means that the API hasn't been configured yet. The drivers that the API uses hasn't been configured. So to configure that, I will copy some work code into my BHA, that YML file. So there is a driver called Drupal and for this driver I need to specify where is the Drupal root. That's how it's going to detect the Drupal installation and be able to perform the operation. Again, just that. If I run this, now it passes. The Drupal extension provides a lot of tools that make this process very easy. One other thing that I want to show briefly is that if I keep running this over and over, I mean, you have to trust me at some point it's going to start failing. In a moment I'm going to explain why, but I want to jump to the second example, which is the node creation process. I am going to create a new form and it's just my new feature file called create article.feature, and in this one. So I am using again the same API to be able to log in as administrator of the box and have access to the regular node creation page and it's the same process. I am simply filling in some form values. The one thing that is important in this example is that if I go to the, I try to create a tag and this tag uses JavaScript for the autocomplete. So that's what I want to do. If I try to run the command, it will run all the tests that are in that folder, but because I know that this one works already, I can simply pass like the route to one of them and it will only execute that particular one. In here, I get an error saying that this step is not defined. I can do something similar as before, but there is actually another package that I already installed called new muleware. And this one gives me more context in addition to what the Drupal extension provides. And the context are pretty easy to install. I just have to put a new line and paste it here. And the way that this work is that if you want to use this project, this one extends the Drupal extension by default. So you need to update the configuration down below. But that's the only change that we're doing here. And I run this again. And now it almost passes. So it already gave me a different error and I could try to debug this, but I know for a fact that it is failing because it is trying to execute JavaScript in a terminal that doesn't have JavaScript enabled. And this is where drivers come into place. By default, these black box drivers is the one that's going to be used. And the black box driver is going to use a browser called good, it is a command line browser. And this one doesn't have JavaScript enabled. So I am trying to execute JavaScript in a browser that doesn't have the capability. So how do I change this? There are two things that I have to do. For one, I need to tag my scenario with the word JavaScript. This is going to instruct VHAP to use JavaScript. So let's see what happened here. Well, it says you're using the tag, but your browser doesn't support it. So probably you can guess it already. I need to modify my VHAP configuration in here. What I am going to use is another package called Chrome extension. And this package is going to allow me to control Chrome directly from VHAP and Mink. This one, I say good is going to be my default browser. My default session, that means sessions that don't know the required JavaScript are going to use the good driver. Sessions that do require JavaScript, it says default. It is kind of confusing, but this default actually refers to the browser name. So the browser name is Chrome. So what I'm going to do is launch Chrome. This is similar to what we had before. It's the base URL. And then I need to tell how to communicate with Chrome. Remember that we are using these tools to communicate with a browser. So we are actually sending commands to the browser so that it will behave as a human. That is the configuration that I need to do there. If I run again, I get a different error. And this time it says, I am trying to communicate with the browser, but it is not available. So what I have to do, and this is in the documentation, I can open, I have to open Chrome, allowing remote debugging. This is going to allow the Mink extension to control the browser remotely. Just execute that command and then run again. It didn't work because something failed. Because I am using the building PHP server, sometimes it just fails and I have to do it again. Let's see if that fix it. It keeps failing. There you go. It's like Groupon. You have to clear the cache many times. Sometimes I have to clear the server more than once for it to work. It's kind of fast, but you saw the different steps. There is no need to have the UI. It can also work as a headless browser. So you just have to pass some extra configuration. And it is dying. Thank you very much. I have killed the server, of course. And now everything works. This error that you see below is something that there's a problem with Umami and the way that I am running the server. But the important part is that we saw down below all that has passed and things are working. So the last thing that I want to mention is that there is a configuration in Drupal. What I said before, that sometimes it fails. It fails because my default Drupal only allows five form submissions of the contact form. If I change this to one, for example, and I import this configuration, it's like, well, what I wanted to explain is that there is another extension that allows me to take screenshots when something fails. Remember that ideally you're running this in a headless browser so you actually don't see what's happening. So with this extension, it's one of the ones that I mentioned in the beginning. Just again, simply copy some code and make sure, because this is jammed, to indenting properly. And by doing this, it will automatically take a photo when something fails. And it is just this configuration. The one thing to remember is that different drivers and different browsers have different capabilities. For example, Chrome can execute JavaScript and Chrome can take screenshots. If you run the regular good driver, it is only text that will not be able to execute Chrome nor take a screenshot. And unfortunately, there is no warning or an error. It just fails and doesn't take any screenshots. So one way to force the screenshot is to tag this with JavaScript. And this can only be just like while you devote why something is not working, you tag it like JavaScript, it will use Chrome, and then you will be able to see the screenshots. Once you figure it out, you simply delete that and that's it. Again, in this case, it's because Drupal imposes some limit to the number of submissions and you would say, hey, this was working before, why it's not working anymore? By actually seeing this region, you can have an idea of why. Again, the slides are already available. So I invite you to check the code, the final repository of the code. And with that, I would like to say thank you and I will request you to evaluate the session. There is no time, so I will be around outside to ask for a question if there are some. Thank you very much.