Passed
Push — master ( e2e77c...798396 )
by
unknown
04:46 queued 12s
created

UserDefinedFormControllerTest   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 391
Duplicated Lines 0 %

Importance

Changes 8
Bugs 0 Features 0
Metric Value
eloc 185
c 8
b 0
f 0
dl 0
loc 391
rs 10
wmc 16

16 Methods

Rating   Name   Duplication   Size   Complexity  
A setupFormFrontend() 0 9 1
A checkTemplateIsCorrect() 0 18 1
A testRenderingIntoTemplateWithSubstringReplacement() 0 11 1
A testGetFormFields() 0 42 1
A testRenderingIntoTemplateWithDisabledInterpolation() 0 17 1
A testImageThumbnailCreated() 0 34 1
A testAppendingFinished() 0 11 1
A testRecipientSubjectMergeFields() 0 31 1
A testRenderingIntoFormTemplate() 0 15 1
A tearDown() 0 4 1
A testForm() 0 18 1
A setUp() 0 8 1
A testGetFormActions() 0 24 1
A testValidation() 0 26 1
A testFinished() 0 11 1
A testProcess() 0 66 1
1
<?php
2
3
namespace SilverStripe\UserForms\Tests\Control;
4
5
use SilverStripe\Assets\Dev\TestAssetStore;
6
use SilverStripe\Assets\File;
7
use SilverStripe\Assets\Folder;
8
use SilverStripe\Assets\Storage\AssetStore;
9
use SilverStripe\Assets\Upload_Validator;
10
use InvalidArgumentException;
11
use SilverStripe\Control\HTTPRequest;
12
use SilverStripe\Control\HTTPResponse;
13
use SilverStripe\Control\Session;
14
use SilverStripe\Core\Config\Config;
15
use SilverStripe\Core\Injector\Injector;
16
use SilverStripe\Dev\CSSContentParser;
17
use SilverStripe\Dev\FunctionalTest;
18
use SilverStripe\Forms\FieldList;
19
use SilverStripe\Forms\FormAction;
20
use SilverStripe\ORM\DataObject;
21
use SilverStripe\Security\InheritedPermissions;
22
use SilverStripe\UserForms\Control\UserDefinedFormController;
23
use SilverStripe\UserForms\Model\EditableFormField;
24
use SilverStripe\UserForms\Model\EditableFormField\EditableFileField;
25
use SilverStripe\UserForms\Model\EditableFormField\EditableTextField;
26
use SilverStripe\UserForms\Model\Recipient\EmailRecipient;
27
use SilverStripe\UserForms\Model\Submission\SubmittedFormField;
28
use SilverStripe\UserForms\Model\UserDefinedForm;
29
use SilverStripe\View\ArrayData;
30
use SilverStripe\View\SSViewer;
31
32
/**
33
 * @package userforms
34
 */
