import { click, findAll, currentURL, currentRouteName, waitFor, visit, } from '@ember/test-helpers'; import { module, test } from 'qunit'; import { setupApplicationTest } from 'ember-qunit'; import { setupIntl, t } from 'ember-intl/test-support'; import { setupMirage } from 'ember-cli-mirage/test-support'; import PollEvaluationPage from 'croodle/tests/pages/poll/evaluation'; import pollParticipate from 'croodle/tests/helpers/poll-participate'; module('Acceptance | participate in a poll', function (hooks) { let yesLabel; let noLabel; hooks.beforeEach(function () { window.localStorage.setItem('locale', 'en'); }); setupApplicationTest(hooks); setupIntl(hooks); setupMirage(hooks); hooks.beforeEach(function () { yesLabel = t('answerTypes.yes.label').toString(); noLabel = t('answerTypes.no.label').toString(); }); test('participate in a default poll', async function (assert) { let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789'; let poll = this.server.create('poll', { encryptionKey, }); await visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`); assert.strictEqual( currentRouteName(), 'poll.participation', 'poll is redirected to poll.participation', ); await pollParticipate('Max Meiner', ['yes', 'no']); assert.strictEqual(currentRouteName(), 'poll.evaluation'); assert.strictEqual( currentURL().split('?')[1], `encryptionKey=${encryptionKey}`, 'encryption key is part of query params', ); assert.strictEqual( PollEvaluationPage.participants.length, 1, 'user is added to participants table', ); let participant = PollEvaluationPage.participants.filterBy( 'name', 'Max Meiner', )[0]; assert.ok(participant, 'user exists in participants table'); assert.deepEqual( participant.selections.map((_) => _.answer), [yesLabel, noLabel], 'participants table shows correct answers for new participant', ); await click('.nav [data-test-link="participation"]'); assert.strictEqual(currentRouteName(), 'poll.participation'); assert.dom('.name input').hasNoValue('input for name is cleared'); assert.notOk( findAll('input[type="radio"]').some((el) => el.checked), 'radios are cleared', ); await pollParticipate('Peter Müller', ['yes', 'yes']); assert.strictEqual(currentRouteName(), 'poll.evaluation'); assert.strictEqual( PollEvaluationPage.participants.length, 2, 'user is added to participants table', ); participant = PollEvaluationPage.participants.filterBy( 'name', 'Peter Müller', )[0]; assert.ok(participant, 'user exists in participants table'); assert.deepEqual( participant.selections.map((_) => _.answer), [yesLabel, yesLabel], 'participants table shows correct answers for new participant', ); }); test('participate in a poll using freetext', async function (assert) { let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789'; let poll = this.server.create('poll', { answerType: 'FreeText', answers: [], encryptionKey, }); await visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`); assert.strictEqual(currentRouteName(), 'poll.participation'); await pollParticipate('Max Manus', ['answer 1', 'answer 2']); assert.strictEqual(currentRouteName(), 'poll.evaluation'); assert.strictEqual( PollEvaluationPage.participants.length, 1, 'user is added to participants table', ); let participant = PollEvaluationPage.participants.filterBy( 'name', 'Max Manus', )[0]; assert.ok(participant, 'user exists in participants table'); assert.deepEqual( participant.selections.map((_) => _.answer), ['answer 1', 'answer 2'], 'participants table shows correct answers for new participant', ); }); test('participate in a poll which does not force an answer to all options', async function (assert) { let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789'; let poll = this.server.create('poll', { encryptionKey, forceAnswer: false, }); await visit( `/poll/${poll.id}/participation?encryptionKey=${encryptionKey}`, ); assert.strictEqual(currentRouteName(), 'poll.participation'); await pollParticipate('Karl Käfer', ['yes', null]); assert.strictEqual(currentRouteName(), 'poll.evaluation'); assert.strictEqual( PollEvaluationPage.participants.length, 1, 'user is added to participants table', ); let participant = PollEvaluationPage.participants.filterBy( 'name', 'Karl Käfer', )[0]; assert.ok(participant, 'user exists in participants table'); assert.deepEqual( participant.selections.map((_) => _.answer), [yesLabel, ''], 'participants table shows correct answers for new participant', ); }); test('participate in a poll which allows anonymous participation', async function (assert) { let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789'; let poll = this.server.create('poll', { anonymousUser: true, encryptionKey, }); await visit( `/poll/${poll.id}/participation?encryptionKey=${encryptionKey}`, ); assert.strictEqual(currentRouteName(), 'poll.participation'); await pollParticipate(null, ['yes', 'no']); assert.strictEqual(currentRouteName(), 'poll.evaluation'); assert.strictEqual( PollEvaluationPage.participants.length, 1, 'user is added to participants table', ); let participant = PollEvaluationPage.participants.filterBy('name', '')[0]; assert.ok(participant, 'user exists in participants table'); assert.deepEqual( participant.selections.map((_) => _.answer), [yesLabel, noLabel], 'participants table shows correct answers for new participant', ); }); test('network connectivity errors', async function (assert) { let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789'; let poll = this.server.create('poll', { encryptionKey, }); this.server.post('/users', undefined, 503); await visit( `/poll/${poll.id}/participation?encryptionKey=${encryptionKey}`, ); assert.strictEqual(currentRouteName(), 'poll.participation'); assert .dom('[data-test-modal="saving-failed"] .modal-content') .isNotVisible( 'failed saving notification is not shown before attempt to save', ); await pollParticipate('John Doe', ['yes', 'no']); assert .dom('[data-test-modal="saving-failed"] .modal-content') .isVisible('user gets notified that saving failed'); this.server.post('/users'); await click('[data-test-modal="saving-failed"] [data-test-button="retry"]'); assert .dom('[data-test-modal="saving-failed"] .modal-content') .isNotVisible( 'Notification is hidden after another save attempt was successful', ); assert.strictEqual(currentRouteName(), 'poll.evaluation'); assert.strictEqual( PollEvaluationPage.participants.length, 1, 'user is added to participants table', ); let participant = PollEvaluationPage.participants.filterBy( 'name', 'John Doe', )[0]; assert.ok(participant, 'user exists in participants table'); assert.deepEqual( participant.selections.map((_) => _.answer), [yesLabel, noLabel], 'participants table shows correct answers for new participant', ); }); test('shows loading spinner while submitting', async function (assert) { let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789'; let poll = this.server.create('poll', { encryptionKey, }); let resolveSubmission; let resolveSubmissionWith; this.server.post('/users', function (schema) { return new Promise((resolve) => { let attrs = this.normalizedRequestAttrs(); resolveSubmission = resolve; resolveSubmissionWith = schema.users.create(attrs); }); }); await visit( `/poll/${poll.id}/participation?encryptionKey=${encryptionKey}`, ); pollParticipate('John Doe', ['yes', 'no']); await waitFor('[data-test-button="submit"] .spinner-border', { timeoutMessage: 'timeout while waiting for loading spinner to appear', }); assert.ok( true, 'loading spinner shown cause otherwise there would have been a timeout', ); // resolve promise for test to finish // need to resolve with a valid response cause otherwise Ember Data would throw resolveSubmission(resolveSubmissionWith); }); module('validation', function () { test('shows validation errors for participation form on submit', async function (assert) { let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789'; let poll = this.server.create('poll', { encryptionKey, }); await visit( `/poll/${poll.id}/participation?encryptionKey=${encryptionKey}`, ); await click('button[type="submit"]'); assert .dom('[data-test-form-element="name"] input') .hasClass('is-invalid'); assert .dom('[data-test-form-element="option-2017-12-24"] input[id$="yes"]') .hasClass('is-invalid'); assert .dom('[data-test-form-element="option-2017-12-24"] input[id$="no"]') .hasClass('is-invalid'); assert .dom('[data-test-form-element="option-2018-01-01"] input[id$="yes"]') .hasClass('is-invalid'); assert .dom('[data-test-form-element="option-2018-01-01"] input[id$="no"]') .hasClass('is-invalid'); assert.dom('[data-test-form-element="name"] input').isFocused(); assert.strictEqual( currentRouteName(), 'poll.participation', 'invalid form prevents a transition', ); }); test('does not show validation error for name if poll allows anonymous participation', async function (assert) { let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789'; let poll = this.server.create('poll', { anonymousUser: true, encryptionKey, }); await visit( `/poll/${poll.id}/participation?encryptionKey=${encryptionKey}`, ); await click('button[type="submit"]'); assert.dom('[data-test-form-element="name"] input').hasClass('is-valid'); assert .dom('[data-test-form-element="option-2017-12-24"] input[id$="yes"]') .hasClass('is-invalid'); assert .dom('[data-test-form-element="option-2017-12-24"] input[id$="no"]') .hasClass('is-invalid'); assert .dom('[data-test-form-element="option-2018-01-01"] input[id$="yes"]') .hasClass('is-invalid'); assert .dom('[data-test-form-element="option-2018-01-01"] input[id$="no"]') .hasClass('is-invalid'); assert .dom('[data-test-form-element="option-2017-12-24"] input[id$="yes"]') .isFocused(); assert.strictEqual( currentRouteName(), 'poll.participation', 'invalid form prevents a transition', ); }); test('does not show validation error for option inputs if poll does not force an answer to each option', async function (assert) { let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789'; let poll = this.server.create('poll', { encryptionKey, forceAnswer: false, }); await visit( `/poll/${poll.id}/participation?encryptionKey=${encryptionKey}`, ); await click('button[type="submit"]'); assert .dom('[data-test-form-element="name"] input') .hasClass('is-invalid'); assert .dom('[data-test-form-element="option-2017-12-24"] input[id$="yes"]') .hasClass('is-valid'); assert .dom('[data-test-form-element="option-2017-12-24"] input[id$="no"]') .hasClass('is-valid'); assert .dom('[data-test-form-element="option-2018-01-01"] input[id$="yes"]') .hasClass('is-valid'); assert .dom('[data-test-form-element="option-2018-01-01"] input[id$="no"]') .hasClass('is-valid'); assert.dom('[data-test-form-element="name"] input').isFocused(); assert.strictEqual( currentRouteName(), 'poll.participation', 'invalid form prevents a transition', ); }); test('does not show validation errors while saving participation', async function (assert) { let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789'; let poll = this.server.create('poll', { encryptionKey, }); let resolveSubmission; let resolveSubmissionWith; this.server.post('/users', function (schema) { return new Promise((resolve) => { let attrs = this.normalizedRequestAttrs(); resolveSubmission = resolve; resolveSubmissionWith = schema.users.create(attrs); }); }); await visit( `/poll/${poll.id}/participation?encryptionKey=${encryptionKey}`, ); pollParticipate('John Doe', ['yes', 'no']); await waitFor('[data-test-button="submit"] .spinner-border', { timeoutMessage: 'timeout while waiting for loading spinner to appear', }); assert .dom('.is-invalid') .doesNotExist('does not show any validation error'); // resolve promise for test to finish // need to resolve with a valid response cause otherwise Ember Data would throw resolveSubmission(resolveSubmissionWith); }); }); });