expect(store.someAction).toHaveBeenLastCalledWith()
```
-Please note that if you are using Vue 2, `@vue/test-utils` requires a [slightly different configuration](#Unit-test-components-Vue-2-).
-
### Initial State
You can set the initial state of **all of your stores** when creating a testing pinia by passing an `initialState` object. This object will be used by the testing pinia to _patch_ stores when they are created. Let's say you want to initialize the state of this store:
## E2E tests
When it comes to Pinia, you don't need to change anything for E2E tests, that's the whole point of these tests! You could maybe test HTTP requests, but that's way beyond the scope of this guide 😄.
-
-## Unit test components (Vue 2)
-
-When using [Vue Test Utils 1](https://v1.test-utils.vuejs.org/), install Pinia on a `localVue`:
-
-```js
-import { PiniaVuePlugin } from 'pinia'
-import { createLocalVue, mount } from '@vue/test-utils'
-import { createTestingPinia } from '@pinia/testing'
-
-const localVue = createLocalVue()
-localVue.use(PiniaVuePlugin)
-
-const wrapper = mount(Counter, {
- localVue,
- pinia: createTestingPinia(),
-})
-
-const store = useSomeStore() // uses the testing pinia!
-```
```js
export function myPiniaPlugin(context) {
context.pinia // the pinia created with `createPinia()`
- context.app // the current app created with `createApp()` (Vue 3 only)
+ context.app // the current app created with `createApp()`
context.store // the store the plugin is augmenting
context.options // the options object defining the store passed to `defineStore()`
// ...
Note that state changes or additions that occur within a plugin (that includes calling `store.$patch()`) happen before the store is active and therefore **do not trigger any subscriptions**.
-:::warning
-If you are using **Vue 2**, Pinia is subject to the [same reactivity caveats](https://v2.vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats) as Vue. You will need to use `Vue.set()` (Vue 2.7) or `set()` (from `@vue/composition-api` for Vue <2.7) for when creating new state properties like `secret` and `hasError`:
-
-```js
-import { set, toRef } from '@vue/composition-api'
-pinia.use(({ store }) => {
- if (!store.$state.hasOwnProperty('secret')) {
- const secretRef = ref('secret')
- // If the data is meant to be used during SSR, you should
- // set it on the `$state` property so it is serialized and
- // picked up during hydration
- set(store.$state, 'secret', secretRef)
- }
- // set it directly on the store too so you can access it
- // both ways: `store.$state.secret` / `store.secret`
- set(store, 'secret', toRef(store.$state, 'secret'))
- store.secret // 'secret'
-})
-```
-
-:::
-
#### Resetting state added in plugins
By default, `$reset()` will not reset state added by plugins but you can override it to also reset the state you add:
```
:::tip
+
There is also a `StoreGetters` type to extract the _getters_ from a Store type. You can also extend the options of _setup stores_ or _option stores_ **only** by extending the types `DefineStoreOptions` and `DefineSetupStoreOptions` respectively.
+
:::
-## Nuxt.js
+## Nuxt
When [using pinia alongside Nuxt](../ssr/nuxt.md), you will have to create a [Nuxt plugin](https://nuxt.com/docs/guide/directory-structure/plugins) first. This will give you access to the `pinia` instance:
:::
-### Nuxt.js 2
-
-If you are using Nuxt.js 2, the types are slightly different:
-
-```ts{3,15-17}
-// plugins/myPiniaPlugin.ts
-import { PiniaPluginContext } from 'pinia'
-import { Plugin } from '@nuxt/types'
-
-function MyPiniaPlugin({ store }: PiniaPluginContext) {
- store.$subscribe((mutation) => {
- // react to store changes
- console.log(`[🍍 ${mutation.storeId}]: ${mutation.type}.`)
- })
-
- // Note this has to be typed if you are using TS
- return { creationTime: new Date() }
-}
-
-const myPlugin: Plugin = ({ $pinia }) => {
- $pinia.use(MyPiniaPlugin)
-}
-
-export default myPlugin
-```
-
## Existing plugins
You can check existing [Pinia plugins on GitHub](https://github.com/topics/pinia-plugin) with the topic _pinia-plugin_.
```
:::tip
-If you are using Vue 2, the data you create in `state` follows the same rules as the `data` in a Vue instance, i.e. the state object must be plain and you need to call `Vue.set()` when **adding new** properties to it. **See also: [Vue#data](https://v2.vuejs.org/v2/api/#data)**.
+
+In order for Vue to properly detect state, you must declare every state piece in `data`, even if its initial value is `undefined`.
+
:::
## TypeScript
<!-- TODO: disable this with `strictMode`, `{ noDirectPatch: true }` -->
-The main difference here is that `$patch()` allows you to group multiple changes into one single entry in the devtools. Note that **both direct changes to `state` and `$patch()` appear in the devtools** and can be time traveled (not yet in Vue 3).
+The main difference here is that `$patch()` allows you to group multiple changes into one single entry in the devtools. Note that **both direct changes to `state` and `$patch()` are tracked in devtools** and can be time traveled.
## Replacing the `state`
app.mount('#app')
```
-If you are using Vue 2, you also need to install a plugin and inject the created `pinia` at the root of the app:
-
-```js {1,3-4,12}
-import { createPinia, PiniaVuePlugin } from 'pinia'
-
-Vue.use(PiniaVuePlugin)
-const pinia = createPinia()
-
-new Vue({
- el: '#app',
- // other options...
- // ...
- // note the same `pinia` instance can be used across multiple Vue apps on
- // the same page
- pinia,
-})
-```
-
-This will also add devtools support. In Vue 3, some features like time traveling and editing are still not supported because vue-devtools doesn't expose the necessary APIs yet but the devtools have way more features and the developer experience as a whole is far superior.
-
## What is a Store?
A Store (like Pinia) is an entity holding state and business logic that isn't bound to your Component tree. In other words, **it hosts global state**. It's a bit like a component that is always there and that everybody can read off and write to. It has **three concepts**, the [state](./core-concepts/state.md), [getters](./core-concepts/getters.md) and [actions](./core-concepts/actions.md) and it's safe to assume these concepts are the equivalent of `data`, `computed` and `methods` in components.
- title: 🔑 Type Safe
details: Types are inferred, which means stores provide you with autocompletion even in JavaScript!
- title: ⚙️ Devtools support
- details: Pinia hooks into Vue devtools to give you an enhanced development experience in both Vue 2 and Vue 3.
+ details: Pinia hooks into Vue devtools to give you an enhanced development experience.
- title: 🔌 Extensible
details: React to store changes and actions to extend Pinia with transactions, local storage synchronization, etc.
- title: 🏗 Modular by design
title="Create your own Pinia from scratch"
/>
-Pinia [started](https://github.com/vuejs/pinia/commit/06aeef54e2cad66696063c62829dac74e15fd19e) as an experiment to redesign what a Store for Vue could look like with the [Composition API](https://github.com/vuejs/composition-api) around November 2019. Since then, the initial principles have remained the same, but Pinia works for both Vue 2 and Vue 3 **and doesn't require you to use the composition API**. The API is the same for both except for _installation_ and _SSR_, and these docs are targeted to Vue 3 **with notes about Vue 2** whenever necessary so it can be read by Vue 2 and Vue 3 users!
+Pinia [started](https://github.com/vuejs/pinia/commit/06aeef54e2cad66696063c62829dac74e15fd19e) as an experiment to redesign what a Store for Vue could look like with the [Composition API](https://github.com/vuejs/composition-api) around November 2019. Since then, the initial principles have remained the same and Vue 2 support has been dropped in 2025, but Pinia **doesn't require you to use the composition API**.
## Why should I use Pinia?