35
class UserDefinedFormControllerTest extends FunctionalTest
36
{
37
    protected static $fixture_file = '../UserFormsTest.yml';
38
39
    protected static $use_draft_site = true;
40
41
    protected static $disable_themes = true;
42
43
    protected function setUp()
44
    {
45
        parent::setUp();
46
47
        // Set backend and base url
48
        TestAssetStore::activate('AssetStoreTest');
49
50
        Config::modify()->merge(SSViewer::class, 'themes', ['simple', '$default']);
51
    }
52
53
    public function tearDown()
54
    {
55
        TestAssetStore::reset();
56
        parent::tearDown();
57
    }
58
59
    public function testProcess()
60
    {
61
        $form = $this->setupFormFrontend();
62
63
        $controller = new UserDefinedFormController($form);
0 ignored issues
show
Unused Code introduced by
The assignment to $controller is dead and can be removed.
Loading history...
64
65
        $this->autoFollowRedirection = false;
66
        $this->clearEmails();
67
68
        // load the form
69
        $this->get($form->URLSegment);
70
71
        $field = $this->objFromFixture(EditableTextField::class, 'basic-text');
72
73
        $response = $this->submitForm('UserForm_Form_' . $form->ID, null, [$field->Name => 'Basic Value']);
74
75
        // should have a submitted form field now
76
        $submitted = DataObject::get(SubmittedFormField::class, "\"Name\" = 'basic_text_name'");
77
        $this->assertListAllMatch(
78
            [
79
                'Name' => 'basic_text_name',
80
                'Value' => 'Basic Value',
81
                'Title' => 'Basic Text Field'
82
            ],
83
            $submitted
84
        );
85
86
        // check emails
87
        $this->assertEmailSent('[email protected]', '[email protected]', 'Email Subject');
88
        $email = $this->findEmail('[email protected]', '[email protected]', 'Email Subject');
89
90
        // assert that the email has the field title and the value html email
91
        $parser = new CSSContentParser($email['Content']);
92
        $title = $parser->getBySelector('strong');
93
94
        $this->assertEquals('Basic Text Field', (string) $title[0], 'Email contains the field name');
95
96
        $value = $parser->getBySelector('dd');
97
        $this->assertEquals('Basic Value', (string) $value[0], 'Email contains the value');
98
99
        // no html
100
        $this->assertEmailSent('[email protected]', '[email protected]', 'Email Subject');
101
        $nohtml = $this->findEmail('[email protected]', '[email protected]', 'Email Subject');
102
103
        $this->assertContains('Basic Text Field: Basic Value', $nohtml['Content'], 'Email contains no html');
104
105
        // no data
106
        $this->assertEmailSent('[email protected]', '[email protected]', 'Email Subject');
107
        $nodata = $this->findEmail('[email protected]', '[email protected]', 'Email Subject');
108
109
        $parser = new CSSContentParser($nodata['Content']);
110
        $list = $parser->getBySelector('dl');
111
112
        $this->assertEmpty($list, 'Email contains no fields');
113
114
        // check to see if the user was redirected (301)
115
        $this->assertEquals($response->getStatusCode(), 302);
116
        $location = $response->getHeader('Location');
117
        $this->assertContains('finished', $location);
118
        $this->assertStringEndsWith('#uff', $location);
119
120
        // check that multiple email addresses are supported in to and from
121
        $this->assertEmailSent(
122
            '[email protected]; [email protected]',
123
            '[email protected]; [email protected]',
124
            'Test Email'
125
        );
126
    }
127
128
    public function testValidation()
129
    {
130
        $form = $this->setupFormFrontend('email-form');
131
132
        // Post with no fields
133
        $this->get($form->URLSegment);
134
        /** @var HTTPResponse $response */
135
        $response = $this->submitForm('UserForm_Form_' . $form->ID, null, []);
136
        $this->assertContains('This field is required', $response->getBody());
137
138
        // Post with all fields, but invalid email
139
        $this->get($form->URLSegment);
140
        /** @var HTTPResponse $response */
141
        $response = $this->submitForm('UserForm_Form_' . $form->ID, null, [
142
            'required-email' => 'invalid',
143
            'required-text' => 'bob'
144
        ]);
145
        $this->assertContains('Please enter an email address', $response->getBody());
146
147
        // Post with only required
148
        $this->get($form->URLSegment);
149
        /** @var HTTPResponse $response */
150
        $response = $this->submitForm('UserForm_Form_' . $form->ID, null, [
151
            'required-text' => 'bob'
152
        ]);
153
        $this->assertContains("Thanks, we've received your submission.", $response->getBody());
154
    }
155
156
    public function testFinished()
157
    {
158
        $form = $this->setupFormFrontend();
159
160
        // set formProcessed and SecurityID to replicate the form being filled out
161
        $this->session()->set('SecurityID', 1);
162
        $this->session()->set('FormProcessed', 1);
163
164
        $response = $this->get($form->URLSegment.'/finished');
165
166
        $this->assertContains($form->OnCompleteMessage, $response->getBody());
167
    }
168
169
    public function testAppendingFinished()
170
    {
171
        $form = $this->setupFormFrontend();
172
173
        // replicate finished being added to the end of the form URL without the form being filled out
174
        $this->session()->set('SecurityID', 1);
175
        $this->session()->set('FormProcessed', null);
176
177
        $response = $this->get($form->URLSegment.'/finished');
178
179
        $this->assertNotContains($form->OnCompleteMessage, $response->getBody());
180
    }
181
182
    public function testForm()
183
    {
184
        $form = $this->objFromFixture(UserDefinedForm::class, 'basic-form-page');
185
186
        $controller = new UserDefinedFormController($form);
187
188
        // test form
189
        $this->assertEquals($controller->Form()->getName(), 'Form_' . $form->ID, 'The form is referenced as Form');
190
        $this->assertEquals($controller->Form()->Fields()->Count(), 1); // disabled SecurityID token fields
191
        $this->assertEquals($controller->Form()->Actions()->Count(), 1);
192
        $this->assertEquals(count($controller->Form()->getValidator()->getRequired()), 0);
193
194
        $requiredForm = $this->objFromFixture(UserDefinedForm::class, 'validation-form');
195
        $controller = new UserDefinedFormController($requiredForm);
196
197
        $this->assertEquals($controller->Form()->Fields()->Count(), 1); // disabled SecurityID token fields
198
        $this->assertEquals($controller->Form()->Actions()->Count(), 1);
199
        $this->assertEquals(count($controller->Form()->getValidator()->getRequired()), 1);
200
    }
201
202
    public function testGetFormFields()
203
    {
204
        // generating the fieldset of fields
205
        $form = $this->objFromFixture(UserDefinedForm::class, 'basic-form-page');
206
207
        $controller = new UserDefinedFormController($form);
208
209
        $formSteps = $controller->Form()->getFormFields();
210
        $firstStep = $formSteps->first();
211
212
        $this->assertEquals($formSteps->Count(), 1);
213
        $this->assertEquals($firstStep->getChildren()->Count(), 1);
214
215
        // custom error message on a form field
216
        $requiredForm = $this->objFromFixture(UserDefinedForm::class, 'validation-form');
217
        $controller = new UserDefinedFormController($requiredForm);
218
219
        Config::modify()->set(UserDefinedForm::class, 'required_identifier', '*');
220
221
        $formSteps = $controller->Form()->getFormFields();
222
        $firstStep = $formSteps->first();
223
        $firstField = $firstStep->getChildren()->first();
224
225
        $this->assertEquals('Custom Error Message', $firstField->getCustomValidationMessage());
226
        $this->assertEquals($firstField->Title(), 'Required Text Field <span class=\'required-identifier\'>*</span>');
227
228
        // test custom right title
229
        $field = $form->Fields()->limit(1, 1)->First();
230
        $field->RightTitle = 'Right Title';
231
        $field->write();
232
233
        $controller = new UserDefinedFormController($form);
234
        $formSteps = $controller->Form()->getFormFields();
235
        $firstStep = $formSteps->first();
236
237
        $this->assertEquals($firstStep->getChildren()->First()->RightTitle(), "Right Title");
238
239
        // test empty form
240
        $emptyForm = $this->objFromFixture(UserDefinedForm::class, 'empty-form');
241
        $controller = new UserDefinedFormController($emptyForm);
242
243
        $this->assertFalse($controller->Form()->getFormFields()->exists());
244
    }
245
246
    public function testGetFormActions()
247
    {
248
        // generating the fieldset of actions
249
        $form = $this->objFromFixture(UserDefinedForm::class, 'basic-form-page');
250
251
        $controller = new UserDefinedFormController($form);
252
        $actions = $controller->Form()->getFormActions();
253
254
        // by default will have 1 submit button which links to process
255
        $expected = new FieldList(new FormAction('process', 'Submit'));
256
        $expected->setForm($controller->Form());
257
258
        $this->assertEquals($actions, $expected);
259
260
        // the custom popup should have a reset button and a custom text
261
        $custom = $this->objFromFixture(UserDefinedForm::class, 'form-with-reset-and-custom-action');
262
        $controller = new UserDefinedFormController($custom);
263
        $actions = $controller->Form()->getFormActions();
264
265
        $expected = new FieldList(new FormAction('process', 'Custom Button'));
266
        $expected->push(FormAction::create('clearForm', 'Clear')->setAttribute('type', 'reset'));
267
        $expected->setForm($controller->Form());
268
269
        $this->assertEquals($actions, $expected);
270
    }
271
272
    public function testRenderingIntoFormTemplate()
273
    {
274
        $form = $this->setupFormFrontend();
275
276
        $this->logInWithPermission('ADMIN');
277
        $form->Content = 'This is some content without a form nested between it';
278
        $form->publishRecursive();
279
280
        $controller = new UserDefinedFormController($form);
281
282
        // check to see if $Form is placed in the template
283
        $index = new ArrayData($controller->index());
284
        $parser = new CSSContentParser($index->renderWith(__CLASS__));
285
286
        $this->checkTemplateIsCorrect($parser, $form);
287
    }
288
289
    public function testRenderingIntoTemplateWithSubstringReplacement()
290
    {
291
        $form = $this->setupFormFrontend();
292
293
        $controller = new UserDefinedFormController($form);
294
295
        // check to see if $Form is replaced to inside the content
296
        $index = new ArrayData($controller->index());
297
        $parser = new CSSContentParser($index->renderWith(__CLASS__));
298
299
        $this->checkTemplateIsCorrect($parser, $form);
300
    }
301
302
    public function testRenderingIntoTemplateWithDisabledInterpolation()
303
    {
304
        $form = $this->setupFormFrontend();
305
306
        $controller = new UserDefinedFormController($form);
307
        $controller->config()->set('disable_form_content_shortcode', true);
308
        // check to see if $Form is replaced to inside the content
309
        $index = new ArrayData($controller->index());
310
        $html = $index->renderWith(__CLASS__);
311
        $parser = new CSSContentParser($html);
312
313
        // Assert Content has been rendered with the shortcode in place
314
        $this->assertContains('<p>Here is my form</p><p>$UserDefinedForm</p><p>Thank you for filling it out</p>', $html);
315
        // And the form in the $From area
316
        $this->assertArrayHasKey(0, $parser->getBySelector('form#UserForm_Form_' . $form->ID));
317
        // check for the input
318
        $this->assertArrayHasKey(0, $parser->getBySelector('input.text'));
319
    }
320
321
    /**
322
     * Publish a form for use on the frontend
323
     *
324
     * @param string $fixtureName
325
     * @return UserDefinedForm
326
     */
327
    protected function setupFormFrontend($fixtureName = 'basic-form-page')
328
    {
329
        $form = $this->objFromFixture(UserDefinedForm::class, $fixtureName);
330
331
        $this->actWithPermission('ADMIN', function () use ($form) {
332
            $form->publishRecursive();
333
        });
334
335
        return $form;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $form returns the type SilverStripe\ORM\DataObject which is incompatible with the documented return type SilverStripe\UserForms\Model\UserDefinedForm.
Loading history...
336
    }
337
338
    public function checkTemplateIsCorrect($parser, $form)
339
    {
340
        $this->assertArrayHasKey(0, $parser->getBySelector('form#UserForm_Form_' . $form->ID));
341
342
        // check for the input
343
        $this->assertArrayHasKey(0, $parser->getBySelector('input.text'));
344
345
        // check for the label and the text
346
        $label = $parser->getBySelector('label.left');
347
        $this->assertArrayHasKey(0, $label);
348
349
        $this->assertEquals((string) $label[0][0], "Basic Text Field", "Label contains correct field name");
350
351
        // check for the action
352
        $action = $parser->getBySelector('input.action');
353
        $this->assertArrayHasKey(0, $action);
354
355
        $this->assertEquals((string) $action[0]['value'], "Submit", "Submit button has default text");
356
    }
357
358
359
    public function testRecipientSubjectMergeFields()
360
    {
361
        $form = $this->setupFormFrontend();
362
363
        $recipient = $this->objFromFixture(EmailRecipient::class, 'recipient-1');
364
        $recipient->EmailSubject = 'Email Subject: $basic_text_name';
365
        $recipient->write();
366
367
        $this->autoFollowRedirection = false;
368
        $this->clearEmails();
369
370
        // load the form
371
        $this->get($form->URLSegment);
372
373
        $field = $this->objFromFixture(EditableTextField::class, 'basic-text');
374
375
        $response = $this->submitForm('UserForm_Form_' . $form->ID, null, [$field->Name => 'Basic Value']);
0 ignored issues
show
Unused Code introduced by
The assignment to $response is dead and can be removed.
Loading history...
376
377
        // should have a submitted form field now
378
        $submitted = DataObject::get(SubmittedFormField::class, "\"Name\" = 'basic_text_name'");
379
        $this->assertListAllMatch(
380
            [
381
                'Name' => 'basic_text_name',
382
                'Value' => 'Basic Value',
383
                'Title' => 'Basic Text Field'
384
            ],
385
            $submitted
386
        );
387
388
        // check emails
389
        $this->assertEmailSent('[email protected]', '[email protected]', 'Email Subject: Basic Value');
390
    }
391
392
    public function testImageThumbnailCreated()
393
    {
394
        Config::modify()->set(Upload_Validator::class, 'use_is_uploaded_file', false);
395
396
        $userForm = $this->setupFormFrontend('upload-form');
397
        $controller = UserDefinedFormController::create($userForm);
398
        $field = $this->objFromFixture(EditableFileField::class, 'file-field-1');
399
400
        $path = realpath(__DIR__ . '/fixtures/testfile.jpg');
401
        $data = [
402
            $field->Name => [
403
                'name' => 'testfile.jpg',
404
                'type' => 'image/jpeg',
405
                'tmp_name' => $path,
406
                'error' => 0,
407
                'size' => filesize($path),
408
            ]
409
        ];
410
        $_FILES[$field->Name] = $data[$field->Name];
411
412
        $controller->getRequest()->setSession(new Session([]));
413
        $controller->process($data, $controller->Form());
414
415
        /** @var File $image */
416
        // Getting File instead of Image so that we still delete the physical file in case it was
417
        // created with the wrong ClassName
418
        // Using StartsWith in-case of existing file so was created as testfile-v2.jpg
419
        $image = File::get()->filter(['Name:StartsWith' => 'testfile'])->last();
420
        $this->assertNotNull($image);
421
422
        // Assert thumbnail variant created
423
        /** @var AssetStore $store */
424
        $store = Injector::inst()->get(AssetStore::class);
425
        $this->assertTrue($store->exists($image->getFilename(), $image->getHash(), 'FitMaxWzM1MiwyNjRd'));
426
    }
427
}
428