From 17cfb4ab6da3330901ee2e8c547356ace88ab09f Mon Sep 17 00:00:00 2001 From: jelhan Date: Tue, 23 Apr 2019 17:37:42 +0200 Subject: [PATCH] Meaningful error pages (#177) Adds meaningful error pages if - poll does not exist - encryption key is wrong. --- app/controllers/error.js | 7 +---- app/controllers/poll-error.js | 11 +++++++ app/locales/ca/translations.js | 8 ++++++ app/locales/de/translations.js | 8 ++++++ app/locales/en/translations.js | 8 ++++++ app/locales/es/translations.js | 8 ++++++ app/locales/it/translations.js | 8 ++++++ app/templates/error.hbs | 11 +++---- app/templates/poll-error.hbs | 32 +++++++++++++++++++++ tests/acceptance/view-poll-test.js | 35 ++++++++++++++++++++++- tests/unit/controllers/poll-error-test.js | 12 ++++++++ 11 files changed, 134 insertions(+), 14 deletions(-) create mode 100644 app/controllers/poll-error.js create mode 100644 app/templates/poll-error.hbs create mode 100644 tests/unit/controllers/poll-error-test.js diff --git a/app/controllers/error.js b/app/controllers/error.js index 2d4ca4c..75ceaae 100644 --- a/app/controllers/error.js +++ b/app/controllers/error.js @@ -1,8 +1,3 @@ -import { computed } from '@ember/object'; import Controller from '@ember/controller'; -export default Controller.extend({ - isDecryptionError: computed('model.type', function() { - return this.get('model.type') === 'decryption-failed'; - }) -}); +export default Controller.extend({}); diff --git a/app/controllers/poll-error.js b/app/controllers/poll-error.js new file mode 100644 index 0000000..56daf02 --- /dev/null +++ b/app/controllers/poll-error.js @@ -0,0 +1,11 @@ +import Controller from '@ember/controller'; +import { computed } from '@ember/object'; +import { equal } from '@ember/object/computed'; +import sjcl from 'sjcl'; + +export default Controller.extend({ + decryptionFailed: computed('model', function() { + return this.model instanceof sjcl.exception.corrupt; + }), + notFound: equal('model.errors.firstObject.status', '404') +}); diff --git a/app/locales/ca/translations.js b/app/locales/ca/translations.js index 33cdf46..b782ff4 100644 --- a/app/locales/ca/translations.js +++ b/app/locales/ca/translations.js @@ -44,6 +44,14 @@ export default { 'create.settings.forceAnswer.label': 'Força una resposta per a cada opció?', 'create.title': 'Crea una enquesta', 'error': 'Error', + 'error.poll.decryptionFailed.title': 'Decryption failed', + 'error.poll.decryptionFailed.description': 'Decrypting poll data failed. This is most likely caused by a wrong encryption key. Please double-check the URL entered, especially the part after the question mark.', + 'error.poll.notFound.title': 'Poll could not be found', + 'error.poll.notFound.description': 'The poll you are looking for could not be found. This could be caused by different reasons, including:', + 'error.poll.notFound.reasons.expired': 'The poll is expired and has been deleted.', + 'error.poll.notFound.reasons.typo': 'There is a typo in the URL. You may want to double-check it - especially the part before the question mark.', + 'error.generic.unexpected.title': 'An unexpected error occured', + 'error.generic.unexpected.description': 'We are sorry. An unexpected error occurred. Please try again later.', 'index.title': 'Croodle simplifica la data i la presa de decisions ...
... i protegeix les teves dades', 'index.features.title': 'Funcions', 'index.features.list.overview': ' Troba una data o fer una enquesta amb tantes persones com vulgui.', diff --git a/app/locales/de/translations.js b/app/locales/de/translations.js index 4ac98c1..25c3dfc 100644 --- a/app/locales/de/translations.js +++ b/app/locales/de/translations.js @@ -44,6 +44,14 @@ export default { 'create.settings.forceAnswer.label': 'Eine Antwort für jede Option erzwingen?', 'create.title': 'Umfrage erstellen', 'error': 'Fehler', + 'error.poll.decryptionFailed.title': 'Decryption failed', + 'error.poll.decryptionFailed.description': 'Decrypting poll data failed. This is most likely caused by a wrong encryption key. Please double-check the URL entered, especially the part after the question mark.', + 'error.poll.notFound.title': 'Poll could not be found', + 'error.poll.notFound.description': 'The poll you are looking for could not be found. This could be caused by different reasons, including:', + 'error.poll.notFound.reasons.expired': 'The poll is expired and has been deleted.', + 'error.poll.notFound.reasons.typo': 'There is a typo in the URL. You may want to double-check it - especially the part before the question mark.', + 'error.generic.unexpected.title': 'An unexpected error occured', + 'error.generic.unexpected.description': 'We are sorry. An unexpected error occurred. Please try again later.', 'index.title': 'Croodle vereinfacht die Termin- und Entscheidungsfindung ...
... und schützt dabei deine Daten', 'index.features.title': 'Funktionen', 'index.features.list.overview': 'Finde einen Termin oder mache eine Umfrage mit so vielen Leuten, wie du möchtest.', diff --git a/app/locales/en/translations.js b/app/locales/en/translations.js index 56135d7..9754057 100644 --- a/app/locales/en/translations.js +++ b/app/locales/en/translations.js @@ -44,6 +44,14 @@ export default { 'create.settings.forceAnswer.label': 'Force an answer for every option?', 'create.title': 'Create a poll', 'error': 'Error', + 'error.poll.decryptionFailed.title': 'Decryption failed', + 'error.poll.decryptionFailed.description': 'Decrypting poll data failed. This is most likely caused by a wrong encryption key. Please double-check the URL entered, especially the part after the question mark.', + 'error.poll.notFound.title': 'Poll could not be found', + 'error.poll.notFound.description': 'The poll you are looking for could not be found. This could be caused by different reasons, including:', + 'error.poll.notFound.reasons.expired': 'The poll is expired and has been deleted.', + 'error.poll.notFound.reasons.typo': 'There is a typo in the URL. You may want to double-check it - especially the part before the question mark.', + 'error.generic.unexpected.title': 'An unexpected error occured', + 'error.generic.unexpected.description': 'We are sorry. An unexpected error occurred. Please try again later.', 'index.title': 'Croodle simplifies date and decision-making ...
... and protects your data', 'index.features.title': 'Functions', 'index.features.list.overview': 'Find a date or make a survey with as many people as you want.', diff --git a/app/locales/es/translations.js b/app/locales/es/translations.js index 84073ad..d95967b 100644 --- a/app/locales/es/translations.js +++ b/app/locales/es/translations.js @@ -44,6 +44,14 @@ export default { 'create.settings.forceAnswer.label': '¿Obligar a responder todas las preguntas/opciones?', 'create.title': 'Crear una encuesta', 'error': 'Error', + 'error.poll.decryptionFailed.title': 'Decryption failed', + 'error.poll.decryptionFailed.description': 'Decrypting poll data failed. This is most likely caused by a wrong encryption key. Please double-check the URL entered, especially the part after the question mark.', + 'error.poll.notFound.title': 'Poll could not be found', + 'error.poll.notFound.description': 'The poll you are looking for could not be found. This could be caused by different reasons, including:', + 'error.poll.notFound.reasons.expired': 'The poll is expired and has been deleted.', + 'error.poll.notFound.reasons.typo': 'There is a typo in the URL. You may want to double-check it - especially the part before the question mark.', + 'error.generic.unexpected.title': 'An unexpected error occured', + 'error.generic.unexpected.description': 'We are sorry. An unexpected error occurred. Please try again later.', 'index.title': 'Croodle simplifica las citas y la toma de decisiones ...
... y al mismo tiempo protege tus datos', 'index.features.title': 'Funciones', 'index.features.list.overview': 'Encontrar una fecha o hacer una encuesta con la cantidad de personas que quieras.', diff --git a/app/locales/it/translations.js b/app/locales/it/translations.js index 85be780..f2808b0 100644 --- a/app/locales/it/translations.js +++ b/app/locales/it/translations.js @@ -44,6 +44,14 @@ export default { 'create.settings.forceAnswer.label': 'Forzare una risposta per ogni opzione?', 'create.title': 'Crea un sondaggio', 'error': 'Errore', + 'error.poll.decryptionFailed.title': 'Decryption failed', + 'error.poll.decryptionFailed.description': 'Decrypting poll data failed. This is most likely caused by a wrong encryption key. Please double-check the URL entered, especially the part after the question mark.', + 'error.poll.notFound.title': 'Poll could not be found', + 'error.poll.notFound.description': 'The poll you are looking for could not be found. This could be caused by different reasons, including:', + 'error.poll.notFound.reasons.expired': 'The poll is expired and has been deleted.', + 'error.poll.notFound.reasons.typo': 'There is a typo in the URL. You may want to double-check it - especially the part before the question mark.', + 'error.generic.unexpected.title': 'An unexpected error occured', + 'error.generic.unexpected.description': 'We are sorry. An unexpected error occurred. Please try again later.', 'index.title': 'Croodle semplifica la scelta delle date e il processo decisionale ...
... e protegge i tuoi dati', 'index.features.title': 'funzioni', 'index.features.list.overview': 'Trova una data o fai una inchiesta con tante persone come vuoi.', diff --git a/app/templates/error.hbs b/app/templates/error.hbs index b3bec0b..de0dda0 100644 --- a/app/templates/error.hbs +++ b/app/templates/error.hbs @@ -1,11 +1,8 @@
-

error

+

+ {{t "error.generic.unexpected.title"}} +

- {{#if isDecryptionError}} - Decryption failed. Please double check the URL. Make sure that no - character is missing. - {{else}} - We are sorry. An unexpected error occurred. - {{/if}} + {{t "error.generic.unexpected.description"}}

diff --git a/app/templates/poll-error.hbs b/app/templates/poll-error.hbs new file mode 100644 index 0000000..ce1de5f --- /dev/null +++ b/app/templates/poll-error.hbs @@ -0,0 +1,32 @@ +
+ {{#if decryptionFailed}} +

+ {{t "error.poll.decryptionFailed.title"}} +

+

+ {{t "error.poll.decryptionFailed.description"}} +

+ {{else if notFound}} +

+ {{t "error.poll.notFound.title"}} +

+

+ {{t "error.poll.notFound.description"}} +

+ + {{else}} +

+ {{t "error.poll.unexpected.title"}} +

+

+ {{t "error.poll.unexpected.description"}} +

+ {{/if}} +
\ No newline at end of file diff --git a/tests/acceptance/view-poll-test.js b/tests/acceptance/view-poll-test.js index 6b33c21..b86c39d 100644 --- a/tests/acceptance/view-poll-test.js +++ b/tests/acceptance/view-poll-test.js @@ -1,4 +1,4 @@ -import { click, visit } from '@ember/test-helpers'; +import { click, currentURL, currentRouteName, visit } from '@ember/test-helpers'; import { module, test } from 'qunit'; import { setupApplicationTest } from 'ember-qunit'; import setupMirage from 'ember-cli-mirage/test-support/setup-mirage'; @@ -211,4 +211,37 @@ module('Acceptance | view poll', function(hooks) { [moment.tz('2015-12-12T11:11:00.000Z', timezonePoll).locale('en').format('LLLL')] ); }); + + test('shows error page if poll does not exist', async function(assert) { + let pollId = 'not-existing'; + let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789'; + + await visit(`/poll/${pollId}?encryptionKey=${encryptionKey}`); + assert.equal(currentURL(), `/poll/${pollId}?encryptionKey=${encryptionKey}`, 'shows URL entered by user'); + assert.equal(currentRouteName(), 'poll_error', 'shows error substate of poll route'); + assert.dom('[data-test-error-type]').hasAttribute('data-test-error-type', 'not-found'); + }); + + test('shows error page if encryption key is wrong', async function(assert) { + let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789'; + let poll = this.server.create('poll', { encryptionKey: 'anotherkey' }); + + await visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`); + assert.equal(currentURL(), `/poll/${poll.id}?encryptionKey=${encryptionKey}`, 'shows URL entered by user'); + assert.equal(currentRouteName(), 'poll_error', 'shows error substate of poll route'); + assert.dom('[data-test-error-type]').hasAttribute('data-test-error-type', 'decryption-failed'); + }); + + test('shows error page if server returns a 500', async function(assert) { + let pollId = 'not-existing'; + let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789'; + + // mock server returning 500 error + this.server.get('polls/:id', () => {}, 500); + + await visit(`/poll/${pollId}?encryptionKey=${encryptionKey}`); + assert.equal(currentURL(), `/poll/${pollId}?encryptionKey=${encryptionKey}`, 'shows URL entered by user'); + assert.equal(currentRouteName(), 'poll_error', 'shows error substate of poll route'); + assert.dom('[data-test-error-type]').hasAttribute('data-test-error-type', 'unexpected'); + }) }); diff --git a/tests/unit/controllers/poll-error-test.js b/tests/unit/controllers/poll-error-test.js new file mode 100644 index 0000000..746ae50 --- /dev/null +++ b/tests/unit/controllers/poll-error-test.js @@ -0,0 +1,12 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Controller | poll-error', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let controller = this.owner.lookup('controller:poll-error'); + assert.ok(controller); + }); +});