]> git.openstreetmap.org Git - nominatim-ui.git/commitdiff
catch and report JSON parsing errors, simulate API HTTP responses (#168)
authormtmail <mtmail@gmx.net>
Wed, 27 Oct 2021 16:32:48 +0000 (18:32 +0200)
committerGitHub <noreply@github.com>
Wed, 27 Oct 2021 16:32:48 +0000 (18:32 +0200)
src/lib/api_utils.js
test/api_errors.js [new file with mode: 0644]

index eb2a549c8eb938a0acd81a0d6a9758145ffbc95f..8de3f0f237e1880fa5bf539be9b09c434a105b2e 100644 (file)
@@ -10,17 +10,43 @@ function api_request_progress(status) {
 export async function fetch_from_api(endpoint_name, params, callback) {
   var api_url = generate_nominatim_api_url(endpoint_name, params);
 
+  // For the test suite:
+  // If httpbin_status URL parameter is set we call https://httpbin.org/#/Status_codes
+  var tmp_params = new URLSearchParams(window.location.search);
+  if (tmp_params && tmp_params.get('httpbin_status')) {
+    api_url = 'https://httpbin.org/status/' + parseInt(tmp_params.get('httpbin_status'), 10);
+  }
+
   api_request_progress('start');
   if (endpoint_name !== 'status') last_api_request_url_store.set(null);
 
   try {
     await fetch(api_url, { headers: Nominatim_Config.Nominatim_API_Endpoint_Headers || {} })
-      .then(response => response.json())
-      .then(data => {
-        if (data.error) {
-          error_store.set(data.error.message);
+      .then(async (response) => {
+        if (!((response.status >= 200 && response.status < 300) || response.status === 404)) {
+          error_store.set(`Error fetching data from ${api_url} (${response.statusText})`);
+          return undefined;
+        }
+
+        // Parse JSON here instead of returning a promise so we can catch possible
+        // errors.
+        var data;
+        try {
+          data = await response.json();
+        } catch (err) {
+          // e.g. 'JSON.parse: unexpected non-whitespace character after JSON data at line 1'
+          error_store.set(`Error parsing JSON data from ${api_url} (${err})`);
+          return undefined;
+        }
+        return data;
+      })
+      .then((data) => {
+        if (data) {
+          if (data.error) {
+            error_store.set(data.error.message);
+          }
+          callback(data);
         }
-        callback(data);
         api_request_progress('finish');
       });
   } catch (error) {
diff --git a/test/api_errors.js b/test/api_errors.js
new file mode 100644 (file)
index 0000000..b5eef6d
--- /dev/null
@@ -0,0 +1,43 @@
+const assert = require('assert');
+
+describe('Nominatim API errors', function () {
+  let page;
+
+  describe('HTTP 503 - service unavailable', function () {
+    before(async function () {
+      page = await browser.newPage();
+      await page.goto('http://localhost:9999/search.html?q=london&httpbin_status=503');
+    });
+
+    after(async function () {
+      await page.close();
+    });
+
+    it('should display an error', async function () {
+      await page.waitForSelector('#error');
+
+      let message = await page.$eval('#error', el => el.textContent);
+      assert.ok(message.includes('httpbin.org'));
+      assert.ok(message.includes('Error fetching data from'));
+    });
+  });
+
+  describe('HTTP 200 - JSON parsing fails', function () {
+    before(async function () {
+      page = await browser.newPage();
+      await page.goto('http://localhost:9999/search.html?q=london&httpbin_status=200');
+    });
+
+    after(async function () {
+      await page.close();
+    });
+
+    it('should display an error', async function () {
+      await page.waitForSelector('#error');
+
+      let message = await page.$eval('#error', el => el.textContent);
+      assert.ok(message.includes('httpbin.org'));
+      assert.ok(message.includes('Error parsing JSON data from'));
+    });
+  });
+});