Skip to content
This repository was archived by the owner on Dec 14, 2023. It is now read-only.

Commit fff3af7

Browse files
committed
Add unit tests for event form
1 parent 2e640a8 commit fff3af7

File tree

60 files changed

+1281
-820
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+1281
-820
lines changed

build/utils.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,6 @@ exports.cssLoaders = function (options) {
4949
css: generateLoaders(),
5050
postcss: generateLoaders(),
5151
less: generateLoaders('less'),
52-
sass: generateLoaders('sass', { indentedSyntax: true }),
53-
scss: generateLoaders('sass'),
5452
stylus: generateLoaders('stylus'),
5553
styl: generateLoaders('stylus')
5654
}

build/webpack.base.conf.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ module.exports = {
3939
},
4040
{
4141
test: /\.less$/,
42-
use: [{
42+
use: [
43+
{
4344
loader: 'style-loader', // creates style nodes from JS strings
4445
}, {
4546
loader: 'css-loader', // translates CSS into CommonJS

build/webpack.test.conf.js

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,6 @@ const webpackConfig = smp.wrap(merge(baseConfig, {
1414
rules: utils.styleLoaders(),
1515
},
1616
devtool: '#inline-source-map',
17-
resolveLoader: {
18-
alias: {
19-
// necessary to to make lang="scss" work in test when using vue-loader's ?inject option
20-
// see discussion at https://github.com/vuejs/vue-loader/issues/724
21-
'scss-loader': 'sass-loader',
22-
},
23-
},
2417
plugins: [
2518
new webpack.DefinePlugin({
2619
'process.env': require('../config/test.env'),

package.json

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"start": "node build/dev-server.js",
99
"build": "node build/build.js",
1010
"unit": "cross-env BABEL_ENV=test karma start test/unit/karma.conf.js --single-run",
11+
"karma": "cross-env BABEL_ENV=test karma start test/unit/karma.conf.js",
1112
"e2e": "wdio wdio.conf.js",
1213
"i18n": "I18N_DEBUG=true yarn e2e-with-mocks",
1314
"e2e-with-mocks": "concurrently --kill-others --success first \"yarn mock-server > /dev/null\" \"TARGET_URL_BASE=http://localhost:8080/ wdio wdio.conf.js\" \"yarn start\" ",
@@ -59,7 +60,7 @@
5960
"babel-preset-stage-2": "^6.22.0",
6061
"babel-register": "^6.22.0",
6162
"body-parser": "^1.17.2",
62-
"chai": "^3.5.0",
63+
"chai": "^4.2.0",
6364
"chalk": "^1.1.3",
6465
"concurrently": "^3.4.0",
6566
"connect-history-api-fallback": "^1.3.0",
@@ -83,13 +84,13 @@
8384
"http-proxy-middleware": "^0.17.3",
8485
"inject-loader": "^3.0.0",
8586
"json-server": "^0.10.1",
86-
"karma": "^1.4.1",
87+
"karma": "^4.1.0",
8788
"karma-chrome-launcher": "^2.1.1",
88-
"karma-coverage": "^1.1.1",
89+
"karma-coverage": "^1.1.2",
8990
"karma-mocha": "^1.3.0",
9091
"karma-phantomjs-launcher": "^1.0.2",
9192
"karma-phantomjs-shim": "^1.4.0",
92-
"karma-sinon-chai": "^1.3.1",
93+
"karma-sinon-chai": "^2.0.2",
9394
"karma-sourcemap-loader": "^0.3.7",
9495
"karma-spec-reporter": "0.0.30",
9596
"karma-webpack": "^2.0.2",
@@ -107,14 +108,14 @@
107108
"rimraf": "^2.6.0",
108109
"semver": "^5.3.0",
109110
"shelljs": "^0.7.6",
110-
"sinon": "^2.1.0",
111-
"sinon-chai": "^2.8.0",
111+
"sinon": "^7.3.2",
112+
"sinon-chai": "^3.2.0",
112113
"spa-http-server": "^0.9.0",
113114
"speed-measure-webpack-plugin": "^1.3.1",
114115
"timeshift-js": "^1.0.1",
115116
"url-loader": "^0.5.8",
116117
"vue-loader": "^11.3.4",
117-
"vue-style-loader": "^2.0.5",
118+
"vue-style-loader": "^4.0.1",
118119
"vue-template-compiler": "^2.2.6",
119120
"vue-unit-helper": "^1.0.9",
120121
"wdio-mocha-framework": "^0.5.11",

src/dashboard/cd-dashboard-events.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@
7979
hasDojos() {
8080
return Object.keys(this.dojos).length > 0;
8181
},
82-
82+
8383
firstDojo() {
8484
return this.hasDojos ? this.dojos[this.dojoAdmins[0].dojoId] : {};
8585
},
@@ -165,7 +165,7 @@
165165
max-width: 824px;
166166
margin: 0 auto;
167167
}
168-
168+
169169
&__list-filler {
170170
background: @cd-very-light-grey;
171171
height: 90px;

src/events/cd-event-form.vue

Lines changed: 105 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,37 @@
66
<div class="cd-event-form">
77
<h3 class="cd-event-form__header">{{ `${$t('Create an event for')} ${dojo.name}` }}</h3>
88
<form @submit="save">
9+
10+
<div v-if="submitError">
11+
<h3 class="text-danger">{{ $t('There was an error processing this request. Please try again or contact support') }}</h3>
12+
</div>
913
<h4 class="cd-event__section-title">{{ $t('Event Title') }}</h4>
1014
<p class="text-danger" v-show="errors.has('name:required')">{{ $t('Title is required') }}</p>
1115
<input type="text" name="name" v-model="name" class="form-control" data-vv-name="name" v-validate="'required'" data-vv-validate-on="blur" :placeholder="$t('e.g. October Dojo')">
1216

1317
<div class="cd-event-form__location">
1418
<!-- is the text relevant when it's been modified? -->
1519
<!-- what about previous event information, default back to Dojo's or previous event ? -->
16-
{{ $t('This event uses the Dojo address.') }}
20+
{{ $t('This event uses the address.') }}:
1721
<span v-show="!addressIsVisible">{{ formattedAddress }}</span>
1822
<i class="fa fa-pencil" @click="addressIsVisible = true" v-show="!addressIsVisible"></i>
1923
<i class="fa fa-times" @click="addressIsVisible = false" v-show="addressIsVisible"></i>
2024
<div v-if="addressIsVisible">
21-
<input type="text" name="city" v-model="city.name" class="form-control">
25+
<input type="text" name="city" v-model="city.nameWithHierarchy" class="form-control">
2226
<textarea name="address" v-model="address" rows="3" class="form-control"></textarea>
2327
</div>
2428
</div>
2529

2630
<div class="cd-event-form__description">
27-
{{ $t('This event uses the previous event description') }}
31+
{{ $t('This event uses the description') }}:
2832
<span v-show="!descriptionIsVisible">{{ truncatedDescription }}</span>
2933
<i class="fa fa-pencil" @click="descriptionIsVisible = true" v-show="!descriptionIsVisible"></i>
3034
<i class="fa fa-times" @click="descriptionIsVisible = false" v-show="descriptionIsVisible"></i>
35+
36+
<p class="text-danger" v-show="errors.has('description:required')">{{ $t('Description is required') }}</p>
37+
<input type="hidden" v-model="description" v-validate="'required'" name="description" />
3138
<div v-if="descriptionIsVisible">
32-
<VueTrix v-model="description" />
39+
<VueTrix v-model="description" ref="trixEditor" />
3340
</div>
3441
</div>
3542

@@ -157,30 +164,76 @@
157164
city: {},
158165
address: '',
159166
dojo: {},
160-
latestEvent: {},
167+
latestEvent: undefined,
161168
// state
162169
addressIsVisible: false,
163170
descriptionIsVisible: false,
164171
public: true,
165-
// TODO: generate start/end based on previous event
166172
startingTime: '09:00',
167173
finishTime: '11:00',
168174
// TODO: momentjs get month of current locale
169-
eventDate: `${moment().year()}-${moment().month() + 1}-${moment().date()}`,
175+
eventDate: moment().format('YYYY-MM-DD'),
170176
sendEmails: true,
177+
submitError: false,
171178
};
172179
},
173180
methods: {
174181
async populateForm() {
175-
if (this.latestEvent !== undefined) {
182+
if (this.latestEvent) {
183+
await this.populateCityFromLatestEvent();
184+
await this.populateDatesAndTimesFromLatestEvent();
185+
await this.populateTicketQuantitiesFromLatestEvent();
186+
176187
this.description = this.latestEvent.description;
177-
this.city = this.latestEvent.city;
178188
this.address = this.latestEvent.address;
179189
} else {
180-
// TODO: use dojo description?
181-
// this.description = 'standard desc';
190+
this.description = this.dojo.notes;
182191
this.address = this.dojo.address1;
183-
this.city = this.dojo.city;
192+
this.city = { nameWithHierarchy: this.dojo.city.name };
193+
}
194+
},
195+
async populateCityFromLatestEvent() {
196+
// format the event city correctly :(
197+
const city = this.latestEvent.city;
198+
if (city && city.toponymName) {
199+
city.nameWithHierarchy = city.toponymName;
200+
delete city.toponymName;
201+
}
202+
this.city = city;
203+
},
204+
async populateDatesAndTimesFromLatestEvent() {
205+
const startDate = moment.utc(this.latestEvent.startTime);
206+
let newDate = startDate.add(7, 'days');
207+
const inPast = moment().diff(newDate, 'days') > 0;
208+
209+
if (inPast) {
210+
const neededDay = startDate.day();
211+
newDate = (moment().isoWeekday() <= neededDay) ?
212+
moment().isoWeekday(neededDay) :
213+
moment().add(1, 'weeks').isoWeekday(neededDay);
214+
}
215+
216+
this.eventDate = newDate.format('YYYY-MM-DD');
217+
218+
const endDate = moment.utc(this.latestEvent.endTime);
219+
this.startingTime = startDate.format('HH:mm');
220+
this.finishTime = endDate.format('HH:mm');
221+
},
222+
async populateTicketQuantitiesFromLatestEvent() {
223+
if (this.latestEvent.sessions && this.latestEvent.sessions.length > 0) {
224+
// If there are any sessions for the last event just take the first one.
225+
// Any event that has more than one session was created using the old form
226+
// and it is unlikely to map to the new form structure
227+
const previousTickets = this.latestEvent.sessions[0].tickets;
228+
const youthTickets = previousTickets.find(ticket => ticket.name === 'Youth');
229+
const mentorTickets = previousTickets.find(ticket => ticket.name === 'Mentor');
230+
231+
if (youthTickets !== undefined) {
232+
this.$refs.youthTickets.setQuantity(youthTickets.quantity);
233+
}
234+
if (mentorTickets !== undefined) {
235+
this.$refs.mentorTickets.setQuantity(mentorTickets.quantity);
236+
}
184237
}
185238
},
186239
async validateForm() {
@@ -191,27 +244,37 @@
191244
return false;
192245
}
193246
},
247+
194248
async save(e) {
195249
e.preventDefault();
196250
const valid = await this.validateForm();
197251
if (valid) {
198-
await EventsService.v3.create({
199-
name: this.name,
200-
description: this.description,
201-
city: this.city,
202-
address: this.address,
203-
dates: [{ startTime: this.startTime, endTime: this.endTime }],
204-
type: 'one-off',
205-
status: 'saved',
206-
public: this.public,
207-
useDojoAddress: false,
208-
ticketApproval: false,
209-
notifyOnApplicant: false,
210-
country: this.dojo.country,
211-
sessions: this.sessions,
212-
dojoId: this.dojo.id,
213-
});
252+
try {
253+
const foo = await EventsService.v3.create({
254+
name: this.name,
255+
description: this.description,
256+
city: this.city,
257+
address: this.address,
258+
dates: [{ startTime: this.startTime, endTime: this.endTime }],
259+
// type: 'one-off',
260+
status: 'published',
261+
public: this.public,
262+
useDojoAddress: false,
263+
ticketApproval: false,
264+
notifyOnApplicant: false,
265+
// country: this.dojo.country,
266+
// sessions: this.sessions,
267+
dojoId: this.dojo.id,
268+
});
269+
270+
console.log(foo);
271+
this.$router.push({ name: 'DojoDetailsId', params: { id: this.dojo.id } });
272+
} catch (err) {
273+
this.submitError = true;
274+
}
214275
}
276+
277+
// TODO: forward to event page
215278
},
216279
217280
toggle(field) { // eslint-disable-line no-unused-vars
@@ -221,16 +284,23 @@
221284
},
222285
computed: {
223286
truncatedDescription() {
224-
return this.description.substring(0, 20);
287+
if (this.description) {
288+
const str = this.description.replace(/<[^<|>]+?>/gi, ' ');
289+
const words = str.split(' ').filter(word => word !== '');
290+
return `${words.slice(0, 6).join(' ')}... `;
291+
}
292+
return '';
225293
},
226294
formattedAddress() {
227-
return `${this.address.substring(0, 15)}... ${this.city.name}`;
295+
const str = this.address.replace(/<[^<|>]+?>/gi, ' ');
296+
const words = str.split(' ').filter(word => word !== '');
297+
return `${words.slice(0, 5).join(' ')}... ${this.city.nameWithHierarchy}`;
228298
},
229299
tickets() {
230300
return [this.$refs.youthTickets, this.$refs.mentorTickets];
231301
},
232302
startTime() {
233-
const startDay = moment.utc(this.eventDate);
303+
const startDay = moment.utc(this.eventDate, 'YYYY-MM-DD');
234304
const startingTimeElements = this.startingTime.split(':');
235305
startDay.hours(startingTimeElements[0]);
236306
startDay.minutes(startingTimeElements[1]);
@@ -246,8 +316,9 @@
246316
sessions() {
247317
const tickets = this.tickets.map(t => t.createTicket());
248318
return [{
249-
name: 'General',
250-
description: 'General Session',
319+
// TODO: this needs to be translated?
320+
name: 'Dojo',
321+
description: 'Dojo Session',
251322
tickets,
252323
}];
253324
},
@@ -256,14 +327,8 @@
256327
// TODO: if eventId in params load event, otherwise populate defaults
257328
258329
// TODO: get previous event, use that info to populate defaults
259-
260-
// const query = { status: 'published' };
261-
// query.afterDate = moment().unix();
262-
// query.utcOffset = moment().utcOffset();
263-
// query.pageSize = 1;
264330
const { dojoId } = this.$route.params;
265331
266-
// const query = { pageSize: 1 };
267332
const latestEvent = await EventsService.v3.get(
268333
dojoId,
269334
{
@@ -273,10 +338,10 @@
273338
page: 1,
274339
orderBy: 'startTime',
275340
direction: 'desc',
341+
related: 'sessions.tickets',
276342
},
277343
});
278344
279-
// TODO: will this error when no events
280345
this.latestEvent = latestEvent.body.results[0];
281346
this.dojo = (await DojosService.getDojoById(dojoId)).body;
282347
this.populateForm();

src/events/form/form-tickets.vue

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,9 @@
44
<label class="cd-form-ticket__label" for="quantity">{{ $t(label) }}</label>
55
</div>
66
<div class="col-sm-2">
7-
<input type="number"
8-
class="form-control"
9-
v-model="quantity"
10-
name="quantity" />
7+
<input type="number" class="form-control" v-model="quantity" name="quantity" />
118
</div>
129
</div>
13-
1410
</template>
1511
<script>
1612
export default {
@@ -33,6 +29,7 @@ export default {
3329
quantity: null,
3430
};
3531
},
32+
3633
methods: {
3734
createTicket() {
3835
return {
@@ -41,6 +38,9 @@ export default {
4138
quantity: this.quantity,
4239
};
4340
},
41+
setQuantity(q) {
42+
this.quantity = q;
43+
},
4444
},
4545
created() {
4646
this.quantity = this.defaultQuantity;

0 commit comments

Comments
 (0)