1 |
|
2 | 'use strict';
|
3 |
|
4 | let assert = require('assert');
|
5 | let fs = require('fs');
|
6 | let docker = process.env.DOCKER;
|
7 | var request = require('supertest');
|
8 |
|
9 | module.exports = function(app, template, hook) {
|
10 | let Thread = require('formio-workers/Thread');
|
11 |
|
12 | |
13 |
|
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 |
|
48 | while (true) {}
|
49 | }
|
50 | }
|
51 | })
|
52 | .then(test => {
|
53 |
|
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 |
|
67 | while (true) {}
|
68 | }
|
69 | }
|
70 | })
|
71 | .then(test => {
|
72 |
|
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 |
|
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 |
|
114 | while (true) {}
|
115 | }
|
116 | }
|
117 | })
|
118 | .then(test => {
|
119 | finished.push('request1');
|
120 |
|
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 |
|
163 | let tempPassword = template.users.admin.data.password;
|
164 | template.users.admin = response;
|
165 | template.users.admin.data.password = tempPassword;
|
166 |
|
167 |
|
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 |
|
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 | };
|