Passed
Pull Request — 4 (#10297)
by Guy
07:46
created

testAddFormWithPolymorphicHasOne()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 24
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 16
nc 1
nop 0
dl 0
loc 24
rs 9.7333
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 = PolymorphicPeopleGroup::get()
131
            ->filter('Name', 'My Group')
132
            ->sort('Name')
133
            ->First();
134
        $gridField = $group->getCMSFields()->dataFieldByName('People');
135
        $gridField->setForm(new Form());
136
        $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

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

240
        $favouriteGroup = $person->/** @scrutinizer ignore-call */ FavouriteGroups()->first();
Loading history...
241
242
        $this->assertInstanceOf(PeopleGroup::class, $favouriteGroup);
243
    }
244
245
    public function testEditFormWithManyManyExtraData()
246
    {
247
        $this->logInWithPermission('ADMIN');
248
249
        // Lists all categories for a person
250
        $response = $this->get('GridFieldDetailFormTest_CategoryController');
251
        $this->assertFalse($response->isError());
252
        $parser = new CSSContentParser($response->getBody());
253
        $editlinkitem = $parser->getBySelector('.ss-gridfield-items .first .edit-link');
254
        $editlink = (string) $editlinkitem[0]['href'];
255
256
        // Edit a single category, incl. manymany extrafields added manually
257
        // through GridFieldDetailFormTest_CategoryController
258
        $response = $this->get($editlink);
259
        $this->assertFalse($response->isError());
260
        $parser = new CSSContentParser($response->getBody());
261
        $editform = $parser->getBySelector('#Form_ItemEditForm');
262
        $editformurl = (string) $editform[0]['action'];
263
264
        $manyManyField = $parser->getByXpath('//*[@id="Form_ItemEditForm"]//input[@name="ManyMany[IsPublished]"]');
265
        $this->assertTrue((bool)$manyManyField);
266
267
        // Test save of IsPublished field
268
        $response = $this->post(
269
            $editformurl,
270
            [
271
                'Name' => 'Updated Category',
272
                'ManyMany' => [
273
                    'IsPublished' => 1,
274
                    'PublishedBy' => 'Richard'
275
                ],
276
                'action_doSave' => 1
277
            ]
278
        );
279
        $this->assertFalse($response->isError());
280
        $person = $this->objFromFixture(Person::class, 'jane');
281
        $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

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

393
            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...
394
                $form->Fields()->push(new HiddenField('Callback'));
395
            }
396
        );
397
        // Note: A lot of scaffolding to execute the tested logic,
398
        // due to the coupling of form creation with itemRequest handling (and its context)
399
        /** @skipUpgrade */
400
        $itemRequest = new GridFieldDetailForm_ItemRequest(
401
            GridField::create('Categories', 'Categories'),
402
            $component,
403
            $category,
404
            Controller::curr(),
405
            'Form'
406
        );
407
        $itemRequest->setRequest(Controller::curr()->getRequest());
408
        $form = $itemRequest->ItemEditForm();
409
        $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

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