diff --git a/README.md b/README.md index b47c08f..1076c37 100644 --- a/README.md +++ b/README.md @@ -45,23 +45,12 @@ remote-input[loading] .loading-icon { display: inline; } ### Events -```js -const remoteInput = document.querySelector('remote-input') - -// Network request lifecycle events. -remoteInput.addEventListener('loadstart', function(event) { - console.log('Network request started', event) -}) -remoteInput.addEventListener('loadend', function(event) { - console.log('Network request complete', event) -}) -remoteInput.addEventListener('load', function(event) { - console.log('Network request succeeded', event) -}) -remoteInput.addEventListener('error', function(event) { - console.log('Network request failed', event) -}) -``` +- `loadstart` - The server fetch has started. +- `load` - The network request completed successfully. +- `error` - The network request failed. +- `loadend` - The network request has completed. +- `remote-input-success` – Received a successful response (status code 200-299). Bubbles. +- `remote-input-error` – Received a not successful response. Bubbles. ## Browser support diff --git a/index.js b/index.js index 16a1227..45e12d6 100644 --- a/index.js +++ b/index.js @@ -70,18 +70,30 @@ async function fetchResults(remoteInput: RemoteInputElement, checkCurrentQuery: remoteInput.dispatchEvent(new CustomEvent('loadstart')) remoteInput.setAttribute('loading', '') + let response + let errored = false + let html = '' try { - const response = await fetch(url, { + response = await fetch(url, { credentials: 'same-origin', headers: {accept: 'text/html; fragment'} }) - const html = await response.text() + html = await response.text() remoteInput.dispatchEvent(new CustomEvent('load')) - resultsContainer.innerHTML = html } catch { + errored = true remoteInput.dispatchEvent(new CustomEvent('error')) } remoteInput.removeAttribute('loading') + if (errored) return + + if (response && response.ok) { + remoteInput.dispatchEvent(new CustomEvent('remote-input-success', {bubbles: true})) + resultsContainer.innerHTML = html + } else { + remoteInput.dispatchEvent(new CustomEvent('remote-input-error', {bubbles: true})) + } + remoteInput.dispatchEvent(new CustomEvent('loadend')) } diff --git a/test/karma.config.js b/test/karma.config.js index edf3501..8c2620a 100644 --- a/test/karma.config.js +++ b/test/karma.config.js @@ -1,13 +1,23 @@ function reply(request, response, next) { if (request.method === 'GET') { - response.writeHead(200) - response.end(` -
    -
  1. item
  2. -
  3. item
  4. -
  5. item
  6. -
- `) + if (request.url.startsWith('/500')) { + response.writeHead(500) + response.ok = false + response.end('Server error') + } else if (request.url.startsWith('/network-error')) { + request.destroy(new Error()) + response.end() + } else { + response.writeHead(200) + response.ok = true + response.end(` +
    +
  1. item
  2. +
  3. item
  4. +
  5. item
  6. +
+ `) + } return } next() diff --git a/test/test.js b/test/test.js index 00b6ef0..81b2e79 100644 --- a/test/test.js +++ b/test/test.js @@ -30,7 +30,12 @@ describe('remote-input', function() { const input = document.querySelector('input') const results = document.querySelector('#results') assert.equal(results.innerHTML, '') + let successEvent = false + remoteInput.addEventListener('remote-input-success', function() { + successEvent = true + }) remoteInput.addEventListener('loadend', function() { + assert.ok(successEvent, 'success event happened') assert.equal(results.querySelector('ol').getAttribute('data-src'), '/results?q=test') done() }) @@ -38,6 +43,42 @@ describe('remote-input', function() { input.focus() }) + it('handles not ok responses', function(done) { + const remoteInput = document.querySelector('remote-input') + const input = document.querySelector('input') + const results = document.querySelector('#results') + remoteInput.src = '/500' + assert.equal(results.innerHTML, '') + let errorEvent = false + remoteInput.addEventListener('remote-input-error', function() { + errorEvent = true + }) + remoteInput.addEventListener('loadend', function() { + assert.ok(errorEvent, 'error event happened') + assert.equal(results.innerHTML, '', 'nothing was appended') + done() + }) + input.value = 'test' + input.focus() + }) + + it('handles network error', function(done) { + const remoteInput = document.querySelector('remote-input') + const input = document.querySelector('input') + const results = document.querySelector('#results') + remoteInput.src = '/network-error' + assert.equal(results.innerHTML, '') + remoteInput.addEventListener('error', async function() { + await Promise.resolve() + assert.equal(results.innerHTML, '', 'nothing was appended') + assert.notOk(remoteInput.hasAttribute('loading'), 'loading attribute was removed') + done() + }) + input.value = 'test' + input.focus() + assert.ok(remoteInput.hasAttribute('loading'), 'loading attribute was added') + }) + it('repects param attribute', function(done) { const remoteInput = document.querySelector('remote-input') const input = document.querySelector('input')