{"id":18327275,"url":"https://github.com/v-trof/vuex-snapshot","last_synced_at":"2026-04-29T00:33:45.874Z","repository":{"id":57396956,"uuid":"119479393","full_name":"v-trof/vuex-snapshot","owner":"v-trof","description":"Module to snapshot test vuex actions with jest","archived":false,"fork":false,"pushed_at":"2018-02-09T18:42:55.000Z","size":285,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-04-25T09:17:12.450Z","etag":null,"topics":["javascript","jest","mocks","snapshot-testing","testing","vuex"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/v-trof.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-01-30T03:53:03.000Z","updated_at":"2019-01-02T16:37:00.000Z","dependencies_parsed_at":"2022-09-13T10:22:08.545Z","dependency_job_id":null,"html_url":"https://github.com/v-trof/vuex-snapshot","commit_stats":null,"previous_names":["vsevolodtrofimov/vuex-snapshot"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/v-trof/vuex-snapshot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/v-trof%2Fvuex-snapshot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/v-trof%2Fvuex-snapshot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/v-trof%2Fvuex-snapshot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/v-trof%2Fvuex-snapshot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/v-trof","download_url":"https://codeload.github.com/v-trof/vuex-snapshot/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/v-trof%2Fvuex-snapshot/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32405901,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-28T19:38:08.556Z","status":"ssl_error","status_checked_at":"2026-04-28T19:37:55.688Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["javascript","jest","mocks","snapshot-testing","testing","vuex"],"created_at":"2024-11-05T19:10:15.553Z","updated_at":"2026-04-29T00:33:45.858Z","avatar_url":"https://github.com/v-trof.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# vuex-snapshot • [![codecov][codecov-img]][codecov-link] [![Build Status][travis-img]][travis-link]\n\nModule to snapshot test vuex actions with jest\n\n## Table of contents\n* [Why use snapshot tests for actions?](#why-use-snapshot-tests-for-actions-)\n* [Getting started](#getting-started)\n  + [Prerequisites](#prerequisites)\n  + [Installation](#installation)\n  + [Basic example](#basic-example)\n* [Usage](#usage)\n  + [Testing async actions](#testing-async-actions)\n  + [mocks](#mocks)\n  + [MockPromises](#mockpromises)\n  + [snapAction overloads](#snapaction-overloads)\n  + [Utilities](#utilities)\n  + [Config](#config)\n* [Tips](#tips)\n  + [Mocking timers for vuex-snapshot resolutions](#mocking-timers-for-vuex-snapshot-resolutions)\n  + [Deep testing (execute called actions)](#deep-testing--execute-called-actions-)\n\n## Why use snapshot tests for actions?\nI hope you are familiar with what [jest][jest-main], [vuex][vuex-main] \nand [snapshot testing][jest-snapshot-testing] are.\n\nVuex actions are straightforward to read, and writing tests that are \nmore complex and 10 times longer than the code they cover feels really wrong.\n\nActions fulfill 3 roles:\n 1. Representation of app logic (conditions \u0026 calls of commits\\dispatches)\n 2. API for components\n 3. Asynchronous layer for store (as mutations must be sync)\n\nAs such we unit test them to make sure that: \n 1. When we change \\ add execution path others don't get broken\n 2. Our component API didn't change\n\n**vuex-snapshot** makes this easy and declarative, even for async actions.\n\n## Getting started\n### Prerequisites\n - :heavy_check_mark: Node 6 stable or later\n - :heavy_check_mark: `jest` and, `babel-jest` installed \n   (es6-modules imports would be used in examples, but `vuex-snapshot` is also output as CommonJS)\n\n### Installation\n#### via npm\n```bash\nnpm install --save-dev vuex-snapshot\n```\n\n#### via yarn\n```bash\nyarn add --dev vuex-snapshot\n```\n\n\n### Basic example\nSay, you are testing some card game\n\n```js\n// @/store/actions.js\nexport const restartGame = ({commit}) =\u003e {\n  commit('shuffleDeck')\n  commit('setScore', 0)\n}\n\n\n// actions.spec.js\nimport {snapAction} from 'vuex-snapshot'\nimport {restartGame} from '@/store/actions'\n\ntest('restartGame matches snapshot', () =\u003e {\n  expect(snapAction(restartGame)).toMatchSnapshot()\n})\n\n/*\n__snapshots__/actions.spec.js\nafter running jest\n*/\n\n// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`play restartGame matches snapshot 1`] = `\nArray [\n  Object {\n    \"message\": \"COMMIT: shuffleDeck\",\n  },\n  Object {\n    \"message\": \"COMMIT: setScore\",\n    \"payload\": 0,\n  },\n]\n`;\n```\n\u003e **NOTE:** by default vuex-snapshot would not use commit \u0026 dispatch from your store, but you can pass them via mocks\n\n\n## Usage\n### Testing async actions\n```js\n// @/store/actions.js\nexport const openDashboard = ({commit, dispatch}) =\u003e new Promise((resolve, reject) =\u003e {\n  commit('setRoute', 'loading')\n  dispatch('load', 'dashboard')\n    .then(() =\u003e {\n      commit('setRoute', 'dashboard')\n      resolve()\n    })\n    .catch('reject')\n})\n\n// actions.spec.js\nimport {snapAction, MockPromise} from 'vuex-snapshot'\nimport {openDashboard} from '@/store/actions'\n\ntest('openDashboard matches success snapshot', done =\u003e {\n  // MockPromise can be resolved manually unlike default Promise\n  const dispatch = name =\u003e new MockPromise(name)\n\n  // order in which promises would be resolved\n  const resolutions = ['load']\n\n  snapAction(openDashboard, {dispatch}, resolutions)\n    .then(run =\u003e {\n      expect(run).toMatchSnapshot()\n      done()\n    })\n})\n```\n\n### Testing async actions [2]\n```js\n// @/store/actions.js\nexport const login = ({commit, dispatch, getters}, creditals) =\u003e {\n  return new Promise((resolve, reject) =\u003e {\n    if(!getters.user.loggedIn) {\n      fetch('/api/login/', {\n        method: 'POST',\n        body: JSON.stringify(creditals)\n      })\n        .then(res =\u003e res.json())\n        .then(data =\u003e {\n          commit('setUser', data)\n          dispatch('setRoute', 'profile')\n          resolve()\n        })\n        .catch(reject)\n    } else {\n      resolve()\n    }\n  })\n}\n\n\n// actions.spec.js\nimport {snapAction, useMockFetch, MockPromise} from 'vuex-snapshot'\nimport {login} from '@/store/actions'\n\ntest('login matches success snapshot', done =\u003e {\n  useMockFetch()\n  \n  const payload = { authCode: 1050 }\n  const getters = {\n    user: {\n      loggedIn: false\n    }\n  }\n\n  // this is equivalent to calling resolve(payload) inside promise cb\n  const resolutions = [{\n    name: '/api/login/',\n    payload: { json: () =\u003e new MockPromise('json') }\n  }, {\n    name: 'json',\n    payload: { name: 'someUser', id: 21 }\n  }]\n\n  snapAction(login, {getters, payload}, resolutions)\n    .then(run =\u003e {\n      expect(run).toMatchSnapshot()\n      done()\n    })\n})\n\n\n// testing error scenarios is just as easy\ntest('login matches network fail snapshot', done =\u003e {\n  useMockFetch()\n  \n  const payload = { authCode: 1050 }\n  const getters = {\n    user: {\n      loggedIn: false\n    }\n  }\n\n  const resolutions = [{\n    name: '/api/login/',\n    type: 'reject', // resolve is default value\n    payload: new TypeError('Failed to fetch')\n  }]\n\n  snapAction(login, {getters, payload}, resolutions)\n    .then(run =\u003e {\n      /* vuex-snapshot would write that action rejected in the snapshot\n         so you can test rejections as well */\n      expect(run).toMatchSnapshot()\n      done()\n    })\n})\n```\n\u003e **NOTE:** promises with same names would be matched to resolutions in order they were created\n\n\n### mocks\nBy using mocks object you can pass state, getters, payload(action's second argument) of any type,\nas well as custom `commit` and `dispatch` functions.\n\n\u003e **NOTE:** Make sure your getters are what they return, not how they calculate it\n\n#### Example\n```js\nconst action = jest.fn()\n\nconst mocks = {\n  payload: 0,\n  state: {\n    stateValue: 'smth'\n  },\n  getters: {\n    answer: 42\n  },\n  commit: console.log\n  dispatch: jest.fn()\n}\n\nsnapAction(action, mocks)\n\n// would call the action like\naction({\n  state: mocks.state,\n  getters: mocks.getters,\n  commit: (name, payload) =\u003e mocks.commit(name, payload, proxies),\n  dispatch: (name, payload) =\u003e mocks.dispatch(name, payload, proxies),\n}, mocks.payload)\n```\nProxies is an object with commit and dispatch that were actually passed to action (not those from mocks)\n\n\u003e **Note:** state and getters are being reassigned. \n\u003e Like they would pass `.toEqual` test, but not a `.toBe` one.\n\n### MockPromises\n```js\nimport {MockPromise} from 'vuex-snapshot'\n\nconst name = 'some string'\nconst cb = (resolve, reject) =\u003e {}\nnew MockPromise(cb, name)\nnew MockPromise(cb) // name will be 'Promise'\nnew MockPromise(name) //cb will be  () =\u003e {}\n\n// some manual control\nconst toResolve = new MockPromise('some name')\nconst toReject = new MockPromise('some other name')\nconst payload = {type: 'any'}\n\ntoResolve.resolve(payload)\ntoReject.reject(payload)\n\nconsole.log(toReject.name) // some other name\n```\nThis class extends Promise, so Promise.all and other promise methods work perfectly for it\n\n\u003e **NOTE:** `new MockPromise.then(cb)` actually creates new `MockPromise` (that is default Promise behavior).\n\u003e As such there is a risk of `resolutions = ['Promise', 'Promise']`\n\u003e matching this one instead of the Promise you've meant.\n\u003e This is just as true for `catch`, `finally`, `Promise.all` and `Promise.race`\n\n### snapAction overloads\n```js\nimport {snapAction, Snapshot} from 'vuex-snapshot'\n\nsnapAction(action)\nsnapAction(action, mocks)\nsnapAction(action, resolutions)\nsnapAction(action, mocks, resolutions)\nsnapAction(action, mocks, resolutions, snapshotToWriteTo)\n// where snapshotToWriteTo is instance of Snapshot class \n```\n\nIf action returned a promise `snapAction` would do the same.\nThat promise will resolve with an `Array` of `Object`s that represents action's execution. \nIt could be compared to snapshot, or tested manually.\n\nIf vuex-snapshot experienced internal error snapAction would reject with an `Object`\nof following structure:\n```js\n{\n  err, // Actual error that has been thrown\n  run // action's execution up to the error point\n}\n```\n\n\nIf action returned anything that is not a promise (including `undefined`) `snapAction` would\nsynchronously return an array mentioned above.\n\n\n### Utilities\n```js\n\n// all vuex-snapshot Utilities\nimport {\n  reset,\n  \n  resetTimetable,\n  resetConfig,\n\n  useMockPromise,\n  useRealPromise,\n\n  useMockFetch,\n  useRealFetch,\n} from 'vuex-snapshot'\n```\n\n#### `reset`\nReset calls all other resets and useReal.\n\n#### `resetTimetable`\nMakes sure no already created promises could be matched to resolutions.\n\n#### `resetConfig`\nResets `vuexSnapshot.config` to default values.\n\n#### `useMockPromise`\nReplaces `window.Promise` (same as `global.Promise`) with vuexSnapshot.MockPromise \nthat could be named and resolved manually.\n\n#### `useRealPromise`\nSets `window.Promise` to its original value.\n\n#### `useMockFetch`\nReplaces `window.fetch` (same as `global.fetch`) with vuexSnapshot.MockPromise \nthat could be named and resolved manually.\n\n#### `useRealFetch`\nSets `window.fetch` to its original value.\n\n\n### Config\nThese fit very specific types of tests, so using \n`beforeEach(vuexSnapshot.reset)` is highly encouraged.\n\n#### `vuexSnapshot.config.autoResolve`\n##### Default\nfalse\n\n##### Description\nInstead of acting according to passed resolutions vuex-snapshot will\nautomatically trigger resolve on each mock promise in \norder they were created.\n\n\n#### `vuexSnapshot.config.snapEnv`\n##### Default\nfalse\n##### Description\nStarts snapshot with 2 entries:\n``` js\n{\n  message: 'DATA MOCKS'\n  payload: {\n    state //value of state\n    getters // value of getters\n  }\n}\n\n{\n  message: 'ACTION MOCKS'\n  payload // passed action payload if there was one\n}\n\n// values of state, gettes and payload are not being copied\n```\n\n\n#### `vuexSnapshot.config.allowManualActionResolution`\n##### Default\nfalse\n##### Description\nAllows vuexSnapshot to resolve promise returned by action.\n\n\n## Tips\n### Mocking timers for vuex-snapshot resolutions\n```js\nimport {snapAction, MockPromise} from 'vuex-snapshot'\n\ntest('action snapshot usnig timers', done =\u003e {\n  const realSetTimeout = setTimeout\n  window.setTimeout = (cb, time) =\u003e {\n    const mock = new MockPromise('Timeout')\n    mock.then(cb)\n    return realSetTimeout(mock.resolve, time)\n  }\n\n  // actual \"test\"\n  const action = () =\u003e new Promise(resolve =\u003e {\n    setTimeout(resolve, 100500)\n  })\n\n  snapAction(action, ['Timeout'])\n    .then(run =\u003e {\n      expect(run).toMatchSnapshot()\n      done()\n    })\n    .catch(err =\u003e {\n      console.error(err)\n      console.log(timetable.entries)\n      done()\n    })\n\n  window.setTimeout = realSetTimeout\n})\n```\n\n\u003e **NOTE:** This is not fully accurate simulation because resolving it manually or via resolutions\n\u003e would cause a bit higher priority in [event-loop], and resolution on timeout would be 1 tick late\n\u003e Because Promise.then() is not synchronous\n\n### Deep testing (execute called actions)\n```js\n// @/store/actions.js\nexport const action1 = ({commit, dispatch}) =\u003e {\n  commit('mutation1')\n  dispatch('action2')\n}\n\nexport const action2 = ({commit, dispatch}) =\u003e {\n  commit('mutation2')\n}\n\n\n// actions.spec.js\nimport {snapAction} from 'vuex-snapshot'\nimport * as actions from '@/store/actions'\n\ntest('Many actions', () =\u003e {\n  const state = {}\n  const getters = {}\n\n  const dispatch = (namy, payload, {commit, dispatch}) =\u003e {\n    return actions[name]({state, getters, commit, dispatch}, payload)\n  }\n\n  expect(snapAction(actions.action1, {state, getters, dispatch})).toMatchSnapshot()\n})\n```\n\nThis should work for async actions too\n\n\n\u003c!-- Links --\u003e\n[vuex-main]: https://vuex.vuejs.org/\n[jest-main]: https://facebook.github.io/jest/\n[jest-snapshot-testing]: https://facebook.github.io/jest/docs/en/snapshot-testing.html\n[event-loop]: https://youtu.be/8aGhZQkoFbQ\n\u003c!-- Badges --\u003e\n[codecov-img]: https://codecov.io/gh/VsevolodTrofimov/vuex-snapshot/branch/master/graph/badge.svg\n[codecov-link]: https://codecov.io/gh/VsevolodTrofimov/vuex-snapshot\n\n[travis-img]: https://travis-ci.org/VsevolodTrofimov/vuex-snapshot.svg?branch=master\n[travis-link]: https://travis-ci.org/VsevolodTrofimov/vuex-snapshot\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fv-trof%2Fvuex-snapshot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fv-trof%2Fvuex-snapshot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fv-trof%2Fvuex-snapshot/lists"}