upgrade to ember 3.4

This commit is contained in:
Jeldrik Hanschke 2018-12-29 20:35:04 +01:00 committed by jelhan
parent b7e63ed83b
commit bcd4bc7ac6
94 changed files with 5485 additions and 6034 deletions

18
.eslintignore Normal file
View file

@ -0,0 +1,18 @@
# unconventional js
/blueprints/*/files/
/vendor/
# compiled output
/dist/
/tmp/
# dependencies
/bower_components/
# misc
/coverage/
# ember-try
/.node_modules.ember-try/
/bower.json.ember-try
/package.json.ember-try

View file

@ -1,7 +1,4 @@
module.exports = {
globals: {
server: true,
},
root: true,
parserOptions: {
ecmaVersion: 2017,
@ -24,8 +21,10 @@ module.exports = {
// node files
{
files: [
'testem.js',
'.template-lintrc.js',
'ember-cli-build.js',
'testem.js',
'blueprints/*/index.js',
'config/**/*.js',
'lib/*/index.js'
],
@ -37,24 +36,6 @@ module.exports = {
browser: false,
node: true
}
},
// test files
{
files: ['tests/**/*.js'],
excludedFiles: ['tests/dummy/**/*.js'],
env: {
embertest: true
},
globals: {
backButton: true,
pollHasUser: true,
pollHasUsersCount: true,
pollParticipate: true,
setupBrowserNavigationButtons: true,
switchTab: true,
t: true,
}
}
]
};

30
.gitignore vendored
View file

