If we want to do full end-to-end testing, then we need to seed our database into a reliable state at the start of every test. In this lesson, we'll learn how to build a Cypress plugin that updates the data in our database.
Instructor: [00:00] Up until now, we've been stubbing out our backend in tests with cy.fixture and cy.route. In order to do full end-to-end tests, we're going to want to start seeding our database. Let's write a Cypress task that seeds the database.
[00:19] We can call the task db seed and that'll take an argument of a hash whose keys are the names of our model. To-dos is our first model right now.
[00:29] We can pass an array of to-dos. In the future, we could add a users model and pass an array of users or any other models we might think of, but for right now, we just have to-dos.
[00:40] We'll pass an array of hashes. In fact, we can just copy in the data from our fixtures file and paste that in. Now that we know what our task will look like, let's go ahead and define it in Cypress plug-ins index where we defined our Hello World task. This task is called db seed and it takes an argument which is r-seeds.
[01:14] We'll assume that there's going to be some kind of a default case. The default seed would be an empty to-dos array and that's just us resetting the database to a clean, empty state.
[01:28] Then we're either going to use the seeds if they were passed in or the default seed. We'll say the seeds to use is if the seeds are precedent then the seeds, otherwise the default seed.
[01:44] We're going to write a library. We'll probably call it db. We'll import that and we'll say that it has a seed method. We'll pass it into seeds to use. We return null, remembering that null is the case where the plug-in is used successfully.
[02:01] Then we need to import our db library. We'll say const db equals require and this will be relative to our path, so go up to -- we have Cypress plug-ins, yeah. If we want it to be in our route to this, we'll call it db seeder.
[02:25] Now we have to write our db seeder, so we'll create a new file, call it db seeder. For this project, we used the load db library. I'm going to copy in some boilerplate for writing to that particular database. If you happen to use Postgres or MySQL, you'll have your own version of this code.
[02:46] Here's our module. We had a seed function that takes some state. That's the seeds that we passed in in the plug-in. This library writes to a JSON file which is located at the root of our project.
[03:02] This is just some more boilerplate for writing to this particular database. Again, use your own version of this code and set state. That's it. That's all the boilerplate.
[03:13] We just have to rerun Cypress so it can pick up our new plug-in. Let's go ahead and make sure that we visit the page after we've seeded the database. That way, we can see the changes on the page, and we do see them there.
[03:28] Just to double-check that this is in fact working the way we expect it to, let's update one of our seeds, and we see the changes reflected. That's great.
[03:41] Let's go into our database file, and we can see the changes reflected in our database. We can see that in our test file, we're actually able to interact with and update our backend. That's pretty cool.
[03:55] But one problem that we are going to notice is that if we visit our actual development environment, oh no, the changes are reflected here as well.
[04:06] The reason for this is because we have no separate testing environment. We're using the same db.json file in both our tests and our dev workspace.
[04:15] While every application will have different requirements for separating the dev and test environments, let's go ahead and take a look at some of the basics.
[04:25] Since we're going to have a separate version of the server running for both dev and test, we'll need to configure the port and the database file for each so we can separate them.
[04:36] We can detect the node environment. If it's test then we will configure the port to be 3001 and the db file to be db.test.json. Otherwise, we'll just use the defaults that we've used before.
[04:54] Then all we have to do is go through the file, find any place the database has used and replace that with db file. You can see it's hard-coded in a couple of places, so we just replace these. The same thing with the port that's used down here. We'll just pass in the port.
[05:13] Let's go ahead and create a new file called db.test.json. We can preset that up with an empty to-dos array, save that out. In our package.json, we have the scripts that we run when we actually run our project.
[05:34] Let's create a separate frontend test environment and API test environment. We have to pass node-n equals test, change the port to 5001 and 3001. When we run npm-run-start, which starts all of our processes, we also want it to start frontend test and API test.
[05:55] We'll just go ahead and copy these in and there we go. Our frontend needs to know what the React app API URL is, so that whenever we make a call to the backend, we call this URL.
[06:12] We want to make sure that we have isolated the locations in our application that actually call the backend. For us, they exist in this sagas file. We have this get-base URL which knows the application base URL and returns it.
[06:27] For us, we'll just say it's this React app API URL. If it's present, we will return that. Otherwise, we'll just return this default which was our dev environment URL.
[06:42] When we actually run npm-run-start, we'll see that we start up four separate processes -- a frontend and frontend test, an API and API test. These will all run on separate ports and using separate database files.
[06:56] When these load up, we'll see that we have test environment running on port 5001 and a dev environment running on port 5000. Clearly, they have different databases here.
[07:06] You can say that this is the dev to-do one. This has not impacted our testing environment against a test to-do one. These are totally isolated.