Test your Firestore security rules like a pro using the new database emulator and Jest https://angularfirebase.com/lessons/testing-firestore-security-rules-with-the-emulator/

- Firebase Summit https://firebase.googleblog.com/2018/10/whats-new-at-firebase-summit-2018.html
- Jest https://github.com/facebook/jest
- Emulator https://firebase.google.com/docs/firestore/security/test-rules-emulator
2024-02-04T07:09:24.399Z
nova-2
2-general-nova
2024-01-09.29447
30089e05-99d1-4376-b32e-c263170674af
1e12fdf5-703f-4691-a9be-c5208a27a804
c3c88b371f4fc74673069995a5f803b3b2453c9430691e66e41364bd111a0bf2
67875a7f-c9c4-48a0-aa55-5bdb8a91c34a
deprecated
Firebase Summit wrapped up a few days ago, and although I wasn't able to make it in person, they did announce a bunch of cool new features.
The feature that is most exciting to me is the local emulator for Fire Store and the real time database.
The emulators allow you to run an instance of your database locally, meaning you can build up a test suite around your security rules.
This not only speeds up development time, but it So increases the integrity of your back end security.
In today's video you'll learn how to set up the emulator and build out a full test suite using Jest.
If you're new here like and subscribe, and make sure to grab the full source code from angularfirebase.com.
Now before we get going with the emulator, I'd also like to point out that Firebase announced a new Project Management API.
This API makes it possible for apps to manage Firebase projects of other users.
For example, you can now deploy your Firebase projects directly from StackBlitz or Glitch, but the more exciting thing going on there is that you can use this project management API to build your own apps that do the exact same thing.
So let me know in the comments if you want to see that covered in a future video.
So now let's get started talking about the emulator.
The emulator just runs Firestore or the Realtime Database locally on your machine.
This means you can now simulate interaction with the database without actually having to run it in the cloud.
This makes it so much easier to be confident that a complex set of security rules are working the way that they should.
I'm gonna go ahead and set this project up with just vanilla JavaScript and Jest as the testing library.
The reason I choose Jest is because it's very developer friendly, and also really good at testing asynchronous code.
To start testing your rules in isolation, I'd recommend starting from a brand new directory, and then install the latest version of Firebase Tools.
Once that's done, you can run Firebase init Firestore, and that will pull in your existing security rules from whichever project you select.
From there, you can run npm init to set up a package JSON in this folder.
Then after that, we can install our testing utilities, which include Firebase testing and Jest.
That'll give us a directory structure that looks something like this.
I've also created a spec folder that includes our testing files.
All of our testing code will be written there, then the thing we're actually testing is this Firestore rules file.
If you're not already familiar with Firestore security rules, I recommend checking out Episode 92 where I teach you all about rules and how to hack a Firebase app.
And one additional pro tip I have for you here is to install the Firebase Security Rules plugin for Versus Code to get syntax highlighting and autocomplete while you write out your rules.
Now there are a few additional steps to install the emulator.
You can do it directly from the command line with the directions here, or you can install the Java JAR file directly.
You'll probably wanna go with the command line option, but in either case, you need to have Java installed on your system.
If JAWA is not already on your system, head over to their super modern website and get it installed today.
Now I wanna show you what a basic test run will look like.
We have 2 terminal windows set up here.
On the left side we'll go ahead and run the emulator, which we can do with Firebase serve only Firestore.
That will run the local emulator in the ground, you really just need to keep this in mind for debugging if it's not behaving the way you expect.
Then on the right side, we can run the jess command to run our actual specs.
Now I've been working with the emulator for a couple days now, and I want to start this video off by giving you some helpers that will just make your test easier to write.
And also just to warn you, we're going to be writing a lot of async functions, so if you haven't seen the AsyncAwait video, make sure to check that out as well.
The first helper function is called setup, and this will create an instance of the emulated Firestore data It also has the option to take an auth object, which will create a fake user and also mock data that will be written to the database when it's initialized.
Every time you initialize a test database, you'll want to give it a unique project ID.
You can do this easily by just making your project ID a random number or a date timestamp.
From this point, you'll want to go ahead and call Firebase Initialize Test App.
It's important to note that when you initialize the app for the first time, it will not have any security rules applied to it.
This is actually very useful because we can seed the database with some mock data before the rules are applied to it.
And you can also provide a user context, which would just be an object with a user ID that you could then use to test your rules.
The way that I see the database is I provide a data object where every key in that object is the path to the document and then the value is the data that we wanna write to the database.
This makes it really easy to see the database because we can just loop over keys in that object and then write the data to their corresponding paths.
Now that we have the mock data seeded in the database, we'll go ahead and apply the security rules.
That can be done by calling loadFirestoreRules, and then we'll want to use the file system to point to the actual raw rules file.
And finally, we'll return the actual database instance from this method so we can use it throughout our specs.
So now that we have our setup done, I'm also going to Support a function called teardown, which will just look for all the Firebase apps that were created on this test run and then delete them once the tests are finished.
So those should make your life a lot easier.
Now let's look at how we can use them in an actual test.
You typically want your database to be secure by default, which means that you'll have allow read and write if false at the very top level of the database.
This means that all paths are locked down by default unless you specifically allow test to them.
Let's go ahead and test if this actually works by first importing our setup and teardown methods.
Then Firebase provides us with 2 testing utilities that we can use to determine whether or not Operation was successful or failed.
The first thing we'll do is describe our Test Suite, which is just our database rules.
Then we'll declare the database as a global variable that can reuse throughout the tests.
Then we can use the before all hook to define the database with our setup method that we define in the helpers file.
The thing we actually want to test here is that our database is secure by default.
So if we try to read or write to any random collection, it should give us a permission denied error.
And after all the test run, we'll also want to run our teardown method to delete those App instances.
In Jest, you can write a test by using the test method and then describing what Your testing in this case, the operation should fail when reading or writing to an unauthorized collection.
So there are a few different ways to write your will test and this really just boils down to the developer's preference.
I would definitely recommend making this an async function if you like readable code.
Then the Firebase assertion helpers will take a Promise as their argument such as a document read.
If the read is blocked by security rules in this case, then this Promise will resolve.
But if the read is successful, then the Promise will be rejected.
All we have to do is add the result to an expectation and our first test is completed.
If you want to make your code even more concise, you can actually just inline the await statement directly in the expectation.
That'll give you a nice and concise single line test, But these get very hard to read as your tests get more complex.
I'm gonna give you one more option here, which is slightly more advanced, and that's creating your own custom matcher with Jest.
What we can do is pass our read directly into expect, and then we can resolve it as a custom matcher that will either be to deny or to allow.
Basically, every test that you write will be checking whether or not a document operation was denied or allowed.
So having a custom matcher here is super useful because it not only keeps your code Size but also readable.
Let's go ahead and switch back to our helpers file and then I'm going to write expect extend and provide it with an async function called to allow.
The x argument to this function is whatever you pass to the expectation, which should be a Firebase Promise.
For example, reading or writing a certain path in the database.
We will try to resolve the Promise.
And if it resolves, we know that the test should pass.
Otherwise, we're going to have the test fail.
Then from the custom assertion, you just need to return an object that has a pass value, which should either be true or false, and then a message, which is a function that returns a string.
And keep in mind that this message will only be shown if the test fails.
So now we have a Matcher that will fail if the database read or write is blocked by Firebase rules.
Then we'll also want to create an inverse matcher to check if a Firebase rule is allowed when it should have been denied.
So we'll say to deny and just check with the assert fails method from Firebase.
You can use whatever testing methods you want, but I'll be using my custom matchers throughout this lesson.
Now I'm going to open up our comment spec, which defines the rules for our comments collection.
And in this particular app, a user needs to be authenticated to View Comments.
And when writing a comment, it must have a user ID that matches the auth user ID.
If we look at the actual rules logic, you can see we're allowing reads if the request auth UID does not equal null.
And then we're allowing rights if the UID is equal to the request resource data user ID.
In other words, the document that the user is trying to write to the database has the Same user ID as the actual authentication object user ID.
Ensuring that these rights fail is pretty easy.
All we have to do is set up the database with an unauthenticated user.
And then we can make a reference to our collection and expect that that read or write is denied.
But it's even more important that we verify that the operations are allowed when the user has the proper credentials.
So this time, we'll set up our database with an auth object has a user ID and an email address.
This time, we'll expect the reads to be allowed because we have a user that's logged in.
I currently have my test running in Watch mode.
So you can see here if we switch out the Matcher that the test will fail if we expect this to be denied.
Now when writing to the database, we'll expect the right to succeed if the user sends an object that has the corresponding user ID.
So we would expect this add operation to be allowed because it has the same user ID as the auth UID.
Then we can add another line here that tries to add an item to the database with a different user ID and we'll expect that one to be denied.
So that's how you test basic user authentication logic.
In the next step, we'll look at how we can see the database with mock data and handle things like role based access control.
Now going back to our rules, have a function here called GetUserData, which will read a document in the user's collection in the database.
So in order to test this function, we'll need to first seed our database with some mock data for the user.
Then in that document, we'll have an object that has different roles that the user can have such as an admin role.
So now in our Projects collection, we can see if the user has this admin role.
And if they do, we'll allow access.
And then we could also do the inverse of this and have the actual document self define who has access.
In that case, we would be building an Access Control List and we would check if the Resource data has any members with the current auth user ID.
So essentially, we have one rule here that defines logic for Role Based Access Control and also Access Control Lists.
The last thing I wanna show you is how to set up the mock data.
We defined this earlier in the setup function, and we're going to create an object where each key in that object is the path to the document.
Then its value is the object that we want to write to the database.
For example, we might have a user that has an admin role Or you might have a project that has an access control list with a certain user in it.
Now when we set up the database, we can add the argument as the authenticated user and then the second argument will be the mock data object.
That will automatically seed our database with the required data and then we can test it in relation to the authenticated user.
Then the remaining test will look basically the same as they've looked in the past.
We'll try to do a read or write operation and then see if it's denied or allowed.
So just to wrap things up, writing solid security rules is essential to securing your Firebase app.
I'm super excited about the emulator because makes testing rules much easier and reliable especially when you're dealing with a big complex app.
I'm gonna go ahead and wrap the video up there.
If it helped you, like and Subscribe and if you want to take your development to the next level consider becoming a pro member at angularfirebase.com.
You'll get access to all kinds of exclusive resources designed to help you build and Ship your app faster.
Thanks for watching, and I'll talk to you soon.

Speaker 0: Firebase Summit wrapped up a few days ago, and although I wasn't able to make it in person, they did announce a bunch of cool new features. The feature that is most exciting to me is the local emulator for Fire Store and the real time database. The emulators allow you to run an instance of your database locally, meaning you can build up a test suite around your security rules. This not only speeds up development time, but it So increases the integrity of your back end security. In today's video you'll learn how to set up the emulator and build out a full test suite using Jest.

If you're new here like and subscribe, and make sure to grab the full source code from angularfirebase.com. Now before we get going with the emulator, I'd also like to point out that Firebase announced a new Project Management API. This API makes it possible for apps to manage Firebase projects of other users. For example, you can now deploy your Firebase projects directly from StackBlitz or Glitch, but the more exciting thing going on there is that you can use this project management API to build your own apps that do the exact same thing. So let me know in the comments if you want to see that covered in a future video.