@ -1,27 +1,27 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist
/tmp
/api/tests/_output
/api/tests/_tmp
/api/tests/_support/_generated
/dist/
/tmp/
/api/tests/_output/
/api/tests/_tmp/
/api/tests/_support/_generated/
# dependencies
/node_modules
/bower_components
/api/vendor
/bower_components/
/node_modules/
/api/vendor/
# misc
/.sass-cache
/connect.lock
/coverage/*
/coverage/
/libpeerconnection.log
npm-debug.log*
yarn-error.log
testem.log
/npm-debug.log*
/testem.log
/yarn-error.log
# ember-try
.node_modules.ember-try/
bower.json.ember-try
package.json.ember-try
/.node_modules.ember-try/
/bower.json.ember-try
/package.json.ember-try

5
.template-lintrc.js Normal file
View file

@ -0,0 +1,5 @@
'use strict';
module.exports = {
extends: 'recommended'
};

View file

@ -45,6 +45,7 @@ before_script:
script:
# run frontend and integration tests
- if $TEST_EMBER; then yarn run lint:hbs; fi
- if $TEST_EMBER; then yarn run lint:js; fi
- if $TEST_EMBER; then yarn test; fi
# test against different browsers using sauce lab

View file

@ -1,252 +0,0 @@
## Module Report
### Unknown Global
**Global**: `Ember.inject`
**Location**: `app/controllers/create.js` at line 3
```js
import Ember from 'ember';
const { computed, Controller, getOwner, inject } = Ember;
const formStepObject = Ember.Object.extend({
```
### Unknown Global
**Global**: `Ember.inject`
**Location**: `app/adapters/application.js` at line 5
```js
const { RESTAdapter } = DS;
const { inject } = Ember;
export default RESTAdapter.extend({
```
### Unknown Global
**Global**: `Ember.inject`
**Location**: `app/controllers/poll.js` at line 7
```js
computed,
Controller,
inject,
isEmpty,
isPresent,
```
### Unknown Global
**Global**: `Ember.inject`
**Location**: `app/components/create-options-dates.js` at line 4
```js
import moment from 'moment';
const { computed, Component, inject, isArray, isEmpty } = Ember;
export default Component.extend({
```
### Unknown Global
**Global**: `Ember.inject`
**Location**: `app/components/create-options-datetime.js` at line 9
```js
import Form from 'ember-bootstrap/components/bs-form';
const { computed, Component, inject, isArray, isEmpty, isPresent, observer } = Ember;
const { filter, mapBy, readOnly } = computed;
```
### Unknown Global
**Global**: `Ember.inject`
**Location**: `app/components/create-options-text.js` at line 5
```js
import { anyBy } from 'ember-array-computed-macros';
const { Component, computed, inject, observer, run } = Ember;
export default Component.extend({
```
### Unknown Global
**Global**: `Ember.inject`
**Location**: `app/components/create-options.js` at line 7
```js
from 'ember-cp-validations';
const { Component, inject } = Ember;
let Validations = buildValidations({
```
### Unknown Global
**Global**: `Ember.inject`
**Location**: `app/components/form-navigation-buttons.js` at line 4
```js
import { translationMacro as t } from 'ember-i18n';
const { Component, computed, get, inject } = Ember;
export default Component.extend({
```
### Unknown Global
**Global**: `Ember.inject`
**Location**: `app/components/language-select.js` at line 4
```js
import localesMeta from 'croodle/locales/meta';
const { Component, computed, inject } = Ember;
export default Component.extend({
```
### Unknown Global
**Global**: `Ember.inject`
**Location**: `app/components/poll-evaluation-chart.js` at line 4
```js
import moment from 'moment';
const { Component, computed, get, inject, isArray, isPresent } = Ember;
const addArrays = function() {
```
### Unknown Global
**Global**: `Ember.inject`
**Location**: `app/models/option.js` at line 12
```js
const { attr } = DS;
const { assert, computed, inject, isEmpty } = Ember;
const Validations = buildValidations({
```
### Unknown Global
**Global**: `Ember.inject`
**Location**: `app/controllers/create/index.js` at line 7
```js
from 'ember-cp-validations';
const { computed, Controller, getOwner, Object: EmberObject, inject } = Ember;
const Validations = buildValidations({
```
### Unknown Global
**Global**: `Ember.inject`
**Location**: `app/controllers/create/meta.js` at line 7
```js
from 'ember-cp-validations';
const { computed, Controller, inject } = Ember;
const Validations = buildValidations({
```
### Unknown Global
**Global**: `Ember.inject`
**Location**: `app/controllers/create/settings.js` at line 13
```js
copy,
getOwner,
inject,
isEmpty,
Object: EmberObject,
```
### Unknown Global
**Global**: `Ember.ObjectController`
**Location**: `app/controllers/modal/save-retry.js` at line 3
```js
import Ember from 'ember';
const { $, ObjectController } = Ember;
export default ObjectController.extend({
```
### Unknown Global
**Global**: `Ember.inject`
**Location**: `app/controllers/poll/evaluation.js` at line 3
```js
import Ember from 'ember';
const { $, computed, Controller, inject } = Ember;
export default Controller.extend({
```
### Unknown Global
**Global**: `Ember.inject`
**Location**: `app/controllers/poll/participation.js` at line 12
```js
Controller,
getOwner,
inject,
isEmpty,
isPresent,
```
### Unknown Global
**Global**: `Ember.K`
**Location**: `tests/helpers/flash-message.js` at line 4
```js
import FlashObject from 'ember-cli-flash/flash/object';
const { K } = Ember;
FlashObject.reopen({ init: K });
```

View file

@ -13,7 +13,7 @@ export default Component.extend({
*/
optionsBootstrapDatepicker: computed('options', {
get() {
const options = this.get('options');
const options = this.options;
const validDates = options.filter(function(option) {
return moment(option.get('title')).isValid();
});
@ -38,7 +38,7 @@ export default Component.extend({
* value is an of Date objects set by ember-cli-bootstrap-datepicker
*/
set(key, days) {
const options = this.get('options');
const options = this.options;
// remove all days if value isn't an array of if it's empty
if (!isArray(days) || isEmpty(days)) {
@ -81,7 +81,7 @@ export default Component.extend({
}
options.insertAt(
position,
this.get('store').createFragment('option', {
this.store.createFragment('option', {
title: moment(newDay).format('YYYY-MM-DD')
})
);

View file

@ -28,9 +28,9 @@ let modelValidations = buildValidations({
export default Component.extend(modelValidations, {
actions: {
addOption(afterOption) {
let options = this.get('dates');
let options = this.dates;
let dayString = afterOption.get('day');
let fragment = this.get('store').createFragment('option', {
let fragment = this.store.createFragment('option', {
title: dayString
});
let position = options.indexOf(afterOption) + 1;
@ -40,10 +40,10 @@ export default Component.extend(modelValidations, {
);
},
adoptTimesOfFirstDay() {
const dates = this.get('dates');
const datesForFirstDay = this.get('datesForFirstDay');
const timesForFirstDay = this.get('timesForFirstDay');
const datesWithoutFirstDay = this.get('groupedDates').slice(1);
const dates = this.dates;
const datesForFirstDay = this.datesForFirstDay;
const timesForFirstDay = this.timesForFirstDay;
const datesWithoutFirstDay = this.groupedDates.slice(1);
/* validate if times on firstDay are valid */
const datesForFirstDayAreValid = datesForFirstDay.every((date) => {
@ -82,7 +82,7 @@ export default Component.extend(modelValidations, {
const basisDate = get(items[0], 'date').clone();
let [hour, minute] = timeOfFirstDate.split(':');
let dateString = basisDate.hour(hour).minute(minute).toISOString();
let fragment = this.get('store').createFragment('option', {
let fragment = this.store.createFragment('option', {
title: dateString
});
dates.insertAt(
@ -104,12 +104,12 @@ export default Component.extend(modelValidations, {
* otherwise it deletes time for this date
*/
deleteOption(target) {
let position = this.get('dates').indexOf(target);
let datesForThisDay = this.get('groupedDates').find((group) => {
let position = this.dates.indexOf(target);
let datesForThisDay = this.groupedDates.find((group) => {
return group.value === target.get('day');
}).items;
if (datesForThisDay.length > 1) {
this.get('dates').removeAt(position);
this.dates.removeAt(position);
} else {
target.set('time', null);
}
@ -154,7 +154,7 @@ export default Component.extend(modelValidations, {
return isArray(formElements) ? formElements : [];
}),
daysValidationState: computed('formElements.@each.validation', function() {
return this.get('formElements').reduce(function(daysValidationState, item) {
return this.formElements.reduce(function(daysValidationState, item) {
const day = item.get('model.day');
const validation = item.get('validation');
let currentValidationState;

View file

@ -2,24 +2,32 @@ import { inject as service } from '@ember/service';
import { filter } from '@ember/object/computed';
import Component from '@ember/component';
import { observer, computed, get } from '@ember/object';
import { run } from '@ember/runloop';
import { run, next } from '@ember/runloop';
import BsFormElement from 'ember-bootstrap/components/bs-form/element';
import { any } from 'ember-awesome-macros/array';
export default Component.extend({
actions: {
addOption(element) {
let fragment = this.get('store').createFragment('option');
let options = this.get('options');
let position = this.get('options').indexOf(element) + 1;
let fragment = this.store.createFragment('option');
let options = this.options;
let position = this.options.indexOf(element) + 1;
options.insertAt(
position,
fragment
);
next(() => {
this.notifyPropertyChange('childViews');
});
},
deleteOption(element) {
let position = this.get('options').indexOf(element);
this.get('options').removeAt(position);
let position = this.options.indexOf(element);
this.options.removeAt(position);
next(() => {
this.notifyPropertyChange('childViews');
});
}
},
@ -32,13 +40,13 @@ export default Component.extend({
}),
everyElementIsValid: computed('childFormElements.@each.validation', function() {
const anyElementIsInvalid = this.get('anyElementIsInvalid');
const anyElementIsInvalid = this.anyElementIsInvalid;
if (anyElementIsInvalid) {
return false;
}
// childFormElements contains button wrapper element which should not be taken into account here
const childFormElements = this.get('childFormElements').filterBy('hasValidator');
const childFormElements = this.childFormElements.filterBy('hasValidator');
if (childFormElements) {
return childFormElements.every((childFormElement) => {
return childFormElement.get('hasFeedback') && childFormElement.get('validation') === 'success';
@ -57,11 +65,11 @@ export default Component.extend({
run.scheduleOnce('sync', () => {
let validationClass;
if (!this.get('anyElementHasFeedback')) {
if (!this.anyElementHasFeedback) {
validationClass = 'label-has-no-validation';
} else if (this.get('anyElementIsInvalid')) {
} else if (this.anyElementIsInvalid) {
validationClass = 'label-has-error';
} else if (this.get('everyElementIsValid')) {
} else if (this.everyElementIsValid) {
validationClass = 'label-has-success';
} else {
validationClass = 'label-has-no-validation';
@ -75,14 +83,18 @@ export default Component.extend({
enforceMinimalOptionsAmount: observer('options', 'isMakeAPoll', function() {
if (this.get('options.length') < 2) {
let options = this.get('options');
let options = this.options;
for (let missingOptions = 2 - this.get('options.length'); missingOptions > 0; missingOptions--) {
options.pushObject(
this.get('store').createFragment('option')
this.store.createFragment('option')
);
}
}
}).on('init'),
store: service('store')
store: service('store'),
didInsertElement() {
this.notifyPropertyChange('childViews');
}
});

View file

@ -1,6 +1,6 @@
import { inject as service } from '@ember/service';
import Component from '@ember/component';
import { get, computed } from '@ember/object';
import { computed } from '@ember/object';
import { translationMacro as t } from 'ember-i18n';
export default Component.extend({
@ -38,7 +38,7 @@ export default Component.extend({
* @private
*/
nextButtonClasses: computed('renderPrevButton', function() {
let renderPrevButton = get(this, 'renderPrevButton');
let renderPrevButton = this.renderPrevButton;
if (renderPrevButton) {
return ['col-xs-6', 'col-md-8'];
@ -53,7 +53,7 @@ export default Component.extend({
* @private
*/
nextButtonClassesString: computed('nextButtonClasses.[]', function() {
let nextButtonClasses = get(this, 'nextButtonClasses');
let nextButtonClasses = this.nextButtonClasses;
return nextButtonClasses.join(' ');
}),

View file

@ -25,6 +25,12 @@ export default Component.extend({
change() {
let locale = this.$().val();
this.get('i18n').set('locale', locale);
this.i18n.set('locale', locale);
this.moment.changeLocale(locale);
if (window.localStorage) {
window.localStorage.setItem('locale', locale);
}
}
});

View file

@ -27,30 +27,30 @@ export default Component.extend({
i18n: service(),
type: 'bar',
data: computed('users.[]', 'options.{[],each.title}', 'currentLocale', function() {
let labels = this.get('options').map((option) => {
let labels = this.options.map((option) => {
let value = get(option, 'title');
if (!get(this, 'isFindADate')) {
if (!this.isFindADate) {
return value;
}
let hasTime = value.length > 10; // 'YYYY-MM-DD'.length === 10
let momentFormat = hasTime ? 'LLLL' : get(this, 'momentLongDayFormat');
let timezone = get(this, 'timezone');
let momentFormat = hasTime ? 'LLLL' : this.momentLongDayFormat;
let timezone = this.timezone;
let date = hasTime && isPresent(timezone) ? moment.tz(value, timezone) : moment(value);
date.locale(get(this, 'currentLocale'));
date.locale(this.currentLocale);
return date.format(momentFormat);
});
let datasets = [];
let participants = this.get('users.length');
let yes = this.get('users').map((user) => {
let yes = this.users.map((user) => {
return user.get('selections').map((selection) => {
return selection.get('type') === 'yes' ? 1 : 0;
});
});
datasets.push({
label: this.get('i18n').t('answerTypes.yes.label').toString(),
label: this.i18n.t('answerTypes.yes.label').toString(),
backgroundColor: 'rgba(151,187,205,0.5)',
borderColor: 'rgba(151,187,205,0.8)',
hoverBackgroundColor: 'rgba(151,187,205,0.75)',
@ -58,14 +58,14 @@ export default Component.extend({
data: addArrays.apply(this, yes).map((value) => Math.round(value / participants * 100))
});
if (this.get('answerType') === 'YesNoMaybe') {
let maybe = this.get('users').map((user) => {
if (this.answerType === 'YesNoMaybe') {
let maybe = this.users.map((user) => {
return user.get('selections').map((selection) => {
return selection.get('type') === 'maybe' ? 1 : 0;
});
});
datasets.push({
label: this.get('i18n').t('answerTypes.maybe.label').toString(),
label: this.i18n.t('answerTypes.maybe.label').toString(),
backgroundColor: 'rgba(220,220,220,0.5)',
borderColor: 'rgba(220,220,220,0.8)',
hoverBackgroundColor: 'rgba(220,220,220,0.75)',

View file

@ -7,7 +7,7 @@ import { getOwner } from '@ember/application';
const formStepObject = EmberObject.extend({
active: computed('routing.currentRouteName', function() {
const currentRouteName = this.get('routing.currentRouteName');
return currentRouteName === this.get('route');
return currentRouteName === this.route;
}),
disabled: true,
hidden: false,
@ -15,7 +15,7 @@ const formStepObject = EmberObject.extend({
route: null,
routing: service('-routing'),
updateDisabledState: observer('active', function() {
if (this.get('active')) {
if (this.active) {
this.set('disabled', false);
}
}).on('init'),
@ -35,7 +35,7 @@ export default Controller.extend({
}),
formStepObject.extend({
label: computed('pollType', function() {
const pollType = this.get('pollType');
const pollType = this.pollType;
if (pollType === 'FindADate') {
return 'create.formStep.options.days';
} else {
@ -44,18 +44,18 @@ export default Controller.extend({
}),
pollType: readOnly('model.pollType')
}).create(owner.ownerInjection(), {
model: this.get('model'),
model: this.model,
route: 'create.options'
}),
formStepObject.extend({
hidden: computed('pollType', function() {
const pollType = this.get('pollType');
const pollType = this.pollType;
return pollType !== 'FindADate';
}),
pollType: readOnly('model.pollType')
}).create(owner.ownerInjection(), {
label: 'create.formStep.options-datetime',
model: this.get('model'),
model: this.model,
route: 'create.options-datetime'
}),
formStepObject.create(owner.ownerInjection(), {

View file

@ -24,7 +24,7 @@ const Validations = buildValidations({
const TranslateableObject = EmberObject.extend({
i18n: service(),
label: computed('labelTranslation', 'i18n.locale', function() {
return this.get('i18n').t(this.get('labelTranslation'));
return this.i18n.t(this.labelTranslation);
}),
labelTranslation: undefined
});

View file

@ -12,7 +12,7 @@ export default Controller.extend({
},
normalizeOptions() {
const options = this.get('options');
const options = this.options;
// remove all days from options which haven't a time but there is atleast
// one option with time for that day

View file

@ -4,7 +4,7 @@ import Controller from '@ember/controller';
export default Controller.extend({
actions: {
nextPage() {
if (this.get('isFindADate')) {
if (this.isFindADate) {
this.transitionToRoute('create.options-datetime');
} else {
this.transitionToRoute('create.settings');

View file

@ -1,7 +1,6 @@
import { inject as service } from '@ember/service';
import { alias } from '@ember/object/computed';
import Controller from '@ember/controller';
import { copy } from '@ember/object/internals';
import { getOwner } from '@ember/application';
import { isEmpty } from '@ember/utils';
import EmberObject, { observer, computed } from '@ember/object';
@ -32,7 +31,7 @@ const Validations = buildValidations({
const TranslateableObject = EmberObject.extend({
i18n: service(),
label: computed('labelTranslation', 'i18n.locale', function() {
return this.get('i18n').t(this.get('labelTranslation'));
return this.i18n.t(this.labelTranslation);
}),
labelTranslation: undefined
});
@ -41,7 +40,7 @@ export default Controller.extend(Validations, {
actions: {
submit() {
if (this.get('validations.isValid')) {
const model = this.get('model');
const model = this.model;
// set timezone if there is atleast one option with time
if (
this.get('model.isFindADate') &&
@ -58,7 +57,7 @@ export default Controller.extend(Validations, {
// reload as workaround for bug: duplicated records after save
model.reload().then((model) => {
// redirect to new poll
this.get('target').send('transitionToPoll', model);
this.target.send('transitionToPoll', model);
});
})
.catch(() => {
@ -169,13 +168,13 @@ export default Controller.extend(Validations, {
*/
updateAnswers: observer('model.answerType', function() {
const selectedAnswer = this.get('model.answerType');
const answerTypes = this.get('answerTypes');
const answerTypes = this.answerTypes;
let answers = [];
if (selectedAnswer !== null) {
for (let i = 0; i < answerTypes.length; i++) {
if (answerTypes[i].id === selectedAnswer) {
answers = answerTypes[i].answers.map(copy);
answers = answerTypes[i].answers.slice();
}
}
@ -184,7 +183,7 @@ export default Controller.extend(Validations, {
}),
updateExpirationDate: observer('expirationDuration', function() {
const expirationDuration = this.get('expirationDuration');
const expirationDuration = this.expirationDuration;
if (isEmpty(expirationDuration)) {
this.set('model.expirationDate', '');

View file

@ -8,7 +8,7 @@ import moment from 'moment';
export default Controller.extend({
actions: {
linkAction(type) {
let flashMessages = this.get('flashMessages');
let flashMessages = this.flashMessages;
switch (type) {
case 'copied':
flashMessages.success(`poll.link.copied`);
@ -47,7 +47,7 @@ export default Controller.extend({
i18n: service(),
momentLongDayFormat: computed('currentLocale', function() {
let currentLocale = this.get('currentLocale');
let currentLocale = this.currentLocale;
return moment.localeData(currentLocale)
.longDateFormat('LLLL')
.replace(
@ -62,10 +62,10 @@ export default Controller.extend({
preventEncryptionKeyChanges: observer('encryptionKey', function() {
if (
!isEmpty(this.get('encryption.key')) &&
this.get('encryptionKey') !== this.get('encryption.key')
this.encryptionKey !== this.get('encryption.key')
) {
// work-a-round for url not being updated
window.location.hash = window.location.hash.replace(this.get('encryptionKey'), this.get('encryption.key'));
window.location.hash = window.location.hash.replace(this.encryptionKey, this.get('encryption.key'));
this.set('encryptionKey', this.get('encryption.key'));
}
@ -92,10 +92,10 @@ export default Controller.extend({
useLocalTimezone: false,
mustChooseTimezone: computed('timezoneDiffers', 'timezoneChoosen', function() {
return this.get('timezoneDiffers') && !this.get('timezoneChoosen');
return this.timezoneDiffers && !this.timezoneChoosen;
}),
timezone: computed('useLocalTimezone', function() {
return this.get('useLocalTimezone') ? undefined : this.get('model.timezone');
return this.useLocalTimezone ? undefined : this.get('model.timezone');
})
});

View file

@ -65,14 +65,14 @@ export default Controller.extend(Validations, {
version: config.APP.version,
});
user.set('name', this.get('name'));
user.set('name', this.name);
const selections = user.get('selections');
const possibleAnswers = this.get('pollController.model.answers');
this.get('selections').forEach((selection) => {
this.selections.forEach((selection) => {
if (selection.get('value') !== null) {
if (this.get('isFreeText')) {
if (this.isFreeText) {
selections.createFragment({
label: selection.get('value')
});
@ -95,18 +95,18 @@ export default Controller.extend(Validations, {
}
},
save() {
const user = this.get('newUserRecord');
const user = this.newUserRecord;
user.save()
.then(() => {
this.set('savingFailed', false);
// reset form
this.set('name', '');
this.get('selections').forEach((selection) => {
this.selections.forEach((selection) => {
selection.set('value', null);
});
this.transitionToRoute('poll.evaluation', this.get('model'), {
this.transitionToRoute('poll.evaluation', this.model, {
queryParams: { encryptionKey: this.get('encryption.key') }
});
}, () => {
@ -151,7 +151,7 @@ export default Controller.extend(Validations, {
return AnswerObject.extend(owner.ownerInjection(), {
i18n: service(),
label: computed('i18n.locale', function() {
return this.get('i18n').t(this.get('labelTranslation'));
return this.i18n.t(this.labelTranslation);
}),
labelTranslation: answer.get('labelTranslation')
}).create();
@ -166,8 +166,8 @@ export default Controller.extend(Validations, {
savingFailed: false,
selections: computed('options', 'pollController.dates', function() {
let options = this.get('options');
let isFindADate = this.get('isFindADate');
let options = this.options;
let isFindADate = this.isFindADate;
let lastDate;
// https://github.com/offirgolan/ember-cp-validations#basic-usage---objects
@ -177,8 +177,8 @@ export default Controller.extend(Validations, {
let SelectionObject = EmberObject.extend(owner.ownerInjection(), SelectionValidations, {
// forceAnswer and isFreeText must be included in model
// cause otherwise validations can't depend on it
forceAnswer: this.get('forceAnswer'),
isFreeText: this.get('isFreeText'),
forceAnswer: this.forceAnswer,
isFreeText: this.isFreeText,
value: null
});
@ -190,7 +190,7 @@ export default Controller.extend(Validations, {
// format label
if (isFindADate) {
let hasTime = value.length > 10; // 'YYYY-MM-DD'.length === 10
let timezone = this.get('timezone');
let timezone = this.timezone;
let date = isPresent(timezone) ? moment.tz(value, timezone) : moment(value);
if (hasTime && lastDate && date.format('YYYY-MM-DD') === lastDate.format('YYYY-MM-DD')) {
labelValue = value;

View file

@ -1,14 +1,16 @@
import { getOwner } from '@ember/application';
import { isPresent, isEmpty } from '@ember/utils';
export default {
name: 'i18n',
initialize(appInstance) {
let i18n = appInstance.lookup('service:i18n');
let availableLocales = i18n.get('locales');
let moment = appInstance.lookup('service:moment');
i18n.addObserver('locale', i18n, localeChanged);
i18n.set('locale', getLocale(availableLocales));
let availableLocales = i18n.get('locales');
let locale = getLocale(availableLocales);
i18n.set('locale', locale);
moment.changeLocale(locale);
}
};
@ -102,20 +104,3 @@ function getSavedLocale() {
return [locale];
}
function saveLocale(locale) {
let { localStorage } = window;
// test browser support
if (!localStorage) {
return;
}
localStorage.setItem('locale', locale);
}
function localeChanged() {
let locale = this.get('locale');
getOwner(this).lookup('service:moment').changeLocale(locale);
saveLocale(locale);
}

View file

@ -9,7 +9,7 @@ export default Mixin.create({
didInsertElement() {
this._super(...arguments);
if (this.get('autofocus')) {
if (this.autofocus) {
this.$().focus();
}
}

View file

@ -61,7 +61,7 @@ export default Fragment.extend(Validations, {
'YYYY-MM-DD',
'YYYY-MM-DDTHH:mm:ss.SSSZ'
];
const value = this.get('title');
const value = this.title;
if (isEmpty(value)) {
return;
}
@ -79,7 +79,7 @@ export default Fragment.extend(Validations, {
}),
day: computed('date', function() {
const date = this.get('date');
const date = this.date;
if (!moment.isMoment(date)) {
return;
}
@ -87,7 +87,7 @@ export default Fragment.extend(Validations, {
}),
dayFormatted: computed('date', 'i18n.locale', function() {
let date = this.get('date');
let date = this.date;
if (!moment.isMoment(date)) {
return;
}
@ -110,19 +110,19 @@ export default Fragment.extend(Validations, {
}),
hasTime: computed('title', function() {
return moment.isMoment(this.get('date')) &&
this.get('title').length === 'YYYY-MM-DDTHH:mm:ss.SSSZ'.length;
return moment.isMoment(this.date) &&
this.title.length === 'YYYY-MM-DDTHH:mm:ss.SSSZ'.length;
}),
time: computed('date', {
get() {
const date = this.get('date');
const date = this.date;
if (!moment.isMoment(date)) {
return;
}
// verify that value is an ISO 8601 date string containg time
// testing length is faster than parsing with moment
const value = this.get('title');
const value = this.title;
if (value.length !== 'YYYY-MM-DDTHH:mm:ss.SSSZ'.length) {
return;
}
@ -130,7 +130,7 @@ export default Fragment.extend(Validations, {
return date.format('HH:mm');
},
set(key, value) {
const date = this.get('date');
const date = this.date;
assert(
'can not set a time if current value is not a valid date',
moment.isMoment(date)

View file

@ -65,14 +65,14 @@ export default Model.extend({
* computed properties
*/
isFindADate: computed('pollType', function() {
return this.get('pollType') === 'FindADate';
return this.pollType === 'FindADate';
}),
isFreeText: computed('answerType', function() {
return this.get('answerType') === 'FreeText';
return this.answerType === 'FreeText';
}),
isMakeAPoll: computed('pollType', function() {
return this.get('pollType') === 'MakeAPoll';
return this.pollType === 'MakeAPoll';
})
});

View file

@ -9,7 +9,7 @@ export default Route.extend({
transitionToPoll(poll) {
this.transitionTo('poll', poll, {
queryParams: {
encryptionKey: this.get('encryptionKey')
encryptionKey: this.encryptionKey
}
});
}
@ -22,7 +22,7 @@ export default Route.extend({
}
// set encryption key
this.get('encryption').generateKey();
this.encryption.generateKey();
},
encryption: service(),

View file

@ -31,7 +31,7 @@ export default DS.RESTSerializer.extend({
attributes.options.encrypted !== false
) {
if (typeof resourceHash[key] !== 'undefined' && resourceHash[key] !== null) {
resourceHash[key] = this.get('encryption').decrypt(resourceHash[key]);
resourceHash[key] = this.encryption.decrypt(resourceHash[key]);
}
}
}, this);
@ -63,7 +63,7 @@ export default DS.RESTSerializer.extend({
if (
attribute.options.encrypted !== false
) {
json[key] = this.get('encryption').encrypt(json[key]);
json[key] = this.encryption.encrypt(json[key]);
}
}
});

View file

@ -8,7 +8,7 @@ export default Service.extend({
decrypt(value) {
return JSON.parse(
sjcl.decrypt(
this.get('key'),
this.key,
value
)
);
@ -16,7 +16,7 @@ export default Service.extend({
encrypt(value) {
return sjcl.encrypt(
this.get('key'),
this.key,
JSON.stringify(value)
);
},

View file

@ -1,8 +1,8 @@
{{title 'Croodle'}}
{{title "Croodle"}}
<div class="container">
<div id="header">
<h1 class="logo">{{#link-to 'index'}}Croodle{{/link-to}}</h1>
<h1 class="logo">{{#link-to "index"}}Croodle{{/link-to}}</h1>
<form class="form-inline">
{{language-select class="form-control"}}
</form>
@ -12,11 +12,6 @@
{{#each flashMessages.queue as |flash|}}
{{#flash-message flash=flash}}
{{t flash.message}}
{{#if showProgressBar}}
<div class="alert-progress">
<div class="alert-progressBar" style={{progressDuration}}></div>
</div>
{{/if}}
{{/flash-message}}
{{/each}}
</div>
@ -25,4 +20,4 @@
</div>
</div>
{{outlet 'modal'}}
{{outlet "modal"}}

View file

@ -1,8 +1,8 @@
{{#form.element
classNames='days'
label=(t 'create.options.dates.label')
property='options'
as |el|
classNames="days"
label=(t "create.options.dates.label")
property="options"
as |el|
}}
{{bootstrap-datepicker-inline
id=el.id

View file

@ -6,18 +6,24 @@
{{/if}}
{{#bs-form
onSubmit=(action 'submit')
formLayout='horizontal'
onSubmit=(action "submit")
formLayout="horizontal"
model=this
novalidate=true
as |form|
as |form|
}}
<div class="days">
{{#each dates as |date index|}}
{{!
show summarized validation state for all times in a day
}}
<div class="{{unless (get daysValidationState date.day) 'label-has-no-validation' (concat 'label-has-' (get daysValidationState date.day))}}">
<div
class={{if
(get daysValidationState date.day)
(concat "label-has-" (get daysValidationState date.day))
"label-has-no-validation"
}}
>
{{!
show label only if it differ from label before
Nested-helpers are called first and object-at requires a positive integer
@ -26,34 +32,56 @@
by zero there can't be any element with an index === array.length.
}}
{{#form.element
classNames='option'
classNames="option"
label=date.dayFormatted
invisibleLabel=(eq date.dayFormatted (get (object-at (if index (sub index 1) dates.length) dates) 'dayFormatted'))
invisibleLabel=(eq date.dayFormatted (get (object-at (if index (sub index 1) dates.length) dates) "dayFormatted"))
model=date
property='time'
as |el|
property="time"
as |el|
}}
<div class="input-group">
{{bs-form/element/control/input
autofocus=(unless index true false)
id=el.id
placeholder='00:00'
type='time'
placeholder="00:00"
type="time"
value=el.value
onChange=(action (mut el.value))
}}
<div class="input-group-btn">
{{! disable delete button if there is only one option }}
<button {{action 'deleteOption' date}}
class="delete btn {{if (eq el.validation 'success') 'btn-success'}} {{if (eq el.validation 'error') 'btn-danger'}} {{unless el.validation 'btn-default'}}">
<span class='glyphicon glyphicon-trash' aria-hidden='true'></span>
<span class='sr-only'>{{t 'create.options.button.delete.label'}}</span>
</button>
<button {{action 'addOption' date}}
class="add btn {{if (eq el.validation 'success') 'btn-success'}} {{if (eq el.validation 'error') 'btn-danger'}} {{unless el.validation 'btn-default'}}">
<span class='glyphicon glyphicon-plus' aria-hidden='true'></span>
<span class='sr-only'>{{t 'create.options.button.add.label'}}</span>
</button>
{{#bs-button
onClick=(action "deleteOption" date)
type=(if
(eq el.validation "success")
"btn-success"
(if
(eq el.validation "error")
"btn-danger"
"btn-default"
)
)
class="delete"
}}
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
<span class="sr-only">{{t "create.options.button.delete.label"}}</span>
{{/bs-button}}
{{#bs-button
onClick=(action "addOption" date)
type=(if
(eq el.validation "success")
"btn-success"
(if
(eq el.validation "error")
"btn-danger"
"btn-default"
)
)
class="add"
}}
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
<span class="sr-only">{{t "create.options.button.add.label"}}</span>
{{/bs-button}}
</div>
</div>
{{/form.element}}
@ -63,12 +91,17 @@
{{#if (gt groupedDates.length 1)}}
{{#form.element}}
<button {{action "adoptTimesOfFirstDay"}} class="btn btn-default adopt-times-of-first-day">{{t "create.options-datetime.copy-first-line"}}</button>
{{#bs-button
onClick=(action "adoptTimesOfFirstDay")
class="adopt-times-of-first-day"
}}
{{t "create.options-datetime.copy-first-line"}}
{{/bs-button}}
{{/form.element}}
{{/if}}
{{form-navigation-buttons
onPrev=(action 'previousPage')
onPrev=(action "previousPage")
}}
{{/bs-form}}
</div>

View file

@ -1,11 +1,11 @@
{{#each options as |option index|}}
{{! show label only on first item }}
{{#form.element
classNames='option'
label=(unless index (t 'create.options.options.label'))
classNames="option"
label=(unless index (t "create.options.options.label"))
model=option
property='title'
as |el|
property="title"
as |el|
}}
<div class="input-group">
{{bs-form/element/control/input
@ -16,17 +16,39 @@
}}
<div class="input-group-btn">
{{! disable delete button if there is only one option }}
<button {{action 'deleteOption' option}}
class="delete btn {{if (eq el.validation 'success') 'btn-success'}} {{if (eq el.validation 'error') 'btn-danger'}} {{unless el.validation 'btn-default'}}"
disabled={{if (gt options.length 1) false true}}>
<span class='glyphicon glyphicon-trash' aria-hidden='true'></span>
<span class='sr-only'>{{t 'create.options.button.delete.label'}}</span>
</button>
<button {{action 'addOption' option}}
class="add btn {{if (eq el.validation 'success') 'btn-success'}} {{if (eq el.validation 'error') 'btn-danger'}} {{unless el.validation 'btn-default'}}">
<span class='glyphicon glyphicon-plus' aria-hidden='true'></span>
<span class='sr-only'>{{t 'create.options.button.add.label'}}</span>
</button>
{{#bs-button
onClick=(action "deleteOption" option)
type=(if
(eq el.validation "success")
"btn-success"
(if
(eq el.validation "error")
"btn-danger"
"btn-default"
)
)
disabled=(lte options.length 1)
class="delete"
}}
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
<span class="sr-only">{{t "create.options.button.delete.label"}}</span>
{{/bs-button}}
{{#bs-button
onClick=(action "addOption" option)
type=(if
(eq el.validation "success")
"btn-success"
(if
(eq el.validation "error")
"btn-danger"
"btn-default"
)
)
class="add"
}}
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
<span class="sr-only">{{t "create.options.button.add.label"}}</span>
{{/bs-button}}
</div>
</div>
{{/form.element}}

View file

@ -1,17 +1,17 @@
<div class="box">
{{#bs-form
action='submit'
formLayout='horizontal'
action="submit"
formLayout="horizontal"
model=this
novalidate=true
onSubmit=(action 'submit')
as |form|
onSubmit=(action "submit")
as |form|
}}
{{#if isMakeAPoll}}
{{create-options-text
options=options
addOption='addOption'
deleteOption='deleteOption'
addOption="addOption"
deleteOption="deleteOption"
form=form
}}
{{else}}
@ -22,7 +22,7 @@
{{/if}}
{{form-navigation-buttons
onPrev=(action 'previousPage')
onPrev=(action "previousPage")
}}
{{/bs-form}}
</div>

View file

@ -2,21 +2,21 @@
{{#if renderPrevButton}}
<div class="col-xs-6 col-md-4 text-right">
{{bs-button
onClick=(action 'prev')
classNames='prev'
onClick=(action "prev")
classNames="prev"
disabled=disablePrevButton
defaultText=prevButtonText
}}
</div>
{{/if}}
{{#if renderNextButton}}
<div class="{{nextButtonClassesString}}">
<div class={{nextButtonClassesString}}>
{{bs-button
buttonType='submit'
classNames='next'
buttonType="submit"
classNames="next"
defaultText=nextButtonText
disabled=disableNextButton
type='primary'
type="primary"
}}
</div>
{{/if}}

View file

@ -1,3 +1,5 @@
{{#each locales as |locale|}}
<option value="{{locale.id}}" selected={{locale.selected}}>{{locale.text}}</option>
<option value={{locale.id}} selected={{locale.selected}}>
{{locale.text}}
</option>
{{/each}}

View file

@ -5,7 +5,7 @@
<tr class="dateGroups">
<th>&nbsp;</th>
{{#each optionsGroupedByDates as |optionGroup|}}
<th colspan="{{optionGroup.items.length}}">
<th colspan={{optionGroup.items.length}}>
{{moment-format
optionGroup.value
momentLongDayFormat
@ -26,7 +26,7 @@
{{#if option.hasTime}}
{{moment-format
option.title
'LT'
"LT"
locale=currentLocale
timeZone=timezone
}}
@ -60,8 +60,8 @@
{{/if}}
{{#if selection.labelTranslation}}
{{#unless isFreeText}}
<span class="{{selection.type}}">
<span class="{{selection.icon}}"></span>
<span class={{selection.type}}>
<span class={{selection.icon}}></span>
{{t selection.labelTranslation}}
</span>
{{/unless}}

View file

@ -3,37 +3,58 @@
we will see a space between option string and following dot.
--}}
{{#if isFindADate}}
<strong class='best-option-value'>{{moment-format
evaluationBestOption.option.title
(if evaluationBestOption.option.hasTime 'LLLL' momentLongDayFormat)
locale=currentLocale
timeZone=timezone
}}</strong>.
{{! Need to disable block indentation rule cause there shouldn't be a space between date and dot }}
{{! template-lint-disable block-indentation }}
<strong class="best-option-value">
{{moment-format
evaluationBestOption.option.title
(if evaluationBestOption.option.hasTime "LLLL" momentLongDayFormat)
locale=currentLocale
timeZone=timezone
}}</strong>.
{{! template-lint-enable block-indentation }}
{{else}}
<strong class='best-option-value'>{{evaluationBestOption.option.title}}</strong>.
<strong class="best-option-value">{{evaluationBestOption.option.title}}</strong>.
{{/if}}
<br/>
<br>
{{#if isFindADate}}
{{#if evaluationBestOption.answers.yes}}
{{t "poll.evaluation.bestOptionParticipants.findADate.yes" count=evaluationBestOption.answers.yes}}
{{t
"poll.evaluation.bestOptionParticipants.findADate.yes"
count=evaluationBestOption.answers.yes
}}
{{/if}}
{{#if evaluationBestOption.answers.maybe}}
{{t "poll.evaluation.bestOptionParticipants.findADate.maybe" count=evaluationBestOption.answers.maybe}}
{{t
"poll.evaluation.bestOptionParticipants.findADate.maybe"
count=evaluationBestOption.answers.maybe
}}
{{/if}}
{{#if evaluationBestOption.answers.no}}
{{t "poll.evaluation.bestOptionParticipants.findADate.no" count=evaluationBestOption.answers.no}}
{{t
"poll.evaluation.bestOptionParticipants.findADate.no"
count=evaluationBestOption.answers.no
}}
{{/if}}
{{else}}
{{#if evaluationBestOption.answers.yes}}
{{t "poll.evaluation.bestOptionParticipants.makeAPoll.yes" count=evaluationBestOption.answers.yes}}
{{t
"poll.evaluation.bestOptionParticipants.makeAPoll.yes"
count=evaluationBestOption.answers.yes
}}
{{/if}}
{{#if evaluationBestOption.answers.maybe}}
{{t "poll.evaluation.bestOptionParticipants.makeAPoll.maybe" count=evaluationBestOption.answers.maybe}}
{{t
"poll.evaluation.bestOptionParticipants.makeAPoll.maybe"
count=evaluationBestOption.answers.maybe
}}
{{/if}}
{{#if evaluationBestOption.answers.no}}
{{t "poll.evaluation.bestOptionParticipants.makeAPoll.no" count=evaluationBestOption.answers.no}}
{{t
"poll.evaluation.bestOptionParticipants.makeAPoll.no"
count=evaluationBestOption.answers.no
}}
{{/if}}
{{/if}}

View file

@ -8,38 +8,47 @@
<p class="best-options">
{{#if poll.isFindADate}}
{{t "poll.evaluation.bestOption.label.findADate" count=evaluationBestOptions.length}}
{{t
"poll.evaluation.bestOption.label.findADate"
count=evaluationBestOptions.length
}}
{{else}}
{{t "poll.evaluation.bestOption.label.makeAPoll" count=evaluationBestOptions.length}}
{{t
"poll.evaluation.bestOption.label.makeAPoll"
count=evaluationBestOptions.length
}}
{{/if}}
{{#if evaluationBestOptionsMultiple}}
<ul>
{{#each evaluationBestOptions as |evaluationBestOption|}}
{{component 'poll-evaluation-summary-option'
{{component
"poll-evaluation-summary-option"
currentLocale=currentLocale
evaluationBestOption=evaluationBestOption
isFindADate=poll.isFindADate
momentLongDayFormat=momentLongDayFormat
tagName='li'
tagName="li"
timezone=timezone
}}
{{/each}}
</ul>
{{else}}
{{component 'poll-evaluation-summary-option'
{{component
"poll-evaluation-summary-option"
currentLocale=currentLocale
evaluationBestOption=evaluationBestOptions.firstObject
isFindADate=poll.isFindADate
momentLongDayFormat=momentLongDayFormat
tagName='span'
tagName="span"
timezone=timezone
}}
{{/if}}
</p>
<p class="last-participation">
{{t "poll.evaluation.lastParticipation"
{{t
"poll.evaluation.lastParticipation"
ago=(moment-from-now evaluationLastParticipation locale=currentLocale timezone=timezone)
}}
</p>

View file

@ -1,10 +1,14 @@
{{title (t 'create.title')}}
{{title (t "create.title")}}
{{#bs-button-group justified=true classNames="form-steps"}}
{{#each formSteps as |formStep|}}
{{#unless formStep.hidden}}
<div class="btn-group" role="group">
{{#bs-button action=(transition-to formStep.route) type=(if formStep.active 'primary' 'default') disabled=formStep.disabled}}
{{#bs-button
onClick=(transition-to formStep.route)
type=(if formStep.active "primary" "default")
disabled=formStep.disabled
}}
{{t formStep.label}}
{{/bs-button}}
</div>

View file

@ -3,16 +3,16 @@
formLayout="horizontal"
model=this
novalidate=true
onSubmit=(action 'submit')
as |form|
onSubmit=(action "submit")
as |form|
}}
{{#form.element
classNames='poll-type'
label=(t 'create.index.input.pollType.label')
classNames="poll-type"
label=(t "create.index.input.pollType.label")
property="pollType"
showValidationOn=(array 'change' 'focusOut')
showValidationOn=(array "change" "focusOut")
useIcons=false
as |el|
as |el|
}}
{{simple-select
autofocus=true
@ -21,7 +21,7 @@
optionLabelPath="label"
optionValuePath="id"
value=el.value
action=(action (mut el.value) value='id')
action=(action (mut el.value) value="id")
}}
{{/form.element}}
{{form-navigation-buttons

View file

@ -3,26 +3,26 @@
formLayout="horizontal"
model=this
novalidate=true
onSubmit=(action 'submit')
as |form|
onSubmit=(action "submit")
as |form|
}}
{{form.element
autofocus=true
classNames='title'
classNames="title"
controlType="text"
label=(t 'create.meta.input.title.label')
placeholder=(t 'create.meta.input.title.placeholder')
label=(t "create.meta.input.title.label")
placeholder=(t "create.meta.input.title.placeholder")
property="title"
}}
{{form.element
classNames='description'
classNames="description"
controlType="textarea"
label=(t 'create.meta.input.description.label')
placeholder=(t 'create.meta.input.description.placeholder')
label=(t "create.meta.input.description.label")
placeholder=(t "create.meta.input.description.placeholder")
property="description"
}}
{{form-navigation-buttons
onPrev=(route-action 'previousPage')
onPrev=(route-action "previousPage")
}}
{{/bs-form}}
</div>

View file

@ -1,5 +1,5 @@
{{create-options-datetime
dates=options
onNextPage=(action 'nextPage')
onPrevPage=(route-action 'previousPage')
onNextPage=(action "nextPage")
onPrevPage=(route-action "previousPage")
}}

View file

@ -2,6 +2,6 @@
isFindADate=model.isFindADate
isMakeAPoll=model.isMakeAPoll
options=model.options
onPrevPage=(route-action 'previousPage')
onNextPage=(action 'nextPage')
onPrevPage=(route-action "previousPage")
onNextPage=(action "nextPage")
}}

View file

@ -3,16 +3,16 @@
formLayout="horizontal"
model=this
novalidate=true
onSubmit=(action 'submit')
as |form|
onSubmit=(action "submit")
as |form|
}}
{{#form.element
classNames='answer-type'
label=(t 'create.settings.answerType.label')
classNames="answer-type"
label=(t "create.settings.answerType.label")
property="answerType"
showValidationOn=(array 'change' 'focusOut')
showValidationOn=(array "change" "focusOut")
useIcons=false
as |el|
as |el|
}}
{{simple-select
autofocus=true
@ -21,43 +21,43 @@
optionLabelPath="label"
optionValuePath="id"
value=el.value
action=(action (mut el.value) value='id')
action=(action (mut el.value) value="id")
}}
{{/form.element}}
{{#form.element
classNames='expiration-duration'
label=(t 'create.settings.expirationDate.label')
property='expirationDuration'
showValidationOn=(array 'change' 'focusOut')
classNames="expiration-duration"
label=(t "create.settings.expirationDate.label")
property="expirationDuration"
showValidationOn=(array "change" "focusOut")
useIcons=false
as |el|
as |el|
}}
{{simple-select
id=el.id
content=expirationDurations
optionLabelPath='label'
optionValuePath='id'
optionLabelPath="label"
optionValuePath="id"
value=el.value
action=(action (mut el.value) value='id')
action=(action (mut el.value) value="id")
}}
{{/form.element}}
{{form.element
classNames='anonymous-user'
controlType='checkbox'
label=(t 'create.settings.anonymousUser.label')
showValidationOn='change'
classNames="anonymous-user"
controlType="checkbox"
label=(t "create.settings.anonymousUser.label")
showValidationOn="change"
value=anonymousUser
}}
{{form.element
classNames='force-answer'
controlType='checkbox'
label=(t 'create.settings.forceAnswer.label')
showValidationOn='change'
classNames="force-answer"
controlType="checkbox"
label=(t "create.settings.forceAnswer.label")
showValidationOn="change"
value=forceAnswer
}}
{{form-navigation-buttons
nextButtonText=(t 'action.save')
onPrev=(route-action 'previousPage')
nextButtonText=(t "action.save")
onPrev=(route-action "previousPage")
}}
{{/bs-form}}
</div>

View file

@ -31,7 +31,7 @@
<p class="have-a-try">
<span class="glyphicon glyphicon-share-alt"></span>
{{#link-to 'create'}}{{t "index.link.have-a-try"}}{{/link-to}}
{{#link-to "create"}}{{t "index.link.have-a-try"}}{{/link-to}}
</p>
</div>
</div>

View file

@ -7,10 +7,20 @@
<h2 class="title">{{model.title}}</h2>
<p class="description">{{model.description}}</p>
<p class="dates">
<span class="creationDate">{{t "poll.created-date" date=(moment-format model.creationDate 'LLLL' locale=currentLocale)}}</span>
<span class="creationDate">
{{t
"poll.created-date"
date=(moment-format model.creationDate "LLLL" locale=currentLocale)
}}
</span>
{{#if model.expirationDate}}
<br>
<span class="expirationDate">{{t "poll.expiration-date" date=(moment-format model.expirationDate 'LLLL' locale=currentLocale)}}</span>
<span class="expirationDate">
{{t
"poll.expiration-date"
date=(moment-format model.expirationDate "LLLL" locale=currentLocale)
}}
</span>
{{/if}}
</p>
</div>
@ -19,18 +29,20 @@
<div class="box poll-link">
<p>{{t "poll.share"}}</p>
<p class="link">
<a href="{{pollUrl}}">{{pollUrl}}</a>
<a href={{pollUrl}}>
{{pollUrl}}
</a>
{{#copy-button
clipboardText=pollUrl
classNames="btn btn-default"
success=(action 'linkAction' 'copied')
error=(action 'linkAction' 'selected')
success=(action "linkAction" "copied")
error=(action "linkAction" "selected")
}}
<span class="glyphicon glyphicon-copy"></span>
{{/copy-button}}
</p>
<p class="notice">
{{t "poll.share.notice"}}
{{t "poll.share.notice"}}
</p>
</div>
</div>
@ -39,8 +51,11 @@
{{#if showExpirationWarning}}
<div class="row">
<div class="col-xs-12">
{{#bs-alert type="warning" classNames='expiration-warning'}}
{{t "poll.expiration-date-warning" timeToNow=(moment-from-now model.expirationDate locale=currentLocale)}}
{{#bs-alert type="warning" classNames="expiration-warning"}}
{{t
"poll.expiration-date-warning"
timeToNow=(moment-from-now model.expirationDate locale=currentLocale)
}}
{{/bs-alert}}
</div>
</div>
@ -48,14 +63,26 @@
<div class="box container-fluid">
<ul class="nav nav-tabs" role="tablist">
{{#link-to "poll.participation" model tagName='li' activeClass='active' class='participation'}}
{{#link-to
"poll.participation"
model
tagName="li"
activeClass="active"
class="participation"
}}
{{#link-to "poll.participation" model}}
{{t 'poll.tab-title.participation'}}
{{t "poll.tab-title.participation"}}
{{/link-to}}
{{/link-to}}
{{#link-to "poll.evaluation" model tagName='li' activeClass='active' class='evaluation'}}
{{#link-to
"poll.evaluation"
model
tagName="li"
activeClass="active"
class="evaluation"
}}
{{#link-to "poll.evaluation" model}}
{{t 'poll.tab-title.evaluation'}}
{{t "poll.tab-title.evaluation"}}
{{/link-to}}
{{/link-to}}
</ul>
@ -75,19 +102,25 @@
closeButton=false
keyboard=false
autoClose=false
id='modal-choose-timezone'
as |modal|
id="modal-choose-timezone"
as |modal|
}}
{{#modal.body}}
<p>
{{t "poll.modal.timezoneDiffers.body"}}
</p>
{{/modal.body}}
{{#modal.footer as |footer|}}
{{#bs-button onClick=(action "useLocalTimezone") class="use-local-timezone"}}
{{#modal.footer}}
{{#bs-button
onClick=(action "useLocalTimezone")
class="use-local-timezone"
}}
{{t "poll.modal.timezoneDiffers.button.useLocalTimezone"}}
{{/bs-button}}
{{#bs-button onClick=(action (mut timezoneChoosen) true) classNames="use-poll-timezone"}}
{{#bs-button
onClick=(action (mut timezoneChoosen) true)
classNames="use-poll-timezone"
}}
{{t "poll.modal.timezoneDiffers.button.usePollTimezone"}}
{{/bs-button}}
{{/modal.footer}}

View file

@ -7,7 +7,7 @@
timezone=timezone
}}
<h3>{{t 'poll.evaluation.overview'}}</h3>
<h3>{{t "poll.evaluation.overview"}}</h3>
{{poll-evaluation-chart
answerType=model.answerType
currentLocale=currentLocale
@ -19,7 +19,7 @@
}}
{{/if}}
<h3>{{t 'poll.evaluation.participantTable'}}</h3>
<h3>{{t "poll.evaluation.participantTable"}}</h3>
{{poll-evaluation-participants-table
currentLocale=currentLocale
hasTimes=hasTimes

View file

@ -1,52 +1,52 @@
<div class="participation">
{{#bs-form
onSubmit=(action 'submit')
formLayout='horizontal'
onSubmit=(action "submit")
formLayout="horizontal"
model=this
novalidate=true
as |form|
as |form|
}}
{{form.element
autofocus=true
controlType='text'
label=(t 'poll.input.newUserName.label')
placeholder=(t 'poll.input.newUserName.placeholder')
property='name'
classNames='name'
controlType="text"
label=(t "poll.input.newUserName.label")
placeholder=(t "poll.input.newUserName.placeholder")
property="name"
classNames="name"
}}
<div class="selections">
{{#each selections as |selection index|}}
{{#each selections as |selection|}}
{{#if isFreeText}}
{{form.element
controlType='text'
controlType="text"
label=(if isFindADate
(moment-format
selection.labelValue
(if (eq selection.momentFormat 'day') momentLongDayFormat selection.momentFormat)
(if (eq selection.momentFormat "day") momentLongDayFormat selection.momentFormat)
locale=currentLocale
timeZone=timezone
)
selection.labelValue
)
model=selection
property='value'
property="value"
}}
{{else}}
{{#form.element
label=(if isFindADate
(moment-format
selection.labelValue
(if (eq selection.momentFormat 'day') momentLongDayFormat selection.momentFormat)
(if (eq selection.momentFormat "day") momentLongDayFormat selection.momentFormat)
locale=currentLocale
timeZone=timezone
)
selection.labelValue
)
model=selection
property='value'
showValidationOn='change'
property="value"
showValidationOn="change"
useIcons=false
as |el|
as |el|
}}
{{#each possibleAnswers as |possibleAnswer|}}
<div class="radio {{possibleAnswer.type}}">
@ -73,22 +73,22 @@
{{#bs-modal
open=savingFailed
title=(t 'modal.save-retry.title')
title=(t "modal.save-retry.title")
body=false
footer=false
closeButton=false
autoClose=false
id='modal-saving-failed'
as |modal|
id="modal-saving-failed"
as |modal|
}}
{{#modal.body}}
<p>{{t "modal.save-retry.text"}}</p>
{{/modal.body}}
{{#modal.footer}}
{{bs-button
defaultText=(t 'modal.save-retry.button-retry')
type='primary'
onClick=(action 'save')
defaultText=(t "modal.save-retry.button-retry")
type="primary"
onClick=(action "save")
}}
{{/modal.footer}}
{{/bs-modal}}

View file

@ -0,0 +1,3 @@
{
"jquery-integration": true
}

View file

@ -1,8 +1,18 @@
'use strict';
const browsers = [
'last 1 Chrome versions',
'last 1 Firefox versions',
'last 1 Safari versions'
];
const isCI = !!process.env.CI;
const isProduction = process.env.EMBER_ENV === 'production';
if (isCI || isProduction) {
browsers.push('ie 11');
}
module.exports = {
browsers: [
'ie 9',
'last 1 Chrome versions',
'last 1 Firefox versions',
'last 1 Safari versions'
]
browsers
};

View file

@ -2,76 +2,81 @@
"name": "croodle",
"version": "0.5.6",
"private": true,
"repository": "https://github.com/jelhan/croodle",
"license": "MIT",
"author": "",
"directories": {
"doc": "doc",
"test": "tests"
},
"repository": "https://github.com/jelhan/croodle",
"scripts": {
"build": "ember build",
"lint:js": "eslint ./*.js app config lib server tests",
"lint:hbs": "ember-template-lint .",
"lint:js": "eslint .",
"start": "ember serve",
"test": "ember test"
},
"devDependencies": {
"@ember/jquery": "^0.5.2",
"@ember/optional-features": "^0.6.3",
"bootstrap": "^3.3.7",
"ember-ajax": "^3.0.0",
"ember-ajax": "^4.0.0",
"ember-array-helper": "^5.0.0",
"ember-awesome-macros": "^3.1.0",
"ember-bootstrap": "^2.1.2",
"ember-bootstrap-cp-validations": "^1.0.0",
"ember-browserify": "^1.1.11",
"ember-cli": "~2.18.2",
"ember-cli": "~3.4.4",
"ember-cli-acceptance-test-helpers": "^1.0.0",
"ember-cli-app-version": "^3.0.0",
"ember-cli-babel": "^6.6.0",
"ember-cli-app-version": "^3.2.0",
"ember-cli-babel": "^6.16.0",
"ember-cli-bootstrap-datepicker": "^0.6.1",
"ember-cli-browser-navigation-button-test-helper": "^0.0.4",
"ember-cli-browser-navigation-button-test-helper": "^0.1.1",
"ember-cli-chart": "^3.3.1",
"ember-cli-clipboard": "^0.8.0",
"ember-cli-content-security-policy": "^0.6.2",
"ember-cli-dependency-checker": "^2.0.0",
"ember-cli-dependency-checker": "^3.0.0",
"ember-cli-deprecation-workflow": "^0.2.3",
"ember-cli-eslint": "^4.2.1",
"ember-cli-eslint": "^4.2.3",
"ember-cli-flash": "^1.4.0",
"ember-cli-htmlbars": "^2.0.1",
"ember-cli-htmlbars-inline-precompile": "^1.0.0",
"ember-cli-inject-live-reload": "^1.4.1",
"ember-cli-htmlbars": "^3.0.0",
"ember-cli-htmlbars-inline-precompile": "^1.0.3",
"ember-cli-inject-live-reload": "^1.8.2",
"ember-cli-less": "^1.5.3",
"ember-cli-mirage": "^0.4.10",
"ember-cli-moment-shim": "^3.7.1",
"ember-cli-page-object": "^1.11.0",
"ember-cli-qunit": "^4.1.1",
"ember-cli-qunit": "^4.3.2",
"ember-cli-release": "^0.2.9",
"ember-cli-sauce": "^1.6.0",
"ember-cli-shims": "^1.2.0",
"ember-cli-sri": "^2.1.0",
"ember-cli-uglify": "^2.0.0",
"ember-cli-sri": "^2.1.1",
"ember-cli-template-lint": "^1.0.0-beta.1",
"ember-cli-uglify": "^2.1.0",
"ember-composable-helpers": "^2.1.0",
"ember-cp-validations": "^3.5.0",
"ember-data": "~2.18.0",
"ember-data-model-fragments": "^2.14.0",
"ember-data": "~3.4.0",
"ember-data-model-fragments": "^3.3.0",
"ember-export-application-global": "^2.0.0",
"ember-i18n": "^5.0.2",
"ember-i18n-cp-validations": "^3.0.2",
"ember-load-initializers": "^1.0.0",
"ember-load-initializers": "^1.1.0",
"ember-math-helpers": "^2.8.1",
"ember-maybe-import-regenerator": "^0.1.6",
"ember-moment": "^7.8.0",
"ember-native-dom-helpers": "^0.6.2",
"ember-page-title": "^3.0.6",
"ember-radio-buttons": "^4.0.1",
"ember-resolver": "^4.0.0",
"ember-resolver": "^5.0.1",
"ember-route-action-helper": "^2.0.6",
"ember-simple-select": "^0.6.1",
"ember-source": "~2.18.0",
"ember-simple-select": "jelhan/ember-simple-select#ember-3.4",
"ember-source": "~3.4.0",
"ember-transition-helper": "^1.0.0",
"ember-truth-helpers": "^2.1.0",
"eslint-plugin-ember": "^5.0.0",
"loader.js": "^4.2.3"
"eslint-plugin-ember": "^5.2.0",
"loader.js": "^4.7.0",
"qunit-dom": "^0.7.1"
},
"engines": {
"node": "^4.5 || 6.* || >= 7.*"
"node": "6.* || 8.* || >= 10.*"
},
"ember-addon": {
"paths": [

View file

@ -9,13 +9,14 @@ module.exports = {
],
browser_args: {
Chrome: {
mode: 'ci',
args: [
ci: [
// --no-sandbox is needed when running Chrome inside a container
process.env.TRAVIS ? '--no-sandbox' : null,
'--disable-gpu',
process.env.CI ? '--no-sandbox' : null,
'--headless',
'--disable-gpu',
'--disable-dev-shm-usage',
'--disable-software-rasterizer',
'--mute-audio',
'--remote-debugging-port=0',
'--window-size=1440,900'
].filter(Boolean)

View file

@ -1,13 +1,14 @@
import { test } from 'qunit';
import { visit } from '@ember/test-helpers';
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import jQuery from 'jquery';
import moduleForAcceptance from 'croodle/tests/helpers/module-for-acceptance';
moduleForAcceptance('Acceptance | build info');
module('Acceptance | build info', function(hooks) {
setupApplicationTest(hooks);
test('version is included as html meta tag', function(assert) {
visit('/');
test('version is included as html meta tag', async function(assert) {
await visit('/');
andThen(function() {
// ToDo: figure out why find() helper does not work but jQuery does
assert.ok(jQuery('head meta[name="build-info"]').length === 1, 'tag exists');
assert.ok(

File diff suppressed because it is too large Load diff

View file

@ -1,26 +1,24 @@
import { test } from 'qunit';
import moduleForAcceptance from 'croodle/tests/helpers/module-for-acceptance';
import { find, visit } from '@ember/test-helpers';
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import pageIndex from 'croodle/tests/pages/index';
moduleForAcceptance('Acceptance | i18n', {
beforeEach() {
window.localStorage.setItem('locale', 'en');
}
});
module('Acceptance | i18n', function(hooks) {
hooks.beforeEach(function() {
window.localStorage.setItem('locale', 'de');
});
test('locale is saved in localStorage', function(assert) {
visit('/');
setupApplicationTest(hooks);
andThen(() => {
assert.equal(find('.language-select').val(), 'en');
pageIndex.locale('de');
test('locale is saved in localStorage', async function(assert) {
await visit('/');
assert.equal(find('.language-select').value, 'de', 'picks up locale in locale storage');
andThen(function() {
assert.equal(find('.language-select').val(), 'de');
assert.equal(
window.localStorage.getItem('locale'), 'de',
'persisted in localeStorage'
);
});
await pageIndex.locale('en');
assert.equal(find('.language-select').value, 'en');
assert.equal(
window.localStorage.getItem('locale'), 'en',
'persisted in localeStorage'
);
});
});

View file

@ -1,43 +1,47 @@
import { test } from 'qunit';
import moduleForAcceptance from 'croodle/tests/helpers/module-for-acceptance';
import { 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';
import { t } from 'ember-i18n/test-support';
import switchTab from 'croodle/tests/helpers/switch-tab';
import pollHasUser from 'croodle/tests/helpers/poll-has-user';
import pollParticipate from 'croodle/tests/helpers/poll-participate';
import moment from 'moment';
import pagePollParticipation from 'croodle/tests/pages/poll/participation';
/* jshint proto: true */
moduleForAcceptance('Acceptance | legacy support', {
beforeEach() {
module('Acceptance | legacy support', function(hooks) {
hooks.beforeEach(function() {
window.localStorage.setItem('locale', 'en');
moment.locale('en');
}
});
test('show a default poll created with v0.3.0', function(assert) {
const encryptionKey = '5MKFuNTKILUXw6RuqkAw6ooZw4k3mWWx98ZQw8vH';
let poll = server.create('poll', {
encryptionKey,
// property 'id' of answers has been renamed to 'type' in v0.4.0
answers: [{ 'id': 'yes','labelTranslation': 'answerTypes.yes.label','icon': 'glyphicon glyphicon-thumbs-up','label': 'Ja' },{ 'id': 'maybe','labelTranslation': 'answerTypes.maybe.label','icon': 'glyphicon glyphicon-hand-right','label': 'Vielleicht' },{ 'id': 'no','labelTranslation': 'answerTypes.no.label','icon': 'glyphicon glyphicon-thumbs-down','label': 'Nein' }],
options: [{ 'title': '2015-12-24T17:00:00.000Z' },{ 'title': '2015-12-24T19:00:00.000Z' },{ 'title': '2015-12-31T22:59:00.000Z' }],
users: [
server.create('user', {
encryptionKey,
name: 'Fritz Bauer',
// selections.value was renamed to selections.label
// selections.id was renamed to selections.type
selections: [{ 'value': { 'id': 'yes','labelTranslation': 'answerTypes.yes.label','icon': 'glyphicon glyphicon-thumbs-up','label': 'Ja' } },{ 'value': { 'id': 'no','labelTranslation': 'answerTypes.no.label','icon': 'glyphicon glyphicon-thumbs-down','label': 'Nein' } },{ 'value': { 'id': 'no','labelTranslation': 'answerTypes.no.label','icon': 'glyphicon glyphicon-thumbs-down','label': 'Nein' } }],
// version tag had have wrong format
version: 'v0.3-0'
})
],
// version tag had have wrong format
version: 'v0.3-0'
});
visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`);
setupApplicationTest(hooks);
setupMirage(hooks);
andThen(function() {
assert.equal(currentPath(), 'poll.participation');
test('show a default poll created with v0.3.0', async function(assert) {
const encryptionKey = '5MKFuNTKILUXw6RuqkAw6ooZw4k3mWWx98ZQw8vH';
let poll = this.server.create('poll', {
encryptionKey,
// property 'id' of answers has been renamed to 'type' in v0.4.0
answers: [{ 'id': 'yes','labelTranslation': 'answerTypes.yes.label','icon': 'glyphicon glyphicon-thumbs-up','label': 'Ja' },{ 'id': 'maybe','labelTranslation': 'answerTypes.maybe.label','icon': 'glyphicon glyphicon-hand-right','label': 'Vielleicht' },{ 'id': 'no','labelTranslation': 'answerTypes.no.label','icon': 'glyphicon glyphicon-thumbs-down','label': 'Nein' }],
options: [{ 'title': '2015-12-24T17:00:00.000Z' },{ 'title': '2015-12-24T19:00:00.000Z' },{ 'title': '2015-12-31T22:59:00.000Z' }],
users: [
this.server.create('user', {
encryptionKey,
name: 'Fritz Bauer',
// selections.value was renamed to selections.label
// selections.id was renamed to selections.type
selections: [{ 'value': { 'id': 'yes','labelTranslation': 'answerTypes.yes.label','icon': 'glyphicon glyphicon-thumbs-up','label': 'Ja' } },{ 'value': { 'id': 'no','labelTranslation': 'answerTypes.no.label','icon': 'glyphicon glyphicon-thumbs-down','label': 'Nein' } },{ 'value': { 'id': 'no','labelTranslation': 'answerTypes.no.label','icon': 'glyphicon glyphicon-thumbs-down','label': 'Nein' } }],
// version tag had have wrong format
version: 'v0.3-0'
})
],
// version tag had have wrong format
version: 'v0.3-0'
});
await visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`);
assert.equal(currentRouteName(), 'poll.participation');
assert.deepEqual(
pagePollParticipation.options().labels,
[
@ -55,70 +59,57 @@ test('show a default poll created with v0.3.0', function(assert) {
]
);
switchTab('evaluation');
await switchTab('evaluation');
assert.equal(currentRouteName(), 'poll.evaluation');
pollHasUser(assert,
'Fritz Bauer',
[
t('answerTypes.yes.label'),
t('answerTypes.no.label'),
t('answerTypes.no.label')
]
);
andThen(function() {
assert.equal(currentPath(), 'poll.evaluation');
await switchTab('participation');
assert.equal(currentRouteName(), 'poll.participation');
pollHasUser(assert,
'Fritz Bauer',
[
t('answerTypes.yes.label'),
t('answerTypes.no.label'),
t('answerTypes.no.label')
]
);
await pollParticipate('Hermann Langbein', ['yes', 'maybe', 'yes']);
assert.equal(currentRouteName(), 'poll.evaluation');
pollHasUser(assert,
'Hermann Langbein',
[
t('answerTypes.yes.label'),
t('answerTypes.maybe.label'),
t('answerTypes.yes.label')
]
);
});
switchTab('participation');
andThen(function() {
assert.equal(currentPath(), 'poll.participation');
pollParticipate('Hermann Langbein', ['yes', 'maybe', 'yes']);
andThen(function() {
assert.equal(currentPath(), 'poll.evaluation');
pollHasUser(assert,
'Hermann Langbein',
[
t('answerTypes.yes.label'),
t('answerTypes.maybe.label'),
t('answerTypes.yes.label')
]
);
});
});
test('show a poll using free text created with v0.3.0', async function(assert) {
let encryptionKey = 'Rre6dAGOYLW9gYKOP4LhX7Qwfhe5Th3je0uKDtyy';
let poll = this.server.create('poll', {
encryptionKey,
answerType: 'FreeText',
answers: [],
options: [{ 'title': 'apple pie' }, { 'title': 'pecan pie' }, { 'title': 'plum pie' }],
pollType: 'MakeAPoll',
users: [
this.server.create('user', {
encryptionKey,
name: 'Paul Levi',
// selections.value was renamed to selections.label
// selections.id was renamed to selections.type
selections: [{ 'value': 'would be great!' }, { 'value': 'no way' }, { 'value': 'if I had to' }],
// version tag had have wrong format
version: 'v0.3-0'
})
],
// version tag had have wrong format
version: 'v0.3-0'
});
});
});
test('show a poll using free text created with v0.3.0', function(assert) {
let encryptionKey = 'Rre6dAGOYLW9gYKOP4LhX7Qwfhe5Th3je0uKDtyy';
let poll = server.create('poll', {
encryptionKey,
answerType: 'FreeText',
answers: [],
options: [{ 'title': 'apple pie' }, { 'title': 'pecan pie' }, { 'title': 'plum pie' }],
pollType: 'MakeAPoll',
users: [
server.create('user', {
encryptionKey,
name: 'Paul Levi',
// selections.value was renamed to selections.label
// selections.id was renamed to selections.type
selections: [{ 'value': 'would be great!' }, { 'value': 'no way' }, { 'value': 'if I had to' }],
// version tag had have wrong format
version: 'v0.3-0'
})
],
// version tag had have wrong format
version: 'v0.3-0'
});
visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`);
andThen(function() {
assert.equal(currentPath(), 'poll.participation');
await visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`);
assert.equal(currentRouteName(), 'poll.participation');
assert.deepEqual(
pagePollParticipation.options().labels,
[
@ -128,37 +119,29 @@ test('show a poll using free text created with v0.3.0', function(assert) {
]
);
switchTab('evaluation');
await switchTab('evaluation');
assert.equal(currentRouteName(), 'poll.evaluation');
pollHasUser(assert,
'Paul Levi',
[
'would be great!',
'no way',
'if I had to'
]
);
andThen(function() {
assert.equal(currentPath(), 'poll.evaluation');
pollHasUser(assert,
'Paul Levi',
[
'would be great!',
'no way',
'if I had to'
]
);
await switchTab('participation');
assert.equal(currentRouteName(), 'poll.participation');
switchTab('participation');
andThen(function() {
assert.equal(currentPath(), 'poll.participation');
pollParticipate('Hermann Langbein', ["I don't care", 'would be awesome', "can't imagine anything better"]);
andThen(function() {
assert.equal(currentPath(), 'poll.evaluation');
pollHasUser(assert,
'Hermann Langbein',
[
"I don't care",
'would be awesome',
"can't imagine anything better"
]
);
});
});
});
await pollParticipate('Hermann Langbein', ["I don't care", 'would be awesome', "can't imagine anything better"]);
assert.equal(currentRouteName(), 'poll.evaluation');
pollHasUser(assert,
'Hermann Langbein',
[
"I don't care",
'would be awesome',
"can't imagine anything better"
]
);
});
});

View file

@ -1,145 +1,135 @@
import { test } from 'qunit';
import {
click,
find,
findAll,
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';
import { t } from 'ember-i18n/test-support';
import pollHasUser, { pollHasUsersCount } from 'croodle/tests/helpers/poll-has-user';
import pollParticipate from 'croodle/tests/helpers/poll-participate';
import jQuery from 'jquery';
import moduleForAcceptance from 'croodle/tests/helpers/module-for-acceptance';
/* jshint proto: true */
moduleForAcceptance('Acceptance | participate in a poll', {
beforeEach() {
module('Acceptance | participate in a poll', function(hooks) {
hooks.beforeEach(function() {
window.localStorage.setItem('locale', 'en');
}
});
test('participate in a default poll', function(assert) {
server.logging = true;
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let poll = server.create('poll', {
encryptionKey
});
visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`).then(function() {
assert.equal(currentPath(), 'poll.participation', 'poll is redirected to poll.participation');
pollParticipate('Max Meiner', ['yes', 'no']);
setupApplicationTest(hooks);
setupMirage(hooks);
andThen(function() {
assert.equal(currentPath(), 'poll.evaluation');
assert.equal(
currentURL().split('?')[1],
`encryptionKey=${encryptionKey}`,
'encryption key is part of query params'
);
pollHasUsersCount(assert, 1, 'user is added to user selections table');
pollHasUser(assert, 'Max Meiner', [t('answerTypes.yes.label'), t('answerTypes.no.label')]);
click('.nav .participation');
andThen(() => {
assert.equal(currentPath(), 'poll.participation');
assert.equal(find('.name input').val(), '', 'input for name is cleared');
assert.ok(
!find('input[type="radio"]').toArray().some((el) => jQuery(el).prop('checked')),
'radios are cleared'
);
pollParticipate('Peter Müller', ['yes', 'yes']);
andThen(() => {
assert.equal(currentPath(), 'poll.evaluation');
pollHasUsersCount(assert, 2, 'user is added to user selections table');
pollHasUser(assert, 'Peter Müller', [t('answerTypes.yes.label'), t('answerTypes.yes.label')]);
});
});
test('participate in a default poll', async function(assert) {
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let poll = this.server.create('poll', {
encryptionKey
});
});
});
test('participate in a poll using freetext', function(assert) {
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let poll = server.create('poll', {
answerType: 'FreeText',
answers: [],
encryptionKey
await visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`);
assert.equal(currentRouteName(), 'poll.participation', 'poll is redirected to poll.participation');
await pollParticipate('Max Meiner', ['yes', 'no']);
assert.equal(currentRouteName(), 'poll.evaluation');
assert.equal(
currentURL().split('?')[1],
`encryptionKey=${encryptionKey}`,
'encryption key is part of query params'
);
pollHasUsersCount(assert, 1, 'user is added to user selections table');
pollHasUser(assert, 'Max Meiner', [t('answerTypes.yes.label'), t('answerTypes.no.label')]);
await click('.nav .participation');
assert.equal(currentRouteName(), 'poll.participation');
assert.equal(find('.name input').value, '', 'input for name is cleared');
assert.ok(
!findAll('input[type="radio"]').toArray().some((el) => el.checked),
'radios are cleared'
);
await pollParticipate('Peter Müller', ['yes', 'yes']);
assert.equal(currentRouteName(), 'poll.evaluation');
pollHasUsersCount(assert, 2, 'user is added to user selections table');
pollHasUser(assert, 'Peter Müller', [t('answerTypes.yes.label'), t('answerTypes.yes.label')]);
});
visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`).then(function() {
assert.equal(currentPath(), 'poll.participation');
pollParticipate('Max Manus', ['answer 1', 'answer 2']);
andThen(function() {
assert.equal(currentPath(), 'poll.evaluation');
pollHasUsersCount(assert, 1, 'user is added to user selections table');
pollHasUser(assert, 'Max Manus', ['answer 1', 'answer 2']);
test('participate in a poll using freetext', async function(assert) {
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let poll = this.server.create('poll', {
answerType: 'FreeText',
answers: [],
encryptionKey
});
});
});
test('participate in a poll which does not force an answer to all options', function(assert) {
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let poll = server.create('poll', {
encryptionKey,
forceAnswer: false
await visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`)
assert.equal(currentRouteName(), 'poll.participation');
await pollParticipate('Max Manus', ['answer 1', 'answer 2']);
assert.equal(currentRouteName(), 'poll.evaluation');
pollHasUsersCount(assert, 1, 'user is added to user selections table');
pollHasUser(assert, 'Max Manus', ['answer 1', 'answer 2']);
});
visit(`/poll/${poll.id}/participation?encryptionKey=${encryptionKey}`).then(function() {
assert.equal(currentPath(), 'poll.participation');
pollParticipate('Karl Käfer', ['yes', null]);
andThen(function() {
assert.equal(currentPath(), 'poll.evaluation');
pollHasUsersCount(assert, 1, 'user is added to user selections table');
pollHasUser(assert, 'Karl Käfer', [t('answerTypes.yes.label'), '']);
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
});
});
});
test('participate in a poll which allows anonymous participation', function(assert) {
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let poll = server.create('poll', {
anonymousUser: true,
encryptionKey
await visit(`/poll/${poll.id}/participation?encryptionKey=${encryptionKey}`);
assert.equal(currentRouteName(), 'poll.participation');
await pollParticipate('Karl Käfer', ['yes', null]);
assert.equal(currentRouteName(), 'poll.evaluation');
pollHasUsersCount(assert, 1, 'user is added to user selections table');
pollHasUser(assert, 'Karl Käfer', [t('answerTypes.yes.label'), '']);
});
visit(`/poll/${poll.id}/participation?encryptionKey=${encryptionKey}`).then(function() {
assert.equal(currentPath(), 'poll.participation');
pollParticipate(null, ['yes', 'no']);
andThen(function() {
assert.equal(currentPath(), 'poll.evaluation');
pollHasUsersCount(assert, 1, 'user is added to user selections table');
pollHasUser(assert, '', [t('answerTypes.yes.label'), t('answerTypes.no.label')]);
test('participate in a poll which allows anonymous participation', async function(assert) {
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let poll = this.server.create('poll', {
anonymousUser: true,
encryptionKey
});
});
});
test('network connectivity errors', function(assert) {
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let poll = server.create('poll', {
encryptionKey
await visit(`/poll/${poll.id}/participation?encryptionKey=${encryptionKey}`);
assert.equal(currentRouteName(), 'poll.participation');
await pollParticipate(null, ['yes', 'no']);
assert.equal(currentRouteName(), 'poll.evaluation');
pollHasUsersCount(assert, 1, 'user is added to user selections table');
pollHasUser(assert, '', [t('answerTypes.yes.label'), t('answerTypes.no.label')]);
});
server.post('/users', undefined, 503);
visit(`/poll/${poll.id}/participation?encryptionKey=${encryptionKey}`).then(function() {
assert.equal(currentPath(), 'poll.participation');
pollParticipate('foo bar', ['yes', 'no']);
andThen(() => {
assert.ok(
find('#modal-saving-failed-modal').is(':visible'),
'user gets notified that saving failed'
);
server.post('/users');
click('#modal-saving-failed-modal button');
andThen(() => {
assert.notOk(
find('#modal-saving-failed-modal').is(':visible'),
'modal is hidden after saving was successful'
);
assert.equal(currentPath(), 'poll.evaluation');
pollHasUsersCount(assert, 1, 'user is added to user selections table');
pollHasUser(assert, 'foo bar', [t('answerTypes.yes.label'), t('answerTypes.no.label')]);
});
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.equal(currentRouteName(), 'poll.participation');
await pollParticipate('foo bar', ['yes', 'no']);
assert.ok(
jQuery(find('#modal-saving-failed-modal')).is(':visible'),
'user gets notified that saving failed'
);
this.server.post('/users');
await click('#modal-saving-failed-modal button');
assert.notOk(
jQuery(find('#modal-saving-failed-modal')).is(':visible'),
'modal is hidden after saving was successful'
);
assert.equal(currentRouteName(), 'poll.evaluation');
pollHasUsersCount(assert, 1, 'user is added to user selections table');
pollHasUser(assert, 'foo bar', [t('answerTypes.yes.label'), t('answerTypes.no.label')]);
});
});

View file

@ -1,307 +1,295 @@
import { test } from 'qunit';
import jQuery from 'jquery';
import moduleForAcceptance from 'croodle/tests/helpers/module-for-acceptance';
import { findAll, currentRouteName, find, 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';
import { t } from 'ember-i18n/test-support';
import switchTab from 'croodle/tests/helpers/switch-tab';
import moment from 'moment';
/* jshint proto: true */
moduleForAcceptance('Acceptance | view evaluation', {
beforeEach() {
module('Acceptance | view evaluation', function(hooks) {
hooks.beforeEach(function() {
window.localStorage.setItem('locale', 'en');
moment.locale('en');
}
});
test('evaluation summary is not present for poll without participants', function(assert) {
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let poll = server.create('poll', {
encryptionKey
});
visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`);
setupApplicationTest(hooks);
setupMirage(hooks);
andThen(function() {
assert.equal(currentPath(), 'poll.participation');
switchTab('evaluation');
andThen(function() {
assert.equal(find('.tab-content .tab-pane .evaluation-summary').length, 0, 'evaluation summary is not present');
test('evaluation summary is not present for poll without participants', async function(assert) {
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let poll = this.server.create('poll', {
encryptionKey
});
});
});
test('evaluation is correct for FindADate', function(assert) {
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let user1 = server.create('user', {
creationDate: '2015-01-01T00:00:00.000Z',
encryptionKey,
name: 'Maximilian',
selections: [
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
},
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
}
]
});
let user2 = server.create('user', {
creationDate: '2015-08-01T00:00:00.000Z',
encryptionKey,
name: 'Peter',
selections: [
{
type: 'no',
labelTranslation: 'answerTypes.no.label',
icon: 'glyphicon glyphicon-thumbs-down',
label: 'No'
},
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
}
]
});
let poll = server.create('poll', {
answers: [
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
},
{
type: 'no',
labelTranslation: 'answerTypes.no.label',
icon: 'glyphicon glyphicon-thumbs-down',
label: 'No'
}
],
encryptionKey,
options: [
{ title: '2015-12-12' },
{ title: '2016-01-01' }
],
users: [user1, user2]
await visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`);
assert.equal(currentRouteName(), 'poll.participation');
await switchTab('evaluation');
assert.equal(findAll('.tab-content .tab-pane .evaluation-summary').length, 0, 'evaluation summary is not present');
});
visit(`/poll/${poll.id}/evaluation?encryptionKey=${encryptionKey}`);
test('evaluation is correct for FindADate', async function(assert) {
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let user1 = this.server.create('user', {
creationDate: '2015-01-01T00:00:00.000Z',
encryptionKey,
name: 'Maximilian',
selections: [
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
},
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
}
]
});
let user2 = this.server.create('user', {
creationDate: '2015-08-01T00:00:00.000Z',
encryptionKey,
name: 'Peter',
selections: [
{
type: 'no',
labelTranslation: 'answerTypes.no.label',
icon: 'glyphicon glyphicon-thumbs-down',
label: 'No'
},
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
}
]
});
let poll = this.server.create('poll', {
answers: [
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
},
{
type: 'no',
labelTranslation: 'answerTypes.no.label',
icon: 'glyphicon glyphicon-thumbs-down',
label: 'No'
}
],
encryptionKey,
options: [
{ title: '2015-12-12' },
{ title: '2016-01-01' }
],
users: [user1, user2]
});
andThen(function() {
assert.equal(currentPath(), 'poll.evaluation');
assert.equal(find('.tab-content .tab-pane .evaluation-summary').length, 1, 'evaluation summary is present');
await visit(`/poll/${poll.id}/evaluation?encryptionKey=${encryptionKey}`);
assert.equal(currentRouteName(), 'poll.evaluation');
assert.equal(findAll('.tab-content .tab-pane .evaluation-summary').length, 1, 'evaluation summary is present');
assert.equal(
find('.participants').text().trim(),
find('.participants').textContent.trim(),
t('poll.evaluation.participants', { count: 2 }).toString(),
'participants are counted correctly'
);
assert.equal(
find('.best-options strong').text().trim(),
find('.best-options strong').textContent.trim(),
'Friday, January 1, 2016',
'options are evaluated correctly'
);
assert.equal(
find('.last-participation').text().trim(),
find('.last-participation').textContent.trim(),
t('poll.evaluation.lastParticipation', {
ago: moment('2015-08-01T00:00:00.000Z').from()
}).toString(),
'last participation is evaluated correctly'
);
});
});
test('evaluation is correct for MakeAPoll', function(assert) {
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let user1 = server.create('user', {
creationDate: '2015-01-01T00:00:00.000Z',
encryptionKey,
name: 'Maximilian',
selections: [
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
},
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
}
]
});
let user2 = server.create('user', {
creationDate: '2015-08-01T00:00:00.000Z',
encryptionKey,
name: 'Peter',
selections: [
{
type: 'no',
labelTranslation: 'answerTypes.no.label',
icon: 'glyphicon glyphicon-thumbs-down',
label: 'No'
},
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
}
]
});
let poll = server.create('poll', {
answers: [
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
},
{
type: 'no',
labelTranslation: 'answerTypes.no.label',
icon: 'glyphicon glyphicon-thumbs-down',
label: 'No'
}
],
encryptionKey,
options: [
{ title: 'first option' },
{ title: 'second option' }
],
pollType: 'MakeAPoll',
users: [user1, user2]
});
test('evaluation is correct for MakeAPoll', async function(assert) {
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let user1 = this.server.create('user', {
creationDate: '2015-01-01T00:00:00.000Z',
encryptionKey,
name: 'Maximilian',
selections: [
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
},
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
}
]
});
let user2 = this.server.create('user', {
creationDate: '2015-08-01T00:00:00.000Z',
encryptionKey,
name: 'Peter',
selections: [
{
type: 'no',
labelTranslation: 'answerTypes.no.label',
icon: 'glyphicon glyphicon-thumbs-down',
label: 'No'
},
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
}
]
});
let poll = this.server.create('poll', {
answers: [
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
},
{
type: 'no',
labelTranslation: 'answerTypes.no.label',
icon: 'glyphicon glyphicon-thumbs-down',
label: 'No'
}
],
encryptionKey,
options: [
{ title: 'first option' },
{ title: 'second option' }
],
pollType: 'MakeAPoll',
users: [user1, user2]
});
visit(`/poll/${poll.id}/evaluation?encryptionKey=${encryptionKey}`);
andThen(function() {
assert.equal(currentPath(), 'poll.evaluation');
assert.equal(find('.tab-content .tab-pane .evaluation-summary').length, 1, 'evaluation summary is present');
await visit(`/poll/${poll.id}/evaluation?encryptionKey=${encryptionKey}`);
assert.equal(currentRouteName(), 'poll.evaluation');
assert.equal(findAll('.tab-content .tab-pane .evaluation-summary').length, 1, 'evaluation summary is present');
assert.equal(
find('.participants').text().trim(),
find('.participants').textContent.trim(),
t('poll.evaluation.participants', { count: 2 }).toString(),
'participants are counted correctly'
);
assert.equal(
find('.best-options strong').text().trim(),
find('.best-options strong').textContent.trim(),
'second option',
'options are evaluated correctly'
);
assert.ok(
find('.user-selections-table').length,
findAll('.user-selections-table').length,
'has a table showing user selections'
);
assert.deepEqual(
find('.user-selections-table thead th').map((i, el) => jQuery(el).text().trim()).get(),
findAll('.user-selections-table thead th').toArray().map((el) => el.textContent.trim()),
['', 'first option', 'second option'],
'dates are used as table headers'
);
assert.deepEqual(
find('.user-selections-table tbody tr:nth-child(1) td').map((i, el) => jQuery(el).text().trim()).get(),
findAll('.user-selections-table tbody tr:nth-child(1) td').toArray().map((el) => el.textContent.trim()),
['Maximilian', 'Yes', 'Yes'],
'answers shown in table are correct for first user'
);
assert.deepEqual(
find('.user-selections-table tbody tr:nth-child(2) td').map((i, el) => jQuery(el).text().trim()).get(),
findAll('.user-selections-table tbody tr:nth-child(2) td').toArray().map((el) => el.textContent.trim()),
['Peter', 'No', 'Yes'],
'answers shown in table are correct for second user'
);
assert.equal(
find('.last-participation').text().trim(),
find('.last-participation').textContent.trim(),
t('poll.evaluation.lastParticipation', {
ago: moment('2015-08-01T00:00:00.000Z').from()
}).toString(),
'last participation is evaluated correctly'
);
});
});
test('could open evaluation by tab from poll participation', function(assert) {
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let poll = server.create('poll', {
answers: [
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
},
{
type: 'no',
labelTranslation: 'answerTypes.no.label',
icon: 'glyphicon glyphicon-thumbs-down',
label: 'No'
}
],
encryptionKey,
options: [
{ title: '2015-12-12' },
{ title: '2016-01-01' }
],
users: [
server.create('user', {
creationDate: '2015-01-01T00:00:00.000Z',
encryptionKey,
name: 'Maximilian',
selections: [
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
},
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
}
]
}),
server.create('user', {
creationDate: '2015-08-01T00:00:00.000Z',
encryptionKey,
name: 'Peter',
selections: [
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
},
{
id: 'no',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
}
]
})
]
});
visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`);
andThen(function() {
assert.equal(currentPath(), 'poll.participation');
switchTab('evaluation');
andThen(function() {
assert.equal(currentPath(), 'poll.evaluation');
assert.equal(
find('.tab-pane h2').text().trim(),
t('poll.evaluation.label').toString(),
'headline is there'
);
test('could open evaluation by tab from poll participation', async function(assert) {
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let poll = this.server.create('poll', {
answers: [
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
},
{
type: 'no',
labelTranslation: 'answerTypes.no.label',
icon: 'glyphicon glyphicon-thumbs-down',
label: 'No'
}
],
encryptionKey,
options: [
{ title: '2015-12-12' },
{ title: '2016-01-01' }
],
users: [
this.server.create('user', {
creationDate: '2015-01-01T00:00:00.000Z',
encryptionKey,
name: 'Maximilian',
selections: [
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
},
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
}
]
}),
this.server.create('user', {
creationDate: '2015-08-01T00:00:00.000Z',
encryptionKey,
name: 'Peter',
selections: [
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
},
{
id: 'no',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
}
]
})
]
});
await visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`);
assert.equal(currentRouteName(), 'poll.participation');
await switchTab('evaluation');
assert.equal(currentRouteName(), 'poll.evaluation');
assert.equal(
find('.tab-pane h2').textContent.trim(),
t('poll.evaluation.label').toString(),
'headline is there'
);
});
});

View file

@ -1,24 +1,27 @@
import { test } from 'qunit';
import moduleForAcceptance from 'croodle/tests/helpers/module-for-acceptance';
import { find, click, 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';
import switchTab from 'croodle/tests/helpers/switch-tab';
import pageParticipation from 'croodle/tests/pages/poll/participation';
import pageEvaluation from 'croodle/tests/pages/poll/evaluation';
import moment from 'moment';
/* jshint proto: true */
import jQuery from 'jquery';
moduleForAcceptance('Acceptance | view poll', {
beforeEach() {
module('Acceptance | view poll', function(hooks) {
hooks.beforeEach(function() {
window.localStorage.setItem('locale', 'en');
moment.locale('en');
}
});
});
test('poll url', function(assert) {
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz012345789';
let poll = server.create('poll', { encryptionKey });
let pollUrl = `/poll/${poll.id}?encryptionKey=${encryptionKey}`;
setupApplicationTest(hooks);
setupMirage(hooks);
visit(pollUrl);
andThen(function() {
test('poll url', async function(assert) {
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz012345789';
let poll = this.server.create('poll', { encryptionKey });
let pollUrl = `/poll/${poll.id}?encryptionKey=${encryptionKey}`;
await visit(pollUrl);
assert.equal(
pageParticipation.url,
window.location.href,
@ -34,32 +37,31 @@ test('poll url', function(assert) {
* https://github.com/poteto/ember-cli-flash/issues/202
*/
});
});
test('shows a warning if poll is about to be expired', function(assert) {
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let poll = server.create('poll', {
encryptionKey,
expirationDate: moment().add(1, 'week')
});
visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`).then(function() {
test('shows a warning if poll is about to be expired', async function(assert) {
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let poll = this.server.create('poll', {
encryptionKey,
expirationDate: moment().add(1, 'week')
});
await visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`);
assert.ok(
pageParticipation.showsExpirationWarning
);
});
});
test('view a poll with dates', function(assert) {
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let poll = server.create('poll', {
encryptionKey,
options: [
{ title: '2015-12-12' },
{ title: '2016-01-01' }
]
});
test('view a poll with dates', async function(assert) {
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let poll = this.server.create('poll', {
encryptionKey,
options: [
{ title: '2015-12-12' },
{ title: '2016-01-01' }
]
});
visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`).then(function() {
await visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`);
assert.deepEqual(
pageParticipation.options().labels,
[
@ -68,24 +70,23 @@ test('view a poll with dates', function(assert) {
]
);
});
});
test('view a poll with dates and times', function(assert) {
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let timezone = moment.tz.guess();
let poll = server.create('poll', {
encryptionKey,
expirationDate: moment().add(1, 'year'),
isDateTime: true,
options: [
{ title: '2015-12-12T11:11:00.000Z' },
{ title: '2015-12-12T13:13:00.000Z' },
{ title: '2016-01-01T11:11:00.000Z' }
],
timezone
});
test('view a poll with dates and times', async function(assert) {
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let timezone = moment.tz.guess();
let poll = this.server.create('poll', {
encryptionKey,
expirationDate: moment().add(1, 'year'),
isDateTime: true,
options: [
{ title: '2015-12-12T11:11:00.000Z' },
{ title: '2015-12-12T13:13:00.000Z' },
{ title: '2016-01-01T11:11:00.000Z' }
],
timezone
});
visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`).then(function() {
await visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`);
assert.deepEqual(
pageParticipation.options().labels,
[
@ -102,123 +103,122 @@ test('view a poll with dates and times', function(assert) {
'does not show an expiration warning if poll will not expire in next weeks'
);
});
});
test('view a poll while timezone differs from the one poll got created in and choose local timezone', async function(assert) {
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let timezoneUser = moment.tz.guess();
let timezonePoll = timezoneUser !== 'America/Caracas' ? 'America/Caracas' : 'Europe/Moscow';
let poll = server.create('poll', {
encryptionKey,
isDateTime: true,
options: [
{ title: '2015-12-12T11:11:00.000Z' },
{ title: '2016-01-01T11:11:00.000Z' }
],
timezone: timezonePoll,
users: [
server.create('user', {
encryptionKey,
selections: [
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
},
{
type: 'no',
labelTranslation: 'answerTypes.no.label',
icon: 'glyphicon glyphicon-thumbs-down',
label: 'No'
}
]
})
]
test('view a poll while timezone differs from the one poll got created in and choose local timezone', async function(assert) {
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let timezoneUser = moment.tz.guess();
let timezonePoll = timezoneUser !== 'America/Caracas' ? 'America/Caracas' : 'Europe/Moscow';
let poll = this.server.create('poll', {
encryptionKey,
isDateTime: true,
options: [
{ title: '2015-12-12T11:11:00.000Z' },
{ title: '2016-01-01T11:11:00.000Z' }
],
timezone: timezonePoll,
users: [
this.server.create('user', {
encryptionKey,
selections: [
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
},
{
type: 'no',
labelTranslation: 'answerTypes.no.label',
icon: 'glyphicon glyphicon-thumbs-down',
label: 'No'
}
]
})
]
});
await visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`);
assert.ok(
jQuery(find('#modal-choose-timezone-modal')).is(':visible'),
'user gets asked which timezone should be used'
);
await click('#modal-choose-timezone-modal button.use-local-timezone');
assert.deepEqual(
pageParticipation.options().labels,
[
moment.tz('2015-12-12T11:11:00.000Z', timezoneUser).locale('en').format('LLLL'),
moment.tz('2016-01-01T11:11:00.000Z', timezoneUser).locale('en').format('LLLL')
]
);
assert.notOk(
jQuery(find('#modal-choose-timezone-modal')).is(':visible'),
'modal is closed'
);
await switchTab('evaluation');
assert.deepEqual(
pageEvaluation.preferedOptions,
[moment.tz('2015-12-12T11:11:00.000Z', timezoneUser).locale('en').format('LLLL')]
);
});
await visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`);
assert.ok(
find('#modal-choose-timezone-modal').is(':visible'),
'user gets asked which timezone should be used'
);
test('view a poll while timezone differs from the one poll got created in and choose poll timezone', async function(assert) {
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let timezoneUser = moment.tz.guess();
let timezonePoll = timezoneUser !== 'America/Caracas' ? 'America/Caracas' : 'Europe/Moscow';
let poll = this.server.create('poll', {
encryptionKey,
isDateTime: true,
options: [
{ title: '2015-12-12T11:11:00.000Z' },
{ title: '2016-01-01T11:11:00.000Z' }
],
timezone: timezonePoll,
users: [
this.server.create('user', {
encryptionKey,
selections: [
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
},
{
type: 'no',
labelTranslation: 'answerTypes.no.label',
icon: 'glyphicon glyphicon-thumbs-down',
label: 'No'
}
]
})
]
});
await click('#modal-choose-timezone-modal button.use-local-timezone');
assert.deepEqual(
pageParticipation.options().labels,
[
moment.tz('2015-12-12T11:11:00.000Z', timezoneUser).locale('en').format('LLLL'),
moment.tz('2016-01-01T11:11:00.000Z', timezoneUser).locale('en').format('LLLL')
]
);
assert.notOk(
find('#modal-choose-timezone-modal').is(':visible'),
'modal is closed'
);
await visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`);
assert.ok(
jQuery(find('#modal-choose-timezone-modal')).is(':visible'),
'user gets asked which timezone should be used'
);
await switchTab('evaluation');
assert.deepEqual(
pageEvaluation.preferedOptions,
[moment.tz('2015-12-12T11:11:00.000Z', timezoneUser).locale('en').format('LLLL')]
);
});
await click('#modal-choose-timezone-modal button.use-poll-timezone');
assert.deepEqual(
pageParticipation.options().labels,
[
moment.tz('2015-12-12T11:11:00.000Z', timezonePoll).locale('en').format('LLLL'),
moment.tz('2016-01-01T11:11:00.000Z', timezonePoll).locale('en').format('LLLL')
]
);
assert.notOk(
jQuery(find('#modal-choose-timezone-modal')).is(':visible'),
'modal is closed'
);
test('view a poll while timezone differs from the one poll got created in and choose poll timezone', async function(assert) {
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let timezoneUser = moment.tz.guess();
let timezonePoll = timezoneUser !== 'America/Caracas' ? 'America/Caracas' : 'Europe/Moscow';
let poll = server.create('poll', {
encryptionKey,
isDateTime: true,
options: [
{ title: '2015-12-12T11:11:00.000Z' },
{ title: '2016-01-01T11:11:00.000Z' }
],
timezone: timezonePoll,
users: [
server.create('user', {
encryptionKey,
selections: [
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
},
{
type: 'no',
labelTranslation: 'answerTypes.no.label',
icon: 'glyphicon glyphicon-thumbs-down',
label: 'No'
}
]
})
]
await switchTab('evaluation');
assert.deepEqual(
pageEvaluation.preferedOptions,
[moment.tz('2015-12-12T11:11:00.000Z', timezonePoll).locale('en').format('LLLL')]
);
});
await visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`);
assert.ok(
find('#modal-choose-timezone-modal').is(':visible'),
'user gets asked which timezone should be used'
);
await click('#modal-choose-timezone-modal button.use-poll-timezone');
assert.deepEqual(
pageParticipation.options().labels,
[
moment.tz('2015-12-12T11:11:00.000Z', timezonePoll).locale('en').format('LLLL'),
moment.tz('2016-01-01T11:11:00.000Z', timezonePoll).locale('en').format('LLLL')
]
);
assert.notOk(
find('#modal-choose-timezone-modal').is(':visible'),
'modal is closed'
);
await switchTab('evaluation');
assert.deepEqual(
pageEvaluation.preferedOptions,
[moment.tz('2015-12-12T11:11:00.000Z', timezonePoll).locale('en').format('LLLL')]
);
});

0
tests/helpers/.gitkeep Normal file
View file

View file

@ -1,10 +0,0 @@
import { run } from '@ember/runloop';
export default function destroyApp(application) {
// this is required to fix "second Pretender instance" warnings
if (server) {
server.shutdown();
}
run(application, 'destroy');
}

View file

@ -1,21 +0,0 @@
import { module } from 'qunit';
import { resolve } from 'rsvp';
import startApp from '../helpers/start-app';
import destroyApp from '../helpers/destroy-app';
export default function(name, options = {}) {
module(name, {
beforeEach(assert) {
this.application = startApp({ assert });
if (options.beforeEach) {
return options.beforeEach.apply(this, arguments);
}
},
afterEach() {
let afterEach = options.afterEach && options.afterEach.apply(this, arguments);
return resolve(afterEach).then(() => destroyApp(this.application));
}
});
}

View file

@ -0,0 +1,33 @@
import { isEmpty } from '@ember/utils';
import { findAll } from '@ember/test-helpers';
function pollHasUser(assert, name, selections) {
let elBase = findAll('.user').find((el) => {
return el.querySelector('td:nth-child(1)').textContent.trim() === name;
});
assert.ok(elBase, `user ${name} exists`);
if (elBase) {
selections.forEach((selection, index) => {
assert.equal(
elBase.querySelector(`td:nth-child(${index + 2})`).textContent.trim(),
selection.toString(),
`selection ${index} is as expected`
);
});
}
}
function pollHasUsersCount(assert, count, message) {
if (isEmpty(message)) {
message = 'poll has expected count of users';
}
assert.equal(
findAll('.user').length,
count,
message
);
}
export default pollHasUser;
export { pollHasUsersCount };

View file

@ -1,37 +0,0 @@
import { isEmpty } from '@ember/utils';
import { registerHelper } from '@ember/test';
const helpers = function() {
registerHelper('pollHasUser', function(app, assert, name, selections) {
let elBase;
find('.user').each((index, el) => {
if (find('td:nth-child(1)', el).text().trim() === name) {
elBase = el;
}
});
assert.ok(elBase, `user ${name} exists`);
if (elBase) {
selections.forEach((selection, index) => {
assert.equal(
find(`td:nth-child(${index + 2})`, elBase).text().trim(),
selection,
`selection ${index} is as expected`
);
});
}
});
registerHelper('pollHasUsersCount', function(app, assert, count, message) {
if (isEmpty(message)) {
message = 'poll has expected count of users';
}
assert.equal(
find('.user').length,
count,
message
);
});
};
export default helpers();

View file

@ -1,21 +1,21 @@
import { isEmpty } from '@ember/utils';
import { registerAsyncHelper } from '@ember/test';
import { findAll, fillIn, click } from '@ember/test-helpers';
export default registerAsyncHelper('pollParticipate', function(app, name, selections) {
export default async function(name, selections) {
if (!isEmpty(name)) {
fillIn('.participation .name input', name);
await fillIn('.participation .name input', name);
}
const isFreeText = find('.participation .selections .radio').length ? false : true;
selections.forEach((selection, index) => {
const isFreeText = findAll('.participation .selections .radio').length > 0 ? false : true;
for (let [index, selection] of selections.entries()) {
if (!isEmpty(selection)) {
if (isFreeText) {
fillIn(`.participation .selections .form-group:nth-child(${index + 1}) input`, selection);
await fillIn(`.participation .selections .form-group:nth-child(${index + 1}) input`, selection);
} else {
click(`.participation .selections .form-group:nth-child(${index + 1}) .${selection}.radio input`);
await click(`.participation .selections .form-group:nth-child(${index + 1}) .${selection}.radio input`);
}
}
});
}
click('.participation button[type="submit"]');
});
await click('.participation button[type="submit"]');
}

View file

@ -1,27 +0,0 @@
import Application from '../../app';
import config from '../../config/environment';
import { merge } from '@ember/polyfills';
import { run } from '@ember/runloop';
import './poll-has-users';
import './poll-participate';
import './switch-tab';
import registerAcceptanceTestHelpers from './201-created/register-acceptance-test-helpers';
import registerBrowserNavigationButtonTestHelpers from './browser-navigation-buttons';
import './ember-i18n/test-helpers';
export default function startApp(attrs) {
let attributes = merge({}, config.APP);
attributes.autoboot = true;
attributes = merge(attributes, attrs); // use defaults, but you can override;
return run(() => {
let application = Application.create(attributes);
application.setupForTesting();
registerAcceptanceTestHelpers(attrs.assert || window.QUnit.assert);
registerBrowserNavigationButtonTestHelpers();
application.injectTestHelpers();
return application;
});
}

View file

@ -1,5 +1,5 @@
import { registerAsyncHelper } from '@ember/test';
import { click } from '@ember/test-helpers';
export default registerAsyncHelper('switchTab', function(app, tab) {
click(`.nav-tabs .${tab} a`);
});
export default function(tab) {
return click(`.nav-tabs .${tab} a`);
}

View file

@ -1,66 +1,68 @@
import EmberObject from '@ember/object';
import { moduleForComponent, test } from 'ember-qunit';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import moment from 'moment';
moduleForComponent('create-options-dates', 'Integration | Component | create options dates', {
integration: true
});
test('it renders a ember-cli-bootstrap-datepicker component', function(assert) {
this.set('options', []);
this.render(hbs`{{#bs-form as |form|}}{{create-options-dates options=options form=form}}{{/bs-form}}`);
assert.equal(
this.$('.days .ember-view:has(.datepicker:first-child)').length, 1
);
});
test('bootstrap-datepicker shows dates in options', function(assert) {
this.set('options', [
EmberObject.create({ title: '2015-01-01' }),
EmberObject.create({ title: '2015-01-02' })
]);
this.render(hbs`{{#bs-form as |form|}}{{create-options-dates options=options form=form}}{{/bs-form}}`);
assert.equal(
this.$('.days .ember-view:has(.datepicker:first-child)').datepicker('getDates')[0].toISOString(),
moment('2015-01-01').toISOString(),
'date is correct (a)'
);
assert.equal(
this.$('.days .ember-view:has(.datepicker:first-child)').datepicker('getDates')[1].toISOString(),
moment('2015-01-02').toISOString(),
'date is correct (b)'
);
});
test('dates set in bootstrap-datepicker are set to options', function(assert) {
this.set('options', []);
this.render(hbs`{{#bs-form as |form|}}{{create-options-dates options=options form=form}}{{/bs-form}}`);
this.$('.days .ember-view:has(.datepicker:first-child)').datepicker('setDates', [
moment('2015-01-01').toDate(),
moment('2015-01-02').toDate()
]);
assert.equal(
this.get('options.0.title'),
'2015-01-01',
'dates are correct (a)'
);
assert.equal(
this.get('options.1.title'),
'2015-01-02',
'dates are correct (b)'
);
this.$('.days .ember-view:has(.datepicker:first-child)').datepicker('setDates', [
moment('2016-12-31').toDate(),
moment('2016-01-01').toDate()
]);
assert.equal(
this.get('options.firstObject.title'),
'2016-01-01',
'dates are sorted'
);
module('Integration | Component | create options dates', function(hooks) {
setupRenderingTest(hooks);
test('it renders a ember-cli-bootstrap-datepicker component', async function(assert) {
this.set('options', []);
await render(hbs`{{#bs-form as |form|}}{{create-options-dates options=options form=form}}{{/bs-form}}`);
assert.equal(
this.$('.days .ember-view:has(.datepicker:first-child)').length, 1
);
});
test('bootstrap-datepicker shows dates in options', async function(assert) {
this.set('options', [
EmberObject.create({ title: '2015-01-01' }),
EmberObject.create({ title: '2015-01-02' })
]);
await render(hbs`{{#bs-form as |form|}}{{create-options-dates options=options form=form}}{{/bs-form}}`);
assert.equal(
this.$('.days .ember-view:has(.datepicker:first-child)').datepicker('getDates')[0].toISOString(),
moment('2015-01-01').toISOString(),
'date is correct (a)'
);
assert.equal(
this.$('.days .ember-view:has(.datepicker:first-child)').datepicker('getDates')[1].toISOString(),
moment('2015-01-02').toISOString(),
'date is correct (b)'
);
});
test('dates set in bootstrap-datepicker are set to options', async function(assert) {
this.set('options', []);
await render(hbs`{{#bs-form as |form|}}{{create-options-dates options=options form=form}}{{/bs-form}}`);
this.$('.days .ember-view:has(.datepicker:first-child)').datepicker('setDates', [
moment('2015-01-01').toDate(),
moment('2015-01-02').toDate()
]);
assert.equal(
this.get('options.0.title'),
'2015-01-01',
'dates are correct (a)'
);
assert.equal(
this.get('options.1.title'),
'2015-01-02',
'dates are correct (b)'
);
this.$('.days .ember-view:has(.datepicker:first-child)').datepicker('setDates', [
moment('2016-12-31').toDate(),
moment('2016-01-01').toDate()
]);
assert.equal(
this.get('options.firstObject.title'),
'2016-01-01',
'dates are sorted'
);
});
});

View file

@ -1,196 +1,204 @@
import { alias } from '@ember/object/computed';
import { run } from '@ember/runloop';
import { moduleForComponent, test } from 'ember-qunit';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import {
render,
click,
fillIn,
find,
findAll,
triggerEvent
} from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import jQuery from 'jquery';
import moment from 'moment';
moduleForComponent('create-options-datetime', 'Integration | Component | create options datetime', {
integration: true,
beforeEach() {
this.inject.service('store');
}
});
module('Integration | Component | create options datetime', function(hooks) {
setupRenderingTest(hooks);
/*
* watch out:
* polyfill adds another input[type="text"] for every input[type="time"]
* if browser doesn't support input[type="time"]
* that ones could be identifed by class 'ws-inputreplace'
*/
test('it generates inpute field for options iso 8601 date string (without time)', function(assert) {
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
run(() => {
this.set('poll', this.store.createRecord('poll', {
isFindADate: true,
isMakeAPoll: false,
options: [
{ title: '2015-01-01' }
]
}));
hooks.beforeEach(function() {
this.store = this.owner.lookup('service:store');
});
this.render(hbs`{{create-options-datetime dates=poll.options}}`);
assert.equal(
this.$('.days .form-group input').length,
1,
'there is one input field'
);
assert.equal(
this.$('.days .form-group input').val(),
'',
'value is an empty string'
);
});
/*
* watch out:
* polyfill adds another input[type="text"] for every input[type="time"]
* if browser doesn't support input[type="time"]
* that ones could be identifed by class 'ws-inputreplace'
*/
test('it generates inpute field for options iso 8601 datetime string (with time)', function(assert) {
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
run(() => {
this.set('poll', this.store.createRecord('poll', {
isFindADate: true,
isMakeAPoll: false,
options: [
{ title: '2015-01-01T11:11:00.000Z' }
]
}));
});
this.render(hbs`{{create-options-datetime dates=poll.options}}`);
test('it generates inpute field for options iso 8601 date string (without time)', async function(assert) {
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
run(() => {
this.set('poll', this.store.createRecord('poll', {
isFindADate: true,
isMakeAPoll: false,
options: [
{ title: '2015-01-01' }
]
}));
});
await render(hbs`{{create-options-datetime dates=poll.options}}`);
assert.equal(
this.$('.days .form-group input').length,
1,
'there is one input field'
);
assert.equal(
this.$('.days .form-group input').val(),
moment('2015-01-01T11:11:00.000Z').format('HH:mm'),
'it has time in option as value'
);
});
test('it hides repeated labels', function(assert) {
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
run(() => {
this.set('poll', this.store.createRecord('poll', {
isFindADate: true,
isMakeAPoll: false,
options: [
{ title: moment('2015-01-01T10:11').toISOString() },
{ title: moment('2015-01-01T22:22').toISOString() },
{ title: '2015-02-02' }
]
}));
});
this.render(hbs`{{create-options-datetime dates=poll.options}}`);
assert.equal(
this.$('.days label').length,
3,
'every form-group has a label'
);
assert.equal(
this.$('.days label:not(.sr-only)').length,
2,
'there are two not hidden labels for two different dates'
);
assert.notOk(
this.$('.days .form-group').eq(0).find('label').hasClass('sr-only'),
'the first label is shown'
);
assert.ok(
this.$('.days .form-group').eq(1).find('label').hasClass('sr-only'),
'the repeated label on second form-group is hidden by sr-only class'
);
assert.notOk(
this.$('.days .form-group').eq(2).find('label').hasClass('sr-only'),
'the new label on third form-group is shown'
);
});
test('allows to add another option', function(assert) {
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
run(() => {
this.set('poll', this.store.createRecord('poll', {
options: [
{ title: '2015-01-01' },
{ title: '2015-02-02' }
]
}));
});
this.render(hbs`{{create-options-datetime dates=poll.options}}`);
assert.equal(
this.$('.days .form-group input').length,
2,
'there are two input fields before'
);
this.$('.days .form-group').eq(0).find('.add').click();
assert.equal(
this.$('.days .form-group input').length,
3,
'another input field is added'
);
assert.equal(
this.$('.days .form-group').eq(1).find('label').text(),
this.$('.days .form-group').eq(0).find('label').text(),
'new input has correct label'
);
assert.ok(
this.$('.days .form-group').eq(1).find('label').hasClass('sr-only'),
'label ofnew input is hidden cause it\'s repeated'
);
});
test('allows to delete an option', function(assert) {
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
run(() => {
this.set('poll', this.store.createRecord('poll', {
isFindADate: true,
isMakeAPoll: false,
options: [
{ title: moment('2015-01-01T11:11').toISOString() },
{ title: moment('2015-01-01T22:22').toISOString() }
]
}));
});
this.render(hbs`{{create-options-datetime dates=poll.options}}`);
assert.equal(
this.$('.days input').length,
2,
'there are two input fields before'
);
assert.ok(
this.$('.delete').get().every((el) => {
return el.disabled === false;
}),
'options are deleteable'
);
this.$('.days .form-group').eq(0).find('.delete').click();
run(() => {
assert.equal(
this.$('.days .form-group input').length,
findAll('.days .form-group input').length,
1,
'there is one input field'
);
assert.equal(
find('.days .form-group input').value,
'',
'value is an empty string'
);
});
test('it generates inpute field for options iso 8601 datetime string (with time)', async function(assert) {
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
run(() => {
this.set('poll', this.store.createRecord('poll', {
isFindADate: true,
isMakeAPoll: false,
options: [
{ title: '2015-01-01T11:11:00.000Z' }
]
}));
});
await render(hbs`{{create-options-datetime dates=poll.options}}`);
assert.equal(
findAll('.days .form-group input').length,
1,
'there is one input field'
);
assert.equal(
find('.days .form-group input').value,
moment('2015-01-01T11:11:00.000Z').format('HH:mm'),
'it has time in option as value'
);
});
test('it hides repeated labels', async function(assert) {
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
run(() => {
this.set('poll', this.store.createRecord('poll', {
isFindADate: true,
isMakeAPoll: false,
options: [
{ title: moment('2015-01-01T10:11').toISOString() },
{ title: moment('2015-01-01T22:22').toISOString() },
{ title: '2015-02-02' }
]
}));
});
await render(hbs`{{create-options-datetime dates=poll.options}}`);
assert.equal(
findAll('.days label').length,
3,
'every form-group has a label'
);
assert.equal(
findAll('.days label:not(.sr-only)').length,
2,
'there are two not hidden labels for two different dates'
);
assert.notOk(
this.$('.days .form-group').eq(0).find('label').hasClass('sr-only'),
'the first label is shown'
);
assert.ok(
this.$('.days .form-group').eq(1).find('label').hasClass('sr-only'),
'the repeated label on second form-group is hidden by sr-only class'
);
assert.notOk(
this.$('.days .form-group').eq(2).find('label').hasClass('sr-only'),
'the new label on third form-group is shown'
);
});
test('allows to add another option', async function(assert) {
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
run(() => {
this.set('poll', this.store.createRecord('poll', {
options: [
{ title: '2015-01-01' },
{ title: '2015-02-02' }
]
}));
});
await render(hbs`{{create-options-datetime dates=poll.options}}`);
assert.equal(
findAll('.days .form-group input').length,
2,
'there are two input fields before'
);
await click(findAll('.days .form-group')[0].querySelector('.add'));
assert.equal(
findAll('.days .form-group input').length,
3,
'another input field is added'
);
assert.equal(
this.$('.days .form-group').eq(1).find('label').text(),
this.$('.days .form-group').eq(0).find('label').text(),
'new input has correct label'
);
assert.ok(
this.$('.days .form-group').eq(1).find('label').hasClass('sr-only'),
'label ofnew input is hidden cause it\'s repeated'
);
});
test('allows to delete an option', async function(assert) {
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
run(() => {
this.set('poll', this.store.createRecord('poll', {
isFindADate: true,
isMakeAPoll: false,
options: [
{ title: moment('2015-01-01T11:11').toISOString() },
{ title: moment('2015-01-01T22:22').toISOString() }
]
}));
});
await render(hbs`{{create-options-datetime dates=poll.options}}`);
assert.equal(
findAll('.days input').length,
2,
'there are two input fields before'
);
assert.ok(
findAll('.delete').every((el) => el.disabled === false),
'options are deleteable'
);
await click(findAll('.days .form-group')[0].querySelector('.delete'));
assert.equal(
findAll('.days .form-group input').length,
1,
'one input field is removed after deletion'
);
assert.equal(
this.$('.days .form-group input').val(),
find('.days .form-group input').value,
'22:22',
'correct input field is deleted'
);
@ -205,150 +213,141 @@ test('allows to delete an option', function(assert) {
'correct option is deleted'
);
});
});
test('adopt times of first day - simple', function(assert) {
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
run(() => {
this.set('poll', this.store.createRecord('poll', {
options: [
{ title: moment().hour(10).minute(0).toISOString() },
{ title: '2015-02-02' },
{ title: '2015-03-03' }
]
}));
test('adopt times of first day - simple', async function(assert) {
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
run(() => {
this.set('poll', this.store.createRecord('poll', {
options: [
{ title: moment().hour(10).minute(0).toISOString() },
{ title: '2015-02-02' },
{ title: '2015-03-03' }
]
}));
});
await render(hbs`{{create-options-datetime dates=poll.options}}`);
await click('button.adopt-times-of-first-day');
assert.equal(
findAll('.days .form-group')[0].querySelector('input').value,
'10:00',
'time was not changed for first day'
);
assert.equal(
findAll('.days .form-group')[1].querySelector('input').value,
'10:00',
'time was adopted for second day'
);
assert.equal(
findAll('.days .form-group')[2].querySelector('input').value,
'10:00',
'time was adopted for third day'
);
});
this.render(hbs`{{create-options-datetime dates=poll.options}}`);
run(() => {
this.$('button.adopt-times-of-first-day').click();
});
assert.equal(
this.$('.days .form-group').eq(0).find('input').val(),
'10:00',
'time was not changed for first day'
);
assert.equal(
this.$('.days .form-group').eq(1).find('input').val(),
'10:00',
'time was adopted for second day'
);
assert.equal(
this.$('.days .form-group').eq(2).find('input').val(),
'10:00',
'time was adopted for third day'
);
});
test('adopt times of first day - more times on first day than on others', function(assert) {
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
run(() => {
this.set('poll', this.store.createRecord('poll', {
options: [
{ title: moment().hour(10).minute(0).toISOString() },
{ title: moment().hour(22).minute(0).toISOString() },
{ title: '2015-02-02' },
{ title: '2015-03-03' }
]
}));
test('adopt times of first day - more times on first day than on others', async function(assert) {
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
run(() => {
this.set('poll', this.store.createRecord('poll', {
options: [
{ title: moment().hour(10).minute(0).toISOString() },
{ title: moment().hour(22).minute(0).toISOString() },
{ title: '2015-02-02' },
{ title: '2015-03-03' }
]
}));
});
await render(hbs`{{create-options-datetime dates=poll.options}}`);
await click('button.adopt-times-of-first-day');
assert.deepEqual(
this.$('.days .form-group input').map((i, el) => jQuery(el).val()).toArray(),
['10:00', '22:00', '10:00', '22:00', '10:00', '22:00'],
'times were adopted correctly'
);
});
this.render(hbs`{{create-options-datetime dates=poll.options}}`);
run(() => {
this.$('button.adopt-times-of-first-day').click();
});
assert.deepEqual(
this.$('.days .form-group input').map((i, el) => jQuery(el).val()).toArray(),
['10:00', '22:00', '10:00', '22:00', '10:00', '22:00'],
'times were adopted correctly'
);
});
test('adopt times of first day - excess times on other days got deleted', function(assert) {
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
run(() => {
this.set('poll', this.store.createRecord('poll', {
isFindADate: true,
isMakeAPoll: false,
options: [
{ title: moment().hour(10).minute(0).toISOString() },
{ title: moment().add(1, 'day').hour(10).minute(0).toISOString() },
{ title: moment().add(1, 'day').hour(22).minute(0).toISOString() }
]
}));
test('adopt times of first day - excess times on other days got deleted', async function(assert) {
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
run(() => {
this.set('poll', this.store.createRecord('poll', {
isFindADate: true,
isMakeAPoll: false,
options: [
{ title: moment().hour(10).minute(0).toISOString() },
{ title: moment().add(1, 'day').hour(10).minute(0).toISOString() },
{ title: moment().add(1, 'day').hour(22).minute(0).toISOString() }
]
}));
});
await render(hbs`{{create-options-datetime dates=poll.options}}`);
await click('button.adopt-times-of-first-day');
assert.equal(
findAll('.days .form-group').length,
2,
'one excess time input got deleted'
);
assert.deepEqual(
this.$('.days .form-group input').map((i, el) => jQuery(el).val()).toArray(),
['10:00', '10:00'],
'additional time on secondary day got deleted'
);
});
this.render(hbs`{{create-options-datetime dates=poll.options}}`);
run(() => {
this.$('button.adopt-times-of-first-day').click();
});
assert.equal(
this.$('.days .form-group').length,
2,
'one excess time input got deleted'
);
assert.deepEqual(
this.$('.days .form-group input').map((i, el) => jQuery(el).val()).toArray(),
['10:00', '10:00'],
'additional time on secondary day got deleted'
);
});
test('validation', function(assert) {
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
run(() => {
this.set('poll', this.store.createRecord('poll', {
isFindADate: true,
isMakeAPoll: false
}));
this.set('options', alias('poll.options'));
this.get('options').pushObjects([
{ title: '2015-01-01' },
{ title: '2015-02-02' }
]);
test('validation', async function(assert) {
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
run(() => {
this.set('poll', this.store.createRecord('poll', {
isFindADate: true,
isMakeAPoll: false
}));
this.set('options', alias('poll.options'));
this.get('options').pushObjects([
{ title: '2015-01-01' },
{ title: '2015-02-02' }
]);
});
await render(hbs`{{create-options-datetime dates=options}}`);
assert.ok(
findAll('.has-error').length === 0,
'does not show a validation error before user interaction'
);
await fillIn(findAll('.form-group')[1].querySelector('input'), '10:');
assert.ok(
findAll('.form-group')[1].classList.contains('has-error') ||
// browsers with input type time support prevent non time input
findAll('.form-group')[1].querySelector('input').value === '',
'shows error after invalid input or prevents invalid input'
);
// simulate unique violation
await click(findAll('.form-group')[0].querySelector('.add'));
await fillIn(findAll('.form-group')[0].querySelector('input'), '10:00');
await fillIn(findAll('.form-group')[1].querySelector('input'), '10:00');
await fillIn(findAll('.form-group')[2].querySelector('input'), '10:00');
await triggerEvent('form', 'submit');
assert.ok(
findAll('.form-group')[0].classList.contains('has-success'),
'first time shows validation success'
);
assert.ok(
findAll('.form-group')[1].classList.contains('has-error'),
'same time for same day shows validation error'
);
assert.ok(
findAll('.form-group')[2].classList.contains('has-success'),
'same time for different day shows validation success'
);
});
this.render(hbs`{{create-options-datetime dates=options}}`);
assert.ok(
this.$('.has-error').length === 0,
'does not show a validation error before user interaction'
);
this.$('.form-group').eq(1).find('input').trigger('focusout');
assert.ok(
this.$('.form-group').eq(1).hasClass('has-success'),
'does show validation errors after user interaction'
);
this.$('.form-group').eq(1).find('input').val('10:').trigger('change');
assert.ok(
this.$('.form-group').eq(1).hasClass('has-error') ||
// browsers with input type time support prevent non time input
this.$('.form-group').eq(1).find('input').val() === '',
'shows error after invalid input or prevents invalid input'
);
// simulate unique violation
this.$('.form-group').eq(0).find('.add').click();
this.$('.form-group input').eq(0).val('10:00').trigger('change');
this.$('.form-group input').eq(1).val('10:00').trigger('change');
this.$('.form-group input').eq(2).val('10:00').trigger('change');
this.$('form').submit();
assert.ok(
this.$('.form-group').eq(0).hasClass('has-success'),
'first time shows validation success'
);
assert.ok(
this.$('.form-group').eq(1).hasClass('has-error'),
'same time for same day shows validation error'
);
assert.ok(
this.$('.form-group').eq(2).hasClass('has-success'),
'same time for different day shows validation success'
);
});

View file

@ -1,187 +1,197 @@
import { run } from '@ember/runloop';
import { moduleForComponent, test } from 'ember-qunit';
import { blur, fillIn, findAll, focus } from 'ember-native-dom-helpers';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, findAll, blur, fillIn, focus } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import hasComponent from 'croodle/tests/helpers/201-created/raw/has-component';
moduleForComponent('create-options', 'Integration | Component | create options', {
integration: true,
beforeEach() {
this.inject.service('store');
}
});
module('Integration | Component | create options', function(hooks) {
setupRenderingTest(hooks);
test('renders component', function(assert) {
this.set('options', []);
this.set('isDateTime', false);
this.set('isFindADate', true);
this.set('isMakeAPoll', false);
this.render(hbs`{{create-options options=options isDateTime=isDateTime isFindADate=isFindADate isMakeAPoll=isMakeAPoll}}`);
assert.ok(
hasComponent(this.container, assert, 'create-options-dates').ok
);
assert.notOk(
hasComponent(this.container, assert, 'create-options-text').ok
);
this.set('isDateTime', false);
this.set('isFindADate', false);
this.set('isMakeAPoll', true);
assert.notOk(
hasComponent(this.container, assert, 'create-options-dates').ok
);
assert.ok(
hasComponent(this.container, assert, 'create-options-text').ok
);
});
test('shows validation errors if options are not unique (makeAPoll)', async function(assert) {
assert.expect(5);
this.set('isDateTime', false);
this.set('isFindADate', false);
this.set('isMakeAPoll', true);
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
let poll;
run(() => {
poll = this.store.createRecord('poll', {
isFindADate: this.get('isFindADate'),
isDateTime: this.get('isDateTime'),
isMakeAPoll: this.get('isMakeAPoll')
});
hooks.beforeEach(function() {
this.store = this.owner.lookup('service:store');
});
this.set('options', poll.get('options'));
this.render(hbs`{{create-options options=options isDateTime=isDateTime isFindADate=isFindADate isMakeAPoll=isMakeAPoll}}`);
test('renders component', async function(assert) {
this.set('options', []);
this.set('isDateTime', false);
this.set('isFindADate', true);
this.set('isMakeAPoll', false);
await render(
hbs`{{create-options options=options isDateTime=isDateTime isFindADate=isFindADate isMakeAPoll=isMakeAPoll}}`
);
assert.ok(
this.$('input').length === 2,
'assumptions are correct'
);
assert.ok(
hasComponent(this.owner, assert, 'create-options-dates').ok
);
assert.notOk(
hasComponent(this.owner, assert, 'create-options-text').ok
);
await fillIn(findAll('input')[0], 'foo');
await blur(findAll('input')[0]);
await fillIn(findAll('input')[1], 'foo');
await blur(findAll('input')[1]);
assert.ok(
this.$('.form-group').eq(1).hasClass('has-error'),
'second input field has validation error'
);
this.set('isDateTime', false);
this.set('isFindADate', false);
this.set('isMakeAPoll', true);
assert.ok(
this.$('.form-group').eq(1).find('.help-block').length === 1,
'validation error is shown'
);
await fillIn(findAll('input')[0], 'bar');
await blur(findAll('input')[0]);
assert.ok(
this.$('.form-group .help-block').length === 0,
'there is no validation error anymore after a unique value is entered'
);
assert.ok(
this.$('.form-group.has-error').length === 0,
'has-error classes are removed'
);
});
test('shows validation errors if option is empty (makeAPoll)', async function(assert) {
this.set('isDateTime', false);
this.set('isFindADate', false);
this.set('isMakeAPoll', true);
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
let poll;
run(() => {
poll = this.store.createRecord('poll', {
isFindADate: this.get('isFindADate'),
isDateTime: this.get('isDateTime'),
isMakeAPoll: this.get('isMakeAPoll')
});
assert.notOk(
hasComponent(this.owner, assert, 'create-options-dates').ok
);
assert.ok(
hasComponent(this.owner, assert, 'create-options-text').ok
);
});
this.set('options', poll.get('options'));
this.render(hbs`{{create-options options=options isDateTime=isDateTime isFindADate=isFindADate isMakeAPoll=isMakeAPoll}}`);
test('shows validation errors if options are not unique (makeAPoll)', async function(assert) {
assert.expect(5);
assert.equal(
this.$('.form-group.has-error').length, 0
);
this.set('isDateTime', false);
this.set('isFindADate', false);
this.set('isMakeAPoll', true);
await focus(findAll('input')[0]);
await blur(findAll('input')[0]);
await focus(findAll('input')[1]);
await blur(findAll('input')[1]);
assert.equal(
this.$('.form-group.has-error').length, 2
);
await fillIn(findAll('input')[0], 'foo');
await blur(findAll('input')[0]);
assert.equal(
this.$('.form-group.has-error').length, 1
);
await fillIn(findAll('input')[1], 'bar');
await blur(findAll('input')[1]);
assert.equal(
this.$('.form-group.has-error').length, 0
);
});
test('label reflects validation state of all inputs (makeAPoll)', async function(assert) {
this.set('isDateTime', false);
this.set('isFindADate', false);
this.set('isMakeAPoll', true);
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
let poll;
run(() => {
poll = this.store.createRecord('poll', {
isFindADate: this.get('isFindADate'),
isDateTime: this.get('isDateTime'),
isMakeAPoll: this.get('isMakeAPoll')
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
let poll;
run(() => {
poll = this.store.createRecord('poll', {
isFindADate: this.get('isFindADate'),
isDateTime: this.get('isDateTime'),
isMakeAPoll: this.get('isMakeAPoll')
});
});
this.set('options', poll.get('options'));
await render(
hbs`{{create-options options=options isDateTime=isDateTime isFindADate=isFindADate isMakeAPoll=isMakeAPoll}}`
);
assert.ok(
findAll('input').length === 2,
'assumptions are correct'
);
await fillIn(findAll('input')[0], 'foo');
await blur(findAll('input')[0]);
await fillIn(findAll('input')[1], 'foo');
await blur(findAll('input')[1]);
assert.ok(
this.$('.form-group').eq(1).hasClass('has-error'),
'second input field has validation error'
);
assert.ok(
this.$('.form-group').eq(1).find('.help-block').length === 1,
'validation error is shown'
);
await fillIn(findAll('input')[0], 'bar');
await blur(findAll('input')[0]);
assert.ok(
findAll('.form-group .help-block').length === 0,
'there is no validation error anymore after a unique value is entered'
);
assert.ok(
findAll('.form-group.has-error').length === 0,
'has-error classes are removed'
);
});
this.set('options', poll.get('options'));
this.render(hbs`{{create-options options=options isDateTime=isDateTime isFindADate=isFindADate isMakeAPoll=isMakeAPoll}}`);
test('shows validation errors if option is empty (makeAPoll)', async function(assert) {
this.set('isDateTime', false);
this.set('isFindADate', false);
this.set('isMakeAPoll', true);
assert.ok(
this.$('form').children().hasClass('label-has-no-validation'),
'does not show validation state if there wasn\'t any user interaction yet'
);
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
let poll;
run(() => {
poll = this.store.createRecord('poll', {
isFindADate: this.get('isFindADate'),
isDateTime: this.get('isDateTime'),
isMakeAPoll: this.get('isMakeAPoll')
});
});
this.set('options', poll.get('options'));
await focus(findAll('input')[0]);
await blur(findAll('input')[0]);
assert.ok(
this.$('form').children().hasClass('label-has-error'),
'shows as having error if atleast on field has an error'
);
await render(
hbs`{{create-options options=options isDateTime=isDateTime isFindADate=isFindADate isMakeAPoll=isMakeAPoll}}`
);
await fillIn(findAll('input')[0], 'foo');
await blur(findAll('input')[0]);
assert.ok(
this.$('form').children().hasClass('label-has-no-validation'),
'does not show validation state if no field has error but not all fields are showing error yet'
);
assert.equal(
findAll('.form-group.has-error').length, 0
);
await fillIn(findAll('input')[1], 'bar');
await blur(findAll('input')[1]);
assert.ok(
this.$('form').children().hasClass('label-has-success'),
'shows as having success if all fields are showing success'
);
await focus(findAll('input')[0]);
await blur(findAll('input')[0]);
await focus(findAll('input')[1]);
await blur(findAll('input')[1]);
assert.equal(
findAll('.form-group.has-error').length, 2
);
await fillIn(findAll('input')[0], 'foo');
await blur(findAll('input')[0]);
assert.equal(
findAll('.form-group.has-error').length, 1
);
await fillIn(findAll('input')[1], 'bar');
await blur(findAll('input')[1]);
assert.equal(
findAll('.form-group.has-error').length, 0
);
});
test('label reflects validation state of all inputs (makeAPoll)', async function(assert) {
this.set('isDateTime', false);
this.set('isFindADate', false);
this.set('isMakeAPoll', true);
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
let poll;
run(() => {
poll = this.store.createRecord('poll', {
isFindADate: this.get('isFindADate'),
isDateTime: this.get('isDateTime'),
isMakeAPoll: this.get('isMakeAPoll')
});
});
this.set('options', poll.get('options'));
await render(
hbs`{{create-options options=options isDateTime=isDateTime isFindADate=isFindADate isMakeAPoll=isMakeAPoll}}`
);
assert.ok(
this.$('form').children().hasClass('label-has-no-validation'),
'does not show validation state if there wasn\'t any user interaction yet'
);
await focus(findAll('input')[0]);
await blur(findAll('input')[0]);
assert.ok(
this.$('form').children().hasClass('label-has-error'),
'shows as having error if atleast on field has an error'
);
await fillIn(findAll('input')[0], 'foo');
await blur(findAll('input')[0]);
assert.ok(
this.$('form').children().hasClass('label-has-no-validation'),
'does not show validation state if no field has error but not all fields are showing error yet'
);
await fillIn(findAll('input')[1], 'bar');
await blur(findAll('input')[1]);
assert.ok(
this.$('form').children().hasClass('label-has-success'),
'shows as having success if all fields are showing success'
);
});
});

View file

@ -1,173 +1,171 @@
import { run } from '@ember/runloop';
import EmberObject from '@ember/object';
import { moduleForComponent, test } from 'ember-qunit';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, findAll, click } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import jQuery from 'jquery';
moduleForComponent('create-options-text', 'Integration | Component | create options text', {
integration: true,
beforeEach() {
this.inject.service('store');
}
});
module('Integration | Component | create options text', function(hooks) {
setupRenderingTest(hooks);
test('it generates at least two input fields', function(assert) {
this.set('options', []);
this.render(hbs`{{#bs-form as |form|}}{{create-options-text options=options form=form}}{{/bs-form}}`);
hooks.beforeEach(function() {
this.store = this.owner.lookup('service:store');
});
assert.equal(this.$('input').length, 2);
});
test('it generates at least two input fields', async function(assert) {
this.set('options', []);
await render(hbs`{{#bs-form as |form|}}{{create-options-text options=options form=form}}{{/bs-form}}`);
test('generates input fields according options', function(assert) {
this.set('options', [
EmberObject.create({ title: 'foo' }),
EmberObject.create({ title: 'bar' }),
EmberObject.create({ title: 'baz' })
]);
this.render(hbs`{{#bs-form as |form|}}{{create-options-text options=options form=form}}{{/bs-form}}`);
assert.equal(findAll('input').length, 2);
});
assert.equal(
this.$('input').length,
3,
'correct amount of input fields'
);
assert.deepEqual(
this.$('input').map(function() {
return jQuery(this).val();
}).get(),
['foo', 'bar', 'baz'],
'input fields have correct values and order'
);
});
test('observes changes to options', function(assert) {
this.set('options', [
EmberObject.create({ title: 'foo' }),
EmberObject.create({ title: 'bar' })
]);
this.render(hbs`{{#bs-form as |form|}}{{create-options-text options=options form=form}}{{/bs-form}}`);
assert.equal(
this.$('input').length,
2,
'has correct amount of input fields before change'
);
run(() => {
this.get('options').pushObject(
test('generates input fields according options', async function(assert) {
this.set('options', [
EmberObject.create({ title: 'foo' }),
EmberObject.create({ title: 'bar' }),
EmberObject.create({ title: 'baz' })
);
});
]);
await render(hbs`{{#bs-form as |form|}}{{create-options-text options=options form=form}}{{/bs-form}}`);
assert.equal(
this.$('input').length,
3,
'has correct amount of input fields after change'
);
assert.equal(
this.$('input').eq(2).val(),
'baz',
'input field was added with correct value'
);
});
test('changes to value updates option', function(assert) {
this.set('options', [
EmberObject.create({ title: 'foo' }),
EmberObject.create({ title: 'bar' })
]);
this.render(hbs`{{#bs-form as |form|}}{{create-options-text options=options form=form}}{{/bs-form}}`);
this.$('input').eq(0).val('baz').trigger('change');
assert.equal(
this.get('options')[0].get('title'),
'baz',
'option was updated'
);
});
test('allows to add another option', function(assert) {
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
let poll;
run(() => {
poll = this.store.createRecord('poll', {
isFindADate: this.get('isFindADate'),
isDateTime: this.get('isDateTime'),
isMakeAPoll: this.get('isMakeAPoll'),
options: [
{ title: 'foo' },
{ title: 'bar' }
]
});
});
this.set('options', poll.get('options'));
this.render(hbs`{{#bs-form as |form|}}{{create-options-text options=options form=form}}{{/bs-form}}`);
assert.equal(
this.$('.form-group input').length,
2,
'there are two input fields before'
);
run(() => {
this.$('.form-group .add').eq(0).click();
});
assert.equal(
this.$('.form-group input').length,
3,
'another input field is added'
);
assert.deepEqual(
this.$('input').map(function() {
return jQuery(this).val();
}).get(),
['foo', '', 'bar'],
'it is added at correct position'
);
run(() => {
this.$('.form-group input').eq(1).val('baz').trigger('change');
});
assert.equal(
this.get('options').objectAt(1).get('title'),
'baz',
'options are observed for new input field'
);
});
test('allows to delete an option', function(assert) {
this.set('options', [
EmberObject.create({ title: 'foo' }),
EmberObject.create({ title: 'bar' }),
EmberObject.create({ title: 'baz' })
]);
this.render(hbs`{{#bs-form as |form|}}{{create-options-text options=options form=form}}{{/bs-form}}`);
assert.equal(
this.$('.form-group input').length,
3,
'there are three input fields before'
);
assert.ok(
this.$('.delete').get().every((el) => {
return el.disabled === false;
}),
'options are deleteable'
);
this.$('.form-group .delete').eq(1).click();
run(() => {
assert.equal(
this.$('.form-group input').length,
2,
'one input field is deleted'
findAll('input').length,
3,
'correct amount of input fields'
);
assert.deepEqual(
this.$('input').map(function() {
return jQuery(this).val();
}).get(),
['foo', 'bar', 'baz'],
'input fields have correct values and order'
);
});
test('observes changes to options', async function(assert) {
this.set('options', [
EmberObject.create({ title: 'foo' }),
EmberObject.create({ title: 'bar' })
]);
await render(hbs`{{#bs-form as |form|}}{{create-options-text options=options form=form}}{{/bs-form}}`);
assert.equal(
findAll('input').length,
2,
'has correct amount of input fields before change'
);
run(() => {
this.get('options').pushObject(
EmberObject.create({ title: 'baz' })
);
});
assert.equal(
findAll('input').length,
3,
'has correct amount of input fields after change'
);
assert.equal(
this.$('input').eq(2).val(),
'baz',
'input field was added with correct value'
);
});
test('changes to value updates option', async function(assert) {
this.set('options', [
EmberObject.create({ title: 'foo' }),
EmberObject.create({ title: 'bar' })
]);
await render(hbs`{{#bs-form as |form|}}{{create-options-text options=options form=form}}{{/bs-form}}`);
this.$('input').eq(0).val('baz').trigger('change');
assert.equal(
this.get('options')[0].get('title'),
'baz',
'option was updated'
);
});
test('allows to add another option', async function(assert) {
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
let poll;
run(() => {
poll = this.store.createRecord('poll', {
isFindADate: this.get('isFindADate'),
isDateTime: this.get('isDateTime'),
isMakeAPoll: this.get('isMakeAPoll'),
options: [
{ title: 'foo' },
{ title: 'bar' }
]
});
});
this.set('options', poll.get('options'));
await render(hbs`{{#bs-form as |form|}}{{create-options-text options=options form=form}}{{/bs-form}}`);
assert.equal(
findAll('.form-group input').length,
2,
'there are two input fields before'
);
run(() => {
this.$('.form-group .add').eq(0).click();
});
assert.equal(
findAll('.form-group input').length,
3,
'another input field is added'
);
assert.deepEqual(
this.$('input').map(function() {
return jQuery(this).val();
}).get(),
['foo', '', 'bar'],
'it is added at correct position'
);
run(() => {
this.$('.form-group input').eq(1).val('baz').trigger('change');
});
assert.equal(
this.get('options').objectAt(1).get('title'),
'baz',
'options are observed for new input field'
);
});
test('allows to delete an option', async function(assert) {
this.set('options', [
EmberObject.create({ title: 'foo' }),
EmberObject.create({ title: 'bar' }),
EmberObject.create({ title: 'baz' })
]);
await render(hbs`{{#bs-form as |form|}}{{create-options-text options=options form=form}}{{/bs-form}}`);
assert.equal(
findAll('.form-group input').length,
3,
'there are three input fields before'
);
assert.ok(
findAll('.delete').every((el) => el.disabled === false),
'options are deleteable'
);
await click(findAll('.form-group .delete')[1]);
assert.equal(
findAll('.form-group input').length,
2,
'one input field is deleted'
);
assert.deepEqual(
findAll('input').toArray().map((el) => el.value),
['foo', 'baz'],
'correct input field is deleted'
);

View file

@ -1,23 +1,25 @@
import { moduleForComponent, test } from 'ember-qunit';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, findAll, find } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
moduleForComponent('form-navigation-buttons', 'Integration | Component | form navigation buttons', {
integration: true
});
module('Integration | Component | form navigation buttons', function(hooks) {
setupRenderingTest(hooks);
test('it renders two buttons as default', function(assert) {
this.render(hbs`{{form-navigation-buttons}}`);
assert.equal(this.$('button').length, 2);
});
test('it renders two buttons as default', async function(assert) {
await render(hbs`{{form-navigation-buttons}}`);
assert.equal(findAll('button').length, 2);
});
test('buttons could be disabled', function(assert) {
this.render(hbs`{{form-navigation-buttons disableNextButton=true disablePrevButton=true}}`);
assert.equal(this.$('button.next').prop('disabled'), true, 'next button is disabled');
assert.equal(this.$('button.prev').prop('disabled'), true, 'prev button is disabled');
});
test('buttons could be disabled', async function(assert) {
await render(hbs`{{form-navigation-buttons disableNextButton=true disablePrevButton=true}}`);
assert.equal(find('button.next').disabled, true, 'next button is disabled');
assert.equal(find('button.prev').disabled, true, 'prev button is disabled');
});
test('could prevent rendering of prev button', function(assert) {
this.render(hbs`{{form-navigation-buttons renderPrevButton=false}}`);
assert.ok(this.$('button.prev').length === 0, 'prev button is not rendered');
assert.ok(this.$('button.next').length === 1, 'next button is rendered');
test('could prevent rendering of prev button', async function(assert) {
await render(hbs`{{form-navigation-buttons renderPrevButton=false}}`);
assert.ok(findAll('button.prev').length === 0, 'prev button is not rendered');
assert.ok(findAll('button.next').length === 1, 'next button is rendered');
});
});

View file

@ -1,75 +1,78 @@
import EmberObject from '@ember/object';
import { moduleForComponent, test } from 'ember-qunit';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import moment from 'moment';
moduleForComponent('poll-evaluation-chart', 'Integration | Component | poll evaluation chart', {
integration: true,
beforeEach() {
moment.locale('en');
}
});
module('Integration | Component | poll evaluation chart', function(hooks) {
setupRenderingTest(hooks);
test('it renders', function(assert) {
this.set('options', [
EmberObject.create({
formatted: 'Thursday, January 1, 2015',
title: moment('2015-01-01'),
hasTime: false
}),
EmberObject.create({
formatted: 'Monday, February 2, 2015',
title: moment('2015-02-02'),
hasTime: false
}),
EmberObject.create({
formatted: 'Tuesday, March 3, 2015 1:00 AM',
title: moment('2015-03-03T01:00'),
hasTime: true
}),
EmberObject.create({
formatted: 'Tuesday, March 3, 2015 11:00 AM',
title: moment('2015-03-03T11:00'),
hasTime: true
})
]);
this.set('answerType', 'YesNoMaybe');
this.set('users', [
EmberObject.create({
id: 1,
selections: [
EmberObject.create({
type: 'yes'
}),
EmberObject.create({
type: 'yes'
}),
EmberObject.create({
type: 'maybe'
}),
EmberObject.create({
type: 'no'
})
]
}),
EmberObject.create({
id: 2,
selections: [
EmberObject.create({
type: 'yes'
}),
EmberObject.create({
type: 'maybe'
}),
EmberObject.create({
type: 'no'
}),
EmberObject.create({
type: 'no'
})
]
})
]);
this.render(hbs`{{poll-evaluation-chart options=options answerType=answerType users=users}}`);
assert.ok(this.$('canvas'), 'it renders a canvas element');
hooks.beforeEach(function() {
moment.locale('en');
});
test('it renders', async function(assert) {
this.set('options', [
EmberObject.create({
formatted: 'Thursday, January 1, 2015',
title: moment('2015-01-01'),
hasTime: false
}),
EmberObject.create({
formatted: 'Monday, February 2, 2015',
title: moment('2015-02-02'),
hasTime: false
}),
EmberObject.create({
formatted: 'Tuesday, March 3, 2015 1:00 AM',
title: moment('2015-03-03T01:00'),
hasTime: true
}),
EmberObject.create({
formatted: 'Tuesday, March 3, 2015 11:00 AM',
title: moment('2015-03-03T11:00'),
hasTime: true
})
]);
this.set('answerType', 'YesNoMaybe');
this.set('users', [
EmberObject.create({
id: 1,
selections: [
EmberObject.create({
type: 'yes'
}),
EmberObject.create({
type: 'yes'
}),
EmberObject.create({
type: 'maybe'
}),
EmberObject.create({
type: 'no'
})
]
}),
EmberObject.create({
id: 2,
selections: [
EmberObject.create({
type: 'yes'
}),
EmberObject.create({
type: 'maybe'
}),
EmberObject.create({
type: 'no'
}),
EmberObject.create({
type: 'no'
})
]
})
]);
await render(hbs`{{poll-evaluation-chart options=options answerType=answerType users=users}}`);
assert.ok(this.$('canvas'), 'it renders a canvas element');
});
});

View file

@ -3,31 +3,32 @@ import { module, test } from 'qunit';
import { startMirage } from 'croodle/initializers/ember-cli-mirage';
import sjcl from 'sjcl';
module('Integration | Mirage api mocking', {
beforeEach() {
module('Integration | Mirage api mocking', function(hooks) {
hooks.beforeEach(function() {
this.server = startMirage();
},
afterEach() {
});
hooks.afterEach(function() {
this.server.shutdown();
}
});
test('poll factory | encrypts properties', function(assert) {
let encryptionKey = 'abc';
let poll = this.server.create('poll', {
description: 'bar',
encryptionKey,
title: 'foo'
});
assert.equal(JSON.parse(sjcl.decrypt(encryptionKey, get(poll, 'title'))), 'foo');
assert.equal(JSON.parse(sjcl.decrypt(encryptionKey, get(poll, 'description'))), 'bar');
});
test('user factory | encrypts properties', function(assert) {
let encryptionKey = 'abc';
let user = this.server.create('user', {
encryptionKey,
name: 'foo'
test('poll factory | encrypts properties', function(assert) {
let encryptionKey = 'abc';
let poll = this.server.create('poll', {
description: 'bar',
encryptionKey,
title: 'foo'
});
assert.equal(JSON.parse(sjcl.decrypt(encryptionKey, get(poll, 'title'))), 'foo');
assert.equal(JSON.parse(sjcl.decrypt(encryptionKey, get(poll, 'description'))), 'bar');
});
test('user factory | encrypts properties', function(assert) {
let encryptionKey = 'abc';
let user = this.server.create('user', {
encryptionKey,
name: 'foo'
});
assert.equal(JSON.parse(sjcl.decrypt(encryptionKey, get(user, 'name'))), 'foo');
});
assert.equal(JSON.parse(sjcl.decrypt(encryptionKey, get(user, 'name'))), 'foo');
});

View file

@ -1,76 +1,77 @@
import { getOwner } from '@ember/application';
import { moduleFor, test } from 'ember-qunit';
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import config from 'croodle/config/environment';
import LocaleHelper from 'ember-i18n/utils/locale';
import localesMeta from 'croodle/locales/meta';
moduleFor('service:i18n', 'Integration | translations', {
integration: true
});
module('Integration | translations', function(hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('configuration is correct', function(assert) {
const i18n = this.subject();
const locales = i18n.get('locales');
const { defaultLocale } = config.i18n;
// Replace this with your real tests.
test('configuration is correct', function(assert) {
const i18n = this.owner.lookup('service:i18n');
const locales = i18n.get('locales');
const { defaultLocale } = config.i18n;
assert.ok(defaultLocale, 'default locale is set');
assert.ok(locales, 'there are locales');
assert.ok(locales.indexOf(defaultLocale) !== -1, 'default locale is part of locales');
});
test('all locales have same amount of translation strings as default locale', function(assert) {
const i18n = this.subject();
const locales = i18n.get('locales');
const { defaultLocale } = config.i18n;
const { translations: defaultTranslations } = new LocaleHelper(defaultLocale, getOwner(i18n));
assert.expect((locales.length - 1) * 2);
locales.map((locale) => {
if (locale === defaultLocale) {
return;
}
const { translations } = new LocaleHelper(locale, getOwner(i18n));
assert.ok(translations, `could retrive locale ${locale}`);
assert.equal(
Object.keys(translations).length,
Object.keys(defaultTranslations).length,
`correct amount of translations for locale ${locale}`
);
assert.ok(defaultLocale, 'default locale is set');
assert.ok(locales, 'there are locales');
assert.ok(locales.indexOf(defaultLocale) !== -1, 'default locale is part of locales');
});
});
test('all locales have same translation strings as default locale', function(assert) {
const i18n = this.subject();
const locales = i18n.get('locales');
const { defaultLocale } = config.i18n;
const { translations: defaultTranslations } = new LocaleHelper(defaultLocale, getOwner(i18n));
test('all locales have same amount of translation strings as default locale', function(assert) {
const i18n = this.owner.lookup('service:i18n');
const locales = i18n.get('locales');
const { defaultLocale } = config.i18n;
const { translations: defaultTranslations } = new LocaleHelper(defaultLocale, this.owner);
assert.expect(
// count of non default locales * translation strings of default locale
(locales.length - 1) * Object.keys(defaultTranslations).length
);
assert.expect((locales.length - 1) * 2);
Object.keys(defaultTranslations).map((translationString) => {
locales.map((locale) => {
if (locale === defaultLocale) {
return;
}
i18n.set('locale', locale);
assert.ok(
i18n.exists(translationString),
`translation for ${translationString} exists in locale ${locale}`
const { translations } = new LocaleHelper(locale, getOwner(i18n));
assert.ok(translations, `could retrive locale ${locale}`);
assert.equal(
Object.keys(translations).length,
Object.keys(defaultTranslations).length,
`correct amount of translations for locale ${locale}`
);
});
});
});
test('all locales have an entry in locales/meta', function(assert) {
const i18n = this.subject();
assert.deepEqual(
i18n.get('locales'),
Object.keys(localesMeta)
);
test('all locales have same translation strings as default locale', function(assert) {
const i18n = this.owner.lookup('service:i18n');
const locales = i18n.get('locales');
const { defaultLocale } = config.i18n;
const { translations: defaultTranslations } = new LocaleHelper(defaultLocale, this.owner);
assert.expect(
// count of non default locales * translation strings of default locale
(locales.length - 1) * Object.keys(defaultTranslations).length
);
Object.keys(defaultTranslations).map((translationString) => {
locales.map((locale) => {
if (locale === defaultLocale) {
return;
}
i18n.set('locale', locale);
assert.ok(
i18n.exists(translationString),
`translation for ${translationString} exists in locale ${locale}`
);
});
});
});
test('all locales have an entry in locales/meta', function(assert) {
const i18n = this.owner.lookup('service:i18n');
assert.deepEqual(
i18n.get('locales'),
Object.keys(localesMeta)
);
});
});

View file

@ -21,7 +21,7 @@ const setBootstrapDatepicker = function(selector, options = {}) {
return {
isDescriptor: true,
value(dates) {
const el = findElementWithAssert(this, selector, options);
const el = findElementWithAssert(this, selector, options).parent();
if (isPresent(dates)) {
const normalizedDates = dates.map((date) => {
if (typeof date.toDate === 'function') {
@ -41,7 +41,7 @@ const setBootstrapDatepicker = function(selector, options = {}) {
};
export default PageObject.create(assign({}, defaultsForCreate, {
dateOptions: setBootstrapDatepicker('.days .ember-view:has(.datepicker:first-child)'),
dateOptions: setBootstrapDatepicker('.days .datepicker'),
dateHasError: isVisible('.days.has-error'),
dateError: text('.days .help-block'),
textOptions: collection({

View file

@ -4,6 +4,7 @@ import {
isVisible,
text
} from 'ember-cli-page-object';
import { currentURL } from '@ember/test-helpers';
const urlMatches = function(regExp) {
return function() {

View file

@ -1,208 +1,209 @@
import { isArray } from '@ember/array';
import EmberObject from '@ember/object';
import { run } from '@ember/runloop';
import { moduleForComponent, test } from 'ember-qunit';
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import moment from 'moment';
moduleForComponent('create-options-dates', 'Unit | Component | create options dates', {
needs: ['config:environment', 'model:option', 'service:i18n'],
unit: true,
beforeEach() {
this.inject.service('store');
}
});
module('Unit | Component | create options dates', function(hooks) {
setupTest(hooks);
test('options get mapped to dates as optionsBootstrapDatepicker (used by ember-cli-bootstrap-datepicker)', function(assert) {
let controller = this.subject();
controller.set('options', [
EmberObject.create({ title: '1945-05-09' }),
EmberObject.create({ title: '1987-05-01' }),
EmberObject.create({ title: 'non valid date string' })
]);
assert.ok(
isArray(
controller.get('optionsBootstrapDatepicker')
),
"it's an array"
);
assert.equal(
controller.get('optionsBootstrapDatepicker.length'),
2,
'array length is correct'
);
assert.ok(
controller.get('optionsBootstrapDatepicker').every((el) => {
return moment.isDate(el);
}),
'array elements are date objects'
);
assert.equal(
controller.get('optionsBootstrapDatepicker.firstObject').toISOString(),
moment('1945-05-09').toISOString(),
'date is correct'
);
});
test('options having times get mapped to dates as optionsBootstrapDatepicker (used by ember-cli-bootstrap-datepicker)', function(assert) {
let controller = this.subject();
controller.set('options', [
EmberObject.create({ title: '2014-01-01T12:00:00.00Z' }),
EmberObject.create({ title: '2015-02-02T15:00:00.00Z' }),
EmberObject.create({ title: '2015-02-02T15:00:00.00Z' }),
EmberObject.create({ title: '2016-03-03' })
]);
assert.ok(
isArray(
controller.get('optionsBootstrapDatepicker')
),
"it's an array"
);
assert.equal(
controller.get('optionsBootstrapDatepicker.length'),
3,
'array length is correct'
);
assert.ok(
controller.get('optionsBootstrapDatepicker').every((el) => {
return moment.isDate(el);
}),
'array elements are date objects'
);
assert.deepEqual(
controller.get('optionsBootstrapDatepicker').map((option) => {
return option.toISOString();
}),
[
moment('2014-01-01').toISOString(),
moment('2015-02-02').toISOString(),
moment('2016-03-03').toISOString()
],
'date is correct'
);
});
test('options get set correctly by optionsBootstrapDatepicker (used by ember-cli-bootstrap-datepicker)', function(assert) {
let controller = this.subject();
run(() => {
controller.set('options', []);
// dates must be in wrong order to test sorting
controller.set('optionsBootstrapDatepicker', [
moment('1918-11-09').toDate(),
moment('1917-10-25').toDate()
]);
hooks.beforeEach(function() {
this.store = this.owner.lookup('service:store');
});
assert.ok(
isArray(
controller.get('options')
),
'options is still an array'
);
assert.equal(
controller.get('options.length'),
2,
'array has correct length'
);
assert.ok(
controller.get('options').every((option) => {
return typeof option.get('title') === 'string';
}),
'option.title is a string'
);
assert.ok(
controller.get('options').every((option) => {
return moment(option.get('title'), 'YYYY-MM-DD', true).isValid();
}),
'option.title is an ISO-8601 date string without time'
);
assert.ok(
controller.get('options').findBy('title', '1918-11-09'),
'date is correct'
);
assert.equal(
controller.get('options.firstObject.title'),
'1917-10-25',
'dates are in correct order'
);
});
test('existing times are preserved if new days get selected', function(assert) {
let component;
run(() => {
component = this.subject({
options: [
this.store.createFragment('option', {
title: moment('2015-01-01T11:11').toISOString()
}),
this.store.createFragment('option', {
title: moment('2015-01-01T22:22').toISOString()
}),
this.store.createFragment('option', {
title: moment('2015-06-06T08:08').toISOString()
}),
this.store.createFragment('option', {
title: '2016-01-01'
})
]
test('options get mapped to dates as optionsBootstrapDatepicker (used by ember-cli-bootstrap-datepicker)', function(assert) {
let controller = this.owner.factoryFor('component:create-options-dates').create();
controller.set('options', [
EmberObject.create({ title: '1945-05-09' }),
EmberObject.create({ title: '1987-05-01' }),
EmberObject.create({ title: 'non valid date string' })
]);
assert.ok(
isArray(
controller.get('optionsBootstrapDatepicker')
),
"it's an array"
);
assert.equal(
controller.get('optionsBootstrapDatepicker.length'),
2,
'array length is correct'
);
assert.ok(
controller.get('optionsBootstrapDatepicker').every((el) => {
return moment.isDate(el);
}),
'array elements are date objects'
);
assert.equal(
controller.get('optionsBootstrapDatepicker.firstObject').toISOString(),
moment('1945-05-09').toISOString(),
'date is correct'
);
});
test('options having times get mapped to dates as optionsBootstrapDatepicker (used by ember-cli-bootstrap-datepicker)', function(assert) {
let controller = this.owner.factoryFor('component:create-options-dates').create();
controller.set('options', [
EmberObject.create({ title: '2014-01-01T12:00:00.00Z' }),
EmberObject.create({ title: '2015-02-02T15:00:00.00Z' }),
EmberObject.create({ title: '2015-02-02T15:00:00.00Z' }),
EmberObject.create({ title: '2016-03-03' })
]);
assert.ok(
isArray(
controller.get('optionsBootstrapDatepicker')
),
"it's an array"
);
assert.equal(
controller.get('optionsBootstrapDatepicker.length'),
3,
'array length is correct'
);
assert.ok(
controller.get('optionsBootstrapDatepicker').every((el) => {
return moment.isDate(el);
}),
'array elements are date objects'
);
assert.deepEqual(
controller.get('optionsBootstrapDatepicker').map((option) => {
return option.toISOString();
}),
[
moment('2014-01-01').toISOString(),
moment('2015-02-02').toISOString(),
moment('2016-03-03').toISOString()
],
'date is correct'
);
});
test('options get set correctly by optionsBootstrapDatepicker (used by ember-cli-bootstrap-datepicker)', function(assert) {
let controller = this.owner.factoryFor('component:create-options-dates').create();
run(() => {
controller.set('options', []);
// dates must be in wrong order to test sorting
controller.set('optionsBootstrapDatepicker', [
moment('1918-11-09').toDate(),
moment('1917-10-25').toDate()
]);
});
assert.ok(
isArray(
controller.get('options')
),
'options is still an array'
);
assert.equal(
controller.get('options.length'),
2,
'array has correct length'
);
assert.ok(
controller.get('options').every((option) => {
return typeof option.get('title') === 'string';
}),
'option.title is a string'
);
assert.ok(
controller.get('options').every((option) => {
return moment(option.get('title'), 'YYYY-MM-DD', true).isValid();
}),
'option.title is an ISO-8601 date string without time'
);
assert.ok(
controller.get('options').findBy('title', '1918-11-09'),
'date is correct'
);
assert.equal(
controller.get('options.firstObject.title'),
'1917-10-25',
'dates are in correct order'
);
});
// add another day
run(() => {
component.set('optionsBootstrapDatepicker', [
moment('2015-01-01').toDate(),
moment('2015-06-06').toDate(),
moment('2016-01-01').toDate(),
moment('2016-06-06').toDate() // new day
]);
test('existing times are preserved if new days get selected', function(assert) {
let component;
run(() => {
component = this.owner.factoryFor('component:create-options-dates').create({
options: [
this.store.createFragment('option', {
title: moment('2015-01-01T11:11').toISOString()
}),
this.store.createFragment('option', {
title: moment('2015-01-01T22:22').toISOString()
}),
this.store.createFragment('option', {
title: moment('2015-06-06T08:08').toISOString()
}),
this.store.createFragment('option', {
title: '2016-01-01'
})
]
});
});
// add another day
run(() => {
component.set('optionsBootstrapDatepicker', [
moment('2015-01-01').toDate(),
moment('2015-06-06').toDate(),
moment('2016-01-01').toDate(),
moment('2016-06-06').toDate() // new day
]);
});
assert.deepEqual(
component.get('options').map((option) => option.get('title')),
[
moment('2015-01-01T11:11').toISOString(),
moment('2015-01-01T22:22').toISOString(),
moment('2015-06-06T08:08').toISOString(),
'2016-01-01',
'2016-06-06'
],
'preseve existing times if another day is added'
);
// delete a day
run(() => {
component.set('optionsBootstrapDatepicker', [
moment('2015-06-06').toDate(),
moment('2016-01-01').toDate(),
moment('2016-06-06').toDate()
]);
});
assert.deepEqual(
component.get('options').map((option) => option.get('title')),
[
moment('2015-06-06T08:08').toISOString(),
'2016-01-01',
'2016-06-06'
],
'preseve existing times if a day is deleted'
);
// order if multiple days are added
run(() => {
component.set('optionsBootstrapDatepicker', [
moment('2015-06-06').toDate(),
moment('2016-01-01').toDate(),
moment('2016-06-06').toDate(),
moment('2016-12-12').toDate(),
moment('2015-01-01').toDate(),
moment('2016-03-03').toDate()
]);
});
assert.deepEqual(
component.get('options').map((option) => option.get('title')),
[
'2015-01-01',
moment('2015-06-06T08:08').toISOString(),
'2016-01-01',
'2016-03-03',
'2016-06-06',
'2016-12-12'
],
'options are in correct order after multiple days are added'
);
});
assert.deepEqual(
component.get('options').map((option) => option.get('title')),
[
moment('2015-01-01T11:11').toISOString(),
moment('2015-01-01T22:22').toISOString(),
moment('2015-06-06T08:08').toISOString(),
'2016-01-01',
'2016-06-06'
],
'preseve existing times if another day is added'
);
// delete a day
run(() => {
component.set('optionsBootstrapDatepicker', [
moment('2015-06-06').toDate(),
moment('2016-01-01').toDate(),
moment('2016-06-06').toDate()
]);
});
assert.deepEqual(
component.get('options').map((option) => option.get('title')),
[
moment('2015-06-06T08:08').toISOString(),
'2016-01-01',
'2016-06-06'
],
'preseve existing times if a day is deleted'
);
// order if multiple days are added
run(() => {
component.set('optionsBootstrapDatepicker', [
moment('2015-06-06').toDate(),
moment('2016-01-01').toDate(),
moment('2016-06-06').toDate(),
moment('2016-12-12').toDate(),
moment('2015-01-01').toDate(),
moment('2016-03-03').toDate()
]);
});
assert.deepEqual(
component.get('options').map((option) => option.get('title')),
[
'2015-01-01',
moment('2015-06-06T08:08').toISOString(),
'2016-01-01',
'2016-03-03',
'2016-06-06',
'2016-12-12'
],
'options are in correct order after multiple days are added'
);
});

View file

@ -1,255 +1,251 @@
import { run } from '@ember/runloop';
import { moduleForComponent, test } from 'ember-qunit';
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import moment from 'moment';
moduleForComponent('create-options-datetime', 'Unit | Component | create options datetime', {
unit: true,
needs: [
'config:environment',
'model:option', 'model:poll', 'model:user',
'service:i18n',
'validator:alias', 'validator:collection', 'validator:iso8601', 'validator:length', 'validator:presence', 'validator:time', 'validator:unique', 'validator:valid-collection'
],
beforeEach() {
this.inject.service('store');
}
});
module('Unit | Component | create options datetime', function(hooks) {
setupTest(hooks);
test('delete a date', function(assert) {
let component = this.subject();
let a, b, c, d, e;
run(() => {
a = this.store.createFragment('option', { title: moment('2015-01-01T01:01:00.000').toISOString() });
b = this.store.createFragment('option', { title: moment('2015-01-01T11:11:00.000').toISOString() });
c = this.store.createFragment('option', { title: moment('2015-02-02T11:11:00.000').toISOString() });
d = this.store.createFragment('option', { title: '2015-02-02' });
e = this.store.createFragment('option', { title: '2015-02-03' });
component.set('dates', [a, b, c, d, e]);
hooks.beforeEach(function() {
this.store = this.owner.lookup('service:store');
});
component.send('deleteOption', b);
assert.deepEqual(
component.get('dates').map((date) => date.get('title')),
[
moment('2015-01-01T01:01:00.000').toISOString(),
moment('2015-02-02T11:11:00.000').toISOString(),
'2015-02-02',
'2015-02-03'
],
'date get deleted if there is another date with same day (both having a time)'
);
component.send('deleteOption', d);
assert.deepEqual(
component.get('dates').map((date) => date.get('title')),
[
moment('2015-01-01T01:01:00.000').toISOString(),
moment('2015-02-02T11:11:00.000').toISOString(),
'2015-02-03'
],
'date get deleted if there is another date with same day (date does not have a time)'
);
run(() => {
component.send('deleteOption', c);
});
assert.deepEqual(
component.get('dates').map((date) => date.get('title')),
[
moment('2015-01-01T01:01:00.000').toISOString(),
'2015-02-02',
'2015-02-03'
],
'time is removed from date if there isn\' t any other date with same day'
);
component.send('deleteOption', d);
assert.deepEqual(
component.get('dates').map((date) => date.get('title')),
[
moment('2015-01-01T01:01:00.000').toISOString(),
'2015-02-02',
'2015-02-03'
],
'nothing changes if it\'s the only date for this day it it doesn\'t have a time'
);
});
test('datetimes are grouped by date', function(assert) {
let component = this.subject();
let a, b, c;
// have to set dates in local time and than convert to ISO 8601 strings
// because otherwise test could fail caused by timezone
run(() => {
a = this.store.createFragment('option', { title: moment('2015-01-01T01:01:00').toISOString() });
b = this.store.createFragment('option', { title: moment('2015-01-01T11:11:00').toISOString() });
c = this.store.createFragment('option', { title: moment('2015-02-02T01:01:00').toISOString() });
component.set('dates', [a, b, c]);
});
assert.equal(
component.get('groupedDates.length'),
2,
'length is correct'
);
assert.deepEqual(
component.get('groupedDates.firstObject.items').map((item) => {
return item.get('date').toISOString();
}),
[a.get('title'), b.get('title')],
'first dates having same day are grouped together'
);
assert.equal(
component.get('groupedDates.lastObject.items.firstObject.date').toISOString(),
[c.get('title')],
'last date having another day is in a separate group'
);
});
test('bindings are working on grouped datetimes', function(assert) {
let component = this.subject();
run(() => {
component.set('dates', [
this.store.createFragment('option', {
title: moment('2015-01-01T11:11:00.000Z').toISOString()
})
]);
});
assert.equal(
component.get('groupedDates.firstObject.items.firstObject.time'),
moment('2015-01-01T11:11:00.000Z').format('HH:mm'),
'time is correct before'
);
run(() => {
component.set(
'groupedDates.firstObject.items.firstObject.time',
'00:00'
test('delete a date', function(assert) {
let component = this.owner.factoryFor('component:create-options-datetime').create();
let a, b, c, d, e;
run(() => {
a = this.store.createFragment('option', { title: moment('2015-01-01T01:01:00.000').toISOString() });
b = this.store.createFragment('option', { title: moment('2015-01-01T11:11:00.000').toISOString() });
c = this.store.createFragment('option', { title: moment('2015-02-02T11:11:00.000').toISOString() });
d = this.store.createFragment('option', { title: '2015-02-02' });
e = this.store.createFragment('option', { title: '2015-02-03' });
component.set('dates', [a, b, c, d, e]);
});
component.send('deleteOption', b);
assert.deepEqual(
component.get('dates').map((date) => date.get('title')),
[
moment('2015-01-01T01:01:00.000').toISOString(),
moment('2015-02-02T11:11:00.000').toISOString(),
'2015-02-02',
'2015-02-03'
],
'date get deleted if there is another date with same day (both having a time)'
);
component.send('deleteOption', d);
assert.deepEqual(
component.get('dates').map((date) => date.get('title')),
[
moment('2015-01-01T01:01:00.000').toISOString(),
moment('2015-02-02T11:11:00.000').toISOString(),
'2015-02-03'
],
'date get deleted if there is another date with same day (date does not have a time)'
);
run(() => {
component.send('deleteOption', c);
});
assert.deepEqual(
component.get('dates').map((date) => date.get('title')),
[
moment('2015-01-01T01:01:00.000').toISOString(),
'2015-02-02',
'2015-02-03'
],
'time is removed from date if there isn\' t any other date with same day'
);
component.send('deleteOption', d);
assert.deepEqual(
component.get('dates').map((date) => date.get('title')),
[
moment('2015-01-01T01:01:00.000').toISOString(),
'2015-02-02',
'2015-02-03'
],
'nothing changes if it\'s the only date for this day it it doesn\'t have a time'
);
});
assert.equal(
component.get('dates.firstObject.title'),
moment('2015-01-01T00:00').toISOString(),
'option is updated after time changed on grouped datetimes'
);
run(() => {
component.get('dates').pushObject(
this.store.createFragment('option', { title: moment('2015-01-01T12:12').toISOString() })
test('datetimes are grouped by date', function(assert) {
let component = this.owner.factoryFor('component:create-options-datetime').create();
let a, b, c;
// have to set dates in local time and than convert to ISO 8601 strings
// because otherwise test could fail caused by timezone
run(() => {
a = this.store.createFragment('option', { title: moment('2015-01-01T01:01:00').toISOString() });
b = this.store.createFragment('option', { title: moment('2015-01-01T11:11:00').toISOString() });
c = this.store.createFragment('option', { title: moment('2015-02-02T01:01:00').toISOString() });
component.set('dates', [a, b, c]);
});
assert.equal(
component.get('groupedDates.length'),
2,
'length is correct'
);
assert.deepEqual(
component.get('groupedDates.firstObject.items').map((item) => {
return item.get('date').toISOString();
}),
[a.get('title'), b.get('title')],
'first dates having same day are grouped together'
);
assert.equal(
component.get('groupedDates.lastObject.items.firstObject.date').toISOString(),
[c.get('title')],
'last date having another day is in a separate group'
);
});
assert.equal(
component.get('groupedDates.firstObject.items.length'),
2,
'grouped datetimes got updated after option was added (same day)'
);
assert.equal(
component.get('groupedDates.firstObject.items.lastObject.time'),
'12:12',
'grouped datetimes got updated correctly after option was added (same day)'
);
run(() => {
component.get('dates').pushObject(
this.store.createFragment('option', { title: moment('2015-02-02T01:01').toISOString() })
test('bindings are working on grouped datetimes', function(assert) {
let component = this.owner.factoryFor('component:create-options-datetime').create();
run(() => {
component.set('dates', [
this.store.createFragment('option', {
title: moment('2015-01-01T11:11:00.000Z').toISOString()
})
]);
});
assert.equal(
component.get('groupedDates.firstObject.items.firstObject.time'),
moment('2015-01-01T11:11:00.000Z').format('HH:mm'),
'time is correct before'
);
run(() => {
component.set(
'groupedDates.firstObject.items.firstObject.time',
'00:00'
);
});
assert.equal(
component.get('dates.firstObject.title'),
moment('2015-01-01T00:00').toISOString(),
'option is updated after time changed on grouped datetimes'
);
run(() => {
component.get('dates').pushObject(
this.store.createFragment('option', { title: moment('2015-01-01T12:12').toISOString() })
);
});
assert.equal(
component.get('groupedDates.firstObject.items.length'),
2,
'grouped datetimes got updated after option was added (same day)'
);
assert.equal(
component.get('groupedDates.firstObject.items.lastObject.time'),
'12:12',
'grouped datetimes got updated correctly after option was added (same day)'
);
run(() => {
component.get('dates').pushObject(
this.store.createFragment('option', { title: moment('2015-02-02T01:01').toISOString() })
);
});
assert.equal(
component.get('groupedDates.length'),
2,
'grouped datetimes got updated after option was added (other day)'
);
assert.equal(
component.get('groupedDates.lastObject.items.firstObject.time'),
'01:01',
'grouped datetimes got updated correctly after option was added (same day)'
);
});
assert.equal(
component.get('groupedDates.length'),
2,
'grouped datetimes got updated after option was added (other day)'
);
assert.equal(
component.get('groupedDates.lastObject.items.firstObject.time'),
'01:01',
'grouped datetimes got updated correctly after option was added (same day)'
);
});
test('adopt times of first day - simple', function(assert) {
let component;
let poll;
run(() => {
poll = this.store.createRecord('poll', {
options: [
{ title: moment('2015-01-01T11:11:00.000').toISOString() },
{ title: moment('2015-01-01T22:22:00.000').toISOString() },
{ title: moment('2015-01-02').toISOString() },
{ title: moment('2015-01-03').toISOString() }
]
test('adopt times of first day - simple', function(assert) {
let component;
let poll;
run(() => {
poll = this.store.createRecord('poll', {
options: [
{ title: moment('2015-01-01T11:11:00.000').toISOString() },
{ title: moment('2015-01-01T22:22:00.000').toISOString() },
{ title: moment('2015-01-02').toISOString() },
{ title: moment('2015-01-03').toISOString() }
]
});
component = this.owner.factoryFor('component:create-options-datetime').create({
dates: poll.get('options')
});
component.send('adoptTimesOfFirstDay');
});
component = this.subject({
dates: poll.get('options')
});
component.send('adoptTimesOfFirstDay');
assert.deepEqual(
component.get('dates').map((option) => option.get('title')),
[
moment('2015-01-01T11:11:00.000').toISOString(),
moment('2015-01-01T22:22:00.000').toISOString(),
moment('2015-01-02T11:11:00.000').toISOString(),
moment('2015-01-02T22:22:00.000').toISOString(),
moment('2015-01-03T11:11:00.000').toISOString(),
moment('2015-01-03T22:22:00.000').toISOString()
],
'times adopted correctly'
);
});
assert.deepEqual(
component.get('dates').map((option) => option.get('title')),
[
moment('2015-01-01T11:11:00.000').toISOString(),
moment('2015-01-01T22:22:00.000').toISOString(),
moment('2015-01-02T11:11:00.000').toISOString(),
moment('2015-01-02T22:22:00.000').toISOString(),
moment('2015-01-03T11:11:00.000').toISOString(),
moment('2015-01-03T22:22:00.000').toISOString()
],
'times adopted correctly'
);
});
test('adopt times of first day - having times on the other days', function(assert) {
let component;
let poll;
run(() => {
poll = this.store.createRecord('poll', {
options: [
{ title: moment('2015-01-01T11:11:00.000').toISOString() },
{ title: moment('2015-01-01T22:22:00.000').toISOString() },
{ title: moment('2015-01-02T09:11:00.000').toISOString() },
{ title: moment('2015-01-03T01:11:00.000').toISOString() },
{ title: moment('2015-01-03T11:11:00.000').toISOString() },
{ title: moment('2015-01-04T02:11:00.000').toISOString() },
{ title: moment('2015-01-04T05:11:00.000').toISOString() },
{ title: moment('2015-01-04T12:11:00.000').toISOString() }
]
test('adopt times of first day - having times on the other days', function(assert) {
let component;
let poll;
run(() => {
poll = this.store.createRecord('poll', {
options: [
{ title: moment('2015-01-01T11:11:00.000').toISOString() },
{ title: moment('2015-01-01T22:22:00.000').toISOString() },
{ title: moment('2015-01-02T09:11:00.000').toISOString() },
{ title: moment('2015-01-03T01:11:00.000').toISOString() },
{ title: moment('2015-01-03T11:11:00.000').toISOString() },
{ title: moment('2015-01-04T02:11:00.000').toISOString() },
{ title: moment('2015-01-04T05:11:00.000').toISOString() },
{ title: moment('2015-01-04T12:11:00.000').toISOString() }
]
});
component = this.owner.factoryFor('component:create-options-datetime').create({
dates: poll.get('options')
});
component.send('adoptTimesOfFirstDay');
});
component = this.subject({
dates: poll.get('options')
});
component.send('adoptTimesOfFirstDay');
assert.deepEqual(
component.get('dates').map((option) => option.get('title')),
[
moment('2015-01-01T11:11:00.000').toISOString(),
moment('2015-01-01T22:22:00.000').toISOString(),
moment('2015-01-02T11:11:00.000').toISOString(),
moment('2015-01-02T22:22:00.000').toISOString(),
moment('2015-01-03T11:11:00.000').toISOString(),
moment('2015-01-03T22:22:00.000').toISOString(),
moment('2015-01-04T11:11:00.000').toISOString(),
moment('2015-01-04T22:22:00.000').toISOString()
],
'times adopted correctly'
);
});
assert.deepEqual(
component.get('dates').map((option) => option.get('title')),
[
moment('2015-01-01T11:11:00.000').toISOString(),
moment('2015-01-01T22:22:00.000').toISOString(),
moment('2015-01-02T11:11:00.000').toISOString(),
moment('2015-01-02T22:22:00.000').toISOString(),
moment('2015-01-03T11:11:00.000').toISOString(),
moment('2015-01-03T22:22:00.000').toISOString(),
moment('2015-01-04T11:11:00.000').toISOString(),
moment('2015-01-04T22:22:00.000').toISOString()
],
'times adopted correctly'
);
});
test('adopt times of first day - no times on first day', function(assert) {
let component;
let poll;
run(() => {
poll = this.store.createRecord('poll', {
options: [
{ title: '2015-01-01' },
{ title: '2015-01-02' },
{ title: moment('2015-01-03T11:00:00.000Z').toISOString() },
{ title: moment('2015-01-03T15:00:00.000Z').toISOString() }
]
test('adopt times of first day - no times on first day', function(assert) {
let component;
let poll;
run(() => {
poll = this.store.createRecord('poll', {
options: [
{ title: '2015-01-01' },
{ title: '2015-01-02' },
{ title: moment('2015-01-03T11:00:00.000Z').toISOString() },
{ title: moment('2015-01-03T15:00:00.000Z').toISOString() }
]
});
component = this.owner.factoryFor('component:create-options-datetime').create({
dates: poll.get('options')
});
component.send('adoptTimesOfFirstDay');
});
component = this.subject({
dates: poll.get('options')
});
component.send('adoptTimesOfFirstDay');
assert.deepEqual(
component.get('dates').map((option) => option.get('title')),
[
'2015-01-01',
'2015-01-02',
'2015-01-03'
],
'times are removed from all days'
);
});
assert.deepEqual(
component.get('dates').map((option) => option.get('title')),
[
'2015-01-01',
'2015-01-02',
'2015-01-03'
],
'times are removed from all days'
);
});

View file

@ -1,5 +1,6 @@
import { run } from '@ember/runloop';
import { moduleForComponent, test } from 'ember-qunit';
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import moment from 'moment';
// validator consumes i18n service
// have to register it therefore
@ -7,205 +8,185 @@ import moment from 'moment';
import tHelper from 'ember-i18n/helper';
import localeConfig from 'ember-i18n/config/en';
moduleForComponent('create-options', 'Unit | Component | create options', {
needs: [
'model:option',
'model:poll',
'validator:alias',
'model:user',
'validator:collection',
'validator:iso8601',
'validator:length',
'validator:presence',
'validator:time',
'validator:unique',
'validator:valid-collection',
'validator:messages',
module('Unit | Component | create options', function(hooks) {
setupTest(hooks);
hooks.beforeEach(function() {
this.store = this.owner.lookup('service:store');
// validator consumes i18n service
'service:i18n',
'locale:en/translations',
// 'locale:en/config', https://github.com/jamesarosen/ember-i18n/issues/368
'util:i18n/missing-message',
'util:i18n/compile-template',
'config:environment'
],
unit: true,
beforeEach() {
this.inject.service('store');
// validator consumes i18n service
this.container.lookup('service:i18n').set('locale', 'en');
this.registry.register('locale:en/config', localeConfig);
this.registry.register('helper:t', tHelper);
}
});
test('validation for make a poll', function(assert) {
let component = this.subject();
component.set('options', []);
component.set('isFindADate', false);
component.set('isMakeAPoll', true);
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
let poll;
run(() => {
poll = this.store.createRecord('poll', {
isFindADate: component.get('isFindADate'),
isMakeAPoll: component.get('isMakeAPoll')
});
});
assert.notOk(
component.get('validations.isValid'),
'invalid without any options'
);
run(() => {
let option = this.store.createFragment('option', {
title: 'first option'
});
poll.get('options').pushObject(option);
component.get('options').pushObject(option);
});
assert.ok(
component.get('validations.isValid'),
'valid if there is atleast one valid option'
);
run(() => {
let option = this.store.createFragment('option', {
title: 'second option'
});
poll.get('options').pushObject(option);
component.get('options').pushObject(option);
});
assert.ok(
component.get('validations.isValid'),
'valid for two options which are not empty strings'
);
run(() => {
component.set('options.firstObject.title', '');
});
assert.notOk(
component.get('validations.isValid'),
'invalid if atleast one string is empty'
);
});
test('validation for find a date without times', function(assert) {
let component = this.subject();
component.set('options', []);
component.set('isFindADate', true);
component.set('isMakeAPoll', false);
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
let poll;
run(() => {
poll = this.store.createRecord('poll', {
isFindADate: component.get('isFindADate'),
isMakeAPoll: component.get('isMakeAPoll')
});
});
assert.notOk(
component.get('validations.isValid'),
'invalid without any options'
);
run(() => {
let option = this.store.createFragment('option', {
title: '2015-01-01'
});
poll.get('options').pushObject(option);
component.get('options').pushObject(option);
});
assert.ok(
component.get('validations.isValid'),
'valid if there is atleast one valid date'
);
run(() => {
let option = this.store.createFragment('option', {
title: '2015-01-02'
});
poll.get('options').pushObject(option);
component.get('options').pushObject(option);
});
assert.ok(
component.get('validations.isValid'),
'valid for two valid dates'
);
run(() => {
let option = this.store.createFragment('option', {
title: 'foo'
});
poll.get('options').pushObject(option);
component.get('options').pushObject(option);
});
assert.notOk(
component.get('validations.isValid'),
'invalid if atleast one option is not a valid date'
);
run(() => {
component.set('options.lastObject.title', '2015-01-03');
});
assert.ok(
component.get('validations.isValid'),
'valid again after title is a valid date again'
);
run(() => {
component.set('options.firstObject.title', '2015-01-01');
component.set('options.lastObject.title', '2015-01-01');
});
assert.ok(
component.get('validations.isInvalid'),
'invalid if dates are not unique'
);
});
test('validation for find a date with times', function(assert) {
let component = this.subject();
component.set('options', []);
component.set('isMakeAPoll', false);
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
let poll;
run(() => {
poll = this.store.createRecord('poll', {
isFindADate: component.get('isFindADate'),
isMakeAPoll: component.get('isMakeAPoll')
});
});
assert.notOk(
component.get('validations.isValid'),
'invalid without any options'
);
run(() => {
let option = this.store.createFragment('option', {
title: moment().add('1', 'day').format('YYYY-MM-DD')
});
poll.get('options').pushObject(option);
component.get('options').pushObject(option);
});
assert.ok(
component.get('validations.isValid'),
'valid if there is atleast one valid date'
);
/*
Ember.run(() => {
let option = this.store.createFragment('option', {
title: moment().add('1', 'day').hour(22).minute(30).seconds(0).milliseconds(0).toISOString()
});
poll.get('options').pushObject(option);
component.get('options').pushObject(option);
});
assert.notOk(
component.get('validations.isValid'),
'invalid if there is a option without time for a day with has another option with time specified'
);
*/
this.owner.lookup('service:i18n').set('locale', 'en');
this.owner.register('locale:en/config', localeConfig);
this.owner.register('helper:t', tHelper);
});
test('validation for make a poll', function(assert) {
let component = this.owner.factoryFor('component:create-options').create();
component.set('options', []);
component.set('isFindADate', false);
component.set('isMakeAPoll', true);
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
let poll;
run(() => {
poll = this.store.createRecord('poll', {
isFindADate: component.get('isFindADate'),
isMakeAPoll: component.get('isMakeAPoll')
});
});
assert.notOk(
component.get('validations.isValid'),
'invalid without any options'
);
run(() => {
let option = this.store.createFragment('option', {
title: 'first option'
});
poll.get('options').pushObject(option);
component.get('options').pushObject(option);
});
assert.ok(
component.get('validations.isValid'),
'valid if there is atleast one valid option'
);
run(() => {
let option = this.store.createFragment('option', {
title: 'second option'
});
poll.get('options').pushObject(option);
component.get('options').pushObject(option);
});
assert.ok(
component.get('validations.isValid'),
'valid for two options which are not empty strings'
);
run(() => {
component.set('options.firstObject.title', '');
});
assert.notOk(
component.get('validations.isValid'),
'invalid if atleast one string is empty'
);
});
test('validation for find a date without times', function(assert) {
let component = this.owner.factoryFor('component:create-options').create();
component.set('options', []);
component.set('isFindADate', true);
component.set('isMakeAPoll', false);
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
let poll;
run(() => {
poll = this.store.createRecord('poll', {
isFindADate: component.get('isFindADate'),
isMakeAPoll: component.get('isMakeAPoll')
});
});
assert.notOk(
component.get('validations.isValid'),
'invalid without any options'
);
run(() => {
let option = this.store.createFragment('option', {
title: '2015-01-01'
});
poll.get('options').pushObject(option);
component.get('options').pushObject(option);
});
assert.ok(
component.get('validations.isValid'),
'valid if there is atleast one valid date'
);
run(() => {
let option = this.store.createFragment('option', {
title: '2015-01-02'
});
poll.get('options').pushObject(option);
component.get('options').pushObject(option);
});
assert.ok(
component.get('validations.isValid'),
'valid for two valid dates'
);
run(() => {
let option = this.store.createFragment('option', {
title: 'foo'
});
poll.get('options').pushObject(option);
component.get('options').pushObject(option);
});
assert.notOk(
component.get('validations.isValid'),
'invalid if atleast one option is not a valid date'
);
run(() => {
component.set('options.lastObject.title', '2015-01-03');
});
assert.ok(
component.get('validations.isValid'),
'valid again after title is a valid date again'
);
run(() => {
component.set('options.firstObject.title', '2015-01-01');
component.set('options.lastObject.title', '2015-01-01');
});
assert.ok(
component.get('validations.isInvalid'),
'invalid if dates are not unique'
);
});
test('validation for find a date with times', function(assert) {
let component = this.owner.factoryFor('component:create-options').create();
component.set('options', []);
component.set('isMakeAPoll', false);
// validation is based on validation of every option fragment
// which validates according to poll model it belongs to
// therefore each option needs to be pushed to poll model to have it as
// it's owner
let poll;
run(() => {
poll = this.store.createRecord('poll', {
isFindADate: component.get('isFindADate'),
isMakeAPoll: component.get('isMakeAPoll')
});
});
assert.notOk(
component.get('validations.isValid'),
'invalid without any options'
);
run(() => {
let option = this.store.createFragment('option', {
title: moment().add('1', 'day').format('YYYY-MM-DD')
});
poll.get('options').pushObject(option);
component.get('options').pushObject(option);
});
assert.ok(
component.get('validations.isValid'),
'valid if there is atleast one valid date'
);
/*
Ember.run(() => {
let option = this.store.createFragment('option', {
title: moment().add('1', 'day').hour(22).minute(30).seconds(0).milliseconds(0).toISOString()
});
poll.get('options').pushObject(option);
component.get('options').pushObject(option);
});
assert.notOk(
component.get('validations.isValid'),
'invalid if there is a option without time for a day with has another option with time specified'
);
*/
});
});

View file

@ -1,141 +1,37 @@
import EmberObject from '@ember/object';
import { moduleForComponent, test } from 'ember-qunit';
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import moment from 'moment';
import tHelper from 'ember-i18n/helper';
import localeConfig from 'ember-i18n/config/en';
moduleForComponent('poll-evaluation-chart', 'Unit | Component | poll evaluation chart', {
unit: true,
// https://github.com/jamesarosen/ember-i18n/wiki/Doc:-Testing#unit-tests
needs: [
'service:i18n',
'locale:en/translations',
'util:i18n/missing-message',
'util:i18n/compile-template',
'config:environment'
],
beforeEach() {
module('Unit | Component | poll evaluation chart', function(hooks) {
setupTest(hooks);
hooks.beforeEach(function() {
moment.locale('en');
this.container.lookup('service:i18n').set('locale', 'en');
this.registry.register('locale:en/config', localeConfig);
this.registry.register('helper:t', tHelper);
}
});
test('data is a valid ChartJS dataset for FindADate using poll timezone', function(assert) {
let options = [
EmberObject.create({
title: '2015-01-01'
}),
EmberObject.create({
title: '2015-02-02'
}),
EmberObject.create({
title: '2015-03-03T01:00:00.000Z'
}),
EmberObject.create({
title: '2015-03-03T11:00:00.000Z'
})
];
let users = [
EmberObject.create({
id: 1,
selections: [
EmberObject.create({
type: 'yes'
}),
EmberObject.create({
type: 'yes'
}),
EmberObject.create({
type: 'maybe'
}),
EmberObject.create({
type: 'no'
})
]
}),
EmberObject.create({
id: 2,
selections: [
EmberObject.create({
type: 'yes'
}),
EmberObject.create({
type: 'maybe'
}),
EmberObject.create({
type: 'no'
}),
EmberObject.create({
type: 'no'
})
]
})
];
let currentLocale = 'en';
let momentLongDayFormat = moment.localeData(currentLocale)
.longDateFormat('LLLL')
.replace(
moment.localeData(currentLocale).longDateFormat('LT'), '')
.trim();
let component = this.subject({
answerType: 'YesNoMaybe',
currentLocale,
isFindADate: true,
momentLongDayFormat,
options,
timezone: 'Asia/Hong_Kong',
users
this.owner.lookup('service:i18n').set('locale', 'en');
this.owner.register('locale:en/config', localeConfig);
this.owner.register('helper:t', tHelper);
});
const data = component.get('data');
assert.deepEqual(
data.labels,
['Thursday, January 1, 2015', 'Monday, February 2, 2015', 'Tuesday, March 3, 2015 9:00 AM', 'Tuesday, March 3, 2015 7:00 PM'],
'Labels are correct'
);
assert.equal(
data.datasets.length,
2,
'there are two datasets'
);
assert.deepEqual(
data.datasets.map((dataset) => dataset.label),
['Yes', 'Maybe'],
'datasets having answers as label and are in correct order'
);
assert.deepEqual(
data.datasets[0].data,
[100, 50, 0, 0],
'dataset for yes is correct'
);
assert.deepEqual(
data.datasets[1].data,
[0, 50, 50, 0],
'dataset for maybe is correct'
);
});
test('data is a valid ChartJS dataset for MakeAPoll', function(assert) {
const options = [
EmberObject.create({
title: 'first option'
}),
EmberObject.create({
title: 'second option'
}),
EmberObject.create({
title: 'third option'
}),
EmberObject.create({
title: 'fourth option'
})
];
let component = this.subject({
answerType: 'YesNoMaybe',
options,
users: [
test('data is a valid ChartJS dataset for FindADate using poll timezone', function(assert) {
let options = [
EmberObject.create({
title: '2015-01-01'
}),
EmberObject.create({
title: '2015-02-02'
}),
EmberObject.create({
title: '2015-03-03T01:00:00.000Z'
}),
EmberObject.create({
title: '2015-03-03T11:00:00.000Z'
})
];
let users = [
EmberObject.create({
id: 1,
selections: [
@ -170,149 +66,247 @@ test('data is a valid ChartJS dataset for MakeAPoll', function(assert) {
})
]
})
]
];
let currentLocale = 'en';
let momentLongDayFormat = moment.localeData(currentLocale)
.longDateFormat('LLLL')
.replace(
moment.localeData(currentLocale).longDateFormat('LT'), '')
.trim();
let component = this.owner.factoryFor('component:poll-evaluation-chart').create({
answerType: 'YesNoMaybe',
currentLocale,
isFindADate: true,
momentLongDayFormat,
options,
timezone: 'Asia/Hong_Kong',
users
});
const data = component.get('data');
assert.deepEqual(
data.labels,
['Thursday, January 1, 2015', 'Monday, February 2, 2015', 'Tuesday, March 3, 2015 9:00 AM', 'Tuesday, March 3, 2015 7:00 PM'],
'Labels are correct'
);
assert.equal(
data.datasets.length,
2,
'there are two datasets'
);
assert.deepEqual(
data.datasets.map((dataset) => dataset.label),
['Yes', 'Maybe'],
'datasets having answers as label and are in correct order'
);
assert.deepEqual(
data.datasets[0].data,
[100, 50, 0, 0],
'dataset for yes is correct'
);
assert.deepEqual(
data.datasets[1].data,
[0, 50, 50, 0],
'dataset for maybe is correct'
);
});
const data = component.get('data');
assert.deepEqual(
data.labels,
options.map((option) => option.get('title')),
'Labels are correct'
);
assert.equal(
data.datasets.length,
2,
'there are two datasets'
);
assert.deepEqual(
data.datasets.map((dataset) => dataset.label),
['Yes', 'Maybe'],
'datasets having answers as label and are in correct order'
);
assert.deepEqual(
data.datasets[0].data,
[100, 50, 0, 0],
'dataset for yes is correct'
);
assert.deepEqual(
data.datasets[1].data,
[0, 50, 50, 0],
'dataset for maybe is correct'
);
});
test('data is a valid ChartJS dataset for FindADate using poll timezone', function(assert) {
let options = [
EmberObject.create({
title: '2015-01-01'
}),
EmberObject.create({
title: '2015-02-02'
}),
EmberObject.create({
title: '2015-03-03T01:00:00.000Z'
}),
EmberObject.create({
title: '2015-03-03T11:00:00.000Z'
})
];
let users = [
EmberObject.create({
id: 1,
selections: [
test('data is a valid ChartJS dataset for MakeAPoll', function(assert) {
const options = [
EmberObject.create({
title: 'first option'
}),
EmberObject.create({
title: 'second option'
}),
EmberObject.create({
title: 'third option'
}),
EmberObject.create({
title: 'fourth option'
})
];
let component = this.owner.factoryFor('component:poll-evaluation-chart').create({
answerType: 'YesNoMaybe',
options,
users: [
EmberObject.create({
type: 'yes'
id: 1,
selections: [
EmberObject.create({
type: 'yes'
}),
EmberObject.create({
type: 'yes'
}),
EmberObject.create({
type: 'maybe'
}),
EmberObject.create({
type: 'no'
})
]
}),
EmberObject.create({
type: 'yes'
}),
EmberObject.create({
type: 'maybe'
}),
EmberObject.create({
type: 'no'
id: 2,
selections: [
EmberObject.create({
type: 'yes'
}),
EmberObject.create({
type: 'maybe'
}),
EmberObject.create({
type: 'no'
}),
EmberObject.create({
type: 'no'
})
]
})
]
}),
EmberObject.create({
id: 2,
selections: [
EmberObject.create({
type: 'yes'
}),
EmberObject.create({
type: 'maybe'
}),
EmberObject.create({
type: 'no'
}),
EmberObject.create({
type: 'no'
})
]
})
];
let currentLocale = 'en';
let momentLongDayFormat = moment.localeData(currentLocale)
.longDateFormat('LLLL')
.replace(
moment.localeData(currentLocale).longDateFormat('LT'), '')
.trim();
let component = this.subject({
answerType: 'YesNoMaybe',
currentLocale,
isFindADate: true,
momentLongDayFormat,
options,
timezone: 'Asia/Hong_Kong',
users
});
const data = component.get('data');
assert.deepEqual(
data.labels,
options.map((option) => option.get('title')),
'Labels are correct'
);
assert.equal(
data.datasets.length,
2,
'there are two datasets'
);
assert.deepEqual(
data.datasets.map((dataset) => dataset.label),
['Yes', 'Maybe'],
'datasets having answers as label and are in correct order'
);
assert.deepEqual(
data.datasets[0].data,
[100, 50, 0, 0],
'dataset for yes is correct'
);
assert.deepEqual(
data.datasets[1].data,
[0, 50, 50, 0],
'dataset for maybe is correct'
);
});
const data = component.get('data');
assert.deepEqual(
data.labels,
['Thursday, January 1, 2015', 'Monday, February 2, 2015', 'Tuesday, March 3, 2015 9:00 AM', 'Tuesday, March 3, 2015 7:00 PM'],
'Labels are correct'
);
assert.equal(
data.datasets.length,
2,
'there are two datasets'
);
assert.deepEqual(
data.datasets.map((dataset) => dataset.label),
['Yes', 'Maybe'],
'datasets having answers as label and are in correct order'
);
assert.deepEqual(
data.datasets[0].data,
[100, 50, 0, 0],
'dataset for yes is correct'
);
assert.deepEqual(
data.datasets[1].data,
[0, 50, 50, 0],
'dataset for maybe is correct'
);
});
test('data is a valid ChartJS dataset for FindADate using locale timezone', function(assert) {
let options = [
EmberObject.create({
title: '2015-03-03T01:00:00.000Z'
})
];
let component = this.subject({
answerType: 'YesNoMaybe',
currentLocale: 'en',
isFindADate: true,
momentLongDayFormat: '',
options,
timezone: undefined,
users: []
test('data is a valid ChartJS dataset for FindADate using poll timezone', function(assert) {
let options = [
EmberObject.create({
title: '2015-01-01'
}),
EmberObject.create({
title: '2015-02-02'
}),
EmberObject.create({
title: '2015-03-03T01:00:00.000Z'
}),
EmberObject.create({
title: '2015-03-03T11:00:00.000Z'
})
];
let users = [
EmberObject.create({
id: 1,
selections: [
EmberObject.create({
type: 'yes'
}),
EmberObject.create({
type: 'yes'
}),
EmberObject.create({
type: 'maybe'
}),
EmberObject.create({
type: 'no'
})
]
}),
EmberObject.create({
id: 2,
selections: [
EmberObject.create({
type: 'yes'
}),
EmberObject.create({
type: 'maybe'
}),
EmberObject.create({
type: 'no'
}),
EmberObject.create({
type: 'no'
})
]
})
];
let currentLocale = 'en';
let momentLongDayFormat = moment.localeData(currentLocale)
.longDateFormat('LLLL')
.replace(
moment.localeData(currentLocale).longDateFormat('LT'), '')
.trim();
let component = this.owner.factoryFor('component:poll-evaluation-chart').create({
answerType: 'YesNoMaybe',
currentLocale,
isFindADate: true,
momentLongDayFormat,
options,
timezone: 'Asia/Hong_Kong',
users
});
const data = component.get('data');
assert.deepEqual(
data.labels,
['Thursday, January 1, 2015', 'Monday, February 2, 2015', 'Tuesday, March 3, 2015 9:00 AM', 'Tuesday, March 3, 2015 7:00 PM'],
'Labels are correct'
);
assert.equal(
data.datasets.length,
2,
'there are two datasets'
);
assert.deepEqual(
data.datasets.map((dataset) => dataset.label),
['Yes', 'Maybe'],
'datasets having answers as label and are in correct order'
);
assert.deepEqual(
data.datasets[0].data,
[100, 50, 0, 0],
'dataset for yes is correct'
);
assert.deepEqual(
data.datasets[1].data,
[0, 50, 50, 0],
'dataset for maybe is correct'
);
});
test('data is a valid ChartJS dataset for FindADate using locale timezone', function(assert) {
let options = [
EmberObject.create({
title: '2015-03-03T01:00:00.000Z'
})
];
let component = this.owner.factoryFor('component:poll-evaluation-chart').create({
answerType: 'YesNoMaybe',
currentLocale: 'en',
isFindADate: true,
momentLongDayFormat: '',
options,
timezone: undefined,
users: []
});
const data = component.get('data');
assert.deepEqual(
data.labels,
[moment('2015-03-03T01:00:00.000Z').format('LLLL')],
'Labels are correct'
);
});
const data = component.get('data');
assert.deepEqual(
data.labels,
[moment('2015-03-03T01:00:00.000Z').format('LLLL')],
'Labels are correct'
);
});

View file

@ -1,12 +1,12 @@
import { moduleFor, test } from 'ember-qunit';
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
moduleFor('controller:create', 'Unit | Controller | create', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
});
module('Unit | Controller | create', function(hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function(assert) {
let controller = this.subject();
assert.ok(controller);
// Replace this with your real tests.
test('it exists', function(assert) {
let controller = this.owner.lookup('controller:create');
assert.ok(controller);
});
});

View file

@ -1,58 +1,60 @@
import { run } from '@ember/runloop';
import EmberObject from '@ember/object';
import { moduleFor, test } from 'ember-qunit';
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import moment from 'moment';
moduleFor('controller:create/options-datetime', 'Unit | Controller | create/options datetime', {
});
module('Unit | Controller | create/options datetime', function(hooks) {
setupTest(hooks);
test('normalize options - remove days without time if there is another option with a time for that day', function(assert) {
const dirtyOption = EmberObject.create({ title: '2015-01-01' });
let controller = this.subject({
model: {
options: [
EmberObject.create({ title: '2015-01-01T12:00:00.000Z' }),
dirtyOption,
EmberObject.create({ title: '2017-11-11' }),
EmberObject.create({ title: '2018-04-04T11:11:00.000Z' })
]
}
test('normalize options - remove days without time if there is another option with a time for that day', function(assert) {
const dirtyOption = EmberObject.create({ title: '2015-01-01' });
let controller = this.owner.factoryFor('controller:create/options-datetime').create({
model: {
options: [
EmberObject.create({ title: '2015-01-01T12:00:00.000Z' }),
dirtyOption,
EmberObject.create({ title: '2017-11-11' }),
EmberObject.create({ title: '2018-04-04T11:11:00.000Z' })
]
}
});
run(() => {
controller.normalizeOptions();
});
assert.equal(
controller.get('options.length'),
3,
'one option is removed'
);
assert.ok(
controller.get('options').indexOf(dirtyOption) === -1,
'correct option is removed'
);
});
run(() => {
controller.normalizeOptions();
});
assert.equal(
controller.get('options.length'),
3,
'one option is removed'
);
assert.ok(
controller.get('options').indexOf(dirtyOption) === -1,
'correct option is removed'
);
});
test('normalize options - sort them', function(assert) {
const dateA = moment().hour(5).toISOString();
const dateB = moment().hour(10).toISOString();
const dateC = moment().hour(22).toISOString();
const dateD = moment().add(1, 'day').toISOString();
let controller = this.subject({
model: {
options: [
EmberObject.create({ title: dateB }),
EmberObject.create({ title: dateA }),
EmberObject.create({ title: dateC }),
EmberObject.create({ title: dateD })
]
}
test('normalize options - sort them', function(assert) {
const dateA = moment().hour(5).toISOString();
const dateB = moment().hour(10).toISOString();
const dateC = moment().hour(22).toISOString();
const dateD = moment().add(1, 'day').toISOString();
let controller = this.owner.factoryFor('controller:create/options-datetime').create({
model: {
options: [
EmberObject.create({ title: dateB }),
EmberObject.create({ title: dateA }),
EmberObject.create({ title: dateC }),
EmberObject.create({ title: dateD })
]
}
});
run(() => {
controller.normalizeOptions();
});
assert.deepEqual(
controller.get('options').map((option) => option.get('title')),
[dateA, dateB, dateC, dateD],
'options are sorted'
);
});
run(() => {
controller.normalizeOptions();
});
assert.deepEqual(
controller.get('options').map((option) => option.get('title')),
[dateA, dateB, dateC, dateD],
'options are sorted'
);
});

View file

@ -1,12 +1,12 @@
import { moduleFor, test } from 'ember-qunit';
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
moduleFor('controller:create/options', 'Unit | Controller | create/options', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
});
module('Unit | Controller | create/options', function(hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function(assert) {
let controller = this.subject();
assert.ok(controller);
// Replace this with your real tests.
test('it exists', function(assert) {
let controller = this.owner.lookup('controller:create/options');
assert.ok(controller);
});
});

View file

@ -1,12 +1,12 @@
import { moduleFor, test } from 'ember-qunit';
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
moduleFor('controller:error', 'Unit | Controller | error', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
});
module('Unit | Controller | error', function(hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function(assert) {
let controller = this.subject();
assert.ok(controller);
// Replace this with your real tests.
test('it exists', function(assert) {
let controller = this.owner.lookup('controller:error');
assert.ok(controller);
});
});

View file

@ -1,30 +1,31 @@
import { moduleFor, test } from 'ember-qunit';
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import moment from 'moment';
moduleFor('controller:poll', 'Unit | Controller | poll', {
needs: ['service:encryption', 'service:flashMessages', 'service:i18n']
});
module('Unit | Controller | poll', function(hooks) {
setupTest(hooks);
test('#showExpirationWarning', function(assert) {
let controller = this.subject({
model: {
expirationDate: undefined
}
test('#showExpirationWarning', function(assert) {
let controller = this.owner.factoryFor('controller:poll').create({
model: {
expirationDate: undefined
}
});
assert.notOk(
controller.get('showExpirationWarning'),
'is false if expirationDate is undefined'
);
controller.set('model.expirationDate', moment().add(1, 'week').toISOString());
assert.ok(
controller.get('showExpirationWarning'),
'is true if expirationDate is less than 2 weeks in future'
);
controller.set('model.expirationDate', moment().add(1, 'month').toISOString());
assert.notOk(
controller.get('showExpirationWarning'),
'is false if expirationDate is more than 2 weeks in future'
);
});
assert.notOk(
controller.get('showExpirationWarning'),
'is false if expirationDate is undefined'
);
controller.set('model.expirationDate', moment().add(1, 'week').toISOString());
assert.ok(
controller.get('showExpirationWarning'),
'is true if expirationDate is less than 2 weeks in future'
);
controller.set('model.expirationDate', moment().add(1, 'month').toISOString());
assert.notOk(
controller.get('showExpirationWarning'),
'is false if expirationDate is more than 2 weeks in future'
);
});

View file

@ -1,16 +1,12 @@
import { moduleFor, test } from 'ember-qunit';
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
moduleFor('controller:poll/participation', 'Unit | Controller | poll/participation', {
needs: [
'config:environment',
'controller:poll',
'service:encryption', 'service:i18n',
'validator:collection', 'validator:presence', 'validator:unique'
]
});
module('Unit | Controller | poll/participation', function(hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function(assert) {
let controller = this.subject();
assert.ok(controller);
// Replace this with your real tests.
test('it exists', function(assert) {
let controller = this.owner.lookup('controller:poll/participation');
assert.ok(controller);
});
});

View file

@ -2,11 +2,11 @@ import EmberObject from '@ember/object';
import AutofocusSupportMixin from 'croodle/mixins/autofocus-support';
import { module, test } from 'qunit';
module('Unit | Mixin | autofocus support');
// Replace this with your real tests.
test('it works', function(assert) {
let AutofocusSupportObject = EmberObject.extend(AutofocusSupportMixin);
let subject = AutofocusSupportObject.create();
assert.ok(subject);
module('Unit | Mixin | autofocus support', function() {
// Replace this with your real tests.
test('it works', function(assert) {
let AutofocusSupportObject = EmberObject.extend(AutofocusSupportMixin);
let subject = AutofocusSupportObject.create();
assert.ok(subject);
});
});

View file

@ -1,6 +1,7 @@
import { run } from '@ember/runloop';
import Service from '@ember/service';
import { moduleForModel, test } from 'ember-qunit';
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import moment from 'moment';
const i18nStub = Service.extend({
@ -10,356 +11,347 @@ const i18nStub = Service.extend({
locale: 'en'
});
moduleForModel('option', 'Unit | Model | option', {
needs: [
'validator:alias',
'validator:iso8601',
'validator:unique',
'validator:presence',
'validator:messages',
'validator:time',
'model:poll',
'model:user'
],
module('Unit | Model | option', function(hooks) {
setupTest(hooks);
beforeEach() {
this.register('service:i18n', i18nStub);
this.inject.service('i18n', { as: 'i18n' });
hooks.beforeEach(function() {
this.owner.register('service:i18n', i18nStub);
this.i18n = this.owner.lookup('service:i18n');
moment.locale('en');
}
});
test('date property (get)', function(assert) {
let option = this.subject({
title: '2015-01-01'
});
assert.ok(
moment.isMoment(option.get('date')),
'returns a moment instance if title is an ISO 8601 day string'
);
assert.equal(
option.get('date').format('YYYY-MM-DD HH:mm:ss.SSS'),
'2015-01-01 00:00:00.000',
'string to date conversion is correct for ISO 8601 day string'
);
run(() => {
option.set('title', '2015-01-01T11:11:00.000Z');
});
assert.ok(
moment.isMoment(option.get('date')),
'returns a moment instance if title is an ISO 8601 datetime string'
);
assert.equal(
option.get('date').toISOString(),
'2015-01-01T11:11:00.000Z',
'string to date conversion is correct for ISO 8601 datetime string'
);
run(() => {
option.set('title', null);
});
assert.equal(
option.get('date'),
undefined,
'returns undefined if title is empty'
);
run(() => {
option.set('title', 'abc');
});
assert.equal(
option.get('date'),
undefined,
'returns undefined if title is not a valid ISO 8601 date string'
);
run(() => {
option.set('title', '2015');
});
assert.equal(
option.get('date'),
undefined,
'returns undefined if title ISO 8601 string only contains a year'
);
run(() => {
option.set('title', '2015-01');
});
assert.equal(
option.get('date'),
undefined,
'returns undefined if title ISO 8601 string only contains a year and a month'
);
run(() => {
option.set('title', '2013W06');
});
assert.equal(
option.get('date'),
undefined,
'returns undefined if title ISO 8601 string only contains a year and a week'
);
});
test('day property (get)', function(assert) {
let option = this.subject({
title: '2015-01-01'
});
assert.equal(
option.get('day'),
'2015-01-01',
'returns ISO 8601 day string if title is ISO 8601 day string'
);
run(() => {
option.set('title', '2015-01-01T11:11:00.000Z');
});
assert.equal(
option.get('day'),
moment('2015-01-01T11:11:00.000Z').format('YYYY-MM-DD'),
'returns ISO 8601 day string if title is ISO 8601 datetime string'
);
run(() => {
option.set('title', 'abc');
});
assert.equal(
option.get('day'),
undefined,
'returns undefined if title is not a valid ISO 8601 string'
);
run(() => {
option.set('title', null);
});
assert.equal(
option.get('day'),
undefined,
'returns undefined if title is null'
);
});
test('dayFormatted property (get)', function(assert) {
let option = this.subject({
title: '2015-01-01'
});
assert.equal(
option.get('dayFormatted'),
'Thursday, January 1, 2015',
'returns formatted date if title is ISO 8601 day string'
);
run(() => {
option.set('title', moment('2015-01-01').toISOString());
});
assert.equal(
option.get('dayFormatted'),
'Thursday, January 1, 2015',
'returns formatted date if title is ISO 8601 datetime string'
);
run(() => {
option.set('i18n.locale', 'de');
});
assert.equal(
option.get('dayFormatted'),
'Donnerstag, 1. Januar 2015',
'observes locale changes'
);
run(() => {
option.set('title', 'abc');
});
assert.equal(
option.get('dayFormatted'),
undefined,
'returns undfined if title is not a valid ISO 8601 string'
);
});
test('hasTime property', function(assert) {
let option = this.subject({
title: '2015-01-01T11:11:00.000Z'
});
assert.ok(option.get('hasTime'));
run(() => {
option.set('title', '2015-01-01');
});
assert.notOk(option.get('hasTime'));
run(() => {
option.set('title', 'foo');
});
assert.notOk(option.get('hasTime'));
});
test('time property (get)', function(assert) {
let option = this.subject({
title: '2015-01-01T11:11:00.000Z'
});
assert.equal(
option.get('time'),
moment('2015-01-01T11:11:00.000Z').format('HH:mm'),
'returns time if title is ISO 8601 datetime string'
);
run(() => {
option.set('title', '2015-01-01');
});
assert.equal(
option.get('time'),
undefined,
'returns undefined if title is ISO 8601 day string'
);
run(() => {
option.set('title', 'abc');
});
assert.equal(
option.get('time'),
undefined,
'returns undefined if title is not an ISO 8601 date string'
);
});
test('time property (set)', function(assert) {
let option = this.subject({
title: '2015-01-01'
});
run(() => {
option.set('time', '11:00');
});
assert.equal(
option.get('title'),
moment('2015-01-01T11:00').toISOString(),
'sets title according to time'
);
run(() => {
option.set('time', null);
});
assert.equal(
option.get('title'),
'2015-01-01',
'removes time from option if value is false'
);
const before = option.get('title');
run(() => {
option.set('time', 'abc');
});
assert.equal(
option.get('title'),
before,
'does not set title if time is invalid'
);
run(() => {
option.set('title', 'abc');
});
assert.throws(
() => {
option.set('time', '11:11');
},
'throws if attempt to set a time if title is not a date string'
);
});
test('validation for MakeAPoll', function(assert) {
run(() => {
let store = this.store();
let poll = store.createRecord('poll', {
pollType: 'MakeAPoll'
});
let option = store.createFragment('option');
poll.get('options').pushObject(option);
option.validate();
assert.notOk(
option.get('validations.isValid'),
'default value is not valid'
test('date property (get)', function(assert) {
let option = run(() => this.owner.lookup('service:store').createRecord('option', {
title: '2015-01-01'
}));
assert.ok(
moment.isMoment(option.get('date')),
'returns a moment instance if title is an ISO 8601 day string'
);
assert.equal(
option.get('date').format('YYYY-MM-DD HH:mm:ss.SSS'),
'2015-01-01 00:00:00.000',
'string to date conversion is correct for ISO 8601 day string'
);
run(() => {
option.set('title', 'Spasibo!');
option.set('title', '2015-01-01T11:11:00.000Z');
});
assert.ok(
option.get('validations.isValid'),
'is valid for a non empty string'
moment.isMoment(option.get('date')),
'returns a moment instance if title is an ISO 8601 datetime string'
);
run(() => {
option.set('title', '!');
});
assert.ok(
option.get('validations.isValid'),
'is invalid if set to empty string again'
assert.equal(
option.get('date').toISOString(),
'2015-01-01T11:11:00.000Z',
'string to date conversion is correct for ISO 8601 datetime string'
);
});
});
test('validation for FindADate', function(assert) {
run(() => {
let store = this.store();
let poll = store.createRecord('poll', {
isDateTime: false,
pollType: 'FindADate'
});
let option = store.createFragment('option');
poll.get('options').pushObject(option);
option.validate();
assert.notOk(
option.get('validations.isValid'),
'default value is not valid'
);
run(() => {
option.set('title', '1945-05-08');
option.set('title', null);
});
assert.ok(
option.get('validations.isValid'),
'iso 8601 date string is valid'
assert.equal(
option.get('date'),
undefined,
'returns undefined if title is empty'
);
run(() => {
option.set('title', 'Spasibo!');
});
assert.notOk(
option.get('validations.isValid'),
'random string is not valid'
);
});
});
test('validation for FindADate', function(assert) {
run(() => {
let store = this.store();
let poll = store.createRecord('poll', {
pollType: 'FindADate'
});
let option = store.createFragment('option');
poll.get('options').pushObject(option);
option.validate();
assert.notOk(
option.get('validations.isValid'),
'default value is not valid'
);
run(() => {
option.set('title', '1945-05-08T00:00:00.000Z');
option.set('title', 'abc');
});
assert.ok(
option.get('validations.isValid'),
'iso 8601 datetime string is valid'
assert.equal(
option.get('date'),
undefined,
'returns undefined if title is not a valid ISO 8601 date string'
);
run(() => {
option.set('title', 'Spasibo!');
option.set('title', '2015');
});
assert.notOk(
option.get('validations.isValid'),
'random string is not valid'
assert.equal(
option.get('date'),
undefined,
'returns undefined if title ISO 8601 string only contains a year'
);
run(() => {
option.set('title', '1945-05-08');
option.set('title', '2015-01');
});
assert.ok(
option.get('validations.isValid'),
'iso 8601 date string is valid'
assert.equal(
option.get('date'),
undefined,
'returns undefined if title ISO 8601 string only contains a year and a month'
);
run(() => {
option.set('title', '2013W06');
});
assert.equal(
option.get('date'),
undefined,
'returns undefined if title ISO 8601 string only contains a year and a week'
);
});
test('day property (get)', function(assert) {
let option = run(() => this.owner.lookup('service:store').createRecord('option', {
title: '2015-01-01'
}));
assert.equal(
option.get('day'),
'2015-01-01',
'returns ISO 8601 day string if title is ISO 8601 day string'
);
run(() => {
option.set('title', '2015-01-01T11:11:00.000Z');
});
assert.equal(
option.get('day'),
moment('2015-01-01T11:11:00.000Z').format('YYYY-MM-DD'),
'returns ISO 8601 day string if title is ISO 8601 datetime string'
);
run(() => {
option.set('title', 'abc');
});
assert.equal(
option.get('day'),
undefined,
'returns undefined if title is not a valid ISO 8601 string'
);
run(() => {
option.set('title', null);
});
assert.equal(
option.get('day'),
undefined,
'returns undefined if title is null'
);
});
test('dayFormatted property (get)', function(assert) {
let option = run(() => this.owner.lookup('service:store').createRecord('option', {
title: '2015-01-01'
}));
assert.equal(
option.get('dayFormatted'),
'Thursday, January 1, 2015',
'returns formatted date if title is ISO 8601 day string'
);
run(() => {
option.set('title', moment('2015-01-01').toISOString());
});
assert.equal(
option.get('dayFormatted'),
'Thursday, January 1, 2015',
'returns formatted date if title is ISO 8601 datetime string'
);
run(() => {
option.set('i18n.locale', 'de');
});
assert.equal(
option.get('dayFormatted'),
'Donnerstag, 1. Januar 2015',
'observes locale changes'
);
run(() => {
option.set('title', 'abc');
});
assert.equal(
option.get('dayFormatted'),
undefined,
'returns undfined if title is not a valid ISO 8601 string'
);
});
test('hasTime property', function(assert) {
let option = run(() => this.owner.lookup('service:store').createRecord('option', {
title: '2015-01-01T11:11:00.000Z'
}));
assert.ok(option.get('hasTime'));
run(() => {
option.set('title', '2015-01-01');
});
assert.notOk(option.get('hasTime'));
run(() => {
option.set('title', 'foo');
});
assert.notOk(option.get('hasTime'));
});
test('time property (get)', function(assert) {
let option = run(() => this.owner.lookup('service:store').createRecord('option', {
title: '2015-01-01T11:11:00.000Z'
}));
assert.equal(
option.get('time'),
moment('2015-01-01T11:11:00.000Z').format('HH:mm'),
'returns time if title is ISO 8601 datetime string'
);
run(() => {
option.set('title', '2015-01-01');
});
assert.equal(
option.get('time'),
undefined,
'returns undefined if title is ISO 8601 day string'
);
run(() => {
option.set('title', 'abc');
});
assert.equal(
option.get('time'),
undefined,
'returns undefined if title is not an ISO 8601 date string'
);
});
test('time property (set)', function(assert) {
let option = run(() => this.owner.lookup('service:store').createRecord('option', {
title: '2015-01-01'
}));
run(() => {
option.set('time', '11:00');
});
assert.equal(
option.get('title'),
moment('2015-01-01T11:00').toISOString(),
'sets title according to time'
);
run(() => {
option.set('time', null);
});
assert.equal(
option.get('title'),
'2015-01-01',
'removes time from option if value is false'
);
const before = option.get('title');
run(() => {
option.set('time', 'abc');
});
assert.equal(
option.get('title'),
before,
'does not set title if time is invalid'
);
run(() => {
option.set('title', 'abc');
});
assert.throws(
() => {
option.set('time', '11:11');
},
'throws if attempt to set a time if title is not a date string'
);
});
test('validation for MakeAPoll', function(assert) {
run(() => {
let store = this.owner.lookup('service:store');
let poll = store.createRecord('poll', {
pollType: 'MakeAPoll'
});
let option = store.createFragment('option');
poll.get('options').pushObject(option);
option.validate();
assert.notOk(
option.get('validations.isValid'),
'default value is not valid'
);
run(() => {
option.set('title', 'Spasibo!');
});
assert.ok(
option.get('validations.isValid'),
'is valid for a non empty string'
);
run(() => {
option.set('title', '!');
});
assert.ok(
option.get('validations.isValid'),
'is invalid if set to empty string again'
);
});
});
test('validation for FindADate', function(assert) {
run(() => {
let store = this.owner.lookup('service:store');
let poll = store.createRecord('poll', {
isDateTime: false,
pollType: 'FindADate'
});
let option = store.createFragment('option');
poll.get('options').pushObject(option);
option.validate();
assert.notOk(
option.get('validations.isValid'),
'default value is not valid'
);
run(() => {
option.set('title', '1945-05-08');
});
assert.ok(
option.get('validations.isValid'),
'iso 8601 date string is valid'
);
run(() => {
option.set('title', 'Spasibo!');
});
assert.notOk(
option.get('validations.isValid'),
'random string is not valid'
);
});
});
test('validation for FindADate', function(assert) {
run(() => {
let store = this.owner.lookup('service:store');
let poll = store.createRecord('poll', {
pollType: 'FindADate'
});
let option = store.createFragment('option');
poll.get('options').pushObject(option);
option.validate();
assert.notOk(
option.get('validations.isValid'),
'default value is not valid'
);
run(() => {
option.set('title', '1945-05-08T00:00:00.000Z');
});
assert.ok(
option.get('validations.isValid'),
'iso 8601 datetime string is valid'
);
run(() => {
option.set('title', 'Spasibo!');
});
assert.notOk(
option.get('validations.isValid'),
'random string is not valid'
);
run(() => {
option.set('title', '1945-05-08');
});
assert.ok(
option.get('validations.isValid'),
'iso 8601 date string is valid'
);
});
});
});

View file

@ -1,11 +1,11 @@
import { moduleFor, test } from 'ember-qunit';
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
moduleFor('route:create/options-datetime', 'Unit | Route | create/options datetime', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
});
module('Unit | Route | create/options datetime', function(hooks) {
setupTest(hooks);
test('it exists', function(assert) {
let route = this.subject();
assert.ok(route);
test('it exists', function(assert) {
let route = this.owner.lookup('route:create/options-datetime');
assert.ok(route);
});
});

View file

@ -1,12 +1,12 @@
import { moduleFor, test } from 'ember-qunit';
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
moduleFor('service:encryption', 'Unit | Service | encryption', {
// Specify the other units that are required for this test.
// needs: ['service:foo']
});
module('Unit | Service | encryption', function(hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function(assert) {
let service = this.subject();
assert.ok(service);
// Replace this with your real tests.
test('it exists', function(assert) {
let service = this.owner.lookup('service:encryption');
assert.ok(service);
});
});

View file

@ -1,96 +1,98 @@
import { moduleFor, test } from 'ember-qunit';
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
moduleFor('validator:iso8601', 'Unit | Validator | iso8601', {
});
module('Unit | Validator | iso8601', function(hooks) {
setupTest(hooks);
test('default validation is correct', function(assert) {
let validator = this.subject();
assert.equal(
validator.validate('1945-05-08T23:01:00.000Z'),
true,
'iso 8601 datetime string with milliseconds in UTC is valid by default'
);
assert.notOk(
validator.validate(null) === true,
'null is invalid'
);
assert.notOk(
validator.validate(undefined) === true,
'undefined is invalid'
);
assert.notOk(
validator.validate('') === true,
'empty string is invalid'
);
assert.notOk(
validator.validate('abc123') === true,
'random string is invalid'
);
});
test('default validation is correct', function(assert) {
let validator = this.owner.lookup('validator:iso8601');
assert.equal(
validator.validate('1945-05-08T23:01:00.000Z'),
true,
'iso 8601 datetime string with milliseconds in UTC is valid by default'
);
assert.notOk(
validator.validate(null) === true,
'null is invalid'
);
assert.notOk(
validator.validate(undefined) === true,
'undefined is invalid'
);
assert.notOk(
validator.validate('') === true,
'empty string is invalid'
);
assert.notOk(
validator.validate('abc123') === true,
'random string is invalid'
);
});
test('option.active disables validation on false', function(assert) {
let validator = this.subject();
const buildOptions = validator.buildOptions({ active: false }, {});
assert.notOk(
validator.validate(null) === true,
'is validated on default'
);
assert.equal(
validator.validate(null, buildOptions),
true,
'validation is disabled on active === false'
);
});
test('option.active disables validation on false', function(assert) {
let validator = this.owner.lookup('validator:iso8601');
const buildOptions = validator.buildOptions({ active: false }, {});
assert.notOk(
validator.validate(null) === true,
'is validated on default'
);
assert.equal(
validator.validate(null, buildOptions),
true,
'validation is disabled on active === false'
);
});
test('option.active could be a function', function(assert) {
let validator = this.subject();
const buildOptions = validator.buildOptions({
active() {
return false;
}
}, {});
assert.equal(
validator.validate(null, buildOptions),
true,
'validation is dislabed if function returns false'
);
});
test('option.active could be a function', function(assert) {
let validator = this.owner.lookup('validator:iso8601');
const buildOptions = validator.buildOptions({
active() {
return false;
}
}, {});
assert.equal(
validator.validate(null, buildOptions),
true,
'validation is dislabed if function returns false'
);
});
test('valid iso8601 string formats could be defined by options.validFormats', function(assert) {
let validator = this.subject();
const buildOptions = validator.buildOptions({
validFormats: [
'YYYY-MM-DD',
'YYYY-MM-DDTHH:mmZ',
'YYYY-MM-DDTHH:mm:ssZ'
]
}, {});
assert.notOk(
validator.validate('1945-05-08') === true,
'iso 8601 date string is invalid by default'
);
assert.equal(
validator.validate('1945-05-08', buildOptions),
true,
'iso 8601 date string is valid if it\'s in validFormats options'
);
assert.notOk(
validator.validate('1945-05-08T23:01Z') === true,
'iso 8601 datetime string in UTC is invalid by default'
);
assert.equal(
validator.validate('1945-05-08T23:01Z', buildOptions),
true,
'iso 8601 datetime string in UTC is valid if it\'s in validFormats options'
);
assert.notOk(
validator.validate('1945-05-08T23:01:00Z') === true,
true,
'iso 8601 datetime string with seconds in UTC is invalid by default'
);
assert.equal(
validator.validate('1945-05-08T23:01:00Z', buildOptions),
true,
'iso 8601 datetime string with seconds in UTC is valid if it\'s in validFormats options'
);
test('valid iso8601 string formats could be defined by options.validFormats', function(assert) {
let validator = this.owner.lookup('validator:iso8601');
const buildOptions = validator.buildOptions({
validFormats: [
'YYYY-MM-DD',
'YYYY-MM-DDTHH:mmZ',
'YYYY-MM-DDTHH:mm:ssZ'
]
}, {});
assert.notOk(
validator.validate('1945-05-08') === true,
'iso 8601 date string is invalid by default'
);
assert.equal(
validator.validate('1945-05-08', buildOptions),
true,
'iso 8601 date string is valid if it\'s in validFormats options'
);
assert.notOk(
validator.validate('1945-05-08T23:01Z') === true,
'iso 8601 datetime string in UTC is invalid by default'
);
assert.equal(
validator.validate('1945-05-08T23:01Z', buildOptions),
true,
'iso 8601 datetime string in UTC is valid if it\'s in validFormats options'
);
assert.notOk(
validator.validate('1945-05-08T23:01:00Z') === true,
true,
'iso 8601 datetime string with seconds in UTC is invalid by default'
);
assert.equal(
validator.validate('1945-05-08T23:01:00Z', buildOptions),
true,
'iso 8601 datetime string with seconds in UTC is valid if it\'s in validFormats options'
);
});
});

View file

@ -1,47 +1,49 @@
import { moduleFor, test } from 'ember-qunit';
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
moduleFor('validator:time', 'Unit | Validator | time', {
});
test('HH:mm is treated as valid', function(assert) {
let validator = this.subject();
assert.equal(validator.validate('00:00'), true);
assert.equal(validator.validate('23:59'), true);
});
test('24:00 is invalid', function(assert) {
let validator = this.subject();
assert.ok(typeof validator.validate('24:00') === 'string');
});
test('00:60 is invalid', function(assert) {
let validator = this.subject();
assert.ok(typeof validator.validate('00:60') === 'string');
});
test('an empty string is invalid', function(assert) {
let validator = this.subject();
assert.ok(typeof validator.validate('') === 'string');
});
test('null is invalid', function(assert) {
let validator = this.subject();
assert.ok(typeof validator.validate(null) === 'string');
});
test('undefined is invalid', function(assert) {
let validator = this.subject();
assert.ok(typeof validator.validate(undefined) === 'string');
});
test('a valid time wrapped by spaces is valid', function(assert) {
let validator = this.subject();
assert.equal(validator.validate(' 10:00 '), true);
module('Unit | Validator | time', function(hooks) {
setupTest(hooks);
test('HH:mm is treated as valid', function(assert) {
let validator = this.owner.lookup('validator:time');
assert.equal(validator.validate('00:00'), true);
assert.equal(validator.validate('23:59'), true);
});
test('24:00 is invalid', function(assert) {
let validator = this.owner.lookup('validator:time');
assert.ok(typeof validator.validate('24:00') === 'string');
});
test('00:60 is invalid', function(assert) {
let validator = this.owner.lookup('validator:time');
assert.ok(typeof validator.validate('00:60') === 'string');
});
test('an empty string is invalid', function(assert) {
let validator = this.owner.lookup('validator:time');
assert.ok(typeof validator.validate('') === 'string');
});
test('null is invalid', function(assert) {
let validator = this.owner.lookup('validator:time');
assert.ok(typeof validator.validate(null) === 'string');
});
test('undefined is invalid', function(assert) {
let validator = this.owner.lookup('validator:time');
assert.ok(typeof validator.validate(undefined) === 'string');
});
test('a valid time wrapped by spaces is valid', function(assert) {
let validator = this.owner.lookup('validator:time');
assert.equal(validator.validate(' 10:00 '), true);
});
});

View file

@ -1,88 +1,90 @@
import { A } from '@ember/array';
import EmberObject from '@ember/object';
import { moduleFor, test } from 'ember-qunit';
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
moduleFor('validator:unique', 'Unit | Validator | unique', {
});
module('Unit | Validator | unique', function(hooks) {
setupTest(hooks);
test('throws if required option is missing', function(assert) {
const validator = this.subject();
assert.throws(
function() {
validator.validate(null, {
parent: 'foo',
dependentKeys: ['foo']
});
},
'throws if attributeInParrent is not defined'
);
assert.throws(
function() {
validator.validate(null, {
attributeInParent: 'foo',
dependentKeys: ['foo']
});
},
'throws if parent is not defined'
);
assert.throws(
function() {
validator.validate(null, {
parent: 'foo',
attributeInParent: 'foo'
});
},
'throws if dependentKeys is not defined'
);
});
test('validation', function(assert) {
const validator = this.subject();
const parent = EmberObject.create({
collection: A([])
test('throws if required option is missing', function(assert) {
const validator = this.owner.lookup('validator:unique');
assert.throws(
function() {
validator.validate(null, {
parent: 'foo',
dependentKeys: ['foo']
});
},
'throws if attributeInParrent is not defined'
);
assert.throws(
function() {
validator.validate(null, {
attributeInParent: 'foo',
dependentKeys: ['foo']
});
},
'throws if parent is not defined'
);
assert.throws(
function() {
validator.validate(null, {
parent: 'foo',
attributeInParent: 'foo'
});
},
'throws if dependentKeys is not defined'
);
});
const childObject = EmberObject.extend({
parent
test('validation', function(assert) {
const validator = this.owner.lookup('validator:unique');
const parent = EmberObject.create({
collection: A([])
});
const childObject = EmberObject.extend({
parent
});
const options = {
parent: 'parent',
attributeInParent: 'collection',
dependentKeys: ['parent.collection.@each.value']
};
const child1 = childObject.create({ value: 'foo' });
const child2 = childObject.create({ value: 'bar' });
const child3 = childObject.create({ value: 'foo' });
parent.get('collection').push(child1);
assert.ok(
validator.validate(
child1.get('value'),
options,
child1,
'value'
) === true,
'valid for only one element'
);
parent.get('collection').push(child2);
assert.ok(
validator.validate(
child2.get('value'),
options,
child2,
'value'
) === true,
'still valid after pushing another element with different value'
);
parent.get('collection').push(child3);
assert.ok(
typeof validator.validate(
child3.get('value'),
options,
child3,
'value'
) === 'string',
'invalid after pushing element with same value'
);
});
const options = {
parent: 'parent',
attributeInParent: 'collection',
dependentKeys: ['parent.collection.@each.value']
};
const child1 = childObject.create({ value: 'foo' });
const child2 = childObject.create({ value: 'bar' });
const child3 = childObject.create({ value: 'foo' });
parent.get('collection').push(child1);
assert.ok(
validator.validate(
child1.get('value'),
options,
child1,
'value'
) === true,
'valid for only one element'
);
parent.get('collection').push(child2);
assert.ok(
validator.validate(
child2.get('value'),
options,
child2,
'value'
) === true,
'still valid after pushing another element with different value'
);
parent.get('collection').push(child3);
assert.ok(
typeof validator.validate(
child3.get('value'),
options,
child3,
'value'
) === 'string',
'invalid after pushing element with same value'
);
});

View file

@ -1,9 +1,11 @@
import { moduleFor, test } from 'ember-qunit';
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
moduleFor('validator:valid-collection', 'Unit | Validator | valid-collection', {
});
module('Unit | Validator | valid-collection', function(hooks) {
setupTest(hooks);
test('it works', function(assert) {
let validator = this.subject();
assert.ok(validator);
test('it works', function(assert) {
let validator = this.owner.lookup('validator:valid-collection');
assert.ok(validator);
});
});

2572
yarn.lock

File diff suppressed because it is too large Load diff