Completed
Push — 4 ( cb3786...fc8709 )
by Steve
32s queued 24s
created

testAddFormWithPolymorphicHasOne()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 22
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 14
nc 1
nop 0
dl 0
loc 22
rs 9.7998
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\Forms\Tests\GridField;
4
5
use SilverStripe\Control\Controller;
6
use SilverStripe\Dev\CSSContentParser;
7
use SilverStripe\Dev\FunctionalTest;
8
use SilverStripe\Forms\Form;
9
use SilverStripe\Forms\GridField\GridField;
10
use SilverStripe\Forms\GridField\GridFieldDetailForm;
11
use SilverStripe\Forms\GridField\GridFieldDetailForm_ItemRequest;
12
use SilverStripe\Forms\HiddenField;
13
use SilverStripe\Forms\Tests\GridField\GridFieldDetailFormTest\Category;
14
use SilverStripe\Forms\Tests\GridField\GridFieldDetailFormTest\CategoryController;
15
use SilverStripe\Forms\Tests\GridField\GridFieldDetailFormTest\GroupController;
16
use SilverStripe\Forms\Tests\GridField\GridFieldDetailFormTest\PeopleGroup;
17
use SilverStripe\Forms\Tests\GridField\GridFieldDetailFormTest\Person;
18
use SilverStripe\Forms\Tests\GridField\GridFieldDetailFormTest\PolymorphicPeopleGroup;
19
use SilverStripe\Forms\Tests\GridField\GridFieldDetailFormTest\TestController;
20
21
/**
22
 * @skipUpgrade
23
 */