So now let's get started talking about the emulator. The emulator just runs Firestore or the Realtime Database locally on your machine. This means you can now simulate interaction with the database without actually having to run it in the cloud. This makes it so much easier to be confident that a complex set of security rules are working the way that they should. I'm gonna go ahead and set this project up with just vanilla JavaScript and Jest as the testing library.

The reason I choose Jest is because it's very developer friendly, and also really good at testing asynchronous code. To start testing your rules in isolation, I'd recommend starting from a brand new directory, and then install the latest version of Firebase Tools. Once that's done, you can run Firebase init Firestore, and that will pull in your existing security rules from whichever project you select. From there, you can run npm init to set up a package JSON in this folder. Then after that, we can install our testing utilities, which include Firebase testing and Jest.

That'll give us a directory structure that looks something like this. I've also created a spec folder that includes our testing files. All of our testing code will be written there, then the thing we're actually testing is this Firestore rules file. If you're not already familiar with Firestore security rules, I recommend checking out Episode 92 where I teach you all about rules and how to hack a Firebase app. And one additional pro tip I have for you here is to install the Firebase Security Rules plugin for Versus Code to get syntax highlighting and autocomplete while you write out your rules.

Now there are a few additional steps to install the emulator. You can do it directly from the command line with the directions here, or you can install the Java JAR file directly. You'll probably wanna go with the command line option, but in either case, you need to have Java installed on your system. If JAWA is not already on your system, head over to their super modern website and get it installed today. Now I wanna show you what a basic test run will look like.

We have 2 terminal windows set up here. On the left side we'll go ahead and run the emulator, which we can do with Firebase serve only Firestore. That will run the local emulator in the ground, you really just need to keep this in mind for debugging if it's not behaving the way you expect. Then on the right side, we can run the jess command to run our actual specs. Now I've been working with the emulator for a couple days now, and I want to start this video off by giving you some helpers that will just make your test easier to write.

And also just to warn you, we're going to be writing a lot of async functions, so if you haven't seen the AsyncAwait video, make sure to check that out as well. The first helper function is called setup, and this will create an instance of the emulated Firestore data It also has the option to take an auth object, which will create a fake user and also mock data that will be written to the database when it's initialized. Every time you initialize a test database, you'll want to give it a unique project ID. You can do this easily by just making your project ID a random number or a date timestamp. From this point, you'll want to go ahead and call Firebase Initialize Test App.

It's important to note that when you initialize the app for the first time, it will not have any security rules applied to it. This is actually very useful because we can seed the database with some mock data before the rules are applied to it. And you can also provide a user context, which would just be an object with a user ID that you could then use to test your rules. The way that I see the database is I provide a data object where every key in that object is the path to the document and then the value is the data that we wanna write to the database. This makes it really easy to see the database because we can just loop over keys in that object and then write the data to their corresponding paths.

Now that we have the mock data seeded in the database, we'll go ahead and apply the security rules. That can be done by calling loadFirestoreRules, and then we'll want to use the file system to point to the actual raw rules file. And finally, we'll return the actual database instance from this method so we can use it throughout our specs. So now that we have our setup done, I'm also going to Support a function called teardown, which will just look for all the Firebase apps that were created on this test run and then delete them once the tests are finished. So those should make your life a lot easier.

Now let's look at how we can use them in an actual test. You typically want your database to be secure by default, which means that you'll have allow read and write if false at the very top level of the database. This means that all paths are locked down by default unless you specifically allow test to them. Let's go ahead and test if this actually works by first importing our setup and teardown methods. Then Firebase provides us with 2 testing utilities that we can use to determine whether or not Operation was successful or failed.

The first thing we'll do is describe our Test Suite, which is just our database rules. Then we'll declare the database as a global variable that can reuse throughout the tests. Then we can use the before all hook to define the database with our setup method that we define in the helpers file. The thing we actually want to test here is that our database is secure by default. So if we try to read or write to any random collection, it should give us a permission denied error.

And after all the test run, we'll also want to run our teardown method to delete those App instances. In Jest, you can write a test by using the test method and then describing what Your testing in this case, the operation should fail when reading or writing to an unauthorized collection. So there are a few different ways to write your will test and this really just boils down to the developer's preference. I would definitely recommend making this an async function if you like readable code. Then the Firebase assertion helpers will take a Promise as their argument such as a document read.

If the read is blocked by security rules in this case, then this Promise will resolve. But if the read is successful, then the Promise will be rejected. All we have to do is add the result to an expectation and our first test is completed. If you want to make your code even more concise, you can actually just inline the await statement directly in the expectation. That'll give you a nice and concise single line test, But these get very hard to read as your tests get more complex.

I'm gonna give you one more option here, which is slightly more advanced, and that's creating your own custom matcher with Jest. What we can do is pass our read directly into expect, and then we can resolve it as a custom matcher that will either be to deny or to allow. Basically, every test that you write will be checking whether or not a document operation was denied or allowed. So having a custom matcher here is super useful because it not only keeps your code Size but also readable. Let's go ahead and switch back to our helpers file and then I'm going to write expect extend and provide it with an async function called to allow.

The x argument to this function is whatever you pass to the expectation, which should be a Firebase Promise. For example, reading or writing a certain path in the database. We will try to resolve the Promise. And if it resolves, we know that the test should pass. Otherwise, we're going to have the test fail.

Then from the custom assertion, you just need to return an object that has a pass value, which should either be true or false, and then a message, which is a function that returns a string. And keep in mind that this message will only be shown if the test fails. So now we have a Matcher that will fail if the database read or write is blocked by Firebase rules. Then we'll also want to create an inverse matcher to check if a Firebase rule is allowed when it should have been denied. So we'll say to deny and just check with the assert fails method from Firebase.

You can use whatever testing methods you want, but I'll be using my custom matchers throughout this lesson. Now I'm going to open up our comment spec, which defines the rules for our comments collection. And in this particular app, a user needs to be authenticated to View Comments. And when writing a comment, it must have a user ID that matches the auth user ID. If we look at the actual rules logic, you can see we're allowing reads if the request auth UID does not equal null.

And then we're allowing rights if the UID is equal to the request resource data user ID. In other words, the document that the user is trying to write to the database has the Same user ID as the actual authentication object user ID. Ensuring that these rights fail is pretty easy. All we have to do is set up the database with an unauthenticated user. And then we can make a reference to our collection and expect that that read or write is denied.

But it's even more important that we verify that the operations are allowed when the user has the proper credentials. So this time, we'll set up our database with an auth object has a user ID and an email address. This time, we'll expect the reads to be allowed because we have a user that's logged in. I currently have my test running in Watch mode. So you can see here if we switch out the Matcher that the test will fail if we expect this to be denied.

Now when writing to the database, we'll expect the right to succeed if the user sends an object that has the corresponding user ID. So we would expect this add operation to be allowed because it has the same user ID as the auth UID. Then we can add another line here that tries to add an item to the database with a different user ID and we'll expect that one to be denied. So that's how you test basic user authentication logic. In the next step, we'll look at how we can see the database with mock data and handle things like role based access control.

Now going back to our rules, have a function here called GetUserData, which will read a document in the user's collection in the database. So in order to test this function, we'll need to first seed our database with some mock data for the user. Then in that document, we'll have an object that has different roles that the user can have such as an admin role. So now in our Projects collection, we can see if the user has this admin role. And if they do, we'll allow access.

And then we could also do the inverse of this and have the actual document self define who has access. In that case, we would be building an Access Control List and we would check if the Resource data has any members with the current auth user ID. So essentially, we have one rule here that defines logic for Role Based Access Control and also Access Control Lists. The last thing I wanna show you is how to set up the mock data. We defined this earlier in the setup function, and we're going to create an object where each key in that object is the path to the document.

Then its value is the object that we want to write to the database. For example, we might have a user that has an admin role Or you might have a project that has an access control list with a certain user in it. Now when we set up the database, we can add the argument as the authenticated user and then the second argument will be the mock data object. That will automatically seed our database with the required data and then we can test it in relation to the authenticated user. Then the remaining test will look basically the same as they've looked in the past.

We'll try to do a read or write operation and then see if it's denied or allowed. So just to wrap things up, writing solid security rules is essential to securing your Firebase app. I'm super excited about the emulator because makes testing rules much easier and reliable especially when you're dealing with a big complex app. I'm gonna go ahead and wrap the video up there. If it helped you, like and Subscribe and if you want to take your development to the next level consider becoming a pro member at angularfirebase.com.

