From 30e011f41c2a622efa82174dd4e68494c2c08600 Mon Sep 17 00:00:00 2001 From: akhuoa Date: Mon, 20 Oct 2025 11:50:43 +1300 Subject: [PATCH 1/5] Add server error handling for response with different status --- src/components/MultiFlatmapVuer.vue | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/MultiFlatmapVuer.vue b/src/components/MultiFlatmapVuer.vue index 0fe5f6cf..fd2f0757 100644 --- a/src/components/MultiFlatmapVuer.vue +++ b/src/components/MultiFlatmapVuer.vue @@ -167,7 +167,12 @@ export default { //It has not been initialised yet this.requireInitialisation = false fetch(this.flatmapAPI) - .then((response) => response.json()) + .then((response) => { + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + return response.json() + }) .then((data) => { if (data.status_code === 404) { console.error('Flatmap API endpoint is incorrect', data); From ddd02448813057de1e7e5ea3bac3a1f6b0ed1d14 Mon Sep 17 00:00:00 2001 From: akhuoa Date: Mon, 20 Oct 2025 12:17:02 +1300 Subject: [PATCH 2/5] Add flatmap server test --- cypress/component/FlatmapServerTest.cy.js | 86 +++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 cypress/component/FlatmapServerTest.cy.js diff --git a/cypress/component/FlatmapServerTest.cy.js b/cypress/component/FlatmapServerTest.cy.js new file mode 100644 index 00000000..20a422a1 --- /dev/null +++ b/cypress/component/FlatmapServerTest.cy.js @@ -0,0 +1,86 @@ +import MultiFlatmapVuer from '../../src/components/MultiFlatmapVuer.vue'; +const FLATMAP_API = 'https://mapcore-demo.org/current/flatmap/v3/'; + +describe('MultiFlatmapVuer Error Handling', () => { + + it('should handle 500 Internal Server Error', () => { + cy.intercept('GET', FLATMAP_API, { + statusCode: 500, + body: 'Internal Server Error', + }).as('serverError'); + + cy.mount(MultiFlatmapVuer, { + props: { + flatmapAPI: FLATMAP_API, + initial: 'Mouse', + availableSpecies: { + Mouse: { + taxo: 'NCBITaxon:10090', + iconClass: 'mapicon-icon_mouse', + }, + }, + }, + }); + + cy.wait('@serverError'); + + cy.get('.flatmap-error').should('exist'); + cy.contains('MultiFlatmap Error!').should('be.visible'); + cy.contains('unexpected error').should('be.visible'); + cy.contains('try again later').should('be.visible'); + }); + + it('handles 500 with valid JSON body (would bypass catch)', () => { + cy.intercept('GET', '**/flatmap/v3/', { + statusCode: 500, + headers: { 'content-type': 'application/json' }, + body: [], // valid JSON array -> response.json() resolves + }).as('serverErrorJson'); + + cy.mount(MultiFlatmapVuer, { + props: { + flatmapAPI: FLATMAP_API, + initial: 'Mouse', + availableSpecies: { Mouse: { taxo: 'NCBITaxon:10090' } }, + }, + }); + + cy.wait('@serverErrorJson'); + cy.get('.flatmap-error').should('exist'); + }); + + it('should handle 404 endpoint error', () => { + cy.intercept('GET', FLATMAP_API, { + statusCode: 404, + body: { status_code: 404 }, + }).as('notFoundError'); + + cy.mount(MultiFlatmapVuer, { + props: { + flatmapAPI: FLATMAP_API, + initial: 'Mouse', + }, + }); + + cy.wait('@notFoundError'); + + cy.contains('flatmap API endpoint is incorrect').should('be.visible'); + }); + + it('should handle network failure', () => { + cy.intercept('GET', FLATMAP_API, { + forceNetworkError: true, + }).as('networkError'); + + cy.mount(MultiFlatmapVuer, { + props: { + flatmapAPI: FLATMAP_API, + initial: 'Mouse', + }, + }); + + cy.wait('@networkError'); + + cy.get('.flatmap-error').should('exist'); + }); +}); From 0a5bbd7a20b7179e2c727b8833250461319dca5d Mon Sep 17 00:00:00 2001 From: akhuoa Date: Mon, 20 Oct 2025 12:21:26 +1300 Subject: [PATCH 3/5] Change test species in server testing --- cypress/component/FlatmapServerTest.cy.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cypress/component/FlatmapServerTest.cy.js b/cypress/component/FlatmapServerTest.cy.js index 20a422a1..439c45f0 100644 --- a/cypress/component/FlatmapServerTest.cy.js +++ b/cypress/component/FlatmapServerTest.cy.js @@ -12,11 +12,11 @@ describe('MultiFlatmapVuer Error Handling', () => { cy.mount(MultiFlatmapVuer, { props: { flatmapAPI: FLATMAP_API, - initial: 'Mouse', + initial: 'Rat', availableSpecies: { - Mouse: { - taxo: 'NCBITaxon:10090', - iconClass: 'mapicon-icon_mouse', + Rat: { + taxo: 'NCBITaxon:10114', + iconClass: 'mapicon-icon_rat', }, }, }, @@ -40,8 +40,8 @@ describe('MultiFlatmapVuer Error Handling', () => { cy.mount(MultiFlatmapVuer, { props: { flatmapAPI: FLATMAP_API, - initial: 'Mouse', - availableSpecies: { Mouse: { taxo: 'NCBITaxon:10090' } }, + initial: 'Rat', + availableSpecies: { Rat: { taxo: 'NCBITaxon:10114' } }, }, }); @@ -58,7 +58,7 @@ describe('MultiFlatmapVuer Error Handling', () => { cy.mount(MultiFlatmapVuer, { props: { flatmapAPI: FLATMAP_API, - initial: 'Mouse', + initial: 'Rat', }, }); @@ -75,7 +75,7 @@ describe('MultiFlatmapVuer Error Handling', () => { cy.mount(MultiFlatmapVuer, { props: { flatmapAPI: FLATMAP_API, - initial: 'Mouse', + initial: 'Rat', }, }); From cfa7bf53476d5aacab0f4962970814e84c8d64a7 Mon Sep 17 00:00:00 2001 From: akhuoa Date: Mon, 20 Oct 2025 12:46:54 +1300 Subject: [PATCH 4/5] Add more error endling for flatmap api --- src/components/MultiFlatmapVuer.vue | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/components/MultiFlatmapVuer.vue b/src/components/MultiFlatmapVuer.vue index fd2f0757..7b58c45c 100644 --- a/src/components/MultiFlatmapVuer.vue +++ b/src/components/MultiFlatmapVuer.vue @@ -169,12 +169,28 @@ export default { fetch(this.flatmapAPI) .then((response) => { if (!response.ok) { + // HTTP-level errors + if (response.status === 404) { + this.multiflatmapError = {}; + this.multiflatmapError['title'] = 'MultiFlatmap Error!'; + this.multiflatmapError['messages'] = [ + `Sorry, the component could not be loaded because the specified + flatmap API endpoint is incorrect. Please check the endpoint URL + or contact support if the problem persists.` + ]; + this.initialised = true; + resolve(); + this.resolveList.forEach((other) => other()); + + return Promise.reject({ handled: true }); + } throw new Error(`HTTP ${response.status}: ${response.statusText}`); } return response.json() }) .then((data) => { - if (data.status_code === 404) { + // Application-level 404 in a 200 response + if (data && data.status_code === 404) { console.error('Flatmap API endpoint is incorrect', data); this.multiflatmapError = {}; this.multiflatmapError['title'] = 'MultiFlatmap Error!'; @@ -183,6 +199,11 @@ export default { flatmap API endpoint is incorrect. Please check the endpoint URL or contact support if the problem persists.` ]; + + this.initialised = true; + resolve(); + this.resolveList.forEach((other) => other()); + return; } //Check each key in the provided availableSpecies against the one Object.keys(this.availableSpecies).forEach((key) => { @@ -242,6 +263,7 @@ export default { }) }) .catch((error) => { + if (error && error.handled) return; console.error('Error fetching flatmap:', error) this.initialised = true; this.multiflatmapError = {}; From 0d6da95d0eca0a8ccd0f9dbede8db324b76a5a77 Mon Sep 17 00:00:00 2001 From: alan-wu Date: Fri, 24 Oct 2025 15:01:32 +1300 Subject: [PATCH 5/5] Add an error when the server is unresponsive and does not return any error. --- src/components.d.ts | 2 ++ src/components/MultiFlatmapVuer.vue | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/components.d.ts b/src/components.d.ts index 5600e53a..f762859d 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -8,6 +8,7 @@ export {} declare module 'vue' { export interface GlobalComponents { DynamicLegends: typeof import('./components/legends/DynamicLegends.vue')['default'] + ElAutocomplete: typeof import('element-plus/es')['ElAutocomplete'] ElButton: typeof import('element-plus/es')['ElButton'] ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup'] @@ -24,6 +25,7 @@ declare module 'vue' { ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup'] ElRow: typeof import('element-plus/es')['ElRow'] ElSelect: typeof import('element-plus/es')['ElSelect'] + ElSwitch: typeof import('element-plus/es')['ElSwitch'] FlatmapError: typeof import('./components/FlatmapError.vue')['default'] FlatmapVuer: typeof import('./components/FlatmapVuer.vue')['default'] LegendItem: typeof import('./components/legends/LegendItem.vue')['default'] diff --git a/src/components/MultiFlatmapVuer.vue b/src/components/MultiFlatmapVuer.vue index 7b58c45c..cdfe1450 100644 --- a/src/components/MultiFlatmapVuer.vue +++ b/src/components/MultiFlatmapVuer.vue @@ -166,7 +166,11 @@ export default { if (this.requireInitialisation) { //It has not been initialised yet this.requireInitialisation = false - fetch(this.flatmapAPI) + const controller = new AbortController(); + const signal = controller.signal; + const timeoutId = setTimeout(() => controller.abort(), 5000); + + fetch(this.flatmapAPI, {signal}) .then((response) => { if (!response.ok) { // HTTP-level errors @@ -278,6 +282,9 @@ export default { other() }) }) + .finally(() => { + clearTimeout(timeoutId); + }); } else if (this.initialised) { //resolve as it has been initialised resolve()