24
class GridFieldDetailFormTest extends FunctionalTest
25
{
26
    protected static $fixture_file = 'GridFieldDetailFormTest.yml';
27
28
    protected static $extra_dataobjects = [
29
        Person::class,
30
        PeopleGroup::class,
31
        PolymorphicPeopleGroup::class,
32
        Category::class,
33
    ];
34
35
    protected static $extra_controllers = [
36
        CategoryController::class,
37
        TestController::class,
38
        GroupController::class,
39
    ];
40
41
    protected static $disable_themes = true;
42
43
    public function testValidator()
44
    {
45
        $this->logInWithPermission('ADMIN');
46
47
        $response = $this->get('GridFieldDetailFormTest_Controller');
48
        $this->assertFalse($response->isError());
49
        $parser = new CSSContentParser($response->getBody());
50
        $addlinkitem = $parser->getBySelector('.grid-field .new-link');
51
        $addlink = (string) $addlinkitem[0]['href'];
52
53
        $response = $this->get($addlink);
54
        $this->assertFalse($response->isError());
55
56
        $parser = new CSSContentParser($response->getBody());
57
        $addform = $parser->getBySelector('#Form_ItemEditForm');
58
        $addformurl = (string) $addform[0]['action'];
59
60
        $response = $this->post(
61
            $addformurl,
62
            [
63
                'FirstName' => 'Jeremiah',
64
                'ajax' => 1,
65
                'action_doSave' => 1
66
            ]
67
        );
68
69
        $parser = new CSSContentParser($response->getBody());
70
        $errors = $parser->getBySelector('span.required');
71
        $this->assertEquals(1, count($errors ?? []));
72
73
        $response = $this->post(
74
            $addformurl,
75
            [
76
                'ajax' => 1,
77
                'action_doSave' => 1
78
            ]
79
        );
80
81
        $parser = new CSSContentParser($response->getBody());
82
        $errors = $parser->getBySelector('span.required');
83
        $this->assertEquals(2, count($errors ?? []));
84
    }
85
86
    public function testAddForm()
87
    {
88
        $this->logInWithPermission('ADMIN');
89
        $group = PeopleGroup::get()
90
            ->filter('Name', 'My Group')
91
            ->sort('Name')
92
            ->First();
93
        $count = $group->People()->Count();
0 ignored issues
show
Bug introduced by
The method People() does not exist on SilverStripe\ORM\DataObject. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

93
        $count = $group->/** @scrutinizer ignore-call */ People()->Count();
Loading history...
94
95
        $response = $this->get('GridFieldDetailFormTest_Controller');
96
        $this->assertFalse($response->isError());
97
        $parser = new CSSContentParser($response->getBody());
98
        $addlinkitem = $parser->getBySelector('.grid-field .new-link');
99
        $addlink = (string) $addlinkitem[0]['href'];
100
101
        $response = $this->get($addlink);
102
        $this->assertFalse($response->isError());
103
104
        $parser = new CSSContentParser($response->getBody());
105
        $addform = $parser->getBySelector('#Form_ItemEditForm');
106
        $addformurl = (string) $addform[0]['action'];
107
108
        $response = $this->post(
109
            $addformurl,
110
            [
111
                'FirstName' => 'Jeremiah',
112
                'Surname' => 'BullFrog',
113
                'action_doSave' => 1
114
            ]
115
        );
116
        $this->assertFalse($response->isError());
117
118
        $group = PeopleGroup::get()
119
            ->filter('Name', 'My Group')
120
            ->sort('Name')
121
            ->First();
122
        $this->assertEquals($count + 1, $group->People()->Count());
123
    }
124
125
    public function testAddFormWithPolymorphicHasOne()
126
    {
127
        // Log in for permissions check
128
        $this->logInWithPermission('ADMIN');
129
        // Prepare gridfield and other objects
130
        $group = new PolymorphicPeopleGroup();
131
        $group->write();
132
        $gridField = $group->getCMSFields()->dataFieldByName('People');
133
        $gridField->setForm(new Form());
134
        $detailForm = $gridField->getConfig()->getComponentByType(GridFieldDetailForm::class);
0 ignored issues
show
Bug introduced by
The method getConfig() does not exist on SilverStripe\Forms\FormField. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

134
        $detailForm = $gridField->/** @scrutinizer ignore-call */ getConfig()->getComponentByType(GridFieldDetailForm::class);
Loading history...
135
        $record = new Person();
136
137
        // Trigger creation of the item edit form
138
        $reflectionDetailForm = new \ReflectionClass($detailForm);
139
        $reflectionMethod = $reflectionDetailForm->getMethod('getItemRequestHandler');
140
        $reflectionMethod->setAccessible(true);
141
        $itemrequest = $reflectionMethod->invoke($detailForm, $gridField, $record, new Controller());
142
        $itemrequest->ItemEditForm();
143
144
        // The polymorphic values should be pre-loaded
145
        $this->assertEquals(PolymorphicPeopleGroup::class, $record->PolymorphicGroupClass);
0 ignored issues
show
Bug Best Practice introduced by
The property PolymorphicGroupClass does not exist on SilverStripe\Forms\Tests...ldDetailFormTest\Person. Since you implemented __get, consider adding a @property annotation.
Loading history...
146
        $this->assertEquals($group->ID, $record->PolymorphicGroupID);
0 ignored issues
show
Bug Best Practice introduced by
The property PolymorphicGroupID does not exist on SilverStripe\Forms\Tests...ldDetailFormTest\Person. Since you implemented __get, consider adding a @property annotation.
Loading history...
147
    }
148
149
    public function testViewForm()
150
    {
151
        $this->logInWithPermission('ADMIN');
152
153
        $response = $this->get('GridFieldDetailFormTest_Controller');
154
        $parser   = new CSSContentParser($response->getBody());
155
156
        $viewLink = $parser->getBySelector('.ss-gridfield-items .first .view-link');
157
        $viewLink = (string) $viewLink[0]['href'];
158
159
        $response = $this->get($viewLink);
160
        $parser   = new CSSContentParser($response->getBody());
161
162
        $firstName = $parser->getBySelector('#Form_ItemEditForm_FirstName');
163
        $surname   = $parser->getBySelector('#Form_ItemEditForm_Surname');
164
165
        $this->assertFalse($response->isError());
166
        $this->assertEquals('Jane', (string) $firstName[0]);
167
        $this->assertEquals('Doe', (string) $surname[0]);
168
    }
169
170
    public function testEditForm()
171
    {
172
        $this->logInWithPermission('ADMIN');
173
        $group = PeopleGroup::get()
174
            ->filter('Name', 'My Group')
175
            ->sort('Name')
176
            ->First();
177
        $firstperson = $group->People()->First();
178
        $this->assertTrue($firstperson->Surname != 'Baggins');
179
180
        $response = $this->get('GridFieldDetailFormTest_Controller');
181
        $this->assertFalse($response->isError());
182
        $parser = new CSSContentParser($response->getBody());
183
        $editlinkitem = $parser->getBySelector('.ss-gridfield-items .first .edit-link');
184
        $editlink = (string) $editlinkitem[0]['href'];
185
186
        $response = $this->get($editlink);
187
        $this->assertFalse($response->isError());
188
189
        $parser = new CSSContentParser($response->getBody());
190
        $editform = $parser->getBySelector('#Form_ItemEditForm');
191
        $editformurl = (string) $editform[0]['action'];
192
193
        $response = $this->post(
194
            $editformurl,
195
            [
196
                'FirstName' => 'Bilbo',
197
                'Surname' => 'Baggins',
198
                'action_doSave' => 1
199
            ]
200
        );
201
        $this->assertFalse($response->isError());
202
203
        $group = PeopleGroup::get()
204
            ->filter('Name', 'My Group')
205
            ->sort('Name')
206
            ->First();
207
        $this->assertListContains([['Surname' => 'Baggins']], $group->People());
208
    }
209
210
    public function testEditFormWithManyMany()
211
    {
212
        $this->logInWithPermission('ADMIN');
213
214
        // Edit the first person
215
        $response = $this->get('GridFieldDetailFormTest_CategoryController');
216
        // Find the link to add a new favourite group
217
        $parser = new CSSContentParser($response->getBody());
218
        $addLink = $parser->getBySelector('#Form_Form_testgroupsfield .new-link');
219
        $addLink = (string) $addLink[0]['href'];
220
221
        // Add a new favourite group
222
        $response = $this->get($addLink);
223
        $parser = new CSSContentParser($response->getBody());
224
        $addform = $parser->getBySelector('#Form_ItemEditForm');
225
        $addformurl = (string) $addform[0]['action'];
226
227
        $response = $this->post(
228
            $addformurl,
229
            [
230
                'Name' => 'My Favourite Group',
231
                'ajax' => 1,
232
                'action_doSave' => 1
233
            ]
234
        );
235
        $this->assertFalse($response->isError());
236
237
        $person = $this->objFromFixture(Person::class, 'jane');
238
        $favouriteGroup = $person->FavouriteGroups()->first();
0 ignored issues
show
Bug introduced by
The method FavouriteGroups() does not exist on SilverStripe\ORM\DataObject. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

238
        $favouriteGroup = $person->/** @scrutinizer ignore-call */ FavouriteGroups()->first();
Loading history...
239
240
        $this->assertInstanceOf(PeopleGroup::class, $favouriteGroup);
241
    }
242
243
    public function testEditFormWithManyManyExtraData()
244
    {
245
        $this->logInWithPermission('ADMIN');
246
247
        // Lists all categories for a person
248
        $response = $this->get('GridFieldDetailFormTest_CategoryController');
249
        $this->assertFalse($response->isError());
250
        $parser = new CSSContentParser($response->getBody());
251
        $editlinkitem = $parser->getBySelector('.ss-gridfield-items .first .edit-link');
252
        $editlink = (string) $editlinkitem[0]['href'];
253
254
        // Edit a single category, incl. manymany extrafields added manually
255
        // through GridFieldDetailFormTest_CategoryController
256
        $response = $this->get($editlink);
257
        $this->assertFalse($response->isError());
258
        $parser = new CSSContentParser($response->getBody());
259
        $editform = $parser->getBySelector('#Form_ItemEditForm');
260
        $editformurl = (string) $editform[0]['action'];
261
262
        $manyManyField = $parser->getByXpath('//*[@id="Form_ItemEditForm"]//input[@name="ManyMany[IsPublished]"]');
263
        $this->assertTrue((bool)$manyManyField);
264
265
        // Test save of IsPublished field
266
        $response = $this->post(
267
            $editformurl,
268
            [
269
                'Name' => 'Updated Category',
270
                'ManyMany' => [
271
                    'IsPublished' => 1,
272
                    'PublishedBy' => 'Richard'
273
                ],
274
                'action_doSave' => 1
275
            ]
276
        );
277
        $this->assertFalse($response->isError());
278
        $person = $this->objFromFixture(Person::class, 'jane');
279
        $category = $person->Categories()->filter(['Name' => 'Updated Category'])->First();
0 ignored issues
show
Bug introduced by
The method Categories() does not exist on SilverStripe\ORM\DataObject. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

279
        $category = $person->/** @scrutinizer ignore-call */ Categories()->filter(['Name' => 'Updated Category'])->First();
Loading history...
280
        $this->assertEquals(
281
            [
282
                'IsPublished' => 1,
283
                'PublishedBy' => 'Richard'
284
            ],
285
            $person->Categories()->getExtraData('', $category->ID)
286
        );
287
288
        // Test update of value with falsey value
289
        $response = $this->post(
290
            $editformurl,
291
            [
292
                'Name' => 'Updated Category',
293
                'ManyMany' => [
294
                    'PublishedBy' => ''
295
                ],
296
                'action_doSave' => 1
297
            ]
298
        );
299
        $this->assertFalse($response->isError());
300
301
        $person = $this->objFromFixture(Person::class, 'jane');
302
        $category = $person->Categories()->filter(['Name' => 'Updated Category'])->First();
303
        $this->assertEquals(
304
            [
305
                'IsPublished' => 0,
306
                'PublishedBy' => ''
307
            ],
308
            $person->Categories()->getExtraData('', $category->ID)
309
        );
310
    }
311
312
    public function testNestedEditForm()
313
    {
314
        $this->logInWithPermission('ADMIN');
315
316
        $group = $this->objFromFixture(PeopleGroup::class, 'group');
317
        $person = $group->People()->First();
318
        $category = $person->Categories()->First();
319
320
        // Get first form (GridField managing PeopleGroup)
321
        $response = $this->get('GridFieldDetailFormTest_GroupController');
322
        $this->assertFalse($response->isError());
323
        $parser = new CSSContentParser($response->getBody());
324
325
        $groupEditLink = $parser->getByXpath(
326
            '//tr[contains(@class, "ss-gridfield-item") and contains(@data-id, "'
327
            . $group->ID . '")]//a'
328
        );
329
        $this->assertEquals(
330
            'GridFieldDetailFormTest_GroupController/Form/field/testfield/item/' . $group->ID . '/edit',
331
            (string)$groupEditLink[0]['href']
332
        );
333
334
        // Get second level form (GridField managing Person)
335
        $response = $this->get((string)$groupEditLink[0]['href']);
336
        $this->assertFalse($response->isError());
337
        $parser = new CSSContentParser($response->getBody());
338
        $personEditLink = $parser->getByXpath(
339
            '//fieldset[@id="Form_ItemEditForm_People"]' .
340
            '//tr[contains(@class, "ss-gridfield-item") and contains(@data-id, "' . $person->ID . '")]//a'
341
        );
342
        $this->assertEquals(
343
            sprintf(
344
                'GridFieldDetailFormTest_GroupController/Form/field/testfield/item/%d/ItemEditForm/field/People'
345
                . '/item/%d/edit',
346
                $group->ID,
347
                $person->ID
348
            ),
349
            (string)$personEditLink[0]['href']
350
        );
351
352
        // Get third level form (GridField managing Category)
353
        $response = $this->get((string)$personEditLink[0]['href']);
354
        $this->assertFalse($response->isError());
355
        $parser = new CSSContentParser($response->getBody());
356
        $categoryEditLink = $parser->getByXpath(
357
            '//fieldset[@id="Form_ItemEditForm_Categories"]'
358
            . '//tr[contains(@class, "ss-gridfield-item") and contains(@data-id, "' . $category->ID . '")]//a'
359
        );
360
        $this->assertEquals(
361
            sprintf(
362
                'GridFieldDetailFormTest_GroupController/Form/field/testfield/item/%d/ItemEditForm/field/People'
363
                . '/item/%d/ItemEditForm/field/Categories/item/%d/edit',
364
                $group->ID,
365
                $person->ID,
366
                $category->ID
367
            ),
368
            (string)$categoryEditLink[0]['href']
369
        );
370
371
        // Fourth level form would be a Category detail view
372
    }
373
374
    public function testCustomItemRequestClass()
375
    {
376
        $this->logInWithPermission('ADMIN');
377
378
        $component = new GridFieldDetailForm();
379
        $this->assertEquals('SilverStripe\\Forms\\GridField\\GridFieldDetailForm_ItemRequest', $component->getItemRequestClass());
380
        $component->setItemRequestClass('GridFieldDetailFormTest_ItemRequest');
381
        $this->assertEquals('GridFieldDetailFormTest_ItemRequest', $component->getItemRequestClass());
382
    }
383
384
    public function testItemEditFormCallback()
385
    {
386
        $this->logInWithPermission('ADMIN');
387
388
        $category = new Category();
389
        $component = new GridFieldDetailForm();
390
        $component->setItemEditFormCallback(
391
            function ($form, $component) {
0 ignored issues
show
Unused Code introduced by
The parameter $component is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

391
            function ($form, /** @scrutinizer ignore-unused */ $component) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
392
                $form->Fields()->push(new HiddenField('Callback'));
393
            }
394
        );
395
        // Note: A lot of scaffolding to execute the tested logic,
396
        // due to the coupling of form creation with itemRequest handling (and its context)
397
        /** @skipUpgrade */
398
        $itemRequest = new GridFieldDetailForm_ItemRequest(
399
            GridField::create('Categories', 'Categories'),
400
            $component,
401
            $category,
402
            Controller::curr(),
403
            'Form'
404
        );
405
        $itemRequest->setRequest(Controller::curr()->getRequest());
406
        $form = $itemRequest->ItemEditForm();
407
        $this->assertNotNull($form->Fields()->fieldByName('Callback'));
0 ignored issues
show
Bug introduced by
The method Fields() does not exist on SilverStripe\Control\HTTPResponse. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

407
        $this->assertNotNull($form->/** @scrutinizer ignore-call */ Fields()->fieldByName('Callback'));

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
408
    }
409
410
    /**
411
     * Tests that a has-many detail form is pre-populated with the parent ID.
412
     */
413
    public function testHasManyFormPrePopulated()
414
    {
415
        $group = $this->objFromFixture(
416
            PeopleGroup::class,
417
            'group'
418
        );
419
420
        $this->logInWithPermission('ADMIN');
421
422
        $response = $this->get('GridFieldDetailFormTest_Controller');
423
        $parser = new CSSContentParser($response->getBody());
424
        $addLink = $parser->getBySelector('.grid-field .new-link');
425
        $addLink = (string) $addLink[0]['href'];
426
427
        $response = $this->get($addLink);
428
        $parser = new CSSContentParser($response->getBody());
429
        $title = $parser->getBySelector('#Form_ItemEditForm_GroupID_Holder span');
430
        $id = $parser->getBySelector('#Form_ItemEditForm_GroupID_Holder input');
431
432
        $this->assertEquals($group->Name, (string) $title[0]);
0 ignored issues
show
Bug Best Practice introduced by
The property Name does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
433
        $this->assertEquals($group->ID, (string) $id[0]['value']);
434
    }
435
436
    public function testRedirectMissingRecords()
437
    {
438
        $origAutoFollow = $this->autoFollowRedirection;
439
        $this->autoFollowRedirection = false;
440
441
        // GridField is filtered people in "My Group", which doesn't include "jack"
442
        $included = $this->objFromFixture(Person::class, 'joe');
443
        $excluded = $this->objFromFixture(Person::class, 'jack');
444
445
        $response = $this->get(sprintf(
446
            'GridFieldDetailFormTest_Controller/Form/field/testfield/item/%d/edit',
447
            $included->ID
448
        ));
449
        $this->assertFalse(
450
            $response->isRedirect(),
451
            'Existing records are not redirected'
452
        );
453
454
        $response = $this->get(sprintf(
455
            'GridFieldDetailFormTest_Controller/Form/field/testfield/item/%d/edit',
456
            $excluded->ID
457
        ));
458
        $this->assertTrue(
459
            $response->isRedirect(),
460
            'Non-existing records are redirected'
461
        );
462
463
        $this->autoFollowRedirection = $origAutoFollow;
464
    }
465
}
466