Check out a free preview of the full Polyglot Programming: TypeScript, Go, & Rust course
The "Projector CLI App Testing in TypeScript" Lesson is part of the full, Polyglot Programming: TypeScript, Go, & Rust course featured in this preview video. Here's what you'd learn in this lesson:
ThePrimeagen demonstrates creating a series of tests for the TypeScript Projector CLI application. The tests check for the correct present working directory, restrictions on setting and deleting data, and the ability to retrieve data from various directory levels.
Transcript from the "Projector CLI App Testing in TypeScript" Lesson
[00:00:00]
>> So, let's create a nice test and do projector.ts. We're almost there. I know we're writing a lot of code. I feel like we're kinda crushing that out. Hopefully this feels good, I like nothing like a good code crashing time, right? My goodness, it's just the greatest. Hopefully all my ranting about not googling everything and memorizing everything is really showing here, right?
[00:00:20]
The more you just remember to do, the faster you get to move and the less flow you have to break. I feel like that's just what makes it, or at least what gives me a lot of speed advantage, is just simply I don't ever Google a lot of the basic stuff.
[00:00:35]
Cuz I took the time once, memorized a bunch of stuff, and now you can just kinda flow with it. And your LSP kind of can help fill in the gaps in the little places where you're like, is it strings or is it string, is it this or is it this?
[00:00:49]
And it just kinda does the rest for you. Anyways, enough of that nonsense, so let's do the testing, testing of course is gonna be pretty easy on this one I think. We'll import projector from, if you wanna guess, or form from projector, awesome. And so now we're just gonna create a series of tests that do this for us.
[00:01:08]
I am gonna do a little bit of abstraction because one thing I don't wanna have to do is create the same data object over and over again. So let's just do function createData, and this thing is just simply gonna return a padding. So we'll do slash, and this will have foo and bar1, awesome.
[00:01:26]
And we're gonna highlight this over here, add that, paste it in, over foo. I think this is gonna break but, yeah, it's definitely gonna break but it's kinda fun to see what happens. Now, let's just see what happens. Okay, nothing happened. Nothing happened. Okay, whatever, it doesn't matter.
[00:01:46]
I was gonna try to macro this output but then I realized you can't really do that. Let's also get rid of these leading slashes and just have three directories, there we go. We have /foo and foo bar. They each have one key and then we're gonna have one more.
[00:01:59]
We'll have fem : is_great. [LAUGH] Frontend Masters is great, look at that, it's right there on the roofs. Awesome, so we should be able to see these values, and we should be able to test that we can not only grab values from our directory. We can also grab values a few directories behind us, kind of set up all the possibilities.
[00:02:15]
I shouldn't be able to delete them if I'm in directory foo bar. I should be able to set the value, fem, in foo bar but not overwrite it in root, right? We should be able to have all these nice tests kinda pretty easy to do here. And of course, we should be able to have a function getProjector which simply should be returning, based on your present working directory, which is a string, should return out a projector, right?
[00:02:40]
So we'll just have that right away, should be pretty easy. New Projector, it's gonna take in a config, and it's gonna take in, of course, a data. So I can go getData, awesome, we'll just use that same generic data that we've been using. And so the config, of course, is gonna have args, right?
[00:02:57]
So what is the args? Well, it's not gonna matter to us because the args are how we're going to operate on the projector. So we don't actually need anything for the args. The operation, we don't need anything for the operation, right? The only thing that's really mattering is the present working directory right now.
[00:03:16]
If we actually somehow use the config, that would be bad. So the config, of course, we can also do hello Frontend Masters with the e not capitalized. They specifically told me they don't do that. There we go, it's not two words. Awesome, so now we have everything we need to do, apparently getData, createData.
[00:03:34]
I mean, it's technically more correct, but we'll do getData. All right, fantastic argument of this. Is not, yeah, of course not. It's really not. We forgot to do the top level key of projector. So let's just make sure we do that now. Awesome, so now we have the top level key.
[00:04:03]
We forgot to do that cuz it's not a data object, right? That thing was quacking like a duck, but it wasn't locked in like one. Classic draft problem right there. So let's start doing some testing right now. Should be pretty easy. We'll start with the getValueAll function, yeah, that seems right.
[00:04:22]
And let's do a quick function, do one of these. And now we just need to create the projector, add a specific path, and try to get all the values and make sure it gets the values we would expect. So of course const proj = getProjector, and I just want the present working directory of, let's do all the way in, /foo/bar.
[00:04:39]
Cuz we know for a fact /foo/bar should give us bar3, and it should also give us, fem: is_great. So let's go, expect(proj.getValueAll()).toEqual, is there a deepEqual? I think this this works, right? No longer needs that whole deepEqual thing. We should have fem which is_great and we should also have foo and should be bar3, if I'm not mistaken.
[00:05:05]
Yeah, I would say it's gonna be bar3, it's the third one. So if this works, everything should be great. Let's just run this test right now to make sure everything operates how we expect it to, we don't have any bugs. Awesome, we've done it. It turns out I have first tried this, we're gonna keep on going.
[00:05:25]
We're gonna keep first trying this all the way through the sky, it's gonna be fantastic. All right, so I'm gonna just copy that whole getValue. Let's do the exact same thing right here. Let's do getValue, but this time we're gonna have to do it a little bit different.
[00:05:38]
Let's go getValue, and I wanna test out foo, which should just return to me bar3, right? Awesome, so it should do that. And I'm gonna change this to a let, which means that, oopsies, that I should be able to reassign this at a different path and see bar2, correct?
[00:06:03]
I should also be able to get fem, and get this from our root directory, right? I should be able to kinda move ourselves around and do this and get all the correct stuff. Correct, everyone's kind of on board with that? That shows really the power that we're doing all the operations we want.
[00:06:21]
I feel like this is a fairly good test for this. All right, so let's set a value. Let's prove that we can set a value without overriding anything. So I'm gonna actually upgrade this little testing method to include data, and it's just gonna equal getData. So that way, I can provide the same data twice and see that I'm not mutating it in any sort of way that should not happen, right?
[00:06:46]
So let's just do data right here, fantastic. We are now passing in a data, and all of our previous ones won't break, due to the beauty of default arguments. All right, so let's set a value. We're gonna grab out a projector at foo bar. Let's go proj.setValue. And let's first override a value, let's do foo baz, yeah.
[00:07:07]
Hopefully everyone still is always okay with foo, bar, and baz. I like those values, I just find that they're pleasant to use. All right, so when I get this, I should expect to see baz, correct? I think that's the value we should expect, fantastic. So let's just run this one more time, see how we're doing.
[00:07:29]
My goodness, it just keeps on being a first try. It's the greatest moment of my life. And so that's better than my wedding day to be able to do this first try. So let's see if this happens. Hopefully, my wife will never listen to this. All right, so let's do that, everything's great.
[00:07:44]
And now what I should be able to do is also set one more value, right? I should be able to set, fem, is_better_than_great, right? And that should overwrite it at this location of /foo/bar, but shouldn't overwrite it at the root directory. And so we're going to kind of test that out.
[00:08:06]
So when I add one more data = getData, so I can hold on to this, pass in that data, set this value, awesome. I should be able to get that value and have it come right out, right, is_better_than_great, right? Prove that even though we have a value deeper in the tree or higher up in the tree, shallower in the tree.
[00:08:28]
I'm not sure which direction, depending on how you view what is upstream and downstream, should exist, awesome. So I'm just gonna recreate projector, proj = getProjector. And we're just gonna use slash, pass in data, and I should be able to expect this value is_great, correct. We did not overwrite anything.
[00:08:48]
We've properly kept the structure of this projector. Do this one last time. All right, let's do removeValue, awesome. So this should do the exact same thing, we should only remove from our directory and not directories below us. And this one can be done pretty straightforward, it should be pretty easy to be able to do.
[00:09:11]
So I'm just gonna go, const proj. And the first thing I'm gonna do is go proj.deleteValue, no, it's remove. It's removedValue, did I call it removeValue? I thought I had called it deleteValue. Anyway, it doesn't really matter. Let's remove fem. Now remember, fem is at the root directory or at /foo/bar, this should effectively produce nothing.
[00:09:32]
I should be able to get the value, and it should still be is_great, correct? Cuz we shouldn't be removing anything at our level. But we should be able to remove foo and grab foo, which will now become bar2. Because we have removed bar3 from our level, it should fall back.
[00:09:51]
I believe this will pretty much test most conditions that can happen inside of our projector program. And we've kept the state consistent cuz there is almost nothing worse than if you have a bunch of configuration and state gets messed up. It can be an emotionally challenging time. So I feel like it's very good to have some pretty strong tests around this.
[00:10:09]
Let's run the test. My goodness, my gracious, first time. Are we gonna do back-to-back first times? Now that's the real question. Will we get Go correct also? Jury's out. We don't know. Well, let's find out.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops