Skip to content

Commit 85c8896

Browse files
authored
Merge pull request #315 from akhuoa/bugfix/server-error
Fix and Test Flatmap API Server Error
2 parents 4246288 + f036d18 commit 85c8896

File tree

3 files changed

+125
-3
lines changed

3 files changed

+125
-3
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import MultiFlatmapVuer from '../../src/components/MultiFlatmapVuer.vue';
2+
const FLATMAP_API = 'https://mapcore-demo.org/current/flatmap/v3/';
3+
4+
describe('MultiFlatmapVuer Error Handling', () => {
5+
6+
it('should handle 500 Internal Server Error', () => {
7+
cy.intercept('GET', FLATMAP_API, {
8+
statusCode: 500,
9+
body: 'Internal Server Error',
10+
}).as('serverError');
11+
12+
cy.mount(MultiFlatmapVuer, {
13+
props: {
14+
flatmapAPI: FLATMAP_API,
15+
initial: 'Rat',
16+
availableSpecies: {
17+
Rat: {
18+
taxo: 'NCBITaxon:10114',
19+
iconClass: 'mapicon-icon_rat',
20+
},
21+
},
22+
},
23+
});
24+
25+
cy.wait('@serverError');
26+
27+
cy.get('.flatmap-error').should('exist');
28+
cy.contains('MultiFlatmap Error!').should('be.visible');
29+
cy.contains('unexpected error').should('be.visible');
30+
cy.contains('try again later').should('be.visible');
31+
});
32+
33+
it('handles 500 with valid JSON body (would bypass catch)', () => {
34+
cy.intercept('GET', '**/flatmap/v3/', {
35+
statusCode: 500,
36+
headers: { 'content-type': 'application/json' },
37+
body: [], // valid JSON array -> response.json() resolves
38+
}).as('serverErrorJson');
39+
40+
cy.mount(MultiFlatmapVuer, {
41+
props: {
42+
flatmapAPI: FLATMAP_API,
43+
initial: 'Rat',
44+
availableSpecies: { Rat: { taxo: 'NCBITaxon:10114' } },
45+
},
46+
});
47+
48+
cy.wait('@serverErrorJson');
49+
cy.get('.flatmap-error').should('exist');
50+
});
51+
52+
it('should handle 404 endpoint error', () => {
53+
cy.intercept('GET', FLATMAP_API, {
54+
statusCode: 404,
55+
body: { status_code: 404 },
56+
}).as('notFoundError');
57+
58+
cy.mount(MultiFlatmapVuer, {
59+
props: {
60+
flatmapAPI: FLATMAP_API,
61+
initial: 'Rat',
62+
},
63+
});
64+
65+
cy.wait('@notFoundError');
66+
67+
cy.contains('flatmap API endpoint is incorrect').should('be.visible');
68+
});
69+
70+
it('should handle network failure', () => {
71+
cy.intercept('GET', FLATMAP_API, {
72+
forceNetworkError: true,
73+
}).as('networkError');
74+
75+
cy.mount(MultiFlatmapVuer, {
76+
props: {
77+
flatmapAPI: FLATMAP_API,
78+
initial: 'Rat',
79+
},
80+
});
81+
82+
cy.wait('@networkError');
83+
84+
cy.get('.flatmap-error').should('exist');
85+
});
86+
});

src/components.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export {}
88
declare module 'vue' {
99
export interface GlobalComponents {
1010
DynamicLegends: typeof import('./components/legends/DynamicLegends.vue')['default']
11+
ElAutocomplete: typeof import('element-plus/es')['ElAutocomplete']
1112
ElButton: typeof import('element-plus/es')['ElButton']
1213
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
1314
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
@@ -24,6 +25,7 @@ declare module 'vue' {
2425
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
2526
ElRow: typeof import('element-plus/es')['ElRow']
2627
ElSelect: typeof import('element-plus/es')['ElSelect']
28+
ElSwitch: typeof import('element-plus/es')['ElSwitch']
2729
FlatmapError: typeof import('./components/FlatmapError.vue')['default']
2830
FlatmapVuer: typeof import('./components/FlatmapVuer.vue')['default']
2931
LegendItem: typeof import('./components/legends/LegendItem.vue')['default']

src/components/MultiFlatmapVuer.vue

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,10 +166,35 @@ export default {
166166
if (this.requireInitialisation) {
167167
//It has not been initialised yet
168168
this.requireInitialisation = false
169-
fetch(this.flatmapAPI)
170-
.then((response) => response.json())
169+
const controller = new AbortController();
170+
const signal = controller.signal;
171+
const timeoutId = setTimeout(() => controller.abort(), 5000);
172+
173+
fetch(this.flatmapAPI, {signal})
174+
.then((response) => {
175+
if (!response.ok) {
176+
// HTTP-level errors
177+
if (response.status === 404) {
178+
this.multiflatmapError = {};
179+
this.multiflatmapError['title'] = 'MultiFlatmap Error!';
180+
this.multiflatmapError['messages'] = [
181+
`Sorry, the component could not be loaded because the specified
182+
flatmap API endpoint is incorrect. Please check the endpoint URL
183+
or contact support if the problem persists.`
184+
];
185+
this.initialised = true;
186+
resolve();
187+
this.resolveList.forEach((other) => other());
188+
189+
return Promise.reject({ handled: true });
190+
}
191+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
192+
}
193+
return response.json()
194+
})
171195
.then((data) => {
172-
if (data.status_code === 404) {
196+
// Application-level 404 in a 200 response
197+
if (data && data.status_code === 404) {
173198
console.error('Flatmap API endpoint is incorrect', data);
174199
this.multiflatmapError = {};
175200
this.multiflatmapError['title'] = 'MultiFlatmap Error!';
@@ -178,6 +203,11 @@ export default {
178203
flatmap API endpoint is incorrect. Please check the endpoint URL
179204
or contact support if the problem persists.`
180205
];
206+
207+
this.initialised = true;
208+
resolve();
209+
this.resolveList.forEach((other) => other());
210+
return;
181211
}
182212
//Check each key in the provided availableSpecies against the one
183213
Object.keys(this.availableSpecies).forEach((key) => {
@@ -237,6 +267,7 @@ export default {
237267
})
238268
})
239269
.catch((error) => {
270+
if (error && error.handled) return;
240271
console.error('Error fetching flatmap:', error)
241272
this.initialised = true;
242273
this.multiflatmapError = {};
@@ -251,6 +282,9 @@ export default {
251282
other()
252283
})
253284
})
285+
.finally(() => {
286+
clearTimeout(timeoutId);
287+
});
254288
} else if (this.initialised) {
255289
//resolve as it has been initialised
256290
resolve()

0 commit comments

Comments
 (0)