UNPKG

13.1 kBJavaScriptView Raw
1/* eslint-env mocha */
2'use strict';
3
4let assert = require('assert');
5let fs = require('fs');
6let docker = process.env.DOCKER;
7var request = require('supertest');
8
9module.exports = function(app, template, hook) {
10 let Thread = require('formio-workers/Thread');
11
12 /**
13 * Unit tests for various parts of the platform.
14 */
15 describe('Nunjucks Rendering', function() {
16 it('Should render a string with tokens', function(done) {
17 new Thread(Thread.Tasks.nunjucks).start({
18 render: '{{ data.firstName }} {{ data.lastName }}',
19 context: {
20 data: {
21 firstName: 'Travis',
22 lastName: 'Tidwell'
23 }
24 },
25 filters: {
26 test: function(string, param) {
27 var retVal = this.env.params.form + ' : ' + string;
28 if (param) {
29 retVal += ' : ' + param;
30 }
31 return retVal;
32 }
33 }
34 })
35 .then(test => {
36 assert.equal(test, 'Travis Tidwell');
37 done();
38 })
39 .catch(done);
40 });
41
42 it('Should timeout if someone puts bad code in the template', function(done) {
43 new Thread(Thread.Tasks.nunjucks).start({
44 render: '{{ callme() }}',
45 context: {
46 callme: function() {
47 // Loop forever!!!!
48 while (true) {}
49 }
50 }
51 })
52 .then(test => {
53 // FA-857 - No email will be sent if bad code is given.
54 assert.equal(test, null);
55 done();
56 })
57 .catch(done);
58 });
59
60 it('email template threads wont block eachother', function(done) {
61 let request1 = new Promise((resolve, reject) => {
62 new Thread(Thread.Tasks.nunjucks).start({
63 render: '{{ callme() }}',
64 context: {
65 callme: function() {
66 // Loop forever!!!!
67 while (true) {}
68 }
69 }
70 })
71 .then(test => {
72 // FA-857 - No email will be sent if bad code is given.
73 assert.equal(test, null);
74 resolve();
75 })
76 .catch(reject);
77 });
78 let request2 = new Promise((resolve, reject) => {
79 setTimeout(() => {
80 new Thread(Thread.Tasks.nunjucks).start({
81 render: '{{ callme2() }}',
82 context: {
83 callme2: function() {
84 return `hello world`;
85 }
86 }
87 })
88 .then(test => {
89 // FA-857 - No email will be sent if bad code is given.
90 assert.equal(test, `hello world`);
91 resolve();
92 })
93 .catch(reject);
94 }, 5000);
95 });
96
97 Promise.all([request1, request2])
98 .then(() => {
99 return done();
100 })
101 .catch(done);
102 });
103
104 it('email template threads wont block other api requests', function(done) {
105 let started = [];
106 let finished = [];
107 let request1 = new Promise((resolve, reject) => {
108 started.push('request1');
109 new Thread(Thread.Tasks.nunjucks).start({
110 render: '{{ callme() }}',
111 context: {
112 callme: function() {
113 // Loop forever!!!!
114 while (true) {}
115 }
116 }
117 })
118 .then(test => {
119 finished.push('request1');
120 // FA-857 - No email will be sent if bad code is given.
121 assert.equal(test, null);
122 resolve();
123 })
124 .catch(reject);
125 });
126 let request2 = new Promise((resolve, reject) => {
127 setTimeout(() => {
128 started.push('request2');
129 request(app)
130 .post(hook.alter('url', '/form/' + template.forms.adminRegister._id + '/submission', template))
131 .send({
132 data: {
133 'email': template.users.admin.data.email,
134 'password': template.users.admin.data.password
135 }
136 })
137 .expect(200)
138 .expect('Content-Type', /json/)
139 .end(function(err, res) {
140 if (err) {
141 return reject(err);
142 }
143 finished.push('request2');
144
145 let response = res.body;
146 assert(response.hasOwnProperty('_id'), 'The response should contain an `_id`.');
147 assert(response.hasOwnProperty('modified'), 'The response should contain a `modified` timestamp.');
148 assert(response.hasOwnProperty('created'), 'The response should contain a `created` timestamp.');
149 assert(response.hasOwnProperty('data'), 'The response should contain a submission `data` object.');
150 assert(response.data.hasOwnProperty('email'), 'The submission `data` should contain the `email`.');
151 assert.equal(response.data.email, template.users.admin.data.email);
152 assert(!response.data.hasOwnProperty('password'), 'The submission `data` should not contain the `password`.');
153 assert(response.hasOwnProperty('form'), 'The response should contain the resource `form`.');
154 assert.equal(response.form, template.resources.admin._id);
155 assert(res.headers.hasOwnProperty('x-jwt-token'), 'The response should contain a `x-jwt-token` header.');
156 assert(response.hasOwnProperty('owner'), 'The response should contain the resource `owner`.');
157 assert.notEqual(response.owner, null);
158 assert.equal(response.owner, response._id);
159 assert.equal(response.roles.length, 1);
160 assert.equal(response.roles[0].toString(), template.roles.administrator._id.toString());
161
162 // Update our testProject.owners data.
163 let tempPassword = template.users.admin.data.password;
164 template.users.admin = response;
165 template.users.admin.data.password = tempPassword;
166
167 // Store the JWT for future API calls.
168 template.users.admin.token = res.headers['x-jwt-token'];
169
170 resolve();
171 });
172 }, 5000);
173 });
174
175 Promise.all([request1, request2])
176 .then(() => {
177 assert.equal(started.length, 2);
178 assert.equal(started[0], 'request1');
179 assert.equal(started[1], 'request2');
180 assert.equal(finished.length, 2);
181 assert.equal(finished[0], 'request2');
182 assert.equal(finished[1], 'request1');
183 return done();
184 })
185 .catch(done);
186 });
187
188 it('Should not allow them to modify parameters in the template', function(done) {
189 new Thread(Thread.Tasks.nunjucks).start({
190 render: '{% set form = "246" %}{{ form | test1 }} {{ data.firstName }} {{ data.lastName }}',
191 context: {
192 form: '123',
193 data: {
194 firstName: 'Travis',
195 lastName: 'Tidwell'
196 }
197 },
198 filters: {
199 test1: function(string) {
200 return this.env.params.form + ' : ' + string;
201 }.toString()
202 }
203 })
204 .then(test => {
205 assert.equal(test, '123 : 246 Travis Tidwell');
206 done();
207 })
208 .catch(done);
209 });
210
211 it('Should not expose private context variables.', function(done) {
212 new Thread(Thread.Tasks.nunjucks).start({
213 render: '{{ _private.secret }}',
214 context: {
215 _private: {
216 secret: '5678'
217 },
218 form: '123',
219 data: {
220 firstName: 'Travis',
221 lastName: 'Tidwell'
222 }
223 },
224 filters: {
225 test: function(string, param) {
226 var retVal = this.env.params.form + ' : ' + string;
227 if (param) {
228 retVal += ' : ' + param;
229 }
230 return retVal;
231 }
232 }
233 })
234 .then(test => {
235 assert.equal(test, '');
236 done();
237 })
238 .catch(done);
239 });
240
241 it('Should allow filters to have access to secret variables.', function(done) {
242 new Thread(Thread.Tasks.nunjucks).start({
243 render: '{{ "test" | secret }}',
244 context: {
245 _private: {
246 secret: '5678'
247 },
248 form: '123',
249 data: {
250 firstName: 'Travis',
251 lastName: 'Tidwell'
252 }
253 },
254 filters: {
255 secret: function(string, param) {
256 return this.env.params._private.secret;
257 }.toString()
258 }
259 })
260 .then(test => {
261 assert.equal(test, '5678');
262 done();
263 })
264 .catch(done);
265 });
266 });
267
268 describe('Email Template Rendering', function() {
269 if (docker) {
270 return;
271 }
272
273 var formio = hook.alter('formio', app.formio);
274 var email = require('../src/util/email')(formio);
275 var sendMessage = function(to, from, message, content, cb) {
276 var dirName = 'fixtures/email/' + message + '/';
277 var submission = require('./' + dirName + 'submission.json');
278 var form = require('./' + dirName + 'form.json');
279 var res = {
280 token: '098098098098',
281 resource: {
282 item: submission
283 }
284 };
285 var req = {
286 params: {
287 formId: form._id
288 },
289 query: {
290 test: 1
291 },
292 user: {
293 _id: '123123123',
294 data: {
295 email: 'test@example.com',
296 fullName: 'Joe Smith'
297 }
298 }
299 };
300 var messageText = (fs.readFileSync(__dirname + '/' + dirName + 'message.html')).toString();
301 var message = {
302 transport: 'test',
303 from: from,
304 emails: to,
305 sendEach: false,
306 subject: 'New submission for {{ form.title }}.',
307 template: '',
308 message: messageText
309 };
310
311 email.getParams(req, res, form, submission)
312 .then(params => {
313 params.content = content;
314 email.send(req, res, message, params, (err, response) => {
315 if (err) {
316 return cb(err);
317 }
318
319 return cb(null, response);
320 });
321 })
322 .catch(cb)
323 };
324
325 var getProp = function(type, name, message) {
326 var regExp = new RegExp('---' + name + type + ':(.*?)---');
327 var matches = message.match(regExp);
328 if (matches.length > 1) {
329 return matches[1];
330 }
331 return '';
332 };
333
334 var getValue = function(name, message) {
335 return getProp('Value', name, message);
336 };
337
338 var getLabel = function(name, message) {
339 return getProp('Label', name, message);
340 };
341
342 it('Should render an email with all the form and submission variables.', function(done) {
343 template.hooks.reset();
344 sendMessage(['test@example.com'], 'me@example.com', 'test1', '', (err, emails) => {
345 if (err) {
346 return done(err);
347 }
348
349 let email = emails[0];
350 assert.equal(email.subject, 'New submission for Test Form.');
351 assert.equal(getLabel('firstName', email.html), 'First Name');
352 assert.equal(getValue('firstName', email.html), 'Joe');
353 assert.equal(getLabel('lastName', email.html), 'Last Name');
354 assert.equal(getValue('lastName', email.html), 'Smith');
355 assert.equal(getLabel('birthdate', email.html), 'Birth Date');
356 //assert.equal(getValue('birthdate', email.html), '2016-06-17');
357 assert.equal(getValue('vehicles', email.html), '<table border="1" style="width:100%"><tr><th style="padding: 5px 10px;">Make</th><th style="padding: 5px 10px;">Model</th><th style="padding: 5px 10px;">Year</th></tr><tr><td style="padding:5px 10px;">Chevy</td><td style="padding:5px 10px;">Suburban</td><td style="padding:5px 10px;">2014</td></tr><tr><td style="padding:5px 10px;">Chevy</td><td style="padding:5px 10px;">Tahoe</td><td style="padding:5px 10px;">2014</td></tr><tr><td style="padding:5px 10px;">Ford</td><td style="padding:5px 10px;">F150</td><td style="padding:5px 10px;">2011</td></tr></table>');
358 assert.equal(getValue('house', email.html), '<table border="1" style="width:100%"><tr><th style="text-align:right;padding: 5px 10px;">Area</th><td style="width:100%;padding:5px 10px;">2500</td></tr><tr><th style="text-align:right;padding: 5px 10px;">Single Family</th><td style="width:100%;padding:5px 10px;">true</td></tr><tr><th style="text-align:right;padding: 5px 10px;">Rooms</th><td style="width:100%;padding:5px 10px;">Master, Bedroom, Full Bath, Half Bath, Kitchen, Dining, Living, Garage</td></tr><tr><th style="text-align:right;padding: 5px 10px;">Address</th><td style="width:100%;padding:5px 10px;">1234 Main, Hampton, AR 71744, USA</td></tr></table>');
359 done();
360 });
361 });
362
363 it('Should render an email with content within the email.', function(done) {
364 template.hooks.reset();
365 sendMessage(['test@example.com'], 'me@example.com', 'test2', '<p>Hello {{ data.firstName }} {{ data.lastName }}</p>', (err, emails) => {
366 if (err) {
367 return done(err);
368 }
369
370 let email = emails[0];
371 assert.equal(email.subject, 'New submission for Test Form.');
372 assert(email.html.indexOf('<div><p>Hello Joe Smith</p></div>') !== -1, 'Email content rendering failed.');
373 done();
374 });
375 });
376 });
377};