Setting Up Vitest0:05
In this lesson we're going to be testing our stores. Let's start by adding Vite test to our project. Then let's open up our vite.config.js at test and let's say globals through so we don't have to import, describe, et cetera. Let's open up package.json and let's add a test script where we say vite test. There we go. Let's get started with our cart. Let's go here and let's go to our stores. Let's create cart.php file. Alright, great.
Writing Store Tests0:29
Let's go here and let's go to our stores. Let's create cart.pack.js. Alright, great. Because we set global to true, we don't have to import, describe et cetera. So that's imported automatically for us. So we can just say describe cardStore. And there we go. Let's start with our first test. Let's say it is empty and in here we'll say const store equals useCardStore. Don't forget to import it.
and in here we'll say $store equals use CardStore. Don't forget to import it and we will expect $store those Card to equal an empty array. And we expect $store is empty to equal true. And if we run yarn test, we will be presented with an error because we didn't initialize pina and we get the error. getActive: pina was called but there was no active pina. To fix this, we need to initialize pina.
Initializing Pinia in Tests1:18
Get active. Pina was called but there was no active Pina. To fix this, we need to initialize Pina before every test as follows. We'll say beforeEach we'll set our active Pina to createPina and don't forget to import setActivePina from Pina and createPina from Pina as well. Now if you take a look at our tests, we'll see everything passes. Great. Next, let's test if you can add an item to the cart.
we'll see everything passes. Great. Next, let's test if you can add an item to the cart. It adds an item to the cart. We'll say $store equals use Cart::store(). Let's create a $productId. One $title testProduct enterprise of 10. Let's say $store->incrementProducts(). $products. And now we expect $store->cart to equal an array.
And now we expect or store cart to equal an array with an object that contains our product with a quantity of one. And we should see the test fail with an error to success is not a function. And this makes sense because we didn't initialize Pia with our plugin. So let's fix that now we'll say const penia = createPenia.
Mounting Pinia Plugins2:37
So let's fix that now we'll say const penia equals createPenia. And in here we'll pass our instance and then we'll say Penia use and we'll say our toast plugin. Now forget to import it. And now you would assume everything works but our test still fails. And this is a bit of a caveat with PIA, I'm working with plugins. Plugins only get initialized if PIA is
with plugins. Plugins only get initialized if PIA is mounted in a view app. So to make this work we need to create a dummy app to mount PIA into. Outside of our describe function, we'll say const app equals createApp({}) and we will have to import createApp from vue. In our beforeEach function we can say app.use(PIA) and we can always reference the same app instance.
In our beforeEach function we can say app use Pina and we can always reference the same app instance. We don't need to recreate it every time. And now we'll see or test passes create. Let's add a new test which adds two identical products to the card. And let's test that. A quantity updates, I'll make some more space here. Let's say it updates the quantity of existing products.
Let's say it updates the quantity of existing products. We'll say $store equals use Cart store. Store::increment product. We'll add our product and let's actually just ya this out and let's put it here. And there we go. And let's say the quantity is 2 and we'll expect $store to equal an array with a single object with our product and a quantity of 2 and we'll see our test passes.
an array with a single object with our product and a quantity of two and we'll see or test passes. Let's do the same for Decrementing a product, let's say it decrements a product store equals USCardStore, storeIncrementProduct, product two and I will say decrementProducts by one. So we'll have one product in our cart and let's expect storeCart to equal an array with a single object product with a quantity of one.
and let's expect store cart to equal an array with a single object product with a quantity of one and we'll see our test pass. Let's also test to see if we can remove a product. We'll take our store, we'll say store increment product, productTwo, then we'll say store remove products with product and we expect store.isEmpty to equal true. And we'll see our test pass. Great. Now let's add some tests for our subtotal.
True. And we'll see our test pass. Great. Now let's add some tests for our subtotal or taxes and our total. So let's say it calculates the subtotal. Let's also say calculates taxes and let's say the total. There we go. I'm just gonna copy this over because we need our store. We'll say store.increment products, products2. And in here we'll say expect store.subtotal
products, products two. And in here we'll say expect storeSubtotal to equal 20. It is gonna be 20 because our product has a price of 10, we added two products so it's gonna be 20. Let's also do the taxes. We can actually copy this, paste it, and we will expect storeTaxes to equal 2 because our taxes are 10%. And finally, let's copy this over and let's say storeTotal
because our taxes are 10%. And finally, let's copy this over and let's say storeTotal and that's gonna be 20 plus our taxes, which is 2, is gonna be 22. And let's see if our tests pass. Great. So our subtotal, taxes and our total test pass. Next, let's say it clears the cart when we expect it to, we can say store lot increments products. Let's say products 2. So we have 2 items in our cart. Then we'll call store not clearCart.
Let's say products two. So we have two items in our cart. Then we'll call store not clearCart. And we expect store isEmpty to equal true. And our test passes great. For a final test, let's say we can calculate the amount for a product. We'll get our store, we'll say store increment products by two. And let's expect store amountFor products.
Switching to Component Tests7:11
products by two. And let's expect store amount for products. productTwo equal two and it passes. Great. As you can see, testing stores in isolation is actually pretty easy to do. Let's move on to test our components. To begin, we need to add view test vue, dom and pest testing. Open up our vite.config.js and we need to update our test
Testing NavBar With Pinia7:39
dom and penia testing. Open up our Vite config and we need to update our test and we need to say environment.js so our components are being rendered correctly. And let's start by creating a test for our NavBar component. Let's say navBar.spec.js will import our NavBar. Then we'll import mount from vue-test-utils and we can describe our NavBar. And in our first test we'll see if our batch updates with the state.
And in our first test we'll see if our batch updates with the state. Accordingly, we'll say it should render a correct batch. The first thing we need to do is mount the N bar and we'll say wrapper equals the result of this call. Now in the options of our mount call, we need to pass in our PIA store and Pina provides us with a specific testing version. We can import, we can say import,
and Pina provides us with a specific testing version. We can import, we can say import, create testing Pina from pina testing. And in here we'll say global plugins, which is an area I will say create testing Pina. In here we can pause an initial state. For example, we'll say cart is gonna be a cart array with a single object title test product price 10 and a quantity of 1. And now we can test that a batch updates and displays a 1.
price 10 and a quantity of one. And now we can test that a batch updates and displays a one. And to make our Livewire easy, let's jump into the nav bar component. Let's find our batch and let's add a data-test-id equals nav-bar-batch. Going back to our test, we can say expect wrapper find, we will find our data-test-id equals nav-bar-batch and we expect it to exist. Next, we want to make sure the text contains one.
and we expect it to exist. Next, we want to make sure the text contains one. Lo and behold our test passes great and we can validate it passes. If we say two, it's gonna say failed because it received one, it's expected two. If it changes back to one, it's gonna pass again. Great. We can improve this a bit by actually calling the action. So let's get rid of the initial state here. And very important we have to say stopActions to false.
So let's get rid of the initial state here. And very important we have to say stopActions to false. So we're able to really call the actions in our store. Next we'll say a cardStore. We'll say incrementProducts and we'll pause in a domiProduct with the price of them. And if you take a look at our test, it's gonna fail. And this makes sense because we need to await the nextTick. We have to import nextTick from vue.
And this makes sense because we need to await the next tick. We have to import nextTick from you and we have to make our test asynchronous and our test still fails because success is not a function. And we can fix this by saying plugins. Those plugin, Don't forget to import it. And now our test passes. Great. Finally, let's get rid of this warning. That router link was unable to be resolved. We can say stop.
Finally, let's get rid of this warning. That router link was unable to be resolved. We can say stop. Let's say router link and we can stop it with our router link. Stop and router link will be imported from Vue Test Utils. And now we got rid of our warning. Let's add a second test in which we will test if the batch updates to nine plus when we add 10 or more items, we can start by abstracting our code a bit.
updates to nine plus when we add 10 or more items, we can start by abstracting or code a bit. We'll say const wrapper equals navBar. Uh, we can make a function navBar that's gonna return our mounted navBar with the setup we just did. This way we can reuse it. We can say it should render nine plus. Let's make it async. Actually, let's start by getting our navBar. Then we'll say useCardStore increment products.
Actually, let's start by getting our nav bar. Then we'll say use Card store increment products. Let's say id one title test product. Give the price of 10 and let's add 100 items. We have to await the next tick as before. And let's actually copy this over. We expect the batch to exist and we expect the text to contain nine plus. And there we have it, our test passes and our nav bar behavior is tested.
And there we have it, our test passes and our navbar behavior is tested. Finally, let's add a test for our login state and see if our navbar renders our name correctly to make our life easier again, let's go to our navbar component. Let's find our name and add data-testid equals username. Then we can say it. Uh should render the name of the User Async let cat or navbar.
Uh should render the name of the User AsyncLetCat or NavBar. And a cool thing we can do with the testing version of Pina is actually override the state as follows. We can say useUserStore, do $user equals and we can fill it out here. We'll say id 1 name Sabatino email test@test.test, we can await the next stick and we'll expect our testId
At test of test, we can await the next stick and we'll expect our test ID Username to exist to be true. And we want our text to be sabatino. And this is a cool thing you can do with the testing version of Pina. You can override a state and you can even override gathers and we can see our test passes. Great. And on that note, we can conclude the lesson. We first learned how to test our stores in isolation.
Great. And on that note, we can conclude the lesson. We first learned how to test our stores in isolation by creating a test spec for our CardStore. And then we learned how a component that relies on a store in our case, the NavBar can be tested. I'll see you in the next lesson.
