 Hello, everyone, everyone. Hello, bonjour, as they say here in Montreal. I'm here to present robust tests for conventional environments. I want to share with everyone the path that we took, adding tests into our project and how it helped us increase our velocity and helped us go faster. My name is Carolina Pinzon. You can find me on Twitter. I'm GitHub as Karol Pinzon Silva. Please reach out to me. You can write me on Twitter or write an issue in my GitHub repository. So it would be kind of funny to see a contact that way. Here's my page, Carolina Pinzon. And I'm from Colombia. It's funny. Liz, I don't know if you're here in the previous text. She's also from Colombia. There's also Marty here. Tag is tomorrow. So it's funny that we are all here representing that beautiful country. So go to Colombia. And I'm a front-end engineer at Dapper Labs. So what do we do at Dapper Labs? In Dapper Labs, we believe that blockchain should be for everyone. We believe in blockchain as a solution for modern problems. And we want to show the true value of blockchain, building games. We want to bring a broader audience into blockchain. And we want to do it through games. And in Dapper Labs, I work at this product that we called Dapper. I know it's a little bit confusing, because it has the name of the company, but bear with me. And what is Dapper? Dapper is a wallet for blockchain, for Ethereum specifically. So similar in a bank account, you have your wallet application in your phone that in which you can do the transaction, you can send money to other people. It's the same concept, but in the blockchain. So Dapper allows you to interact with the centralized applications and send transactions to other people and buy tokens and assets. And there's some components that Dapper has. Dapper is an Ethereum smart contract. It's built as a Chrome extension, it uses React, and interacts with the centralized games. So at this point, you might have some questions like, what is Ethereum? What is a smart contract? Chrome extension, how does it work? Maybe what is React? Or what are the centralized games? It's Catalina just saying a bunch of random words to confuse you. I promise it's not like that. So I'm just going to go through each of these points and explain them a little bit in detail. The first one, Ethereum smart contract. Ethereum is a blockchain. It's a blockchain that we choose to build upon it. And a smart contract. So in a centralized solution, you have this code that you built. You can build in any language, in JavaScript, in Go, and you deploy the code into one server. And any user can interact with the code using an IP. In the centralized application, you have the same code, but you deploy it into a cluster of computers. This is what we call the blockchain. And the cluster of computers, they communicate with each other, and the user can communicate with your code using the address. So it's similar to the IP in a centralized solution. In this case, it's an address. And the code that we deploy is called a smart contract. It's building solidity in case you're interested about the language. So a Chrome extension. I'm sure you are familiar with Chrome, but how does a Chrome extension work? A Chrome extension has three components that we have to talk about. The first one is a pop-up. So basically, when you download an extension from the Chrome store, it adds an icon into your nav bar. And then when you click the icon, it opens this small pop-up. And something that you need to know about this pop-up is that it acts exactly as a window. So every time you close or open it again, it's just like a window on the pop-up script that is injected into this UI. It stops running when you click outside the pop-up into the window, Chrome window. So because of that, we have the second component, which is a background script. The background is always running in the instance of the window. So this is the thing that persists between the session of the user. And the pop-up communicates with the background. And the third one is a context script. So the idea of an extension is that it wants to interact with web pages. Because of this, we need to inject a script into the applications that we want to interact with. And the script communicates with our background using push messages. So the background is like this communication between the pop-up and the context script that communicates with the application. I'm not gonna talk a lot about a React application because more people are familiar with that, but it's a great library. And the centralized games. The centralized games have the same normal games, but they're built upon the blockchain. So in a centralized game, you have this server with a database, and the database have the information of what user has, which token or which asset. In a decentralized game, we use the blockchain to keep track of this. So we use it to demonstrate the true ownership of the assets and of the tokens. And some examples of games that we work on with Dapperless is Cryptokitties. I don't know if you have heard of it, but it's you collect and read these creatures, one of them creatures that we call Cryptokitties. And after you read them, they have some attributes that then their kids have like a mix of those attributes and you can create different combinations. And the other game that we have developed is called Cheese Wizard in which you buy a wizard and then you compete against other wizards to win power. Like if you kill the other wizard, you get their power. And the idea is that at the end of the tournament, the wizard that survives gets to win the big cheese. We recently had a tournament, like I think it was around two weeks ago and the price was $100,000 around that. And it's interesting because the guy who won the big cheese, he's not a developer. He just read a book about how to break the Nash equilibrium of broke paper scissors, which is like the basic of a cheese wizard and he got into it and he won the prize. So it was one nice thing other people from like not the developer community get into the games and get into blockchain. Yeah, so be sure to check it out. Like there's gonna be an experiment soon, so it's pretty cool. Yeah, so I know all, or we know, sorry, all these concepts right now, but we didn't know when we started developing it. We had no idea, like yes, we did cheese wizards before, sorry, crypto kitties before, but we didn't really know all these concepts. So how did we build it? We started in October of 2018, October of last year with a simple create react app. And then seven months later, we had a public beta. So it was kind of a rushed experience and I wish we could say that we started adding tests from the beginning that everything was moved, that everything was perfect, but it was not the case at the beginning, it was chaos and I mean, I guess it's a lot of projects. And we had a lot of time wasters. We had many unsuccessful QA sessions because we're a startup, we don't have a team of dedicated QA people. So the QA is done by us, by the team, by the product team. And how it works is that, okay, we want to test a feature. We contact some people from the team, so we ask a product designer or the engineers to get into our room and test whatever feature we want to work on. So of course we want to test as many things as possible. So it was like maybe half an hour before the QA session, we were trying to merge everything and merge, re-merge. And then we got into the QA session with all these people, all these people that we were taking their time off. And then sometimes they couldn't even open the application or they couldn't even log in, they couldn't do anything. So we had to first apologize for taking their time, then try to fix the bug as fast as possible and contact back again. So I think we were wasting around five hours of time per week, not only from our time, but from other people's times. We also had multiple fixes for the same bug. We broke things. We broke things without realizing it. We realized it in the QA session. And there was a lot of manual testing, different from a website that you can have bills for HBR and you can access it through a URL. In Chrome extension, if you want to test a change, you need to pull the branch, build the extension, and then upload the extension to your browser. So it's a lot of friction to test things. And we were, as developers, we were doing this a lot. So we were wasting a lot of time. And this is just some examples of the issues that we had at the beginning, just to show you that I'm not saying things. So people were unable to open the build, so they couldn't even open it. This one is funny. We added end-to-end tests, and then we broke the production build. Not the staging or development, we broke production without noticing it. Error of the logins, weird and vague error messages. The activity list is a feature that we have, and we had things like, OK, we broke it and then fixed it. And some days later, we broke it back again. So it was just painful, and the development was not going fast. So I'm going to share with you three challenges that we faced, and then how we fixed them with tests and how it helped us go faster. The first challenge was that blockchain transactions are slow and cost money. So in Ethereum, Ethereum can process around 15 to 20 transactions per second, because all the nodes need to process all the transactions. This compared to a credit card company. As Visa, they process 45,000 transactions per second. So there's more than three orders of magnitude of difference. And because of that, transactions in blockchain, in Ethereum specifically, they take around one or two minutes to get approved, to get accepted. And they cost money. For each transaction that you do, you have to pay a network fee. The network fee that you have to pay depends on how congested the network is in the moment, what type of transaction you have, and how fast your transaction, you want your transaction to go. So you can pay more if you want your transaction to go fast. And I think it's around something like 25 cents per transaction. Yeah, but it costs money. There is a testing network that you can use. It's called Ringly. But it's lower than the main. So you couldn't have a fast free transaction. And how does it affect us? So remember that I told you about how a smart contract works? So that brings a smart contract wallet. That means that for each user, we upload a smart contract into the blockchain. So that means that every time a user creates an account, we have to create a new smart contract and deploy it into blockchain. So it will be similar in a centralized application to deploying a server per user. And since this is such a critical stage of our products, like basically without if this doesn't work, the user doesn't have a wallet, we needed to make sure that it was working all the time. And we saw this screen a lot. At the beginning, this is my story. At the beginning, we didn't have this Pong game. We had an animation. But we saw the screen so much that Nick, one of our great developers, he was like, you know what? I'm going to build a game for this screen. And he went one weekend and then came back to the Monday with this game. And we became quite good at this game because we were just waiting a lot of time to build. But it was frustrating. So how did we solve it? We built a local blockchain in our machine. At this point, we could have said, like, you know what? Let's not worry about it. Our API is the one that interacts with the blockchain. So let's assume that everything is going to work. We are just going to mock the API request that we do to our API. And that's it. That will be our test in the front and in the client side. And we did that at the beginning. But we ended up having some bugs that we could not catch in our automated test. So that's why we wanted to go one step further. And we tried replicating as much as possible the production environment as we could. So how we did it, it was we run a local blockchain using get, which is a go implementation of Ethereum, pull go implementation. And we are in our machines that just recrase these different nodes into one machine, communicating between each other. We also pulled on the API to have the latest version of our API. And with this, we created a production environment, or as similar as possible, into our machines. And that helped us have better tests that were more similar to the final version that we'll have. That's the second challenge that we have. This was more the UX challenge, is that the users have different expectations for extensions compared to a web page when they business a web page. So if you go to a web page and you open a model, you write an input, for example, and then you refresh the web page, the user does not expect for the model to be opened and for the input to still be there. It's because they are used to this. And they know that if they are in an important flow, if they are making a transaction, you cannot close the window in the middle of the transaction. You need to wait until the transaction processes. But in an extension, since the pop-up is really easy to close, basically, if you click anywhere outside the pop-up, we lose this flow of the user. So at the beginning, we had a lot of issues in which, even in a simple login flow, we didn't test when the user clicked outside while they were before writing the password, for example. And going back to our diagram of how the Chrome extension works, that means that we had to make all the IPR requests and have everything saved in the background. So anything that you want to persist throughout the window for instance, we had to do it in the background. And this is also because the pop-up is so small, we had the constraint of the dimensions of the window. That made us have to divide the flows that we had to. For example, the sign of flow, we had to divide it in different steps. So it couldn't be like one long form that could have been easier for us to develop that. We had to break it into separate steps. And things like this, just a simple flow where you had to add your email, your password and your phone number and then an email verification step. We had a lot of bugs in this. And this is how we were testing it at the beginning. So you're going to see me click the refresh button. I'll do it right now multiple times. And this restarts the background script and the pop-up script. So it mimics the user closing the window during the flow. And this is how we were testing it at the beginning, just writing things, then going to the refresh button, refreshing it, and then try it again. But as you can see, this is really manual and it's really easy to miss a step. It's really easy to, yeah, don't do a, for example, what happens if the user writes first the password and not the email, things like that. So it was just not good for us, not good for our speed. And the solution that we had was testing each step separately. So the user is going to interact with this as different steps, right? Because they can close the pop-up whenever it's really easy for them to go out of the pop-up. So take it as that and then do tests as the user would do it, just try to do each step at a time. So in our case, in this, in our login flow, we know that from the first step, we want to save the email and we want to get the token. We know that in the second step, we want to save the phone and the last step, we want to call the API and create the user. And if you see this, this is the same as having documentation from the code. You know that from the first step, they have the email, the token, the second step, phone, and then the third step, you create the account. So this was good, not only for like, it helped us not break the login flow, but it also helped us having the code that documented itself, having tests that helped us documentation for the code. This is a simple flow, like this has three steps and this doesn't have any branches, but we had our flows that were like more complicated and with tests, we could have like a documentation of each step and what did it have to save after each one. And the third challenge that I want to share is that as I said before, the exception communicate using Windows messages. So in a more conventional application like CryptoKitties, for example, the application has the full control of the request that it makes and the full control of when it does it, what it wants to do with the response. So for example, if you have a list and you want to show more Kitties, after the user clicks a button, you have the, you make the HTTP request and it gets back the Kitties and you display them. But in Dapper, in a Chrome extension, it does not have the full control of everything because it needs to interact with the centralized application. So let's say for example, a user wants to buy a Kittie. We'll just go into one second after it, thank you. Yeah, so it wants to buy a Kittie and then the decentralized game is the one that tells when we want to start doing the transaction. So we need to listen to these messages sponsored from the centralized game to do a transaction to start our flow. And how does that affect us? Yes, and that does it with the context script sends that push message into the background and we need to react with this. And yes, this is an important part of our wallet. Basically this is what we build the wallet for. We want applications to be able to do transactions with our wallet, so we want to make sure that that works. And we want to make sure that every time a script, every time an application sends a message into our script it triggers the transaction, the transaction flow. And in order to do this end-to-end test we wanted to use Cypress. We thought it was a, it is a great tool for end-to-end testing if you haven't tried it. But when we started adding it we had this problem and it does not support browser-specific protocols. There's an issue, it's still open, it's number 1965. I actually went to a conference in which Cypress were the sponsors of the conference. I made a joke about this in front of everyone and the issue's still open so I don't think it's going to be fixed soon. And it's because how it works internally is that you tell Cypress to open a URL and then internally it opens an iframe that goes to this URL and then interacts with it. So because of this the browser-specific protocols can't work or are really hard to make them work. Yes, so at this point, like at the beginning we were like, you know what, let's forget about Cypress, let's not have end-to-end tests and move on. But it ended up being worse, just ignoring this and trying to continue with manual tests for the transactions for example. So the solution that we had here was make it work. Don't worry about the implementation details, don't worry about making it perfect as we have the saying in Dapper Labs that it's done before perfect and apply this concept also to your tests. And how we did it was we have to, in order for us to run our end-to-end tests we have to do three stages. First you build extension, then you run a local server that points into the extension build so usually what you do is you upload the build into Chrome but if you want to run the end-to-end test with Cypress we have to access it using the URL because that's how Cypress works so we did that. And the third step was mocking the Chrome API. Yes, and as you can see this is not the best solution because we are after all mocking a really core part of our application which is the Chrome API, the browser-specific protocols. But it was better doing this and having Cypress test rather than not having test at all. So that's why I say make it work. Even deep at the beginning if you have to take some shortcuts it's better having something rather than nothing. And we're still working on this, we want to try to figure out a better solution so we don't have to mock things. For example, I remember that we had some box about coding and decoding of the messages that we didn't capture because we were mocking it but it's better than not having anything at all. So yes, this is our Cypress test running. We had, so we added the test and to end test for the most important flows, not for everything. So for the long for the transactions and that helped us also at the end try to do test-driven development and try to have this code that you will not be scared of changing it in the future because you have tests that validate that the previous functionality is still working. And I mentioned about the unconventional environment. In this case it's because the technology is unconventional. It's a, we work with blockchain with the central line game, CMACOM extension but there aren't many different types of unconventional applications. For example, right now we are working on another game it's an NBA game and I found that tests actually are helping us from the beginning making our development process faster and then conventional aspect in this case is not that it's a blockchain game is that we have a lot of unknowns in our project. We are working like all the teams working really fast and things change all the time and like the API is not ready sometimes when also the frontends are working on some feature but I found that tests actually help us like giving us a guide or where we have to go what we have to do and it makes us go faster. Yeah, so if you are doing an application and want to test, I'll give you like maybe three things that you can think of so you can start adding tests. The first one is think about things that you are repeating a lot. So for example in our case we're repeating a manual testing a lot and things that you are wasting a lot of time doing like this repetition and then write a test for it. It's better like taking one time longer to write the test than spending all this time periodically time that you repeated and repeated. The second one is think about things that break often in our example, for example the activity list. So if it breaks often, the chances is that you're going to break it again in the future and write a test for it. Save yourself time, save yourself like surprises in QA sessions by writing tests. And the third one is think about flows that you, like if the flow breaks at 3 a.m. you have to wake up and you have to fix it and write a test for it. Make sure that you're not breaking it with new code because at the end the tests are for us, the developers. Like we're never going to have a person from product telling us, okay we need to stop production. We're going to add tests. This is what we're going to do in the sprint. It's not going to happen. It's usually us that we have to like push the team to add tests and this is like what I like to say is that test that make your life easier as a developer will make the product better at the end because it will help the team go faster. So yeah, even if the deadline is really short and even if you have a lot of unknowns that you really don't know where to start at, take the time, write a test and it will help you eventually go faster. Yeah, I have a favor to ask you. If you can like open your phone and go into this URL and send me your feedback. So just share with me the thing that you liked, something that you liked. Yes, and if you do that, I'll send you a creep to kitty so you can have this creature. I will really appreciate it if you do that. And yes, much as gracias. Thank you so much. Come to me.