test.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763
  1. import 'babel-polyfill'
  2. import chai, { expect } from 'chai'
  3. import sinonChai from 'sinon-chai'
  4. import sinon from 'sinon'
  5. import Vue from 'vue'
  6. import Vuex, { mapGetters, mapActions } from '../../build/dev-entry'
  7. Vue.use(Vuex)
  8. chai.use(sinonChai)
  9. const TEST = 'TEST'
  10. const TEST2 = 'TEST2'
  11. describe('Vuex', () => {
  12. it('committing mutations', () => {
  13. const store = new Vuex.Store({
  14. state: {
  15. a: 1
  16. },
  17. mutations: {
  18. [TEST] (state, n) {
  19. state.a += n
  20. }
  21. }
  22. })
  23. store.commit(TEST, 2)
  24. expect(store.state.a).to.equal(3)
  25. })
  26. it('dispatching actions, sync', () => {
  27. const store = new Vuex.Store({
  28. state: {
  29. a: 1
  30. },
  31. mutations: {
  32. [TEST] (state, n) {
  33. state.a += n
  34. }
  35. },
  36. actions: {
  37. [TEST] ({ commit }, n) {
  38. commit(TEST, n)
  39. }
  40. }
  41. })
  42. store.dispatch(TEST, 2)
  43. expect(store.state.a).to.equal(3)
  44. })
  45. it('dispatching actions, with returned Promise', done => {
  46. const store = new Vuex.Store({
  47. state: {
  48. a: 1
  49. },
  50. mutations: {
  51. [TEST] (state, n) {
  52. state.a += n
  53. }
  54. },
  55. actions: {
  56. [TEST] ({ commit }, n) {
  57. return new Promise(resolve => {
  58. setTimeout(() => {
  59. commit(TEST, n)
  60. resolve()
  61. }, 0)
  62. })
  63. }
  64. }
  65. })
  66. expect(store.state.a).to.equal(1)
  67. store.dispatch(TEST, 2).then(() => {
  68. expect(store.state.a).to.equal(3)
  69. done()
  70. })
  71. })
  72. it('composing actions with async/await', done => {
  73. const store = new Vuex.Store({
  74. state: {
  75. a: 1
  76. },
  77. mutations: {
  78. [TEST] (state, n) {
  79. state.a += n
  80. }
  81. },
  82. actions: {
  83. [TEST] ({ commit }, n) {
  84. return new Promise(resolve => {
  85. setTimeout(() => {
  86. commit(TEST, n)
  87. resolve()
  88. }, 0)
  89. })
  90. },
  91. two: async ({ commit, dispatch }, n) => {
  92. await dispatch(TEST, 1)
  93. expect(store.state.a).to.equal(2)
  94. commit(TEST, n)
  95. }
  96. }
  97. })
  98. expect(store.state.a).to.equal(1)
  99. store.dispatch('two', 3).then(() => {
  100. expect(store.state.a).to.equal(5)
  101. done()
  102. })
  103. })
  104. it('capturing action Promise errors', done => {
  105. const spy = sinon.spy(console, 'error')
  106. const store = new Vuex.Store({
  107. actions: {
  108. [TEST] () {
  109. return new Promise((resolve, reject) => {
  110. reject(new Error())
  111. })
  112. }
  113. }
  114. })
  115. store.dispatch(TEST).then(() => {
  116. expect(spy).to.have.been.calledWith(`[vuex] error in Promise returned from action "${TEST}":`)
  117. spy.restore()
  118. done()
  119. })
  120. })
  121. it('getters', () => {
  122. const store = new Vuex.Store({
  123. state: {
  124. a: 1
  125. },
  126. getters: {
  127. hasAny: state => state.a > 1
  128. },
  129. mutations: {
  130. [TEST] (state, n) {
  131. state.a += n
  132. }
  133. }
  134. })
  135. expect(store.getters.hasAny).to.equal(false)
  136. store.commit(TEST, 1)
  137. expect(store.getters.hasAny).to.equal(true)
  138. })
  139. it('store injection', () => {
  140. const store = new Vuex.Store()
  141. const vm = new Vue({
  142. store
  143. })
  144. const child = new Vue({ parent: vm })
  145. expect(child.$store).to.equal(store)
  146. })
  147. it('helper: mapGetters (array)', () => {
  148. const store = new Vuex.Store({
  149. state: { count: 0 },
  150. mutations: {
  151. inc: state => state.count++,
  152. dec: state => state.count--
  153. },
  154. getters: {
  155. hasAny: ({ count }) => count > 0,
  156. negative: ({ count }) => count < 0
  157. }
  158. })
  159. const vm = new Vue({
  160. store,
  161. computed: mapGetters(['hasAny', 'negative'])
  162. })
  163. expect(vm.hasAny).to.equal(false)
  164. expect(vm.negative).to.equal(false)
  165. store.commit('inc')
  166. expect(vm.hasAny).to.equal(true)
  167. expect(vm.negative).to.equal(false)
  168. store.commit('dec')
  169. store.commit('dec')
  170. expect(vm.hasAny).to.equal(false)
  171. expect(vm.negative).to.equal(true)
  172. })
  173. it('helper: mapGetters (object)', () => {
  174. const store = new Vuex.Store({
  175. state: { count: 0 },
  176. mutations: {
  177. inc: state => state.count++,
  178. dec: state => state.count--
  179. },
  180. getters: {
  181. hasAny: ({ count }) => count > 0,
  182. negative: ({ count }) => count < 0
  183. }
  184. })
  185. const vm = new Vue({
  186. store,
  187. computed: mapGetters({
  188. a: 'hasAny',
  189. b: 'negative'
  190. })
  191. })
  192. expect(vm.a).to.equal(false)
  193. expect(vm.b).to.equal(false)
  194. store.commit('inc')
  195. expect(vm.a).to.equal(true)
  196. expect(vm.b).to.equal(false)
  197. store.commit('dec')
  198. store.commit('dec')
  199. expect(vm.a).to.equal(false)
  200. expect(vm.b).to.equal(true)
  201. })
  202. it('helper: mapActions (array)', () => {
  203. const a = sinon.spy()
  204. const b = sinon.spy()
  205. const store = new Vuex.Store({
  206. actions: {
  207. a,
  208. b
  209. }
  210. })
  211. const vm = new Vue({
  212. store,
  213. methods: mapActions(['a', 'b'])
  214. })
  215. vm.a()
  216. expect(a).to.have.been.called
  217. expect(b).not.to.have.been.called
  218. vm.b()
  219. expect(b).to.have.been.called
  220. })
  221. it('helper: mapActions (object)', () => {
  222. const a = sinon.spy()
  223. const b = sinon.spy()
  224. const store = new Vuex.Store({
  225. actions: {
  226. a,
  227. b
  228. }
  229. })
  230. const vm = new Vue({
  231. store,
  232. methods: mapActions({
  233. foo: 'a',
  234. bar: 'b'
  235. })
  236. })
  237. vm.foo()
  238. expect(a).to.have.been.called
  239. expect(b).not.to.have.been.called
  240. vm.bar()
  241. expect(b).to.have.been.called
  242. })
  243. it('module: mutation', function () {
  244. const mutations = {
  245. [TEST] (state, n) {
  246. state.a += n
  247. }
  248. }
  249. const store = new Vuex.Store({
  250. state: {
  251. a: 1
  252. },
  253. mutations,
  254. modules: {
  255. nested: {
  256. state: { a: 2 },
  257. mutations,
  258. modules: {
  259. one: {
  260. state: { a: 3 },
  261. mutations
  262. },
  263. nested: {
  264. modules: {
  265. two: {
  266. state: { a: 4 },
  267. mutations
  268. },
  269. three: {
  270. state: { a: 5 },
  271. mutations
  272. }
  273. }
  274. }
  275. }
  276. },
  277. four: {
  278. state: { a: 6 },
  279. mutations
  280. }
  281. }
  282. })
  283. store.commit(TEST, 1)
  284. expect(store.state.a).to.equal(2)
  285. expect(store.state.nested.a).to.equal(3)
  286. expect(store.state.nested.one.a).to.equal(4)
  287. expect(store.state.nested.nested.two.a).to.equal(5)
  288. expect(store.state.nested.nested.three.a).to.equal(6)
  289. expect(store.state.four.a).to.equal(7)
  290. })
  291. it('module: action', function () {
  292. let calls = 0
  293. const makeAction = n => {
  294. return {
  295. [TEST] ({ state }) {
  296. calls++
  297. expect(state.a).to.equal(n)
  298. }
  299. }
  300. }
  301. const store = new Vuex.Store({
  302. state: {
  303. a: 1
  304. },
  305. actions: makeAction(1),
  306. modules: {
  307. nested: {
  308. state: { a: 2 },
  309. actions: makeAction(2),
  310. modules: {
  311. one: {
  312. state: { a: 3 },
  313. actions: makeAction(3)
  314. },
  315. nested: {
  316. modules: {
  317. two: {
  318. state: { a: 4 },
  319. actions: makeAction(4)
  320. },
  321. three: {
  322. state: { a: 5 },
  323. actions: makeAction(5)
  324. }
  325. }
  326. }
  327. }
  328. },
  329. four: {
  330. state: { a: 6 },
  331. actions: makeAction(6)
  332. }
  333. }
  334. })
  335. store.dispatch(TEST)
  336. expect(calls).to.equal(6)
  337. })
  338. it('module: getters', function () {
  339. const makeGetter = n => ({
  340. [`getter${n}`]: state => state.a
  341. })
  342. const store = new Vuex.Store({
  343. state: {
  344. a: 1
  345. },
  346. getters: makeGetter(1),
  347. modules: {
  348. nested: {
  349. state: { a: 2 },
  350. getters: makeGetter(2),
  351. modules: {
  352. one: {
  353. state: { a: 3 },
  354. getters: makeGetter(3)
  355. },
  356. nested: {
  357. modules: {
  358. two: {
  359. state: { a: 4 },
  360. getters: makeGetter(4)
  361. },
  362. three: {
  363. state: { a: 5 },
  364. getters: makeGetter(5)
  365. }
  366. }
  367. }
  368. }
  369. },
  370. four: {
  371. state: { a: 6 },
  372. getters: makeGetter(6)
  373. }
  374. }
  375. })
  376. ;[1, 2, 3, 4, 5, 6].forEach(n => {
  377. expect(store.getters[`getter${n}`]).to.equal(n)
  378. })
  379. })
  380. it('dispatching multiple actions in different modules', done => {
  381. const store = new Vuex.Store({
  382. modules: {
  383. a: {
  384. actions: {
  385. [TEST] () {
  386. return 1
  387. }
  388. }
  389. },
  390. b: {
  391. actions: {
  392. [TEST] () {
  393. return new Promise(r => r(2))
  394. }
  395. }
  396. }
  397. }
  398. })
  399. store.dispatch(TEST).then(res => {
  400. expect(res[0]).to.equal(1)
  401. expect(res[1]).to.equal(2)
  402. done()
  403. })
  404. })
  405. it('plugins', function () {
  406. let initState
  407. const mutations = []
  408. const store = new Vuex.Store({
  409. state: {
  410. a: 1
  411. },
  412. mutations: {
  413. [TEST] (state, n) {
  414. state.a += n
  415. }
  416. },
  417. plugins: [
  418. store => {
  419. initState = store.state
  420. store.subscribe((mut, state) => {
  421. expect(state).to.equal(store.state)
  422. mutations.push(mut)
  423. })
  424. }
  425. ]
  426. })
  427. expect(initState).to.equal(store.state)
  428. store.commit(TEST, 2)
  429. expect(mutations.length).to.equal(1)
  430. expect(mutations[0].type).to.equal(TEST)
  431. expect(mutations[0].payload).to.equal(2)
  432. })
  433. it('plugins should ignore silent mutations', function () {
  434. let initState
  435. const mutations = []
  436. const store = new Vuex.Store({
  437. state: {
  438. a: 1
  439. },
  440. mutations: {
  441. [TEST] (state, { n }) {
  442. state.a += n
  443. }
  444. },
  445. plugins: [
  446. store => {
  447. initState = store.state
  448. store.subscribe((mut, state) => {
  449. expect(state).to.equal(store.state)
  450. mutations.push(mut)
  451. })
  452. }
  453. ]
  454. })
  455. expect(initState).to.equal(store.state)
  456. store.commit(TEST, { n: 1 })
  457. store.commit({
  458. type: TEST,
  459. n: 2
  460. })
  461. store.commit({
  462. type: TEST,
  463. silent: true,
  464. n: 3
  465. })
  466. expect(mutations.length).to.equal(2)
  467. expect(mutations[0].type).to.equal(TEST)
  468. expect(mutations[1].type).to.equal(TEST)
  469. expect(mutations[0].payload.n).to.equal(1) // normal dispatch
  470. expect(mutations[1].n).to.equal(2) // object dispatch
  471. })
  472. it('strict mode: warn mutations outside of handlers', function () {
  473. const store = new Vuex.Store({
  474. state: {
  475. a: 1
  476. },
  477. strict: true
  478. })
  479. expect(() => {
  480. store.state.a++
  481. }).to.throw(/Do not mutate vuex store state outside mutation handlers/)
  482. })
  483. it('hot reload: mutations', function () {
  484. const mutations = {
  485. [TEST] (state, n) {
  486. state.a += n
  487. }
  488. }
  489. const store = new Vuex.Store({
  490. state: {
  491. a: 1
  492. },
  493. mutations,
  494. modules: {
  495. nested: {
  496. state: { a: 2 },
  497. mutations,
  498. modules: {
  499. one: {
  500. state: { a: 3 },
  501. mutations
  502. },
  503. nested: {
  504. modules: {
  505. two: {
  506. state: { a: 4 },
  507. mutations
  508. },
  509. three: {
  510. state: { a: 5 },
  511. mutations
  512. }
  513. }
  514. }
  515. }
  516. },
  517. four: {
  518. state: { a: 6 },
  519. mutations
  520. }
  521. }
  522. })
  523. store.commit(TEST, 1)
  524. expect(store.state.a).to.equal(2)
  525. expect(store.state.nested.a).to.equal(3)
  526. expect(store.state.nested.one.a).to.equal(4)
  527. expect(store.state.nested.nested.two.a).to.equal(5)
  528. expect(store.state.nested.nested.three.a).to.equal(6)
  529. expect(store.state.four.a).to.equal(7)
  530. // hot reload only root mutations
  531. store.hotUpdate({
  532. mutations: {
  533. [TEST] (state, n) {
  534. state.a = n
  535. }
  536. }
  537. })
  538. store.commit(TEST, 1)
  539. expect(store.state.a).to.equal(1) // only root mutation updated
  540. expect(store.state.nested.a).to.equal(4)
  541. expect(store.state.nested.one.a).to.equal(5)
  542. expect(store.state.nested.nested.two.a).to.equal(6)
  543. expect(store.state.nested.nested.three.a).to.equal(7)
  544. expect(store.state.four.a).to.equal(8)
  545. // hot reload modules
  546. store.hotUpdate({
  547. modules: {
  548. nested: {
  549. state: { a: 234 },
  550. mutations,
  551. modules: {
  552. one: {
  553. state: { a: 345 },
  554. mutations
  555. },
  556. nested: {
  557. modules: {
  558. two: {
  559. state: { a: 456 },
  560. mutations
  561. },
  562. three: {
  563. state: { a: 567 },
  564. mutations
  565. }
  566. }
  567. }
  568. }
  569. },
  570. four: {
  571. state: { a: 678 },
  572. mutations
  573. }
  574. }
  575. })
  576. store.commit(TEST, 2)
  577. expect(store.state.a).to.equal(2)
  578. expect(store.state.nested.a).to.equal(6) // should not reload initial state
  579. expect(store.state.nested.one.a).to.equal(7) // should not reload initial state
  580. expect(store.state.nested.nested.two.a).to.equal(8) // should not reload initial state
  581. expect(store.state.nested.nested.three.a).to.equal(9) // should not reload initial state
  582. expect(store.state.four.a).to.equal(10) // should not reload initial state
  583. // hot reload all
  584. store.hotUpdate({
  585. mutations: {
  586. [TEST] (state, n) {
  587. state.a -= n
  588. }
  589. },
  590. modules: {
  591. nested: {
  592. state: { a: 234 },
  593. mutations: {
  594. [TEST] (state, n) {
  595. state.a += n
  596. }
  597. },
  598. modules: {
  599. one: {
  600. state: { a: 345 },
  601. mutations: {
  602. [TEST] (state, n) {
  603. state.a += n
  604. }
  605. }
  606. },
  607. nested: {
  608. modules: {
  609. two: {
  610. state: { a: 456 },
  611. mutations: {
  612. [TEST] (state, n) {
  613. state.a += n
  614. }
  615. }
  616. },
  617. three: {
  618. state: { a: 567 },
  619. mutations: {
  620. [TEST] (state, n) {
  621. state.a -= n
  622. }
  623. }
  624. }
  625. }
  626. }
  627. }
  628. },
  629. four: {
  630. state: { a: 678 },
  631. mutations: {
  632. [TEST] (state, n) {
  633. state.a -= n
  634. }
  635. }
  636. }
  637. }
  638. })
  639. store.commit(TEST, 3)
  640. expect(store.state.a).to.equal(-1)
  641. expect(store.state.nested.a).to.equal(9)
  642. expect(store.state.nested.one.a).to.equal(10)
  643. expect(store.state.nested.nested.two.a).to.equal(11)
  644. expect(store.state.nested.nested.three.a).to.equal(6)
  645. expect(store.state.four.a).to.equal(7)
  646. })
  647. it('hot reload: actions', () => {
  648. const store = new Vuex.Store({
  649. state: {
  650. list: []
  651. },
  652. mutations: {
  653. [TEST] (state, n) {
  654. state.list.push(n)
  655. }
  656. },
  657. actions: {
  658. [TEST] ({ commit }) {
  659. commit(TEST, 1)
  660. }
  661. },
  662. modules: {
  663. a: {
  664. actions: {
  665. [TEST] ({ commit }) {
  666. commit(TEST, 2)
  667. }
  668. }
  669. }
  670. }
  671. })
  672. store.dispatch(TEST)
  673. expect(store.state.list.join()).to.equal('1,2')
  674. // update root
  675. store.hotUpdate({
  676. actions: {
  677. [TEST] ({ commit }) {
  678. commit(TEST, 3)
  679. }
  680. }
  681. })
  682. store.dispatch(TEST)
  683. expect(store.state.list.join()).to.equal('1,2,3,2')
  684. // update modules
  685. store.hotUpdate({
  686. actions: {
  687. [TEST] ({ commit }) {
  688. commit(TEST, 4)
  689. }
  690. },
  691. modules: {
  692. a: {
  693. actions: {
  694. [TEST] ({ commit }) {
  695. commit(TEST, 5)
  696. }
  697. }
  698. }
  699. }
  700. })
  701. store.dispatch(TEST)
  702. expect(store.state.list.join()).to.equal('1,2,3,2,4,5')
  703. })
  704. it('hot reload: getters', done => {
  705. const store = new Vuex.Store({
  706. state: {
  707. count: 0
  708. },
  709. mutations: {
  710. inc: state => state.count++
  711. },
  712. getters: {
  713. hasAny: state => state.count > 0
  714. }
  715. })
  716. const spy = sinon.spy()
  717. const vm = new Vue({
  718. computed: {
  719. a: () => store.getters.hasAny
  720. },
  721. watch: {
  722. a: spy
  723. }
  724. })
  725. expect(vm.a).to.equal(false)
  726. store.commit('inc')
  727. expect(vm.a).to.equal(true)
  728. Vue.nextTick(() => {
  729. expect(spy).to.have.been.called
  730. done()
  731. })
  732. })
  733. })