Skip to content

Commit

Permalink
fix(#408): add more context to error message (#411)
Browse files Browse the repository at this point in the history
* fix(#408): update JSON:API extras integration

* feat(#408): add error for missing index resources

* feat(#408): add context to DruxtModule error

* chore(#408): update tests

* chore(#408): update test coverage

* chore(#408): update test coverage

* refactor(#408): update DruxtModule error method
  • Loading branch information
Decipher authored Dec 30, 2021
1 parent 7b749bd commit bc079cf
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 26 deletions.
28 changes: 16 additions & 12 deletions packages/druxt/src/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,15 +212,23 @@ class DruxtClient {
*
* @throws {Error} A formatted error.
*/
error(err, { url }) {
const title = [(err.response || {}).status, (err.response || {}).statusText].filter((s) => s).join(': ')
const meta = { url: [this.options.baseUrl, url].join('') }
error(err, context = {}) {
let { url } = context
if (!url && ((err.response || {}).config || {}).url) {
url = err.response.config.url
}

const title = [
(err.response || {}).status,
(err.response || {}).statusText || err.message
].filter((s) => s).join(': ')
const meta = { url: url && [this.options.baseUrl, url].join('') }

// Build message.
let message = [title]

// Add meta information.
if (Object.values(meta).filter((o) => o)) {
if (Object.values(meta).filter((o) => o).length) {
message.push(Object.entries(meta).filter(([, v]) => v).map(([key, value]) => `${key.toUpperCase()}: ${value}`).join('\n'))
}

Expand All @@ -231,6 +239,7 @@ class DruxtClient {

const error = Error(message.join('\n\n'))
error.response = err.response
error.druxt = context
throw error
}

Expand Down Expand Up @@ -354,7 +363,7 @@ class DruxtClient {
}

for (const resourceType in resources) {
const resource = resources.data.data[resourceType]
const resource = resources[resourceType]
const internal = resource.attributes.drupal_internal__id.split('--')

const item = {
Expand All @@ -375,12 +384,7 @@ class DruxtClient {
// Set index.
this.index = index

if (resource) {
const response = this.index[resource] ? this.index[resource] : false
return response
}

return this.index
return resource ? this.index[resource] || false : this.index
}

/**
Expand Down Expand Up @@ -434,7 +438,7 @@ class DruxtClient {
href = this.options.endpoint + '/' + type.replace('--', '/')
}

const url = this.buildQueryUrl(`${href}/${id}`, query)
const url = this.buildQueryUrl([href, id].join('/'), query)
const { data } = await this.get(url)
return data
}
Expand Down
22 changes: 17 additions & 5 deletions packages/druxt/src/components/DruxtModule.vue
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ export default {
// Build wrapper component object.
let options = []
const hasDefaultTemplate = !!(this.$vnode.data.scopedSlots || {}).default
const hasDefaultTemplate = !!(((this.$vnode || {}).data || {}).scopedSlots || {}).default
// Load wrapper components if:
if (
// No default template and wrapper isn't false OR
Expand Down Expand Up @@ -144,7 +144,7 @@ export default {
try {
await this.$options.druxt.fetchData.call(this, component.settings)
} catch(err) {
return this.error(err)
return this.error(err, { component })
}
}
Expand Down Expand Up @@ -182,12 +182,24 @@ export default {
/**
* Sets the component to render a DruxtDebug error message.
*/
error(err) {
error(err, context = {}) {
// Build error details.
const { url } = err.druxt || {}
const title = (err.response || {}).statusText || ((((err.response || {}).data || {}).errors || [])[0] || {}).title
const summary = (err.response || {}).status
? [(err.response || {}).status, title].filter((s) => s).join(': ')
: err.message
// Set the component to a Debug component with error details.
this.component = {
...context.component || {},
is: 'DruxtDebug',
props: {
json: (err.response.data || {}).errors,
summary: [err.response.status, err.response.statusText].filter((s) => s).join(': ')
json: {
url,
errors: ((err.response || {}).data || {}).errors
},
summary
}
}
},
Expand Down
4 changes: 2 additions & 2 deletions packages/druxt/src/stores/druxt.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Vue from 'vue'
import { getDrupalJsonApiParams } from '../utils/getDrupalJsonApiParams'

const dehydrateResources = ({ commit, queryObject, resources }) => {
return resources.map((data) => {
return (resources || []).map((data) => {
// Generate a query link for included resources.
// This is used to determine if the resource is a partial.
const link = decodeURI(((data.links || {}).self || {}).href || '')
Expand Down Expand Up @@ -125,7 +125,7 @@ const DruxtStore = ({ store }) => {

// Ensure Resource type array is reactive.
if (!state.resources[type]) Vue.set(state.resources, type, {})

// Extract and store included data.
if (resource.included) {
dehydrateResources({ commit: this.commit, queryObject, resources: resource.included })
Expand Down
16 changes: 16 additions & 0 deletions packages/druxt/test/__snapshots__/client.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,22 @@ Object {
}
`;

exports[`DruxtClient error 1`] = `"Test error"`;

exports[`DruxtClient error 2`] = `
"500: Test error
URL: https://demo-api.druxtjs.org/test/error"
`;

exports[`DruxtClient error 3`] = `
"500: Test error
URL: https://demo-api.druxtjs.org/test/error
Test error details."
`;

exports[`DruxtClient getIndex 1`] = `
Object {
"statusText": "Invalid JSON:API endpoint",
Expand Down
45 changes: 45 additions & 0 deletions packages/druxt/test/client.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,51 @@ describe('DruxtClient', () => {
}
})

test('error', () => {
let mockErr
const url = [baseUrl, 'test/error'].join('/')

// Test basic error.
mockErr = new Error('Test error')
try {
druxt.error(mockErr)
} catch(err) {
expect(err.message).toMatchSnapshot()
}

// Test Axios error.
mockErr = {
response: {
config: { url },
status: '500',
statusText: 'Test error'
}
}
try {
druxt.error(mockErr)
} catch(err) {
expect(err.message).toMatchSnapshot()
}

// Test error with URL context and details.
mockErr = {
response: {
status: '500',
statusText: 'Test error',
data: {
errors: [{
detail: 'Test error details.'
}]
}
}
}
try {
druxt.error(mockErr, { url })
} catch(err) {
expect(err.message).toMatchSnapshot()
}
})

test('getCollection', async () => {
// Get a collection of 'node--page' resources.
const collection = await druxt.getCollection('node--page')
Expand Down
26 changes: 24 additions & 2 deletions packages/druxt/test/components/DruxtModule.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ describe('DruxtModule component', () => {
components: { DruxtModule },
data: () => ({ model: null })
}
const wrapper = mount(Component, { localVue, mocks, stubs: ['DruxtWrapper'] })
const wrapper = mount(Component, { localVue, mocks, stubs: ['DruxtDebug'] })

// Default state.
expect(wrapper.vm.model).toStrictEqual(null)
Expand All @@ -87,7 +87,7 @@ describe('DruxtModule component', () => {
extends: DruxtModule,
}

const wrapper = mount(CustomModule, {localVue, mocks, stubs: ['DruxtWrapper'] })
let wrapper = mount(CustomModule, {localVue, mocks, stubs: ['DruxtDebug'] })
await wrapper.vm.$options.fetch.call(wrapper.vm)

expect(wrapper.vm.component.is).toBe('DruxtWrapper')
Expand All @@ -110,6 +110,28 @@ describe('DruxtModule component', () => {
expect(wrapper.vm.component.is).toBe('DruxtDebug')
// Expect the component props to match snapshot.
expect(wrapper.vm.component.props).toMatchSnapshot()

// Fetch config error.
CustomModule.druxt = {
fetchConfig: async () => { throw new Error('Fetch config error') }
}
wrapper = mount(CustomModule, {localVue, mocks, stubs: ['DruxtDebug'] })
await wrapper.vm.$options.fetch.call(wrapper.vm)
// Expect the component to be DruxtDebug.
expect(wrapper.vm.component.is).toBe('DruxtDebug')
// Expect the component props to match snapshot.
expect(wrapper.vm.component.props).toMatchSnapshot()

// Fetch data error.
CustomModule.druxt = {
fetchData: async () => { throw new Error('Fetch data error') }
}
wrapper = mount(CustomModule, {localVue, mocks, stubs: ['DruxtDebug'] })
await wrapper.vm.$options.fetch.call(wrapper.vm)
// Expect the component to be DruxtDebug.
expect(wrapper.vm.component.is).toBe('DruxtDebug')
// Expect the component props to match snapshot.
expect(wrapper.vm.component.props).toMatchSnapshot()
})

test('custom module - no wrapper', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,34 @@ exports[`DruxtModule component defaults 1`] = `"<div></div>"`;
exports[`DruxtModule component error 1`] = `
Object {
"json": Array [
Object {
"details": "Test error",
},
],
"json": Object {
"errors": Array [
Object {
"details": "Test error",
},
],
"url": undefined,
},
"summary": "500: Test error",
}
`;
exports[`DruxtModule component error 2`] = `
Object {
"json": Object {
"errors": undefined,
"url": undefined,
},
"summary": "Fetch config error",
}
`;
exports[`DruxtModule component error 3`] = `
Object {
"json": Object {
"errors": undefined,
"url": undefined,
},
"summary": "Fetch data error",
}
`;

0 comments on commit bc079cf

Please sign in to comment.