use ember-cli-mirage to mock api

This commit is contained in:
jelhan 2016-12-19 17:04:09 +01:00
parent 0f3aa1bc56
commit 87ad9b0506
28 changed files with 719 additions and 841 deletions

View file

@ -1,4 +1,7 @@
module.exports = {
globals: {
server: true,
},
root: true,
parserOptions: {
ecmaVersion: 2017,

View file

@ -30,7 +30,7 @@ Due to security reasons you should have SSL encryption enabled and provide a val
## Build process and installation
Production builds are provided [here](https://github.com/jelhan/croodle/releases).
Production builds are provided as github [release assets](https://github.com/jelhan/croodle/releases).
If you like to build yourself you have to install [yarn](https://yarnpkg.com/), [bower](http://bower.io/), [ember-cli](http://www.ember-cli.com/) and [composer](https://getcomposer.org/) before.
@ -68,6 +68,8 @@ Files are watched for changes.
If you only like to run tests ones against PhantomJS in command-line
you could use `ember test`. This is also used in CI.
Test are run against a mock-api provided by [ember-cli-mirage](http://www.ember-cli-mirage.com/).
### Api
Api tests are provided by Codeception. To run them change current
directory to `/api` and execute `./vendor/bin/codecept run`. You have

View file

@ -6,7 +6,6 @@
"bootstrap-datepicker": "~1.4.0",
"floatThead": "^1.4.3",
"jstimezonedetect": "~1.0.5",
"pretender": "^0.6.0",
"ceibo": "1.1.0"
}
}

8
mirage/config.js Normal file
View file

@ -0,0 +1,8 @@
export default function() {
this.namespace = '/api/index.php'; // make this `api`, for example, if your API is namespaced
this.timing = 400; // delay for each request, automatically set to 0 during testing
this.get('/polls/:id');
this.post('/polls');
this.post('/users');
}

56
mirage/factories/poll.js Normal file
View file

@ -0,0 +1,56 @@
import { Factory } from 'ember-cli-mirage';
import encrypt from '../utils/encrypt';
export default Factory.extend({
anonymousUser: false,
answers: [
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Ja'
},
{
type: 'no',
labelTranslation: 'answerTypes.no.label',
icon: 'glyphicon glyphicon-thumbs-down',
label: 'Nein'
}
],
answerType: 'YesNo',
creationDate: '2015-04-01T11:11:11.111Z',
description: 'default description',
encryptionKey: 'abcdefghijklmnopqrstuvwxyz',
expirationDate: '',
forceAnswer: true,
isDateTime: false,
options: [
{
title: '2017-12-24'
},
{
title: '2018-01-01'
}
],
pollType: 'FindADate',
title: 'default title',
timezone: '',
version: 'v0.3',
afterCreate(poll, server) {
let propertiesToEncrypt = [
'anonymousUser',
'answers',
'answerType',
'creationDate',
'description',
'expirationDate',
'forceAnswer',
'options',
'pollType',
'timezone',
'title'
];
encrypt(propertiesToEncrypt, poll, server);
}
});

16
mirage/factories/user.js Normal file
View file

@ -0,0 +1,16 @@
import { Factory } from 'ember-cli-mirage';
import encrypt from '../utils/encrypt';
export default Factory.extend({
creationDate: (new Date()).toISOString(),
name: 'John Doe',
selections: [],
afterCreate(user, server) {
let propertiesToEncrypt = [
'creationDate',
'name',
'selections'
];
encrypt(propertiesToEncrypt, user, server);
}
});

View file

@ -0,0 +1,56 @@
import generateRandomString from 'croodle/utils/generate-passphrase';
export default class {
constructor() {
this.reset();
}
/**
* Returns an unique identifier.
*
* @method fetch
* @param {Object} data Records attributes hash
* @return {String} Unique identifier
* @public
*/
fetch() {
let id;
while (id === undefined) {
let randomString = generateRandomString(10);
if (this._ids[randomString] === undefined) {
id = randomString;
}
}
this._ids[id] = true;
return id;
}
/**
* Register an identifier.
* Must throw if identifier is already used.
*
* @method set
* @param {String|Number} id
* @public
*/
set(id) {
if (typeof this._ids[id] !== 'undefined') {
throw new Error(`Id {id} is already used.`);
}
this._ids[id] = true;
}
/**
* Reset identity manager.
*
* @method reset
* @public
*/
reset() {
this._ids = {};
}
}

5
mirage/models/poll.js Normal file
View file

@ -0,0 +1,5 @@
import { Model, hasMany } from 'ember-cli-mirage';
export default Model.extend({
users: hasMany('user')
});

5
mirage/models/user.js Normal file
View file

@ -0,0 +1,5 @@
import { Model, belongsTo } from 'ember-cli-mirage';
export default Model.extend({
poll: belongsTo('poll')
});

View file

@ -0,0 +1,11 @@
export default function(/* server */) {
/*
Seed your development database using your factories.
This data will not be loaded in your tests.
Make sure to define a factory for each model you want to create.
*/
// server.createList('post', 10);
}

View file

@ -0,0 +1,72 @@
import { RestSerializer } from 'ember-cli-mirage';
import { dasherize, pluralize } from 'ember-cli-mirage/utils/inflector';
export default RestSerializer.extend({
keyForForeignKey(relationshipName) {
return relationshipName;
},
keyForRelationshipIds(type) {
return type;
},
normalize(payload) {
let [type] = Object.keys(payload);
let attrs = payload[type];
let { belongsToAssociations, hasManyAssociations } = this.registry.schema._registry[type].class.prototype;
let jsonApiPayload = {
data: {
type: pluralize(type)
}
};
Object.keys(attrs).forEach((key) => {
if (key === 'id') {
// records id
jsonApiPayload.data.id = attrs.id;
} else if (
belongsToAssociations.hasOwnProperty(key) ||
hasManyAssociations.hasOwnProperty(key)
) {
// relationship
if (!jsonApiPayload.data.hasOwnProperty('relationships')) {
jsonApiPayload.data.relationships = {};
}
let association = belongsToAssociations.hasOwnProperty(key) ? belongsToAssociations[key] : hasManyAssociations[key];
let associationType = belongsToAssociations.hasOwnProperty(key) ? 'belongsTo' : 'hasMany';
let associationModel = association.modelName;
let relationshipObject = {};
switch (associationType) {
case 'belongsTo':
relationshipObject.data = {
type: associationModel,
id: attrs[key]
};
break;
case 'hasMany':
relationshipObject.data = [];
attrs[key].forEach((value) => {
relationshipObject.data.push({
type: associationModel,
id: value
});
});
break;
}
jsonApiPayload.data.relationships[key] = relationshipObject;
} else {
// attribute
if (!jsonApiPayload.data.hasOwnProperty('attributes')) {
jsonApiPayload.data.attributes = {};
}
jsonApiPayload.data.attributes[dasherize(key)] = attrs[key];
}
});
return jsonApiPayload;
},
serializeIds: 'always'
});

View file

@ -0,0 +1,6 @@
import ApplicationSerializer from './application';
export default ApplicationSerializer.extend({
embed: true,
include: ['users']
});

28
mirage/utils/encrypt.js Normal file
View file

@ -0,0 +1,28 @@
/*
* Encrypts all properties in mirage model (created by factory), encrypts them using
* sjcl and encryptionKey property of model as passphrase.
* Unsets encryptionKey property afterwards.
*/
import Ember from 'ember';
import sjcl from 'sjcl';
const { assert, get, isArray, isPresent } = Ember;
export default function(propertiesToEncrypt, model) {
assert(isArray(propertiesToEncrypt), 'first argument must be an array');
assert(isPresent(get(model, 'encryptionKey')), 'model must have an encryptionKey property which isn\'t empty');
let passphrase = get(model, 'encryptionKey');
let data = {
encryptionKey: undefined
};
propertiesToEncrypt.forEach((propertyToEncrypt) => {
let value = JSON.stringify(
get(model, propertyToEncrypt)
);
data[propertyToEncrypt] = sjcl.encrypt(passphrase, value);
});
model.update(data);
}

View file

@ -14,13 +14,11 @@
"test": "ember test"
},
"devDependencies": {
"body-parser": "^1.2.0",
"broccoli-asset-rev": "^2.4.5",
"broccoli-funnel": "^1.0.6",
"broccoli-unwatched-tree": "^0.1.1",
"chart.js": "2.2.1",
"connect-restreamer": "^1.0.1",
"cors": "^2.5.3",
"ember-ajax": "^3.0.0",
"ember-array-computed-macros": "martndemus/ember-array-computed-macros#3fde9023336d227aa6009060b40b4de77d8b1a9b",
"ember-array-helper": "^1.0.1",
@ -45,9 +43,9 @@
"ember-cli-htmlbars-inline-precompile": "^0.4.3",
"ember-cli-inject-live-reload": "^1.4.1",
"ember-cli-less": "^1.5.3",
"ember-cli-mirage": "^0.3.4",
"ember-cli-moment-shim": "3.3.3",
"ember-cli-page-object": "1.7.0",
"ember-cli-pretender": "^0.6.0",
"ember-cli-qunit": "^4.0.0",
"ember-cli-release": "^0.2.9",
"ember-cli-sauce": "^1.6.0",
@ -73,10 +71,7 @@
"ember-suave": "^4.0.0",
"ember-transition-helper": "0.0.6",
"ember-truth-helpers": "^1.2.0",
"express": "^4.8.5",
"glob": "^7.0.5",
"loader.js": "^4.2.3",
"node-phpcgi": "^0.3.5"
"loader.js": "^4.2.3"
},
"engines": {
"node": "^4.5 || 6.* || >= 7.*"

View file

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

View file

@ -1,41 +0,0 @@
// To use it create some files under `routes/`
// e.g. `server/routes/ember-hamsters.js`
//
// module.exports = function(app) {
// app.get('/ember-hamsters', function(req, res) {
// res.send('hello');
// });
// };
module.exports = function(app) {
var bodyParser = require('body-parser');
var globSync = require('glob').sync;
var mocks = globSync('./mocks/**/*.js', { cwd: __dirname }).map(require);
var proxies = globSync('./proxies/**/*.js', { cwd: __dirname }).map(require);
/* use cors for testem requests */
var cors = require('cors');
app.use(cors());
/* use node-phpcgi to handle api */
var phpcgi = require('node-phpcgi')({
documentRoot: __dirname.substring(0, __dirname.length - 6) + '/dist',
includePath: '/api/index.php',
entryPoint: '/api/index.php'
});
app.use(phpcgi);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
mocks.forEach(function(route) { route(app); });
// proxy expects a stream, but express will have turned
// the request stream into an object because bodyParser
// has run. We have to convert it back to stream:
// https://github.com/nodejitsu/node-http-proxy/issues/180
app.use(require('connect-restreamer')());
proxies.forEach(function(route) { route(app); });
};

View file

@ -15,6 +15,7 @@ module.exports = {
pollHasUser: false,
pollHasUsersCount: false,
pollParticipate: false,
server: false,
switchTab: false
}
};

View file

@ -1,8 +1,5 @@
import Ember from 'ember';
import { module, test } from 'qunit';
import startApp from '../helpers/start-app';
import Pretender from 'pretender';
import serverPostPolls from '../helpers/server-post-polls';
import { test } from 'qunit';
import moduleForAcceptance from 'croodle/tests/helpers/module-for-acceptance';
import moment from 'moment';
import pageCreateIndex from 'croodle/tests/pages/create/index';
import pageCreateMeta from 'croodle/tests/pages/create/meta';
@ -12,61 +9,10 @@ import pageCreateSettings from 'croodle/tests/pages/create/settings';
import pagePollParticipation from 'croodle/tests/pages/poll/participation';
/* jshint proto: true */
const { run } = Ember;
let application, server;
let serverAvailable = true;
const randomString = function(length) {
return Math.round((Math.pow(36, length + 1) - Math.random() * Math.pow(36, length))).toString(36).slice(1);
};
module('Acceptance | create a poll', {
beforeEach(assert) {
moduleForAcceptance('Acceptance | create a poll', {
beforeEach() {
window.localStorage.setItem('locale', 'en');
let lastCreatedPoll = {};
const pollId = randomString(10);
application = startApp({ assert });
application.__container__.lookup('adapter:application').__proto__.namespace = '';
server = new Pretender();
server.post('/polls',
function(request) {
if (!serverAvailable) {
return [503];
}
let ret = serverPostPolls(request.requestBody, pollId);
lastCreatedPoll = ret[2];
return ret;
}
);
server.get(`/polls/${pollId}`,
function() {
if (!serverAvailable) {
return [503];
}
return [
200,
{ 'Content-Type': 'application/json' },
lastCreatedPoll
];
}
);
moment.locale(
application.__container__.lookup('service:i18n').get('locale')
);
},
afterEach() {
server.shutdown();
run(application, 'destroy');
moment.locale('en');
}
});
@ -187,14 +133,16 @@ test('create a default poll', function(assert) {
);
// simulate temporate server error
serverAvailable = false;
server.post('/polls', undefined, 503);
pageCreateSettings
.save();
andThen(() => {
assert.equal(currentPath(), 'create.settings');
serverAvailable = true;
// simulate server is available again
server.post('/polls');
pageCreateSettings
.save();

View file

@ -1,54 +1,23 @@
import Ember from 'ember';
import { test } from 'qunit';
import jQuery from 'jquery';
import { module, test } from 'qunit';
import startApp from '../helpers/start-app';
import Pretender from 'pretender';
import serverGetPolls from '../helpers/server-get-polls';
import serverPostUsers from '../helpers/server-post-users';
import moduleForAcceptance from 'croodle/tests/helpers/module-for-acceptance';
/* jshint proto: true */
const { run } = Ember;
let application, server;
module('Acceptance | participate in a poll', {
beforeEach(assert) {
moduleForAcceptance('Acceptance | participate in a poll', {
beforeEach() {
window.localStorage.setItem('locale', 'en');
application = startApp({ assert });
application.__container__.lookup('adapter:application').__proto__.namespace = '';
server = new Pretender();
},
afterEach() {
server.shutdown();
run(application, 'destroy');
}
});
test('participate in a default poll', function(assert) {
let id = 'test';
server.logging = true;
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let nextUserId = 1;
server.get(`/polls/${id}`, function() {
return serverGetPolls(
{
id
}, encryptionKey
);
let poll = server.create('poll', {
encryptionKey
});
server.post('/users',
function(request) {
let userId = nextUserId;
nextUserId++;
return serverPostUsers(request.requestBody, userId);
}
);
visit(`/poll/${id}?encryptionKey=${encryptionKey}`).then(function() {
visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`).then(function() {
assert.equal(currentPath(), 'poll.participation', 'poll is redirected to poll.participation');
pollParticipate('Max Meiner', ['yes', 'no']);
@ -84,27 +53,14 @@ test('participate in a default poll', function(assert) {
});
test('participate in a poll using freetext', function(assert) {
let id = 'test2';
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
server.get(`/polls/${id}`,
function() {
return serverGetPolls(
{
id,
let poll = server.create('poll', {
answerType: 'FreeText',
answers: []
}, encryptionKey
);
}
);
server.post('/users',
function(request) {
return serverPostUsers(request.requestBody, 1);
}
);
answers: [],
encryptionKey
});
visit(`/poll/${id}?encryptionKey=${encryptionKey}`).then(function() {
visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`).then(function() {
assert.equal(currentPath(), 'poll.participation');
pollParticipate('Max Manus', ['answer 1', 'answer 2']);
@ -117,26 +73,13 @@ test('participate in a poll using freetext', function(assert) {
});
test('participate in a poll which does not force an answer to all options', function(assert) {
let id = 'test';
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
server.get(`/polls/${id}`,
function() {
return serverGetPolls(
{
id,
let poll = server.create('poll', {
encryptionKey,
forceAnswer: false
}, encryptionKey
);
}
);
server.post('/users',
function(request) {
return serverPostUsers(request.requestBody, 1);
}
);
});
visit(`/poll/${id}/participation?encryptionKey=${encryptionKey}`).then(function() {
visit(`/poll/${poll.id}/participation?encryptionKey=${encryptionKey}`).then(function() {
assert.equal(currentPath(), 'poll.participation');
pollParticipate('Karl Käfer', ['yes', null]);
@ -149,26 +92,13 @@ test('participate in a poll which does not force an answer to all options', func
});
test('participate in a poll which allows anonymous participation', function(assert) {
let id = 'test';
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let poll = server.create('poll', {
anonymousUser: true,
encryptionKey
});
server.get(`/polls/${id}`,
function() {
return serverGetPolls(
{
id,
anonymousUser: true
}, encryptionKey
);
}
);
server.post('/users',
function(request) {
return serverPostUsers(request.requestBody, 1);
}
);
visit(`/poll/${id}/participation?encryptionKey=${encryptionKey}`).then(function() {
visit(`/poll/${poll.id}/participation?encryptionKey=${encryptionKey}`).then(function() {
assert.equal(currentPath(), 'poll.participation');
pollParticipate(null, ['yes', 'no']);
@ -181,26 +111,14 @@ test('participate in a poll which allows anonymous participation', function(asse
});
test('network connectivity errors', function(assert) {
let id = 'test';
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let poll = server.create('poll', {
encryptionKey
});
server.get(`/polls/${id}`,
function() {
return serverGetPolls(
{
id,
anonymousUser: true
}, encryptionKey
);
}
);
server.post('/users',
function() {
return [503]; // server temporary not available
}
);
server.post('/users', undefined, 503);
visit(`/poll/${id}/participation?encryptionKey=${encryptionKey}`).then(function() {
visit(`/poll/${poll.id}/participation?encryptionKey=${encryptionKey}`).then(function() {
assert.equal(currentPath(), 'poll.participation');
pollParticipate('foo bar', ['yes', 'no']);
@ -210,11 +128,7 @@ test('network connectivity errors', function(assert) {
'user gets notified that saving failed'
);
server.post('/users',
function(request) {
return serverPostUsers(request.requestBody, 1);
}
);
server.post('/users');
click('#modal-saving-failed-modal button');
andThen(() => {

View file

@ -1,46 +1,23 @@
import Ember from 'ember';
import { test } from 'qunit';
import jQuery from 'jquery';
import { module, test } from 'qunit';
import startApp from 'croodle/tests/helpers/start-app';
import Pretender from 'pretender';
import serverGetPolls from '../helpers/server-get-polls';
import moduleForAcceptance from 'croodle/tests/helpers/module-for-acceptance';
import moment from 'moment';
/* jshint proto: true */
const { run } = Ember;
let application, server;
module('Acceptance | view evaluation', {
beforeEach(assert) {
moduleForAcceptance('Acceptance | view evaluation', {
beforeEach() {
window.localStorage.setItem('locale', 'en');
application = startApp({ assert });
application.__container__.lookup('adapter:application').__proto__.namespace = '';
server = new Pretender();
},
afterEach() {
server.shutdown();
run(application, 'destroy');
moment.locale('en');
}
});
test('evaluation summary is not present for poll without participants', function(assert) {
let id = 'test';
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
server.get(`/polls/${id}`, function() {
return serverGetPolls(
{
id,
users: []
}, encryptionKey
);
let poll = server.create('poll', {
encryptionKey
});
visit(`/poll/${id}?encryptionKey=${encryptionKey}`);
visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`);
andThen(function() {
assert.equal(currentPath(), 'poll.participation');
@ -53,34 +30,10 @@ test('evaluation summary is not present for poll without participants', function
});
test('evaluation is correct for FindADate', function(assert) {
let id = 'test';
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
server.get(`/polls/${id}`, function() {
return serverGetPolls(
{
id,
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'
}
],
options: [
{ title: '2015-12-12' },
{ title: '2016-01-01' }
],
users: [
{
id: `${id}_0`,
let user1 = server.create('user', {
creationDate: '2015-01-01T00:00:00.000Z',
encryptionKey,
name: 'Maximilian',
selections: [
{
@ -95,11 +48,11 @@ test('evaluation is correct for FindADate', function(assert) {
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
}
],
creationDate: '2015-01-01T00:00:00.000Z'
},
{
id: `${id}_1`,
]
});
let user2 = server.create('user', {
creationDate: '2015-08-01T00:00:00.000Z',
encryptionKey,
name: 'Peter',
selections: [
{
@ -114,15 +67,32 @@ test('evaluation is correct for FindADate', function(assert) {
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
}
],
creationDate: '2015-08-01T00:00:00.000Z'
}
]
}, encryptionKey
);
});
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]
});
visit(`/poll/${id}/evaluation?encryptionKey=${encryptionKey}`);
visit(`/poll/${poll.id}/evaluation?encryptionKey=${encryptionKey}`);
andThen(function() {
assert.equal(currentPath(), 'poll.evaluation');
@ -148,35 +118,10 @@ test('evaluation is correct for FindADate', function(assert) {
});
test('evaluation is correct for MakeAPoll', function(assert) {
let id = 'test';
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
server.get(`/polls/${id}`, function() {
return serverGetPolls(
{
id,
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'
}
],
options: [
{ title: 'first option' },
{ title: 'second option' }
],
pollType: 'MakeAPoll',
users: [
{
id: `${id}_0`,
let user1 = server.create('user', {
creationDate: '2015-01-01T00:00:00.000Z',
encryptionKey,
name: 'Maximilian',
selections: [
{
@ -191,11 +136,11 @@ test('evaluation is correct for MakeAPoll', function(assert) {
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
}
],
creationDate: '2015-01-01T00:00:00.000Z'
},
{
id: `${id}_1`,
]
});
let user2 = server.create('user', {
creationDate: '2015-08-01T00:00:00.000Z',
encryptionKey,
name: 'Peter',
selections: [
{
@ -210,15 +155,33 @@ test('evaluation is correct for MakeAPoll', function(assert) {
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
}
],
creationDate: '2015-08-01T00:00:00.000Z'
}
]
}, encryptionKey
);
});
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]
});
visit(`/poll/${id}/evaluation?encryptionKey=${encryptionKey}`);
visit(`/poll/${poll.id}/evaluation?encryptionKey=${encryptionKey}`);
andThen(function() {
assert.equal(currentPath(), 'poll.evaluation');
@ -263,13 +226,8 @@ test('evaluation is correct for MakeAPoll', function(assert) {
});
test('could open evaluation by tab from poll participation', function(assert) {
let id = 'test';
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
server.get(`/polls/${id}`, function() {
return serverGetPolls(
{
id,
let poll = server.create('poll', {
answers: [
{
type: 'yes',
@ -284,13 +242,15 @@ test('could open evaluation by tab from poll participation', function(assert) {
label: 'No'
}
],
encryptionKey,
options: [
{ title: '2015-12-12' },
{ title: '2016-01-01' }
],
users: [
{
id: `${id}_0`,
server.create('user', {
creationDate: '2015-01-01T00:00:00.000Z',
encryptionKey,
name: 'Maximilian',
selections: [
{
@ -305,11 +265,11 @@ test('could open evaluation by tab from poll participation', function(assert) {
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
}
],
creationDate: '2015-01-01T00:00:00.000Z'
},
{
id: `${id}_1`,
]
}),
server.create('user', {
creationDate: '2015-08-01T00:00:00.000Z',
encryptionKey,
name: 'Peter',
selections: [
{
@ -324,15 +284,12 @@ test('could open evaluation by tab from poll participation', function(assert) {
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Yes'
}
],
creationDate: '2015-08-01T00:00:00.000Z'
}
]
}, encryptionKey
);
})
]
});
visit(`/poll/${id}?encryptionKey=${encryptionKey}`);
visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`);
andThen(function() {
assert.equal(currentPath(), 'poll.participation');

View file

@ -1,40 +1,24 @@
import Ember from 'ember';
import { module, test } from 'qunit';
import startApp from 'croodle/tests/helpers/start-app';
import Pretender from 'pretender';
import serverGetPolls from '../helpers/server-get-polls';
import { test } from 'qunit';
import moduleForAcceptance from 'croodle/tests/helpers/module-for-acceptance';
import pageParticipation from 'croodle/tests/pages/poll/participation';
import moment from 'moment';
/* jshint proto: true */
/* global jstz, moment */
/* global jstz */
const { run } = Ember;
let application, server;
module('Acceptance | view poll', {
beforeEach(assert) {
moduleForAcceptance('Acceptance | view poll', {
beforeEach() {
window.localStorage.setItem('locale', 'en');
application = startApp({ assert });
application.__container__.lookup('adapter:application').__proto__.namespace = '';
server = new Pretender();
},
afterEach() {
server.shutdown();
run(application, 'destroy');
moment.locale('en');
}
});
test('poll url', function(assert) {
let id = 'test';
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz012345789';
let pollUrl = `/poll/${id}?encryptionKey=${encryptionKey}`;
server.get(`/polls/${id}`, function() {
return serverGetPolls({ id }, encryptionKey);
});
let poll = server.create('poll', { encryptionKey });
let pollUrl = `/poll/${poll.id}?encryptionKey=${encryptionKey}`;
visit(pollUrl);
andThen(function() {
@ -56,22 +40,16 @@ test('poll url', function(assert) {
});
test('view a poll with dates', function(assert) {
let id = 'test';
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
server.get(`/polls/${id}`, function() {
return serverGetPolls(
{
id,
let poll = server.create('poll', {
encryptionKey,
options: [
{ title: '2015-12-12' },
{ title: '2016-01-01' }
]
}, encryptionKey
);
});
visit(`/poll/${id}?encryptionKey=${encryptionKey}`).then(function() {
visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`).then(function() {
assert.deepEqual(
pageParticipation.options().labels,
[
@ -83,14 +61,10 @@ test('view a poll with dates', function(assert) {
});
test('view a poll with dates and times', function(assert) {
const id = 'test';
const encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
const timezone = jstz.determine().name();
server.get(`/polls/${id}`, function() {
return serverGetPolls(
{
id,
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let timezone = jstz.determine().name();
let poll = server.create('poll', {
encryptionKey,
isDateTime: true,
options: [
{ title: '2015-12-12T11:11:00.000Z' },
@ -98,11 +72,9 @@ test('view a poll with dates and times', function(assert) {
{ title: '2016-01-01T11:11:00.000Z' }
],
timezone
}, encryptionKey
);
});
visit(`/poll/${id}?encryptionKey=${encryptionKey}`).then(function() {
visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`).then(function() {
assert.deepEqual(
pageParticipation.options().labels,
[
@ -118,33 +90,21 @@ test('view a poll with dates and times', function(assert) {
});
test('view a poll while timezone differs from the one poll got created in and choose local timezone', function(assert) {
const id = 'test';
const encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
const timezoneLocal = jstz.determine().name();
let timezonePoll;
if (timezoneLocal !== 'America/Caracas') {
timezonePoll = 'America/Caracas';
} else {
timezonePoll = 'Europe/Moscow';
}
server.get(`/polls/${id}`, function() {
return serverGetPolls(
{
id,
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let timezoneUser = jstz.determine().name();
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
}, encryptionKey
);
});
visit(`/poll/${id}?encryptionKey=${encryptionKey}`).then(function() {
run.next(function() {
visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`).then(function() {
run.next(() => {
assert.ok(
find('#modal-choose-timezone-modal').is(':visible'),
'user gets asked which timezone should be used'
@ -152,16 +112,16 @@ test('view a poll while timezone differs from the one poll got created in and ch
click('#modal-choose-timezone-modal button.use-local-timezone');
andThen(function() {
andThen(() => {
assert.deepEqual(
pageParticipation.options().labels,
[
moment.tz('2015-12-12T11:11:00.000Z', timezoneLocal).locale('en').format('LLLL'),
moment.tz('2016-01-01T11:11:00.000Z', timezoneLocal).locale('en').format('LLLL')
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')
]
);
run.next(function() {
run.next(() => {
assert.notOk(
find('#modal-choose-timezone-modal').is(':visible'),
'modal is closed'
@ -173,32 +133,20 @@ test('view a poll while timezone differs from the one poll got created in and ch
});
test('view a poll while timezone differs from the one poll got created in and choose poll timezone', function(assert) {
const id = 'test';
const encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
const timezoneLocal = jstz.determine().name();
let timezonePoll;
if (timezoneLocal !== 'America/Caracas') {
timezonePoll = 'America/Caracas';
} else {
timezonePoll = 'Europe/Moscow';
}
server.get(`/polls/${id}`, function() {
return serverGetPolls(
{
id,
let encryptionKey = 'abcdefghijklmnopqrstuvwxyz0123456789';
let timezoneUser = jstz.determine().name();
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
}, encryptionKey
);
});
visit(`/poll/${id}?encryptionKey=${encryptionKey}`).then(function() {
visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`).then(function() {
run.next(function() {
assert.ok(

View file

@ -1,86 +0,0 @@
import Ember from 'ember';
import sjcl from 'sjcl';
export default function(attr, key) {
const defaultAttr = {
id: 'test',
title: 'default title',
description: 'default description',
pollType: 'FindADate',
answerType: 'YesNo',
answers: [
{
type: 'yes',
labelTranslation: 'answerTypes.yes.label',
icon: 'glyphicon glyphicon-thumbs-up',
label: 'Ja'
},
{
type: 'no',
labelTranslation: 'answerTypes.no.label',
icon: 'glyphicon glyphicon-thumbs-down',
label: 'Nein'
}
],
options: [
{
title: '2017-12-24'
},
{
title: '2018-01-01'
}
],
creationDate: '2015-04-01T11:11:11.111Z',
forceAnswer: true,
anonymousUser: false,
isDateTime: false,
users: [],
expirationDate: '',
timezone: '',
version: 'v0.3'
};
const encrypt = function(prop) {
return sjcl.encrypt(
key,
JSON.stringify(prop)
);
};
let data = Ember.merge(defaultAttr, attr);
const users = data.users.map(function(user, index) {
return {
id: `${data.id}_${index}`,
creationDate: encrypt(user.creationDate),
name: encrypt(user.name),
poll: data.id,
selections: encrypt(user.selections),
version: data.version
};
});
return [
200,
{ 'Content-Type': 'application/json' },
JSON.stringify({
poll: {
id: data.id,
title: encrypt(data.title),
description: encrypt(data.description),
pollType: encrypt(data.pollType),
answerType: encrypt(data.answerType),
answers: encrypt(data.answers),
options: encrypt(data.options),
creationDate: encrypt(data.creationDate),
forceAnswer: encrypt(data.forceAnswer),
anonymousUser: encrypt(data.anonymousUser),
isDateTime: encrypt(data.isDateTime),
timezone: encrypt(data.timezone),
expirationDate: encrypt(data.expirationDate),
users,
version: data.version
}
})
];
}

View file

@ -1,9 +0,0 @@
export default function(requestBody, id) {
let poll = JSON.parse(requestBody);
poll.poll.id = id;
return [
200,
{ 'Content-Type': 'application/json' },
JSON.stringify(poll)
];
}

View file

@ -1,13 +0,0 @@
export default function(requestBody, id) {
if (id === null) {
id = 1;
}
let poll = JSON.parse(requestBody);
poll.user.id = id;
return [
200,
{ 'Content-Type': 'application/json' },
JSON.stringify(poll)
];
}

View file

@ -1,6 +1,5 @@
import Ember from 'ember';
import { module, test } from 'qunit';
import startApp from '../helpers/start-app';
import { test } from 'qunit';
import moduleForAcceptance from 'croodle/tests/helpers/module-for-acceptance';
import moment from 'moment';
import pageCreateIndex from 'croodle/tests/pages/create/index';
import pageCreateMeta from 'croodle/tests/pages/create/meta';
@ -10,19 +9,10 @@ import pageCreateSettings from 'croodle/tests/pages/create/settings';
import pagePollParticipation from 'croodle/tests/pages/poll/participation';
/* jshint proto: true */
let application;
module('Integration', {
beforeEach(assert) {
moduleForAcceptance('Integration', {
beforeEach() {
window.localStorage.setItem('locale', 'en');
application = startApp({ assert });
moment.locale(
application.__container__.lookup('service:i18n').get('locale')
);
},
afterEach() {
Ember.run(application, 'destroy');
moment.locale('en');
}
});

View file

@ -1,50 +1,49 @@
import Ember from 'ember';
import { module, test } from 'qunit';
import startApp from 'croodle/tests/helpers/start-app';
import { test } from 'qunit';
import moduleForAcceptance from 'croodle/tests/helpers/module-for-acceptance';
import moment from 'moment';
import pagePollParticipation from 'croodle/tests/pages/poll/participation';
/* global moment */
/* jshint proto: true */
let application;
module('Integration | legacy support', {
beforeEach(assert) {
moduleForAcceptance('Integration | legacy support', {
beforeEach() {
window.localStorage.setItem('locale', 'en');
application = startApp({ assert });
moment.locale(
application.__container__.lookup('service:i18n').get('locale')
);
},
afterEach() {
Ember.run(application, 'destroy');
moment.locale('en');
}
});
test('show a default poll created with v0.3.0', function(assert) {
const id = 'JlHpRs0Pzi';
const encryptionKey = '5MKFuNTKILUXw6RuqkAw6ooZw4k3mWWx98ZQw8vH';
const timezone = 'Europe/Berlin';
visit(`/poll/${id}?encryptionKey=${encryptionKey}`);
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}`);
andThen(function() {
assert.equal(currentPath(), 'poll.participation');
assert.equal(
pagePollParticipation.title,
'default poll created with v0.3.0'
);
assert.equal(
pagePollParticipation.description,
'used for integration tests'
);
assert.deepEqual(
pagePollParticipation.options().labels,
[
moment.tz('2015-12-24T17:00:00.000Z', timezone).format('LLLL'),
moment.tz('2015-12-24T19:00:00.000Z', timezone).format('LT'),
moment.tz('2015-12-31T22:59:00.000Z', timezone).format('LLLL')
moment('2015-12-24T17:00:00.000Z').format('LLLL'),
moment('2015-12-24T19:00:00.000Z').format('LT'),
moment('2015-12-31T22:59:00.000Z').format('LLLL')
]
);
assert.deepEqual(
@ -69,14 +68,6 @@ test('show a default poll created with v0.3.0', function(assert) {
t('answerTypes.no.label')
]
);
pollHasUser(assert,
'Lothar Hermann',
[
t('answerTypes.maybe.label'),
t('answerTypes.yes.label'),
t('answerTypes.no.label')
]
);
switchTab('participation');
@ -101,21 +92,32 @@ test('show a default poll created with v0.3.0', function(assert) {
});
});
test('find a poll using free text created with v0.3.0', function(assert) {
const id = 'PjW3XwbuRc';
const encryptionKey = 'Rre6dAGOYLW9gYKOP4LhX7Qwfhe5Th3je0uKDtyy';
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/${id}?encryptionKey=${encryptionKey}`);
visit(`/poll/${poll.id}?encryptionKey=${encryptionKey}`);
andThen(function() {
assert.equal(
pagePollParticipation.title,
'Which cake for birthday?'
);
assert.equal(
pagePollParticipation.description,
''
);
assert.deepEqual(
pagePollParticipation.options().labels,
[

View file

@ -0,0 +1,35 @@
import { module, test } from 'qunit';
import { startMirage } from 'croodle/initializers/ember-cli-mirage';
import sjcl from 'sjcl';
import Ember from 'ember';
const { get } = Ember;
module('Integration | Mirage api mocking', {
beforeEach() {
this.server = startMirage();
},
afterEach() {
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'
});
assert.equal(JSON.parse(sjcl.decrypt(encryptionKey, get(user, 'name'))), 'foo');
});

185
yarn.lock
View file

@ -1164,7 +1164,7 @@ bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
version "4.11.7"
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.7.tgz#ddb048e50d9482790094c13eb3fcfc833ce7ab46"
body-parser@^1.12.3, body-parser@^1.2.0:
body-parser@^1.12.3:
version "1.17.2"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.17.2.tgz#f8892abc8f9e627d42aedafbca66bf5ab99104ee"
dependencies:
@ -1420,7 +1420,7 @@ broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1, broccoli-funnel@^1.0.6:
symlink-or-copy "^1.0.0"
walk-sync "^0.3.1"
broccoli-funnel@^1.1.0, broccoli-funnel@^1.2.0:
broccoli-funnel@^1.0.2, broccoli-funnel@^1.1.0, broccoli-funnel@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-1.2.0.tgz#cddc3afc5ff1685a8023488fff74ce6fb5a51296"
dependencies:
@ -1489,7 +1489,7 @@ broccoli-lint-eslint@^3.3.0:
lodash.defaultsdeep "^4.6.0"
md5-hex "^2.0.0"
broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.1, broccoli-merge-trees@^1.1.2:
broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.0, broccoli-merge-trees@^1.1.1, broccoli-merge-trees@^1.1.2:
version "1.2.4"
resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-1.2.4.tgz#a001519bb5067f06589d91afa2942445a2d0fdb5"
dependencies:
@ -1516,7 +1516,7 @@ broccoli-middleware@^1.0.0:
handlebars "^4.0.4"
mime "^1.2.11"
broccoli-persistent-filter@^1.0.0, broccoli-persistent-filter@^1.4.0, broccoli-persistent-filter@^1.4.2:
broccoli-persistent-filter@^1.0.0, broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.4.0, broccoli-persistent-filter@^1.4.2:
version "1.4.2"
resolved "https://registry.yarnpkg.com/broccoli-persistent-filter/-/broccoli-persistent-filter-1.4.2.tgz#17af1278a25ff2556f9d7d23e115accfad3a7ce7"
dependencies:
@ -1623,7 +1623,7 @@ broccoli-stew@^1.2.0, broccoli-stew@^1.3.3:
rsvp "^3.0.16"
walk-sync "^0.3.0"
broccoli-stew@^1.4.0:
broccoli-stew@^1.4.0, broccoli-stew@^1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/broccoli-stew/-/broccoli-stew-1.5.0.tgz#d7af8c18511dce510e49d308a62e5977f461883c"
dependencies:
@ -1642,6 +1642,13 @@ broccoli-stew@^1.4.0:
symlink-or-copy "^1.1.8"
walk-sync "^0.3.0"
broccoli-string-replace@^0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/broccoli-string-replace/-/broccoli-string-replace-0.1.2.tgz#1ed92f85680af8d503023925e754e4e33676b91f"
dependencies:
broccoli-persistent-filter "^1.1.5"
minimatch "^3.0.3"
broccoli-uglify-sourcemap@^1.0.0:
version "1.5.1"
resolved "https://registry.yarnpkg.com/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-1.5.1.tgz#9fd2e87f1c177b11a758e73c3a11d6a03d90d086"
@ -2334,13 +2341,6 @@ core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
cors@^2.5.3:
version "2.8.4"
resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.4.tgz#2bd381f2eb201020105cd50ea59da63090694686"
dependencies:
object-assign "^4"
vary "^1"
crc32-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-2.0.0.tgz#e3cdd3b4df3168dd74e3de3fbbcb7b297fe908f4"
@ -3002,6 +3002,25 @@ ember-cli-lodash-subset@^1.0.11, ember-cli-lodash-subset@^1.0.7:
version "1.0.12"
resolved "https://registry.yarnpkg.com/ember-cli-lodash-subset/-/ember-cli-lodash-subset-1.0.12.tgz#af2e77eba5dcb0d77f3308d3a6fd7d3450f6e537"
ember-cli-mirage@^0.3.4:
version "0.3.4"
resolved "https://registry.yarnpkg.com/ember-cli-mirage/-/ember-cli-mirage-0.3.4.tgz#eeb9d6e02c0c49c81915762178bab9a42d86ada8"
dependencies:
broccoli-funnel "^1.0.2"
broccoli-merge-trees "^1.1.0"
broccoli-stew "^1.5.0"
chalk "^1.1.1"
ember-cli-babel "^5.1.7"
ember-cli-node-assets "^0.1.4"
ember-get-config "0.2.1"
ember-inflector "^2.0.0"
ember-lodash "^4.17.3"
exists-sync "0.0.3"
fake-xml-http-request "^1.4.0"
faker "^3.0.0"
pretender "^1.4.2"
route-recognizer "^0.2.3"
ember-cli-moment-shim@3.3.3:
version "3.3.3"
resolved "https://registry.yarnpkg.com/ember-cli-moment-shim/-/ember-cli-moment-shim-3.3.3.tgz#f0609c6ff606287c3eeee717163310331e0e9397"
@ -3018,7 +3037,7 @@ ember-cli-moment-shim@3.3.3:
moment "^2.18.1"
moment-timezone "~0.5.11"
ember-cli-node-assets@^0.1.2:
ember-cli-node-assets@^0.1.2, ember-cli-node-assets@^0.1.4:
version "0.1.6"
resolved "https://registry.yarnpkg.com/ember-cli-node-assets/-/ember-cli-node-assets-0.1.6.tgz#6488a2949048c801ad6d9e33753c7bce32fc1146"
dependencies:
@ -3060,10 +3079,6 @@ ember-cli-preprocess-registry@^3.1.0:
process-relative-require "^1.0.0"
silent-error "^1.0.0"
ember-cli-pretender@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/ember-cli-pretender/-/ember-cli-pretender-0.6.0.tgz#7525ffa3081b8ba7b0791f24f1f229d83e87bd1e"
ember-cli-qunit@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/ember-cli-qunit/-/ember-cli-qunit-4.0.0.tgz#1f0022469a5bd64f627b8102880a25e94e533a3b"
@ -3326,6 +3341,13 @@ ember-factory-for-polyfill@^1.1.0:
ember-cli-babel "^5.1.7"
ember-cli-version-checker "^1.2.0"
ember-get-config@0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/ember-get-config/-/ember-get-config-0.2.1.tgz#a1325cceefcb4534c78fc6ccb2be87a3feda6817"
dependencies:
broccoli-file-creator "^1.1.1"
ember-cli-babel "^5.1.6"
ember-getowner-polyfill@^1.0.1:
version "1.2.3"
resolved "https://registry.yarnpkg.com/ember-getowner-polyfill/-/ember-getowner-polyfill-1.2.3.tgz#ea70f4a48b1c05b91056371d1878bbafe018222e"
@ -3369,6 +3391,17 @@ ember-load-initializers@^1.0.0:
dependencies:
ember-cli-babel "^6.0.0-beta.7"
ember-lodash@^4.17.3:
version "4.17.5"
resolved "https://registry.yarnpkg.com/ember-lodash/-/ember-lodash-4.17.5.tgz#bda557402facae144567d1ef530b3de7c38bcde1"
dependencies:
broccoli-debug "^0.6.1"
broccoli-funnel "^1.1.0"
broccoli-merge-trees "^2.0.0"
broccoli-string-replace "^0.1.1"
ember-cli-babel "^6.4.1"
lodash-es "^4.17.4"
ember-macro-helpers@^0.14.1:
version "0.14.5"
resolved "https://registry.yarnpkg.com/ember-macro-helpers/-/ember-macro-helpers-0.14.5.tgz#52b267db835c2dab25badfd44187e67d1f9c9e2c"
@ -3932,39 +3965,6 @@ express@^4.10.7, express@^4.12.3:
utils-merge "1.0.0"
vary "~1.1.0"
express@^4.8.5:
version "4.15.3"
resolved "https://registry.yarnpkg.com/express/-/express-4.15.3.tgz#bab65d0f03aa80c358408972fc700f916944b662"
dependencies:
accepts "~1.3.3"
array-flatten "1.1.1"
content-disposition "0.5.2"
content-type "~1.0.2"
cookie "0.3.1"
cookie-signature "1.0.6"
debug "2.6.7"
depd "~1.1.0"
encodeurl "~1.0.1"
escape-html "~1.0.3"
etag "~1.8.0"
finalhandler "~1.0.3"
fresh "0.5.0"
merge-descriptors "1.0.1"
methods "~1.1.2"
on-finished "~2.3.0"
parseurl "~1.3.1"
path-to-regexp "0.1.7"
proxy-addr "~1.1.4"
qs "6.4.0"
range-parser "~1.2.0"
send "0.15.3"
serve-static "1.12.3"
setprototypeof "1.0.3"
statuses "~1.3.1"
type-is "~1.6.15"
utils-merge "1.0.0"
vary "~1.1.1"
extend@3:
version "3.0.1"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444"
@ -3995,6 +3995,14 @@ eyes@0.1.x:
version "0.1.8"
resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0"
fake-xml-http-request@^1.4.0, fake-xml-http-request@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/fake-xml-http-request/-/fake-xml-http-request-1.6.0.tgz#bd0ac79ae3e2660098282048a12c730a6f64d550"
faker@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/faker/-/faker-3.1.0.tgz#0f908faf4e6ec02524e54a57e432c5c013e08c9f"
fast-levenshtein@~2.0.4:
version "2.0.6"
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
@ -4080,18 +4088,6 @@ finalhandler@~1.0.0:
statuses "~1.3.1"
unpipe "~1.0.0"
finalhandler@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.3.tgz#ef47e77950e999780e86022a560e3217e0d0cc89"
dependencies:
debug "2.6.7"
encodeurl "~1.0.1"
escape-html "~1.0.3"
on-finished "~2.3.0"
parseurl "~1.3.1"
statuses "~1.3.1"
unpipe "~1.0.0"
find-index@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/find-index/-/find-index-1.1.0.tgz#53007c79cd30040d6816d79458e8837d5c5705ef"
@ -4833,10 +4829,6 @@ ipaddr.js@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.3.0.tgz#1e03a52fdad83a8bbb2b25cbf4998b4cffcd3dec"
ipaddr.js@1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.4.0.tgz#296aca878a821816e5b85d0a285a99bcff4582f0"
is-arrayish@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
@ -5319,6 +5311,10 @@ locate-path@^2.0.0:
p-locate "^2.0.0"
path-exists "^3.0.0"
lodash-es@^4.17.4:
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.4.tgz#dcc1d7552e150a0640073ba9cb31d70f032950e7"
lodash._arraycopy@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz#76e7b7c1f1fb92547374878a562ed06a3e50f6e1"
@ -5848,10 +5844,6 @@ node-notifier@^5.0.1:
shellwords "^0.1.0"
which "^1.2.12"
node-phpcgi@^0.3.5:
version "0.3.7"
resolved "https://registry.yarnpkg.com/node-phpcgi/-/node-phpcgi-0.3.7.tgz#277dc38b6f072a993a99d94942c63fb80ed080b5"
node-pre-gyp@^0.6.36:
version "0.6.36"
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz#db604112cb74e0d477554e9b505b17abddfab786"
@ -5952,7 +5944,7 @@ object-assign@4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0"
object-assign@4.1.1, object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0:
object-assign@4.1.1, object-assign@^4.0.1, object-assign@^4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
@ -6244,6 +6236,13 @@ preserve@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
pretender@^1.4.2:
version "1.5.1"
resolved "https://registry.yarnpkg.com/pretender/-/pretender-1.5.1.tgz#bd9098c03d39c3bc7dcb84a28ee27e096e2e32b8"
dependencies:
fake-xml-http-request "^1.6.0"
route-recognizer "^0.3.3"
printf@^0.2.3:
version "0.2.5"
resolved "https://registry.yarnpkg.com/printf/-/printf-0.2.5.tgz#c438ca2ca33e3927671db4ab69c0e52f936a4f0f"
@ -6299,13 +6298,6 @@ proxy-addr@~1.1.3:
forwarded "~0.1.0"
ipaddr.js "1.3.0"
proxy-addr@~1.1.4:
version "1.1.5"
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.5.tgz#71c0ee3b102de3f202f3b64f608d173fcba1a918"
dependencies:
forwarded "~0.1.0"
ipaddr.js "1.4.0"
prr@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a"
@ -6795,6 +6787,14 @@ rollup@^0.41.4:
dependencies:
source-map-support "^0.4.0"
route-recognizer@^0.2.3:
version "0.2.10"
resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.2.10.tgz#024b2283c2e68d13a7c7f5173a5924645e8902df"
route-recognizer@^0.3.3:
version "0.3.3"
resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.3.3.tgz#1d365e27fa6995e091675f7dc940a8c00353bd29"
rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.2.1:
version "3.5.0"
resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.5.0.tgz#a62c573a4ae4e1dfd0697ebc6242e79c681eaa34"
@ -6926,24 +6926,6 @@ send@0.15.1:
range-parser "~1.2.0"
statuses "~1.3.1"
send@0.15.3:
version "0.15.3"
resolved "https://registry.yarnpkg.com/send/-/send-0.15.3.tgz#5013f9f99023df50d1bd9892c19e3defd1d53309"
dependencies:
debug "2.6.7"
depd "~1.1.0"
destroy "~1.0.4"
encodeurl "~1.0.1"
escape-html "~1.0.3"
etag "~1.8.0"
fresh "0.5.0"
http-errors "~1.6.1"
mime "1.3.4"
ms "2.0.0"
on-finished "~2.3.0"
range-parser "~1.2.0"
statuses "~1.3.1"
serve-static@1.12.1:
version "1.12.1"
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.12.1.tgz#7443a965e3ced647aceb5639fa06bf4d1bbe0039"
@ -6953,15 +6935,6 @@ serve-static@1.12.1:
parseurl "~1.3.1"
send "0.15.1"
serve-static@1.12.3:
version "1.12.3"
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.12.3.tgz#9f4ba19e2f3030c547f8af99107838ec38d5b1e2"
dependencies:
encodeurl "~1.0.1"
escape-html "~1.0.3"
parseurl "~1.3.1"
send "0.15.3"
set-blocking@^2.0.0, set-blocking@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
@ -7781,7 +7754,7 @@ vargs@0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/vargs/-/vargs-0.1.0.tgz#6b6184da6520cc3204ce1b407cac26d92609ebff"
vary@^1, vary@~1.1.0, vary@~1.1.1:
vary@~1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37"