wait-for-update.ts 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. import Vue from 'vue'
  2. // helper for async assertions.
  3. // Use like this:
  4. //
  5. // vm.a = 123
  6. // waitForUpdate(() => {
  7. // expect(vm.$el.textContent).toBe('123')
  8. // vm.a = 234
  9. // })
  10. // .then(() => {
  11. // // more assertions...
  12. // })
  13. // .then(done)
  14. interface Job extends Function {
  15. wait?: boolean
  16. fail?: (e: any) => void
  17. }
  18. const waitForUpdate = (initialCb: Job) => {
  19. let end
  20. const queue: Job[] = initialCb ? [initialCb] : []
  21. function shift() {
  22. const job = queue.shift()
  23. if (queue.length) {
  24. let hasError = false
  25. try {
  26. job!.wait ? job!(shift) : job!()
  27. } catch (e) {
  28. hasError = true
  29. const done = queue[queue.length - 1]
  30. if (done && done.fail) {
  31. done.fail(e)
  32. }
  33. }
  34. if (!hasError && !job!.wait) {
  35. if (queue.length) {
  36. Vue.nextTick(shift)
  37. }
  38. }
  39. } else if (job && (job.fail || job === end)) {
  40. job() // done
  41. }
  42. }
  43. Vue.nextTick(() => {
  44. if (!queue.length || (!end && !queue[queue.length - 1]!.fail)) {
  45. throw new Error('waitForUpdate chain is missing .then(done)')
  46. }
  47. shift()
  48. })
  49. const chainer = {
  50. then: nextCb => {
  51. queue.push(nextCb)
  52. return chainer
  53. },
  54. thenWaitFor: wait => {
  55. if (typeof wait === 'number') {
  56. wait = timeout(wait)
  57. }
  58. wait.wait = true
  59. queue.push(wait)
  60. return chainer
  61. },
  62. end: endFn => {
  63. queue.push(endFn)
  64. end = endFn
  65. }
  66. }
  67. return chainer
  68. }
  69. function timeout(n) {
  70. return next => setTimeout(next, n)
  71. }
  72. export { waitForUpdate }