Transcript from the "Authentication Security Rules" Lesson
>> All right, so I'm going to show how we can have a better sort of development workflow with security rules and how we can actually do some testing with it. So I'm gonna cd into, what is it, 5-security-rules, cd start. Cd is not a command. I can't see my, all right, so let's code into that.
[00:00:28] All right, so, The way this works is that we have a Firebase rules testing library. So it's a library that's completely dedicated to making sure that your rules work the way that they should work. And then this right here, is I'm using a test framework called Ava. But the most important thing is that we have this method called initializeTestEnvironment.
[00:00:53] And this contains a ton of power. Because what it allows us to do is we just pass in a project ID, we use Node's readFileSync to read in our rules. We pass in where the emulator lives, so localhost and port 8080. And then now, look at that, we get to write tests that assert that our rules are going to be working in specific ways.
[00:01:16] So, in this case, and what's really cool is I can say, all right, I'm going to create an unauthenticated context. And so, that gives me a context where I have access to Firestore. And this uses a different, but similar API that does chaining. So you can call firestore.doc.
[00:01:32] And then you could say firestore.collection.doc. It's very jQuery-esque, for those of you who are like me and miss the old days of jQuery. And then what we can do is we have, stop covering up the boxes. We have, my gosh. We have assertFails, which is a test method provided by our library that says, hey, I wanna make sure that when I run this userDoc.set, that it fails because this is an unauthenticated user.
[00:01:59] It shouldn't happen. And then I have this little special thing I wrote to make it work with this test library that just says the result.code is permissioned to that. That's all that is. And so right now, where I write my rules, is I write them in this file.
[00:02:16] And I just have read true, write true. So that's not gonna work. And so what I'm gonna do first is I'm gonna run the emulators. So I'm gonna say, firebase emulators:start. And I'm only gonna run firestore, not function, sorry, firestore. Awesome, so now we're running Firestore. And I'm gonna open up another tab.
[00:02:40] And let's run a test. So I'm gonna say, npm test. And I have all these rules, and all ten of them failed. And we can see that this one rejects that said, hey, I expected this to fail but it succeeded. And this kind of information is so important.
[00:02:57] Because if you have a very important rules file, which all rules file rules are important, you wanna know that any change that you might make to them, might come cause a problem in your system. And this is exactly where you can do that. And so here, I can write rules and I can test the rules at the same time.
[00:03:17] So to kind of get a head-start on myself, I'm going to copy this, which we wrote previously. And just for reference, for those who are watching, when you create a firestore.rules file, it's gonna not have any syntax highlighting. This is really cool. It's a community-made one, but it's so good that we've just been able to use this as our recommended one.
[00:03:42] And you just install this into VSCode and you get nice syntax highlighting. And it even has a little bit of IntelliSense into it. It's really nice. So now, if I go and I run my rules again, nine tests failed. All right, great. So I'm working my way up.
[00:04:02] And so it's very TDD to do it this way, which is test-driven development. But I can write out these tests that say, these are the things that are most important for my app. And I actually find that writing security rules this way with TDD, I'm not a big TDD developer.
[00:04:19] I don't know if someone's gonna [SOUND], but I'm not a big TDD developer unless I'm writing security rules. Because it's really easy for me to map out all the requirements of my security rules. And then from there, I can start writing rules that satisfy those and makes me feel better that I'm getting everything in the right spot.
[00:04:40] So what I can do now is that I wanna say, okay, I've tested that an unauthenticated user fails to write to a profile. But I also wanna test to see if an authenticated user. So I'm gonna paste in similar code. And instead of calling an unauthenticatedContext, I'm gonna say testEnv.authenticatedContext.
[00:05:03] And this is going to be david_123. And so now we'll be logged in a mock way of this user. And so if I try to access user at david_123, instead of assertFails, I can say assertSucceeds. And then I think with this, the way this works is it returns void.
[00:05:24] Because successful ones don't throw any errors or anything, they just return void. So I can say, what is it, t.is (result, undefined). So now we save. Look at, eight tests failed. I'm just making my way up the tree. Every test-driven developer would be really happy with me.