From 66d4e3a8179ce3fa488a25134473fbdfda1c2358 Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Tue, 6 Mar 2018 10:10:59 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Display=20errors=20when=20no=20slot?= =?UTF-8?q?s=20are=20provided?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.js | 16 +++++++++- src/util.js | 5 ++++ test/index.spec.js | 65 ++++++++++++++++++++++++++++++++++++---- test/utils/NoError.vue | 21 +++++++++++++ test/utils/NoPending.vue | 25 ++++++++++++++++ test/utils/NoResolve.vue | 24 +++++++++++++++ 6 files changed, 150 insertions(+), 6 deletions(-) create mode 100644 src/util.js create mode 100644 test/utils/NoError.vue create mode 100644 test/utils/NoPending.vue create mode 100644 test/utils/NoResolve.vue diff --git a/src/index.js b/src/index.js index 76e60ca..0bb2966 100644 --- a/src/index.js +++ b/src/index.js @@ -1,3 +1,5 @@ +import { assert } from './util' + export default { name: 'Promised', props: { @@ -13,10 +15,22 @@ export default { render (h) { if (this.error instanceof Error || (this.error && this.error.length)) { + assert( + this.$scopedSlots && this.$scopedSlots.error, + 'Provide exactly one scoped slot named "error" for the rejected promise' + ) return this.$scopedSlots.error(this.error) } else if (this.resolved) { + assert( + this.$scopedSlots && this.$scopedSlots.default, + 'Provide exactly one default scoped slot for the resolved promise' + ) return this.$scopedSlots.default(this.data) - } else if (this.$slots.default && this.$slots.default.length > 0) { + } else { + assert( + this.$slots.default && this.$slots.default.length === 1, + 'Provide exactly one default slot with no `slot-scope` for the pending promise' + ) return this.$slots.default[0] } }, diff --git a/src/util.js b/src/util.js new file mode 100644 index 0000000..7010a63 --- /dev/null +++ b/src/util.js @@ -0,0 +1,5 @@ +export function assert (condition, message) { + if (!condition) { + throw new Error(`[vue-promised] ${message}`) + } +} diff --git a/test/index.spec.js b/test/index.spec.js index 7e42059..17403c7 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -1,6 +1,9 @@ import { mount } from '@vue/test-utils' import fakePromise from 'faked-promise' import Helper from './utils/Helper' +import NoError from './utils/NoError' +import NoResolve from './utils/NoResolve' +import NoPending from './utils/NoPending' const tick = () => new Promise(resolve => setTimeout(resolve, 0)) @@ -53,11 +56,13 @@ describe('Promised', () => { describe('multiple promise', () => { let fakedPromises beforeEach(async () => { - fakedPromises = Array.from({ length: 3 }, () => fakePromise()).map(([promise, resolve, reject]) => ({ - promise, - resolve, - reject, - })) + fakedPromises = Array.from({ length: 3 }, () => fakePromise()).map( + ([promise, resolve, reject]) => ({ + promise, + resolve, + reject, + }) + ) const promises = fakedPromises.map(({ promise }) => promise) @@ -107,4 +112,54 @@ describe('Promised', () => { expect(wrapper.text()).toBe('loading') }) }) + + describe('errors', () => { + let promise, resolve, reject, errorSpy + beforeEach(() => { + // silence the log + errorSpy = jest.spyOn(console, 'error').mockImplementation(() => { + // useful for debugging + // console.log('CONSOLE ERROR') + }) + ;[promise, resolve, reject] = fakePromise() + }) + + afterEach(() => { + errorSpy.mockRestore() + }) + + test('throws if no error scoped slot provided on error', async () => { + wrapper = mount(NoError, { + propsData: { + promise, + }, + }) + expect(errorSpy).not.toHaveBeenCalled() + reject(new Error('nope')) + await tick() + expect(errorSpy).toHaveBeenCalledTimes(2) + }) + + test('throws if no default scoped slot provided on resolve', async () => { + wrapper = mount(NoResolve, { + propsData: { + promise, + }, + }) + expect(errorSpy).not.toHaveBeenCalled() + resolve() + await tick() + expect(errorSpy).toHaveBeenCalledTimes(2) + }) + + test('throws if no default slot provided while pending', async () => { + expect(errorSpy).not.toHaveBeenCalled() + wrapper = mount(NoPending, { + propsData: { + promise, + }, + }) + expect(errorSpy).toHaveBeenCalledTimes(2) + }) + }) }) diff --git a/test/utils/NoError.vue b/test/utils/NoError.vue new file mode 100644 index 0000000..dd1089e --- /dev/null +++ b/test/utils/NoError.vue @@ -0,0 +1,21 @@ + + + diff --git a/test/utils/NoPending.vue b/test/utils/NoPending.vue new file mode 100644 index 0000000..3b2ccf6 --- /dev/null +++ b/test/utils/NoPending.vue @@ -0,0 +1,25 @@ + + + diff --git a/test/utils/NoResolve.vue b/test/utils/NoResolve.vue new file mode 100644 index 0000000..db89a7f --- /dev/null +++ b/test/utils/NoResolve.vue @@ -0,0 +1,24 @@ + + +