You'll get access to all kinds of exclusive resources designed to help you build and Ship your app faster. Thanks for watching, and I'll talk to you soon.
Firebase Summit wrapped up a few days ago, and although I wasn't able to make it in person, they did announce a bunch of cool new features.
The feature that is most exciting to me is the local emulator for Fire Store and the real time database. The emulators allow you to run an instance of your database locally, meaning you can build up a test suite around your security rules. This not only speeds up development time, but it So increases the integrity of your back end security. In today's video you'll learn how to set up the emulator and build out a full test suite using Jest. If you're new here like and subscribe, and make sure to grab the full source code from angularfirebase.com.
security
software
Now before we get going with the emulator, I'd also like to point out that Firebase announced a new Project Management API. This API makes it possible for apps to manage Firebase projects of other users. For example, you can now deploy your Firebase projects directly from StackBlitz or Glitch, but the more exciting thing going on there is that you can use this project management API to build your own apps that do the exact same thing.
So let me know in the comments if you want to see that covered in a future video. So now let's get started talking about the emulator. The emulator just runs Firestore or the Realtime Database locally on your machine. This means you can now simulate interaction with the database without actually having to run it in the cloud. This makes it so much easier to be confident that a complex set of security rules are working the way that they should. I'm gonna go ahead and set this project up with just vanilla JavaScript and Jest as the testing library. The reason I choose Jest is because it's very developer friendly, and also really good at testing asynchronous code.
streaming
multimedia
security
databases
video gaming
networking
internet
To start testing your rules in isolation, I'd recommend starting from a brand new directory, and then install the latest version of Firebase Tools. Once that's done, you can run Firebase init Firestore, and that will pull in your existing security rules from whichever project you select. From there, you can run npm init to set up a package JSON in this folder. Then after that, we can install our testing utilities, which include Firebase testing and Jest. That'll give us a directory structure that looks something like this. I've also created a spec folder that includes our testing files. All of our testing code will be written there, then the thing we're actually testing is this Firestore rules file.
If you're not already familiar with Firestore security rules, I recommend checking out Episode 92 where I teach you all about rules and how to hack a Firebase app. And one additional pro tip I have for you here is to install the Firebase Security Rules plugin for Versus Code to get syntax highlighting and autocomplete while you write out your rules.
security
Now there are a few additional steps to install the emulator. You can do it directly from the command line with the directions here, or you can install the Java JAR file directly. You'll probably wanna go with the command line option, but in either case, you need to have Java installed on your system. If JAWA is not already on your system, head over to their super modern website and get it installed today. Now I wanna show you what a basic test run will look like. We have 2 terminal windows set up here. On the left side we'll go ahead and run the emulator, which we can do with Firebase serve only Firestore. That will run the local emulator in the ground, you really just need to keep this in mind for debugging if it's not behaving the way you expect.
Then on the right side, we can run the jess command to run our actual specs. Now I've been working with the emulator for a couple days now, and I want to start this video off by giving you some helpers that will just make your test easier to write.
youtube
And also just to warn you, we're going to be writing a lot of async functions, so if you haven't seen the AsyncAwait video, make sure to check that out as well.
The first helper function is called setup, and this will create an instance of the emulated Firestore data It also has the option to take an auth object, which will create a fake user and also mock data that will be written to the database when it's initialized. Every time you initialize a test database, you'll want to give it a unique project ID.
databases
You can do this easily by just making your project ID a random number or a date timestamp. From this point, you'll want to go ahead and call Firebase Initialize Test App. It's important to note that when you initialize the app for the first time, it will not have any security rules applied to it.
This is actually very useful because we can seed the database with some mock data before the rules are applied to it. And you can also provide a user context, which would just be an object with a user ID that you could then use to test your rules. The way that I see the database is I provide a data object where every key in that object is the path to the document and then the value is the data that we wanna write to the database. This makes it really easy to see the database because we can just loop over keys in that object and then write the data to their corresponding paths. Now that we have the mock data seeded in the database, we'll go ahead and apply the security rules. That can be done by calling loadFirestoreRules, and then we'll want to use the file system to point to the actual raw rules file. And finally, we'll return the actual database instance from this method so we can use it throughout our specs.
databases
data management
data
So now that we have our setup done, I'm also going to Support a function called teardown, which will just look for all the Firebase apps that were created on this test run and then delete them once the tests are finished.
So those should make your life a lot easier. Now let's look at how we can use them in an actual test. You typically want your database to be secure by default, which means that you'll have allow read and write if false at the very top level of the database.
databases
data management
This means that all paths are locked down by default unless you specifically allow test to them. Let's go ahead and test if this actually works by first importing our setup and teardown methods.
Then Firebase provides us with 2 testing utilities that we can use to determine whether or not Operation was successful or failed. The first thing we'll do is describe our Test Suite, which is just our database rules. Then we'll declare the database as a global variable that can reuse throughout the tests. Then we can use the before all hook to define the database with our setup method that we define in the helpers file. The thing we actually want to test here is that our database is secure by default. So if we try to read or write to any random collection, it should give us a permission denied error. And after all the test run, we'll also want to run our teardown method to delete those App instances.
databases
data analysis
In Jest, you can write a test by using the test method and then describing what Your testing in this case, the operation should fail when reading or writing to an unauthorized collection. So there are a few different ways to write your will test and this really just boils down to the developer's preference. I would definitely recommend making this an async function if you like readable code. Then the Firebase assertion helpers will take a Promise as their argument such as a document read. If the read is blocked by security rules in this case, then this Promise will resolve. But if the read is successful, then the Promise will be rejected. All we have to do is add the result to an expectation and our first test is completed.
If you want to make your code even more concise, you can actually just inline the await statement directly in the expectation. That'll give you a nice and concise single line test, But these get very hard to read as your tests get more complex. I'm gonna give you one more option here, which is slightly more advanced, and that's creating your own custom matcher with Jest.
programming
What we can do is pass our read directly into expect, and then we can resolve it as a custom matcher that will either be to deny or to allow. Basically, every test that you write will be checking whether or not a document operation was denied or allowed. So having a custom matcher here is super useful because it not only keeps your code Size but also readable. Let's go ahead and switch back to our helpers file and then I'm going to write expect extend and provide it with an async function called to allow. The x argument to this function is whatever you pass to the expectation, which should be a Firebase Promise. For example, reading or writing a certain path in the database. We will try to resolve the Promise. And if it resolves, we know that the test should pass. Otherwise, we're going to have the test fail. Then from the custom assertion, you just need to return an object that has a pass value, which should either be true or false, and then a message, which is a function that returns a string. And keep in mind that this message will only be shown if the test fails. So now we have a Matcher that will fail if the database read or write is blocked by Firebase rules. Then we'll also want to create an inverse matcher to check if a Firebase rule is allowed when it should have been denied. So we'll say to deny and just check with the assert fails method from Firebase. You can use whatever testing methods you want, but I'll be using my custom matchers throughout this lesson. Now I'm going to open up our comment spec, which defines the rules for our comments collection. And in this particular app, a user needs to be authenticated to View Comments. And when writing a comment, it must have a user ID that matches the auth user ID. If we look at the actual rules logic, you can see we're allowing reads if the request auth UID does not equal null. And then we're allowing rights if the UID is equal to the request resource data user ID.
In other words, the document that the user is trying to write to the database has the Same user ID as the actual authentication object user ID. Ensuring that these rights fail is pretty easy. All we have to do is set up the database with an unauthenticated user. And then we can make a reference to our collection and expect that that read or write is denied. But it's even more important that we verify that the operations are allowed when the user has the proper credentials.
databases
So this time, we'll set up our database with an auth object has a user ID and an email address.
This time, we'll expect the reads to be allowed because we have a user that's logged in. I currently have my test running in Watch mode. So you can see here if we switch out the Matcher that the test will fail if we expect this to be denied. Now when writing to the database, we'll expect the right to succeed if the user sends an object that has the corresponding user ID.
reading
So we would expect this add operation to be allowed because it has the same user ID as the auth UID. Then we can add another line here that tries to add an item to the database with a different user ID and we'll expect that one to be denied.
So that's how you test basic user authentication logic. In the next step, we'll look at how we can see the database with mock data and handle things like role based access control. Now going back to our rules, have a function here called GetUserData, which will read a document in the user's collection in the database. So in order to test this function, we'll need to first seed our database with some mock data for the user. Then in that document, we'll have an object that has different roles that the user can have such as an admin role. So now in our Projects collection, we can see if the user has this admin role. And if they do, we'll allow access. And then we could also do the inverse of this and have the actual document self define who has access. In that case, we would be building an Access Control List and we would check if the Resource data has any members with the current auth user ID. So essentially, we have one rule here that defines logic for Role Based Access Control and also Access Control Lists. The last thing I wanna show you is how to set up the mock data. We defined this earlier in the setup function, and we're going to create an object where each key in that object is the path to the document. Then its value is the object that we want to write to the database. For example, we might have a user that has an admin role Or you might have a project that has an access control list with a certain user in it. Now when we set up the database, we can add the argument as the authenticated user and then the second argument will be the mock data object. That will automatically seed our database with the required data and then we can test it in relation to the authenticated user. Then the remaining test will look basically the same as they've looked in the past. We'll try to do a read or write operation and then see if it's denied or allowed. So just to wrap things up, writing solid security rules is essential to securing your Firebase app. I'm super excited about the emulator because makes testing rules much easier and reliable especially when you're dealing with a big complex app. I'm gonna go ahead and wrap the video up there. If it helped you, like and Subscribe and if you want to take your development to the next level consider becoming a pro member at angularfirebase.com. You'll get access to all kinds of exclusive resources designed to help you build and Ship your app faster. Thanks for watching, and I'll talk to you soon.
databases
security
software
youtube
logic
data
data management
computers
video gaming
software development
systems
networking
administration
internet
intellectual property
Firebase Summit wrapped up a few days ago, and although I wasn't able to make it in person, they did announce a bunch of cool new features. The feature that is most exciting to me is the local emulator for Fire Store and the real time database. The emulators allow you to run an instance of your database locally, meaning you can build up a test suite around your security rules. This not only speeds up development time, but it So increases the integrity of your back end security. In today's video you'll learn how to set up the emulator and build out a full test suite using Jest. If you're new here like and subscribe, and make sure to grab the full source code from angularfirebase.com. Now before we get going with the emulator, I'd also like to point out that Firebase announced a new Project Management API. This API makes it possible for apps to manage Firebase projects of other users. For example, you can now deploy your Firebase projects directly from StackBlitz or Glitch, but the more exciting thing going on there is that you can use this project management API to build your own apps that do the exact same thing. So let me know in the comments if you want to see that covered in a future video. So now let's get started talking about the emulator. The emulator just runs Firestore or the Realtime Database locally on your machine. This means you can now simulate interaction with the database without actually having to run it in the cloud. This makes it so much easier to be confident that a complex set of security rules are working the way that they should. I'm gonna go ahead and set this project up with just vanilla JavaScript and Jest as the testing library. The reason I choose Jest is because it's very developer friendly, and also really good at testing asynchronous code. To start testing your rules in isolation, I'd recommend starting from a brand new directory, and then install the latest version of Firebase Tools. Once that's done, you can run Firebase init Firestore, and that will pull in your existing security rules from whichever project you select. From there, you can run npm init to set up a package JSON in this folder. Then after that, we can install our testing utilities, which include Firebase testing and Jest. That'll give us a directory structure that looks something like this. I've also created a spec folder that includes our testing files. All of our testing code will be written there, then the thing we're actually testing is this Firestore rules file. If you're not already familiar with Firestore security rules, I recommend checking out Episode 92 where I teach you all about rules and how to hack a Firebase app. And one additional pro tip I have for you here is to install the Firebase Security Rules plugin for Versus Code to get syntax highlighting and autocomplete while you write out your rules. Now there are a few additional steps to install the emulator. You can do it directly from the command line with the directions here, or you can install the Java JAR file directly. You'll probably wanna go with the command line option, but in either case, you need to have Java installed on your system. If JAWA is not already on your system, head over to their super modern website and get it installed today. Now I wanna show you what a basic test run will look like. We have 2 terminal windows set up here. On the left side we'll go ahead and run the emulator, which we can do with Firebase serve only Firestore. That will run the local emulator in the ground, you really just need to keep this in mind for debugging if it's not behaving the way you expect. Then on the right side, we can run the jess command to run our actual specs. Now I've been working with the emulator for a couple days now, and I want to start this video off by giving you some helpers that will just make your test easier to write. And also just to warn you, we're going to be writing a lot of async functions, so if you haven't seen the AsyncAwait video, make sure to check that out as well. The first helper function is called setup, and this will create an instance of the emulated Firestore data It also has the option to take an auth object, which will create a fake user and also mock data that will be written to the database when it's initialized. Every time you initialize a test database, you'll want to give it a unique project ID. You can do this easily by just making your project ID a random number or a date timestamp. From this point, you'll want to go ahead and call Firebase Initialize Test App. It's important to note that when you initialize the app for the first time, it will not have any security rules applied to it. This is actually very useful because we can seed the database with some mock data before the rules are applied to it. And you can also provide a user context, which would just be an object with a user ID that you could then use to test your rules. The way that I see the database is I provide a data object where every key in that object is the path to the document and then the value is the data that we wanna write to the database. This makes it really easy to see the database because we can just loop over keys in that object and then write the data to their corresponding paths. Now that we have the mock data seeded in the database, we'll go ahead and apply the security rules. That can be done by calling loadFirestoreRules, and then we'll want to use the file system to point to the actual raw rules file. And finally, we'll return the actual database instance from this method so we can use it throughout our specs. So now that we have our setup done, I'm also going to Support a function called teardown, which will just look for all the Firebase apps that were created on this test run and then delete them once the tests are finished. So those should make your life a lot easier. Now let's look at how we can use them in an actual test. You typically want your database to be secure by default, which means that you'll have allow read and write if false at the very top level of the database. This means that all paths are locked down by default unless you specifically allow test to them. Let's go ahead and test if this actually works by first importing our setup and teardown methods. Then Firebase provides us with 2 testing utilities that we can use to determine whether or not Operation was successful or failed. The first thing we'll do is describe our Test Suite, which is just our database rules. Then we'll declare the database as a global variable that can reuse throughout the tests. Then we can use the before all hook to define the database with our setup method that we define in the helpers file. The thing we actually want to test here is that our database is secure by default. So if we try to read or write to any random collection, it should give us a permission denied error. And after all the test run, we'll also want to run our teardown method to delete those App instances. In Jest, you can write a test by using the test method and then describing what Your testing in this case, the operation should fail when reading or writing to an unauthorized collection. So there are a few different ways to write your will test and this really just boils down to the developer's preference. I would definitely recommend making this an async function if you like readable code. Then the Firebase assertion helpers will take a Promise as their argument such as a document read. If the read is blocked by security rules in this case, then this Promise will resolve. But if the read is successful, then the Promise will be rejected. All we have to do is add the result to an expectation and our first test is completed. If you want to make your code even more concise, you can actually just inline the await statement directly in the expectation. That'll give you a nice and concise single line test, But these get very hard to read as your tests get more complex. I'm gonna give you one more option here, which is slightly more advanced, and that's creating your own custom matcher with Jest. What we can do is pass our read directly into expect, and then we can resolve it as a custom matcher that will either be to deny or to allow. Basically, every test that you write will be checking whether or not a document operation was denied or allowed. So having a custom matcher here is super useful because it not only keeps your code Size but also readable. Let's go ahead and switch back to our helpers file and then I'm going to write expect extend and provide it with an async function called to allow. The x argument to this function is whatever you pass to the expectation, which should be a Firebase Promise. For example, reading or writing a certain path in the database. We will try to resolve the Promise. And if it resolves, we know that the test should pass. Otherwise, we're going to have the test fail. Then from the custom assertion, you just need to return an object that has a pass value, which should either be true or false, and then a message, which is a function that returns a string. And keep in mind that this message will only be shown if the test fails. So now we have a Matcher that will fail if the database read or write is blocked by Firebase rules. Then we'll also want to create an inverse matcher to check if a Firebase rule is allowed when it should have been denied. So we'll say to deny and just check with the assert fails method from Firebase. You can use whatever testing methods you want, but I'll be using my custom matchers throughout this lesson. Now I'm going to open up our comment spec, which defines the rules for our comments collection. And in this particular app, a user needs to be authenticated to View Comments. And when writing a comment, it must have a user ID that matches the auth user ID. If we look at the actual rules logic, you can see we're allowing reads if the request auth UID does not equal null. And then we're allowing rights if the UID is equal to the request resource data user ID. In other words, the document that the user is trying to write to the database has the Same user ID as the actual authentication object user ID. Ensuring that these rights fail is pretty easy. All we have to do is set up the database with an unauthenticated user. And then we can make a reference to our collection and expect that that read or write is denied. But it's even more important that we verify that the operations are allowed when the user has the proper credentials. So this time, we'll set up our database with an auth object has a user ID and an email address. This time, we'll expect the reads to be allowed because we have a user that's logged in. I currently have my test running in Watch mode. So you can see here if we switch out the Matcher that the test will fail if we expect this to be denied. Now when writing to the database, we'll expect the right to succeed if the user sends an object that has the corresponding user ID. So we would expect this add operation to be allowed because it has the same user ID as the auth UID. Then we can add another line here that tries to add an item to the database with a different user ID and we'll expect that one to be denied. So that's how you test basic user authentication logic. In the next step, we'll look at how we can see the database with mock data and handle things like role based access control. Now going back to our rules, have a function here called GetUserData, which will read a document in the user's collection in the database. So in order to test this function, we'll need to first seed our database with some mock data for the user. Then in that document, we'll have an object that has different roles that the user can have such as an admin role. So now in our Projects collection, we can see if the user has this admin role. And if they do, we'll allow access. And then we could also do the inverse of this and have the actual document self define who has access. In that case, we would be building an Access Control List and we would check if the Resource data has any members with the current auth user ID. So essentially, we have one rule here that defines logic for Role Based Access Control and also Access Control Lists. The last thing I wanna show you is how to set up the mock data. We defined this earlier in the setup function, and we're going to create an object where each key in that object is the path to the document. Then its value is the object that we want to write to the database. For example, we might have a user that has an admin role Or you might have a project that has an access control list with a certain user in it. Now when we set up the database, we can add the argument as the authenticated user and then the second argument will be the mock data object. That will automatically seed our database with the required data and then we can test it in relation to the authenticated user. Then the remaining test will look basically the same as they've looked in the past. We'll try to do a read or write operation and then see if it's denied or allowed. So just to wrap things up, writing solid security rules is essential to securing your Firebase app. I'm super excited about the emulator because makes testing rules much easier and reliable especially when you're dealing with a big complex app. I'm gonna go ahead and wrap the video up there. If it helped you, like and Subscribe and if you want to take your development to the next level consider becoming a pro member at angularfirebase.com. You'll get access to all kinds of exclusive resources designed to help you build and Ship your app faster. Thanks for watching, and I'll talk to you soon.
Firebase
firebase
Summit
summit
wrapped
wrapped
up
up
a
a
few
few
days
days
ago,
ago
and
and
although
although
I
i
wasn't
wasn't
able
able
to
to
make
make
it
it
in
in
person,
person
they
they
did
did
announce
announce
a
a
bunch
bunch
of
of
cool
cool
new
new
features.
features
The
the
feature
feature
that
that
is
is
most
most
exciting
exciting
to
to
me
me
is
is
the
the
local
local
emulator
emulator
for
for
Fire
fire
Store
store
and
and
the
the
real
real
time
time
database.
database
The
the
emulators
emulators
allow
allow
you
you
to
to
run
run
an
an
instance
instance
of
of
your
your
database
database
locally,
locally
meaning
meaning
you
you
can
can
build
build
up
up
a
a
test
test
suite
suite
around
around
your
your
security
security
rules.
rules
This
this
not
not
only
only
speeds
speeds
up
up
development
development
time,
time
but
but
it
it
So
so
increases
increases
the
the
integrity
integrity
of
of
your
your
back
back
end
end
security.
security
In
in
today's
today's
video
video
you'll
you'll
learn
learn
how
how
to
to
set
set
up
up
the
the
emulator
emulator
and
and
build
build
out
out
a
a
full
full
test
test
suite
suite
using
using
Jest.
jest
If
if
you're
you're
new
new
here
here
like
like
and
and
subscribe,
subscribe
and
and
make
make
sure
sure
to
to
grab
grab
the
the
full
full
source
source
code
code
from
from
angularfirebase.com.
angularfirebase.com
Now
now
before
before
we
we
get
get
going
going
with
with
the
the
emulator,
emulator
I'd
i'd
also
also
like
like
to
to
point
point
out
out
that
that
Firebase
firebase
announced
announced
a
a
new
new
Project
project
Management
management
API.
api
This
this
API
api
makes
makes
it
it
possible
possible
for
for
apps
apps
to
to
manage
manage
Firebase
firebase
projects
projects
of
of
other
other
users.
users
For
for
example,
example
you
you
can
can
now
now
deploy
deploy
your
your
Firebase
firebase
projects
projects
directly
directly
from
from
StackBlitz
stackblitz
or
or
Glitch,
glitch
but
but
the
the
more
more
exciting
exciting
thing
thing
going
going
on
on
there
there
is
is
that
that
you
you
can
can
use
use
this
this
project
project
management
management
API
api
to
to
build
build
your
your
own
own
apps
apps
that
that
do
do
the
the
exact
exact
same
same
thing.
thing
So
so
let
let
me
me
know
know
in
in
the
the
comments
comments
if
if
you
you
want
want
to
to
see
see
that
that
covered
covered
in
in
a
a
future
future
video.
video
So
so
now
now
let's
let's
get
get
started
started
talking
talking
about
about
the
the
emulator.
emulator
The
the
emulator
emulator
just
just
runs
runs
Firestore
firestore
or
or
the
the
Realtime
realtime
Database
database
locally
locally
on
on
your
your
machine.
machine
This
this
means
means
you
you
can
can
now
now
simulate
simulate
interaction
interaction
with
with
the
the
database
database
without
without
actually
actually
having
having
to
to
run
run
it
it
in
in
the
the
cloud.
cloud
This
this
makes
makes
it
it
so
so
much
much
easier
easier
to
to
be
be
confident
confident
that
that
a
a
complex
complex
set
set
of
of
security
security
rules
rules
are
are
working
working
the
the
way
way
that
that
they
they
should.
should
I'm
i'm
gonna
gonna
go
go
ahead
ahead
and
and
set
set
this
this
project
project
up
up
with
with
just
just
vanilla
vanilla
JavaScript
javascript
and
and
Jest
jest
as
as
the
the
testing
testing
library.
library
The
the
reason
reason
I
i
choose
choose
Jest
jest
is
is
because
because
it's
it's
very
very
developer
developer
friendly,
friendly
and
and
also
also
really
really
good
good
at
at
testing
testing
asynchronous
asynchronous
code.
code
To
to
start
start
testing
testing
your
your
rules
rules
in
in
isolation,
isolation
I'd
i'd
recommend
recommend
starting
starting
from
from
a
a
brand
brand
new
new
directory,
directory
and
and
then
then
install
install
the
the
latest
latest
version
version
of
of
Firebase
firebase
Tools.
tools
Once
once
that's
that's
done,
done
you
you
can
can
run
run
Firebase
firebase
init
init
Firestore,
firestore
and
and
that
that
will
will
pull
pull
in
in
your
your
existing
existing
security
security
rules
rules
from
from
whichever
whichever
project
project
you
you
select.
select
From
from
there,
there
you
you
can
can
run
run
npm
npm
init
init
to
to
set
set
up
up
a
a
package
package
JSON
json
in
in
this
this
folder.
folder
Then
then
after
after
that,
that
we
we
can
can
install
install
our
our
testing
testing
utilities,
utilities
which
which
include
include
Firebase
firebase
testing
testing
and
and
Jest.
jest
That'll
that'll
give
give
us
us
a
a
directory
directory
structure
structure
that
that
looks
looks
something
something
like
like
this.
this
I've
i've
also
also
created
created
a
a
spec
spec
folder
folder
that
that
includes
includes
our
our
testing
testing
files.
files
All
all
of
of
our
our
testing
testing
code
code
will
will
be
be
written
written
there,
there
then
then
the
the
thing
thing
we're
we're
actually
actually
testing
testing
is
is
this
this
Firestore
firestore
rules
rules
file.
file
If
if
you're
you're
not
not
already
already
familiar
familiar
with
with
Firestore
firestore
security
security
rules,
rules
I
i
recommend
recommend
checking
checking
out
out
Episode
episode
92
92
where
where
I
i
teach
teach
you
you
all
all
about
about
rules
rules
and
and
how
how
to
to
hack
hack
a
a
Firebase
firebase
app.
app
And
and
one
one
additional
additional
pro
pro
tip
tip
I
i
have
have
for
for
you
you
here
here
is
is
to
to
install
install
the
the
Firebase
firebase
Security
security
Rules
rules
plugin
plugin
for
for
Versus
versus
Code
code
to
to
get
get
syntax
syntax
highlighting
highlighting
and
and
autocomplete
autocomplete
while
while
you
you
write
write
out
out
your
your
rules.
rules
Now
now
there
there
are
are
a
a
few
few
additional
additional
steps
steps
to
to
install
install
the
the
emulator.
emulator
You
you
can
can
do
do
it
it
directly
directly
from
from
the
the
command
command
line
line
with
with
the
the
directions
directions
here,
here
or
or
you
you
can
can
install
install
the
the
Java
java
JAR
jar
file
file
directly.
directly
You'll
you'll
probably
probably
wanna
wanna
go
go
with
with
the
the
command
command
line
line
option,
option
but
but
in
in
either
either
case,
case
you
you
need
need
to
to
have
have
Java
java
installed
installed
on
on
your
your
system.
system
If
if
JAWA
jawa
is
is
not
not
already
already
on
on
your
your
system,
system
head
head
over
over
to
to
their
their
super
super
modern
modern
website
website
and
and
get
get
it
it
installed
installed
today.
today
Now
now
I
i
wanna
wanna
show
show
you
you
what
what
a
a
basic
basic
test
test
run
run
will
will
look
look
like.
like
We
we
have
have
2
2
terminal
terminal
windows
windows
set
set
up
up
here.
here
On
on
the
the
left
left
side
side
we'll
we'll
go
go
ahead
ahead
and
and
run
run
the
the
emulator,
emulator
which
which
we
we
can
can
do
do
with
with
Firebase
firebase
serve
serve
only
only
Firestore.
firestore
That
that
will
will
run
run
the
the
local
local
emulator
emulator
in
in
the
the
ground,
ground
you
you
really
really
just
just
need
need
to
to
keep
keep
this
this
in
in
mind
mind
for
for
debugging
debugging
if
if
it's
it's
not
not
behaving
behaving
the
the
way
way
you
you
expect.
expect
Then
then
on
on
the
the
right
right
side,
side
we
we
can
can
run
run
the
the
jess
jess
command
command
to
to
run
run
our
our
actual
actual
specs.
specs
Now
now
I've
i've
been
been
working
working
with
with
the
the
emulator
emulator
for
for
a
a
couple
couple
days
days
now,
now
and
and
I
i
want
want
to
to
start
start
this
this
video
video
off
off
by
by
giving
giving
you
you
some
some
helpers
helpers
that
that
will
will
just
just
make
make
your
your
test
test
easier
easier
to
to
write.
write
And
and
also
also
just
just
to
to
warn
warn
you,
you
we're
we're
going
going
to
to
be
be
writing
writing
a
a
lot
lot
of
of
async
async
functions,
functions
so
so
if
if
you
you
haven't
haven't
seen
seen
the
the
AsyncAwait
asyncawait
video,
video
make
make
sure
sure
to
to
check
check
that
that
out
out
as
as
well.
well
The
the
first
first
helper
helper
function
function
is
is
called
called
setup,
setup
and
and
this
this
will
will
create
create
an
an
instance
instance
of
of
the
the
emulated
emulated
Firestore
firestore
data
data
It
it
also
also
has
has
the
the
option
option
to
to
take
take
an
an
auth
auth
object,
object
which
which
will
will
create
create
a
a
fake
fake
user
user
and
and
also
also
mock
mock
data
data
that
that
will
will
be
be
written
written
to
to
the
the
database
database
when
when
it's
it's
initialized.
initialized
Every
every
time
time
you
you
initialize
initialize
a
a
test
test
database,
database
you'll
you'll
want
want
to
to
give
give
it
it
a
a
unique
unique
project
project
ID.
id
You
you
can
can
do
do
this
this
easily
easily
by
by
just
just
making
making
your
your
project
project
ID
id
a
a
random
random
number
number
or
or
a
a
date
date
timestamp.
timestamp
From
from
this
this
point,
point
you'll
you'll
want
want
to
to
go
go
ahead
ahead
and
and
call
call
Firebase
firebase
Initialize
initialize
Test
test
App.
app
It's
it's
important
important
to
to
note
note
that
that
when
when
you
you
initialize
initialize
the
the
app
app
for
for
the
the
first
first
time,
time
it
it
will
will
not
not
have
have
any
any
security
security
rules
rules
applied
applied
to
to
it.
it
This
this
is
is
actually
actually
very
very
useful
useful
because
because
we
we
can
can
seed
seed
the
the
database
database
with
with
some
some
mock
mock
data
data
before
before
the
the
rules
rules
are
are
applied
applied
to
to
it.
it
And
and
you
you
can
can
also
also
provide
provide
a
a
user
user
context,
context
which
which
would
would
just
just
be
be
an
an
object
object
with
with
a
a
user
user
ID
id
that
that
you
you
could
could
then
then
use
use
to
to
test
test
your
your
rules.
rules
The
the
way
way
that
that
I
i
see
see
the
the
database
database
is
is
I
i
provide
provide
a
a
data
data
object
object
where
where
every
every
key
key
in
in
that
that
object
object
is
is
the
the
path
path
to
to
the
the
document
document
and
and
then
then
the
the
value
value
is
is
the
the
data
data
that
that
we
we
wanna
wanna
write
write
to
to
the
the
database.
database
This
this
makes
makes
it
it
really
really
easy
easy
to
to
see
see
the
the
database
database
because
because
we
we
can
can
just
just
loop
loop
over
over
keys
keys
in
in
that
that
object
object
and
and
then
then
write
write
the
the
data
data
to
to
their
their
corresponding
corresponding
paths.
paths
Now
now
that
that
we
we
have
have
the
the
mock
mock
data
data
seeded
seeded
in
in
the
the
database,
database
we'll
we'll
go
go
ahead
ahead
and
and
apply
apply
the
the
security
security
rules.
rules
That
that
can
can
be
be
done
done
by
by
calling
calling
loadFirestoreRules,
loadfirestorerules
and
and
then
then
we'll
we'll
want
want
to
to
use
use
the
the
file
file
system
system
to
to
point
point
to
to
the
the
actual
actual
raw
raw
rules
rules
file.
file
And
and
finally,
finally
we'll
we'll
return
return
the
the
actual
actual
database
database
instance
instance
from
from
this
this
method
method
so
so
we
we
can
can
use
use
it
it
throughout
throughout
our
our
specs.
specs
So
so
now
now
that
that
we
we
have
have
our
our
setup
setup
done,
done
I'm
i'm
also
also
going
going
to
to
Support
support
a
a
function
function
called
called
teardown,
teardown
which
which
will
will
just
just
look
look
for
for
all
all
the
the
Firebase
firebase
apps
apps
that
that
were
were
created
created
on
on
this
this
test
test
run
run
and
and
then
then
delete
delete
them
them
once
once
the
the
tests
tests
are
are
finished.
finished
So
so
those
those
should
should
make
make
your
your
life
life
a
a
lot
lot
easier.
easier
Now
now
let's
let's
look
look
at
at
how
how
we
we
can
can
use
use
them
them
in
in
an
an
actual
actual
test.
test
You
you
typically
typically
want
want
your
your
database
database
to
to
be
be
secure
secure
by
by
default,
default
which
which
means
means
that
that
you'll
you'll
have
have
allow
allow
read
read
and
and
write
write
if
if
false
false
at
at
the
the
very
very
top
top
level
level
of
of
the
the
database.
database
This
this
means
means
that
that
all
all
paths
paths
are
are
locked
locked
down
down
by
by
default
default
unless
unless
you
you
specifically
specifically
allow
allow
test
test
to
to
them.
them
Let's
let's
go
go
ahead
ahead
and
and
test
test
if
if
this
this
actually
actually
works
works
by
by
first
first
importing
importing
our
our
setup
setup
and
and
teardown
teardown
methods.
methods
Then
then
Firebase
firebase
provides
provides
us
us
with
with
2
2
testing
testing
utilities
utilities
that
that
we
we
can
can
use
use
to
to
determine
determine
whether
whether
or
or
not
not
Operation
operation
was
was
successful
successful
or
or
failed.
failed
The
the
first
first
thing
thing
we'll
we'll
do
do
is
is
describe
describe
our
our
Test
test
Suite,
suite
which
which
is
is
just
just
our
our
database
database
rules.
rules
Then
then
we'll
we'll
declare
declare
the
the
database
database
as
as
a
a
global
global
variable
variable
that
that
can
can
reuse
reuse
throughout
throughout
the
the
tests.
tests
Then
then
we
we
can
can
use
use
the
the
before
before
all
all
hook
hook
to
to
define
define
the
the
database
database
with
with
our
our
setup
setup
method
method
that
that
we
we
define
define
in
in
the
the
helpers
helpers
file.
file
The
the
thing
thing
we
we
actually
actually
want
want
to
to
test
test
here
here
is
is
that
that
our
our
database
database
is
is
secure
secure
by
by
default.
default
So
so
if
if
we
we
try
try
to
to
read
read
or
or
write
write
to
to
any
any
random
random
collection,
collection
it
it
should
should
give
give
us
us
a
a
permission
permission
denied
denied
error.
error
And
and
after
after
all
all
the
the
test
test
run,
run
we'll
we'll
also
also
want
want
to
to
run
run
our
our
teardown
teardown
method
method
to
to
delete
delete
those
those
App
app
instances.
instances
In
in
Jest,
jest
you
you
can
can
write
write
a
a
test
test
by
by
using
using
the
the
test
test
method
method
and
and
then
then
describing
describing
what
what
Your
your
testing
testing
in
in
this
this
case,
case
the
the
operation
operation
should
should
fail
fail
when
when
reading
reading
or
or
writing
writing
to
to
an
an
unauthorized
unauthorized
collection.
collection
So
so
there
there
are
are
a
a
few
few
different
different
ways
ways
to
to
write
write
your
your
will
will
test
test
and
and
this
this
really
really
just
just
boils
boils
down
down
to
to
the
the
developer's
developer's
preference.
preference
I
i
would
would
definitely
definitely
recommend
recommend
making
making
this
this
an
an
async
async
function
function
if
if
you
you
like
like
readable
readable
code.
code
Then
then
the
the
Firebase
firebase
assertion
assertion
helpers
helpers
will
will
take
take
a
a
Promise
promise
as
as
their
their
argument
argument
such
such
as
as
a
a
document
document
read.
read
If
if
the
the
read
read
is
is
blocked
blocked
by
by
security
security
rules
rules
in
in
this
this
case,
case
then
then
this
this
Promise
promise
will
will
resolve.
resolve
But
but
if
if
the
the
read
read
is
is
successful,
successful
then
then
the
the
Promise
promise
will
will
be
be
rejected.
rejected
All
all
we
we
have
have
to
to
do
do
is
is
add
add
the
the
result
result
to
to
an
an
expectation
expectation
and
and
our
our
first
first
test
test
is
is
completed.
completed
If
if
you
you
want
want
to
to
make
make
your
your
code
code
even
even
more
more
concise,
concise
you
you
can
can
actually
actually
just
just
inline
inline
the
the
await
await
statement
statement
directly
directly
in
in
the
the
expectation.
expectation
That'll
that'll
give
give
you
you
a
a
nice
nice
and
and
concise
concise
single
single
line
line
test,
test
But
but
these
these
get
get
very
very
hard
hard
to
to
read
read
as
as
your
your
tests
tests
get
get
more
more
complex.
complex
I'm
i'm
gonna
gonna
give
give
you
you
one
one
more
more
option
option
here,
here
which
which
is
is
slightly
slightly
more
more
advanced,
advanced
and
and
that's
that's
creating
creating
your
your
own
own
custom
custom
matcher
matcher
with
with
Jest.
jest
What
what
we
we
can
can
do
do
is
is
pass
pass
our
our
read
read
directly
directly
into
into
expect,
expect
and
and
then
then
we
we
can
can
resolve
resolve
it
it
as
as
a
a
custom
custom
matcher
matcher
that
that
will
will
either
either
be
be
to
to
deny
deny
or
or
to
to
allow.
allow
Basically,
basically
every
every
test
test
that
that
you
you
write
write
will
will
be
be
checking
checking
whether
whether
or
or
not
not
a
a
document
document
operation
operation
was
was
denied
denied
or
or
allowed.
allowed
So
so
having
having
a
a
custom
custom
matcher
matcher
here
here
is
is
super
super
useful
useful
because
because
it
it
not
not
only
only
keeps
keeps
your
your
code
code
Size
size
but
but
also
also
readable.
readable
Let's
let's
go
go
ahead
ahead
and
and
switch
switch
back
back
to
to
our
our
helpers
helpers
file
file
and
and
then
then
I'm
i'm
going
going
to
to
write
write
expect
expect
extend
extend
and
and
provide
provide
it
it
with
with
an
an
async
async
function
function
called
called
to
to
allow.
allow
The
the
x
x
argument
argument
to
to
this
this
function
function
is
is
whatever
whatever
you
you
pass
pass
to
to
the
the
expectation,
expectation
which
which
should
should
be
be
a
a
Firebase
firebase
Promise.
promise
For
for
example,
example
reading
reading
or
or
writing
writing
a
a
certain
certain
path
path
in
in
the
the
database.
database
We
we
will
will
try
try
to
to
resolve
resolve
the
the
Promise.
promise
And
and
if
if
it
it
resolves,
resolves
we
we
know
know
that
that
the
the
test
test
should
should
pass.
pass
Otherwise,
otherwise
we're
we're
going
going
to
to
have
have
the
the
test
test
fail.
fail
Then
then
from
from
the
the
custom
custom
assertion,
assertion
you
you
just
just
need
need
to
to
return
return
an
an
object
object
that
that
has
has
a
a
pass
pass
value,
value
which
which
should
should
either
either
be
be
true
true
or
or
false,
false
and
and
then
then
a
a
message,
message
which
which
is
is
a
a
function
function
that
that
returns
returns
a
a
string.
string
And
and
keep
keep
in
in
mind
mind
that
that
this
this
message
message
will
will
only
only
be
be
shown
shown
if
if
the
the
test
test
fails.
fails
So
so
now
now
we
we
have
have
a
a
Matcher
matcher
that
that
will
will
fail
fail
if
if
the
the
database
database
read
read
or
or
write
write
is
is
blocked
blocked
by
by
Firebase
firebase
rules.
rules
Then
then
we'll
we'll
also
also
want
want
to
to
create
create
an
an
inverse
inverse
matcher
matcher
to
to
check
check
if
if
a
a
Firebase
firebase
rule
rule
is
is
allowed
allowed
when
when
it
it
should
should
have
have
been
been
denied.
denied
So
so
we'll
we'll
say
say
to
to
deny
deny
and
and
just
just
check
check
with
with
the
the
assert
assert
fails
fails
method
method
from
from
Firebase.
firebase
You
you
can
can
use
use
whatever
whatever
testing
testing
methods
methods
you
you
want,
want
but
but
I'll
i'll
be
be
using
using
my
my
custom
custom
matchers
matchers
throughout
throughout
this
this
lesson.
lesson
Now
now
I'm
i'm
going
going
to
to
open
open
up
up
our
our
comment
comment
spec,
spec
which
which
defines
defines
the
the
rules
rules
for
for
our
our
comments
comments
collection.
collection
And
and
in
in
this
this
particular
particular
app,
app
a
a
user
user
needs
needs
to
to
be
be
authenticated
authenticated
to
to
View
view
Comments.
comments
And
and
when
when
writing
writing
a
a
comment,
comment
it
it
must
must
have
have
a
a
user
user
ID
id
that
that
matches
matches
the
the
auth
auth
user
user
ID.
id
If
if
we
we
look
look
at
at
the
the
actual
actual
rules
rules
logic,
logic
you
you
can
can
see
see
we're
we're
allowing
allowing
reads
reads
if
if
the
the
request
request
auth
auth
UID
uid
does
does
not
not
equal
equal
null.
null
And
and
then
then
we're
we're
allowing
allowing
rights
rights
if
if
the
the
UID
uid
is
is
equal
equal
to
to
the
the
request
request
resource
resource
data
data
user
user
ID.
id
In
in
other
other
words,
words
the
the
document
document
that
that
the
the
user
user
is
is
trying
trying
to
to
write
write
to
to
the
the
database
database
has
has
the
the
Same
same
user
user
ID
id
as
as
the
the
actual
actual
authentication
authentication
object
object
user
user
ID.
id
Ensuring
ensuring
that
that
these
these
rights
rights
fail
fail
is
is
pretty
pretty
easy.
easy
All
all
we
we
have
have
to
to
do
do
is
is
set
set
up
up
the
the
database
database
with
with
an
an
unauthenticated
unauthenticated
user.
user
And
and
then
then
we
we
can
can
make
make
a
a
reference
reference
to
to
our
our
collection
collection
and
and
expect
expect
that
that
that
that
read
read
or
or
write
write
is
is
denied.
denied
But
but
it's
it's
even
even
more
more
important
important
that
that
we
we
verify
verify
that
that
the
the
operations
operations
are
are
allowed
allowed
when
when
the
the
user
user
has
has
the
the
proper
proper
credentials.
credentials
So
so
this
this
time,
time
we'll
we'll
set
set
up
up
our
our
database
database
with
with
an
an
auth
auth
object
object
has
has
a
a
user
user
ID
id
and
and
an
an
email
email
address.
address
This
this
time,
time
we'll
we'll
expect
expect
the
the
reads
reads
to
to
be
be
allowed
allowed
because
because
we
we
have
have
a
a
user
user
that's
that's
logged
logged
in.
in
I
i
currently
currently
have
have
my
my
test
test
running
running
in
in
Watch
watch
mode.
mode
So
so
you
you
can
can
see
see
here
here
if
if
we
we
switch
switch
out
out
the
the
Matcher
matcher
that
that
the
the
test
test
will
will
fail
fail
if
if
we
we
expect
expect
this
this
to
to
be
be
denied.
denied
Now
now
when
when
writing
writing
to
to
the
the
database,
database
we'll
we'll
expect
expect
the
the
right
right
to
to
succeed
succeed
if
if
the
the
user
user
sends
sends
an
an
object
object
that
that
has
has
the
the
corresponding
corresponding
user
user
ID.
id
So
so
we
we
would
would
expect
expect
this
this
add
add
operation
operation
to
to
be
be
allowed
allowed
because
because
it
it
has
has
the
the
same
same
user
user
ID
id
as
as
the
the
auth
auth
UID.
uid
Then
then
we
we
can
can
add
add
another
another
line
line
here
here
that
that
tries
tries
to
to
add
add
an
an
item
item
to
to
the
the
database
database
with
with
a
a
different
different
user
user
ID
id
and
and
we'll
we'll
expect
expect
that
that
one
one
to
to
be
be
denied.
denied
So
so
that's
that's
how
how
you
you
test
test
basic
basic
user
user
authentication
authentication
logic.
logic
In
in
the
the
next
next
step,
step
we'll
we'll
look
look
at
at
how
how
we
we
can
can
see
see
the
the
database
database
with
with
mock
mock
data
data
and
and
handle
handle
things
things
like
like
role
role
based
based
access
access
control.
control
Now
now
going
going
back
back
to
to
our
our
rules,
rules
have
have
a
a
function
function
here
here
called
called
GetUserData,
getuserdata
which
which
will
will
read
read
a
a
document
document
in
in
the
the
user's
user's
collection
collection
in
in
the
the
database.
database
So
so
in
in
order
order
to
to
test
test
this
this
function,
function
we'll
we'll
need
need
to
to
first
first
seed
seed
our
our
database
database
with
with
some
some
mock
mock
data
data
for
for
the
the
user.
user
Then
then
in
in
that
that
document,
document
we'll
we'll
have
have
an
an
object
object
that
that
has
has
different
different
roles
roles
that
that
the
the
user
user
can
can
have
have
such
such
as
as
an
an
admin
admin
role.
role
So
so
now
now
in
in
our
our
Projects
projects
collection,
collection
we
we
can
can
see
see
if
if
the
the
user
user
has
has
this
this
admin
admin
role.
role
And
and
if
if
they
they
do,
do
we'll
we'll
allow
allow
access.
access
And
and
then
then
we
we
could
could
also
also
do
do
the
the
inverse
inverse
of
of
this
this
and
and
have
have
the
the
actual
actual
document
document
self
self
define
define
who
who
has
has
access.
access
In
in
that
that
case,
case
we
we
would
would
be
be
building
building
an
an
Access
access
Control
control
List
list
and
and
we
we
would
would
check
check
if
if
the
the
Resource
resource
data
data
has
has
any
any
members
members
with
with
the
the
current
current
auth
auth
user
user
ID.
id
So
so
essentially,
essentially
we
we
have
have
one
one
rule
rule
here
here
that
that
defines
defines
logic
logic
for
for
Role
role
Based
based
Access
access
Control
control
and
and
also
also
Access
access
Control
control
Lists.
lists
The
the
last
last
thing
thing
I
i
wanna
wanna
show
show
you
you
is
is
how
how
to
to
set
set
up
up
the
the
mock
mock
data.
data
We
we
defined
defined
this
this
earlier
earlier
in
in
the
the
setup
setup
function,
function
and
and
we're
we're
going
going
to
to
create
create
an
an
object
object
where
where
each
each
key
key
in
in
that
that
object
object
is
is
the
the
path
path
to
to
the
the
document.
document
Then
then
its
its
value
value
is
is
the
the
object
object
that
that
we
we
want
want
to
to
write
write
to
to
the
the
database.
database
For
for
example,
example
we
we
might
might
have
have
a
a
user
user
that
that
has
has
an
an
admin
admin
role
role
Or
or
you
you
might
might
have
have
a
a
project
project
that
that
has
has
an
an
access
access
control
control
list
list
with
with
a
a
certain
certain
user
user
in
in
it.
it
Now
now
when
when
we
we
set
set
up
up
the
the
database,
database
we
we
can
can
add
add
the
the
argument
argument
as
as
the
the
authenticated
authenticated
user
user
and
and
then
then
the
the
second
second
argument
argument
will
will
be
be
the
the
mock
mock
data
data
object.
object
That
that
will
will
automatically
automatically
seed
seed
our
our
database
database
with
with
the
the
required
required
data
data
and
and
then
then
we
we
can
can
test
test
it
it
in
in
relation
relation
to
to
the
the
authenticated
authenticated
user.
user
Then
then
the
the
remaining
remaining
test
test
will
will
look
look
basically
basically
the
the
same
same
as
as
they've
they've
looked
looked
in
in
the
the
past.
past
We'll
we'll
try
try
to
to
do
do
a
a
read
read
or
or
write
write
operation
operation
and
and
then
then
see
see
if
if
it's
it's
denied
denied
or
or
allowed.
allowed
So
so
just
just
to
to
wrap
wrap
things
things
up,
up
writing
writing
solid
solid
security
security
rules
rules
is
is
essential
essential
to
to
securing
securing
your
your
Firebase
firebase
app.
app
I'm
i'm
super
super
excited
excited
about
about
the
the
emulator
emulator
because
because
makes
makes
testing
testing
rules
rules
much
much
easier
easier
and
and
reliable
reliable
especially
especially
when
when
you're
you're
dealing
dealing
with
with
a
a
big
big
complex
complex
app.
app
I'm
i'm
gonna
gonna
go
go
ahead
ahead
and
and
wrap
wrap
the
the
video
video
up
up
there.
there
If
if
it
it
helped
helped
you,
you
like
like
and
and
Subscribe
subscribe
and
and
if
if
you
you
want
want
to
to
take
take
your
your
development
development
to
to
the
the
next
next
level
level
consider
consider
becoming
becoming
a
a
pro
pro
member
member
at
at
angularfirebase.com.
angularfirebase.com
You'll
you'll
get
get
access
access
to
to
all
all
kinds
kinds
of
of
exclusive
exclusive
resources
resources
designed
designed
to
to
help
help
you
you
build
build
and
and
Ship
ship
your
your
app
app
faster.
faster
Thanks
thanks
for
for
watching,
watching
and
and
I'll
i'll
talk
talk
to
to
you
you
soon.
soon
success
The upcoming release of centers has new features including a local emulator for Fire Store and real time database, Project Management API, and a test file. The security of the database is recommended defaulting to it. The speaker explains how to run a test database and how to use the test command to run the specs, as well as how to create a test run and check operation validity. They also give a tutorial on securing developers with secure code and setting up a custom matcher for a file.
Firestore Rules Testing with the Emulator - New Feature
Firebase Summit wrapped up a few days ago, and although I wasn't able to make it in person, they did announce a bunch of cool new features. The feature that is most exciting to me is the local emulator for Fire Store and the real time database. The emulators allow you to run an instance of your database locally, meaning you can build up a test suite around your security rules. This not only speeds up development time, but it So increases the integrity of your back end security. In today's video you'll learn how to set up the emulator and build out a full test suite using Jest. If you're new here like and subscribe, and make sure to grab the full source code from angularfirebase.com. Now before we get going with the emulator, I'd also like to point out that Firebase announced a new Project Management API. This API makes it possible for apps to manage Firebase projects of other users. For example, you can now deploy your Firebase projects directly from StackBlitz or Glitch, but the more exciting thing going on there is that you can use this project management API to build your own apps that do the exact same thing. So let me know in the comments if you want to see that covered in a future video. So now let's get started talking about the emulator. The emulator just runs Firestore or the Realtime Database locally on your machine. This means you can now simulate interaction with the database without actually having to run it in the cloud. This makes it so much easier to be confident that a complex set of security rules are working the way that they should. I'm gonna go ahead and set this project up with just vanilla JavaScript and Jest as the testing library. The reason I choose Jest is because it's very developer friendly, and also really good at testing asynchronous code. To start testing your rules in isolation, I'd recommend starting from a brand new directory, and then install the latest version of Firebase Tools. Once that's done, you can run Firebase init Firestore, and that will pull in your existing security rules from whichever project you select. From there, you can run npm init to set up a package JSON in this folder. Then after that, we can install our testing utilities, which include Firebase testing and Jest. That'll give us a directory structure that looks something like this. I've also created a spec folder that includes our testing files. All of our testing code will be written there, then the thing we're actually testing is this Firestore rules file. If you're not already familiar with Firestore security rules, I recommend checking out Episode 92 where I teach you all about rules and how to hack a Firebase app. And one additional pro tip I have for you here is to install the Firebase Security Rules plugin for Versus Code to get syntax highlighting and autocomplete while you write out your rules. Now there are a few additional steps to install the emulator. You can do it directly from the command line with the directions here, or you can install the Java JAR file directly. You'll probably wanna go with the command line option, but in either case, you need to have Java installed on your system. If JAWA is not already on your system, head over to their super modern website and get it installed today. Now I wanna show you what a basic test run will look like. We have 2 terminal windows set up here. On the left side we'll go ahead and run the emulator, which we can do with Firebase serve only Firestore. That will run the local emulator in the ground, you really just need to keep this in mind for debugging if it's not behaving the way you expect. Then on the right side, we can run the jess command to run our actual specs. Now I've been working with the emulator for a couple days now, and I want to start this video off by giving you some helpers that will just make your test easier to write. And also just to warn you, we're going to be writing a lot of async functions, so if you haven't seen the AsyncAwait video, make sure to check that out as well. The first helper function is called setup, and this will create an instance of the emulated Firestore data It also has the option to take an auth object, which will create a fake user and also mock data that will be written to the database when it's initialized. Every time you initialize a test database, you'll want to give it a unique project ID. You can do this easily by just making your project ID a random number or a date timestamp. From this point, you'll want to go ahead and call Firebase Initialize Test App. It's important to note that when you initialize the app for the first time, it will not have any security rules applied to it. This is actually very useful because we can seed the database with some mock data before the rules are applied to it. And you can also provide a user context, which would just be an object with a user ID that you could then use to test your rules. The way that I see the database is I provide a data object where every key in that object is the path to the document and then the value is the data that we wanna write to the database. This makes it really easy to see the database because we can just loop over keys in that object and then write the data to their corresponding paths. Now that we have the mock data seeded in the database, we'll go ahead and apply the security rules. That can be done by calling loadFirestoreRules, and then we'll want to use the file system to point to the actual raw rules file. And finally, we'll return the actual database instance from this method so we can use it throughout our specs. So now that we have our setup done, I'm also going to Support a function called teardown, which will just look for all the Firebase apps that were created on this test run and then delete them once the tests are finished. So those should make your life a lot easier. Now let's look at how we can use them in an actual test. You typically want your database to be secure by default, which means that you'll have allow read and write if false at the very top level of the database. This means that all paths are locked down by default unless you specifically allow test to them. Let's go ahead and test if this actually works by first importing our setup and teardown methods. Then Firebase provides us with 2 testing utilities that we can use to determine whether or not Operation was successful or failed. The first thing we'll do is describe our Test Suite, which is just our database rules. Then we'll declare the database as a global variable that can reuse throughout the tests. Then we can use the before all hook to define the database with our setup method that we define in the helpers file. The thing we actually want to test here is that our database is secure by default. So if we try to read or write to any random collection, it should give us a permission denied error. And after all the test run, we'll also want to run our teardown method to delete those App instances. In Jest, you can write a test by using the test method and then describing what Your testing in this case, the operation should fail when reading or writing to an unauthorized collection. So there are a few different ways to write your will test and this really just boils down to the developer's preference. I would definitely recommend making this an async function if you like readable code. Then the Firebase assertion helpers will take a Promise as their argument such as a document read. If the read is blocked by security rules in this case, then this Promise will resolve. But if the read is successful, then the Promise will be rejected. All we have to do is add the result to an expectation and our first test is completed. If you want to make your code even more concise, you can actually just inline the await statement directly in the expectation. That'll give you a nice and concise single line test, But these get very hard to read as your tests get more complex. I'm gonna give you one more option here, which is slightly more advanced, and that's creating your own custom matcher with Jest. What we can do is pass our read directly into expect, and then we can resolve it as a custom matcher that will either be to deny or to allow. Basically, every test that you write will be checking whether or not a document operation was denied or allowed. So having a custom matcher here is super useful because it not only keeps your code Size but also readable. Let's go ahead and switch back to our helpers file and then I'm going to write expect extend and provide it with an async function called to allow. The x argument to this function is whatever you pass to the expectation, which should be a Firebase Promise. For example, reading or writing a certain path in the database. We will try to resolve the Promise. And if it resolves, we know that the test should pass. Otherwise, we're going to have the test fail. Then from the custom assertion, you just need to return an object that has a pass value, which should either be true or false, and then a message, which is a function that returns a string. And keep in mind that this message will only be shown if the test fails. So now we have a Matcher that will fail if the database read or write is blocked by Firebase rules. Then we'll also want to create an inverse matcher to check if a Firebase rule is allowed when it should have been denied. So we'll say to deny and just check with the assert fails method from Firebase. You can use whatever testing methods you want, but I'll be using my custom matchers throughout this lesson. Now I'm going to open up our comment spec, which defines the rules for our comments collection. And in this particular app, a user needs to be authenticated to View Comments. And when writing a comment, it must have a user ID that matches the auth user ID. If we look at the actual rules logic, you can see we're allowing reads if the request auth UID does not equal null. And then we're allowing rights if the UID is equal to the request resource data user ID. In other words, the document that the user is trying to write to the database has the Same user ID as the actual authentication object user ID. Ensuring that these rights fail is pretty easy. All we have to do is set up the database with an unauthenticated user. And then we can make a reference to our collection and expect that that read or write is denied. But it's even more important that we verify that the operations are allowed when the user has the proper credentials. So this time, we'll set up our database with an auth object has a user ID and an email address. This time, we'll expect the reads to be allowed because we have a user that's logged in. I currently have my test running in Watch mode. So you can see here if we switch out the Matcher that the test will fail if we expect this to be denied. Now when writing to the database, we'll expect the right to succeed if the user sends an object that has the corresponding user ID. So we would expect this add operation to be allowed because it has the same user ID as the auth UID. Then we can add another line here that tries to add an item to the database with a different user ID and we'll expect that one to be denied. So that's how you test basic user authentication logic. In the next step, we'll look at how we can see the database with mock data and handle things like role based access control. Now going back to our rules, have a function here called GetUserData, which will read a document in the user's collection in the database. So in order to test this function, we'll need to first seed our database with some mock data for the user. Then in that document, we'll have an object that has different roles that the user can have such as an admin role. So now in our Projects collection, we can see if the user has this admin role. And if they do, we'll allow access. And then we could also do the inverse of this and have the actual document self define who has access. In that case, we would be building an Access Control List and we would check if the Resource data has any members with the current auth user ID. So essentially, we have one rule here that defines logic for Role Based Access Control and also Access Control Lists. The last thing I wanna show you is how to set up the mock data. We defined this earlier in the setup function, and we're going to create an object where each key in that object is the path to the document. Then its value is the object that we want to write to the database. For example, we might have a user that has an admin role Or you might have a project that has an access control list with a certain user in it. Now when we set up the database, we can add the argument as the authenticated user and then the second argument will be the mock data object. That will automatically seed our database with the required data and then we can test it in relation to the authenticated user. Then the remaining test will look basically the same as they've looked in the past. We'll try to do a read or write operation and then see if it's denied or allowed. So just to wrap things up, writing solid security rules is essential to securing your Firebase app. I'm super excited about the emulator because makes testing rules much easier and reliable especially when you're dealing with a big complex app. I'm gonna go ahead and wrap the video up there. If it helped you, like and Subscribe and if you want to take your development to the next level consider becoming a pro member at angularfirebase.com. You'll get access to all kinds of exclusive resources designed to help you build and Ship your app faster. Thanks for watching, and I'll talk to you soon.
The upcoming release of centers has new features including a local emulator for Fire Store and real time database, Project Management API, and a test file. The security of the database is recommended defaulting to it. The speaker explains how to run a test database and how to use the test command to run the specs, as well as how to create a test run and check operation validity. They also give a tutorial on securing developers with secure code and setting up a custom matcher for a file.

        [INST]
        You are youtuber called Fireship you make engaging high-intensity and entertaining coding tutorials and tech news. 
        you covers a wide range of topics relevant to programmers, aiming to help them learn and improve their skills quickly.
        
        Given the title of the video : Firestore Rules Testing with the Emulator - New Feature 
        and a small summary : The upcoming release of centers has new features including a local emulator for Fire Store and real time database, Project Management API, and a test file. The security of the database is recommended defaulting to it. The speaker explains how to run a test database and how to use the test command to run the specs, as well as how to create a test run and check operation validity. They also give a tutorial on securing developers with secure code and setting up a custom matcher for a file.
        [/INST]
        
        Generate the video : Firebase Summit wrapped up a few days ago, and although I wasn't able to make it in person, they did announce a bunch of cool new features. The feature that is most exciting to me is the local emulator for Fire Store and the real time database. The emulators allow you to run an instance of your database locally, meaning you can build up a test suite around your security rules. This not only speeds up development time, but it So increases the integrity of your back end security. In today's video you'll learn how to set up the emulator and build out a full test suite using Jest. If you're new here like and subscribe, and make sure to grab the full source code from angularfirebase.com. Now before we get going with the emulator, I'd also like to point out that Firebase announced a new Project Management API. This API makes it possible for apps to manage Firebase projects of other users. For example, you can now deploy your Firebase projects directly from StackBlitz or Glitch, but the more exciting thing going on there is that you can use this project management API to build your own apps that do the exact same thing. So let me know in the comments if you want to see that covered in a future video. So now let's get started talking about the emulator. The emulator just runs Firestore or the Realtime Database locally on your machine. This means you can now simulate interaction with the database without actually having to run it in the cloud. This makes it so much easier to be confident that a complex set of security rules are working the way that they should. I'm gonna go ahead and set this project up with just vanilla JavaScript and Jest as the testing library. The reason I choose Jest is because it's very developer friendly, and also really good at testing asynchronous code. To start testing your rules in isolation, I'd recommend starting from a brand new directory, and then install the latest version of Firebase Tools. Once that's done, you can run Firebase init Firestore, and that will pull in your existing security rules from whichever project you select. From there, you can run npm init to set up a package JSON in this folder. Then after that, we can install our testing utilities, which include Firebase testing and Jest. That'll give us a directory structure that looks something like this. I've also created a spec folder that includes our testing files. All of our testing code will be written there, then the thing we're actually testing is this Firestore rules file. If you're not already familiar with Firestore security rules, I recommend checking out Episode 92 where I teach you all about rules and how to hack a Firebase app. And one additional pro tip I have for you here is to install the Firebase Security Rules plugin for Versus Code to get syntax highlighting and autocomplete while you write out your rules. Now there are a few additional steps to install the emulator. You can do it directly from the command line with the directions here, or you can install the Java JAR file directly. You'll probably wanna go with the command line option, but in either case, you need to have Java installed on your system. If JAWA is not already on your system, head over to their super modern website and get it installed today. Now I wanna show you what a basic test run will look like. We have 2 terminal windows set up here. On the left side we'll go ahead and run the emulator, which we can do with Firebase serve only Firestore. That will run the local emulator in the ground, you really just need to keep this in mind for debugging if it's not behaving the way you expect. Then on the right side, we can run the jess command to run our actual specs. Now I've been working with the emulator for a couple days now, and I want to start this video off by giving you some helpers that will just make your test easier to write. And also just to warn you, we're going to be writing a lot of async functions, so if you haven't seen the AsyncAwait video, make sure to check that out as well. The first helper function is called setup, and this will create an instance of the emulated Firestore data It also has the option to take an auth object, which will create a fake user and also mock data that will be written to the database when it's initialized. Every time you initialize a test database, you'll want to give it a unique project ID. You can do this easily by just making your project ID a random number or a date timestamp. From this point, you'll want to go ahead and call Firebase Initialize Test App. It's important to note that when you initialize the app for the first time, it will not have any security rules applied to it. This is actually very useful because we can seed the database with some mock data before the rules are applied to it. And you can also provide a user context, which would just be an object with a user ID that you could then use to test your rules. The way that I see the database is I provide a data object where every key in that object is the path to the document and then the value is the data that we wanna write to the database. This makes it really easy to see the database because we can just loop over keys in that object and then write the data to their corresponding paths. Now that we have the mock data seeded in the database, we'll go ahead and apply the security rules. That can be done by calling loadFirestoreRules, and then we'll want to use the file system to point to the actual raw rules file. And finally, we'll return the actual database instance from this method so we can use it throughout our specs. So now that we have our setup done, I'm also going to Support a function called teardown, which will just look for all the Firebase apps that were created on this test run and then delete them once the tests are finished. So those should make your life a lot easier. Now let's look at how we can use them in an actual test. You typically want your database to be secure by default, which means that you'll have allow read and write if false at the very top level of the database. This means that all paths are locked down by default unless you specifically allow test to them. Let's go ahead and test if this actually works by first importing our setup and teardown methods. Then Firebase provides us with 2 testing utilities that we can use to determine whether or not Operation was successful or failed. The first thing we'll do is describe our Test Suite, which is just our database rules. Then we'll declare the database as a global variable that can reuse throughout the tests. Then we can use the before all hook to define the database with our setup method that we define in the helpers file. The thing we actually want to test here is that our database is secure by default. So if we try to read or write to any random collection, it should give us a permission denied error. And after all the test run, we'll also want to run our teardown method to delete those App instances. In Jest, you can write a test by using the test method and then describing what Your testing in this case, the operation should fail when reading or writing to an unauthorized collection. So there are a few different ways to write your will test and this really just boils down to the developer's preference. I would definitely recommend making this an async function if you like readable code. Then the Firebase assertion helpers will take a Promise as their argument such as a document read. If the read is blocked by security rules in this case, then this Promise will resolve. But if the read is successful, then the Promise will be rejected. All we have to do is add the result to an expectation and our first test is completed. If you want to make your code even more concise, you can actually just inline the await statement directly in the expectation. That'll give you a nice and concise single line test, But these get very hard to read as your tests get more complex. I'm gonna give you one more option here, which is slightly more advanced, and that's creating your own custom matcher with Jest. What we can do is pass our read directly into expect, and then we can resolve it as a custom matcher that will either be to deny or to allow. Basically, every test that you write will be checking whether or not a document operation was denied or allowed. So having a custom matcher here is super useful because it not only keeps your code Size but also readable. Let's go ahead and switch back to our helpers file and then I'm going to write expect extend and provide it with an async function called to allow. The x argument to this function is whatever you pass to the expectation, which should be a Firebase Promise. For example, reading or writing a certain path in the database. We will try to resolve the Promise. And if it resolves, we know that the test should pass. Otherwise, we're going to have the test fail. Then from the custom assertion, you just need to return an object that has a pass value, which should either be true or false, and then a message, which is a function that returns a string. And keep in mind that this message will only be shown if the test fails. So now we have a Matcher that will fail if the database read or write is blocked by Firebase rules. Then we'll also want to create an inverse matcher to check if a Firebase rule is allowed when it should have been denied. So we'll say to deny and just check with the assert fails method from Firebase. You can use whatever testing methods you want, but I'll be using my custom matchers throughout this lesson. Now I'm going to open up our comment spec, which defines the rules for our comments collection. And in this particular app, a user needs to be authenticated to View Comments. And when writing a comment, it must have a user ID that matches the auth user ID. If we look at the actual rules logic, you can see we're allowing reads if the request auth UID does not equal null. And then we're allowing rights if the UID is equal to the request resource data user ID. In other words, the document that the user is trying to write to the database has the Same user ID as the actual authentication object user ID. Ensuring that these rights fail is pretty easy. All we have to do is set up the database with an unauthenticated user. And then we can make a reference to our collection and expect that that read or write is denied. But it's even more important that we verify that the operations are allowed when the user has the proper credentials. So this time, we'll set up our database with an auth object has a user ID and an email address. This time, we'll expect the reads to be allowed because we have a user that's logged in. I currently have my test running in Watch mode. So you can see here if we switch out the Matcher that the test will fail if we expect this to be denied. Now when writing to the database, we'll expect the right to succeed if the user sends an object that has the corresponding user ID. So we would expect this add operation to be allowed because it has the same user ID as the auth UID. Then we can add another line here that tries to add an item to the database with a different user ID and we'll expect that one to be denied. So that's how you test basic user authentication logic. In the next step, we'll look at how we can see the database with mock data and handle things like role based access control. Now going back to our rules, have a function here called GetUserData, which will read a document in the user's collection in the database. So in order to test this function, we'll need to first seed our database with some mock data for the user. Then in that document, we'll have an object that has different roles that the user can have such as an admin role. So now in our Projects collection, we can see if the user has this admin role. And if they do, we'll allow access. And then we could also do the inverse of this and have the actual document self define who has access. In that case, we would be building an Access Control List and we would check if the Resource data has any members with the current auth user ID. So essentially, we have one rule here that defines logic for Role Based Access Control and also Access Control Lists. The last thing I wanna show you is how to set up the mock data. We defined this earlier in the setup function, and we're going to create an object where each key in that object is the path to the document. Then its value is the object that we want to write to the database. For example, we might have a user that has an admin role Or you might have a project that has an access control list with a certain user in it. Now when we set up the database, we can add the argument as the authenticated user and then the second argument will be the mock data object. That will automatically seed our database with the required data and then we can test it in relation to the authenticated user. Then the remaining test will look basically the same as they've looked in the past. We'll try to do a read or write operation and then see if it's denied or allowed. So just to wrap things up, writing solid security rules is essential to securing your Firebase app. I'm super excited about the emulator because makes testing rules much easier and reliable especially when you're dealing with a big complex app. I'm gonna go ahead and wrap the video up there. If it helped you, like and Subscribe and if you want to take your development to the next level consider becoming a pro member at angularfirebase.com. You'll get access to all kinds of exclusive resources designed to help you build and Ship your app faster. Thanks for watching, and I'll talk to you soon.
        