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

GridFieldDetailFormTest   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 435
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 12
eloc 267
dl 0
loc 435
rs 10
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A testRedirectMissingRecords() 0 28 1
A testEditFormWithManyManyExtraData() 0 66 1
A testEditFormWithManyMany() 0 31 1
A testNestedEditForm() 0 57 1
A testAddForm() 0 37 1
A testViewForm() 0 19 1
A testEditForm() 0 38 1
A testHasManyFormPrePopulated() 0 21 1
A testAddFormWithPolymorphicHasOne() 0 17 1
A testCustomItemRequestClass() 0 8 1
A testItemEditFormCallback() 0 24 1
A testValidator() 0 41 1
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\GridField\GridField;
9
use SilverStripe\Forms\GridField\GridFieldDetailForm;
10
use SilverStripe\Forms\GridField\GridFieldDetailForm_ItemRequest;
11
use SilverStripe\Forms\HiddenField;
12
use SilverStripe\Forms\Tests\GridField\GridFieldDetailFormTest\Category;
13
use SilverStripe\Forms\Tests\GridField\GridFieldDetailFormTest\CategoryController;
14
use SilverStripe\Forms\Tests\GridField\GridFieldDetailFormTest\GroupController;
15
use SilverStripe\Forms\Tests\GridField\GridFieldDetailFormTest\PeopleGroup;
16
use SilverStripe\Forms\Tests\GridField\GridFieldDetailFormTest\Person;
17
use SilverStripe\Forms\Tests\GridField\GridFieldDetailFormTest\PolymorphicPeopleGroup;
18
use SilverStripe\Forms\Tests\GridField\GridFieldDetailFormTest\TestController;
19
20
/**
21
 * @skipUpgrade
22
 */
23
class GridFieldDetailFormTest extends FunctionalTest
24
{
25
    protected static $fixture_file = 'GridFieldDetailFormTest.yml';
26
27
    protected static $extra_dataobjects = [
28
        Person::class,
29
        PeopleGroup::class,
30
        PolymorphicPeopleGroup::class,
31
        Category::class,
32
    ];
33
34
    protected static $extra_controllers = [
35
        CategoryController::class,
36
        TestController::class,
37
        GroupController::class,
38
    ];
39
40
    protected static $disable_themes = true;
41
42
    public function testValidator()
43
    {
44
        $this->logInWithPermission('ADMIN');
45
46
        $response = $this->get('GridFieldDetailFormTest_Controller');
47
        $this->assertFalse($response->isError());
48
        $parser = new CSSContentParser($response->getBody());
49
        $addlinkitem = $parser->getBySelector('.grid-field .new-link');
50
        $addlink = (string) $addlinkitem[0]['href'];
51
52
        $response = $this->get($addlink);
53
        $this->assertFalse($response->isError());
54
55
        $parser = new CSSContentParser($response->getBody());
56
        $addform = $parser->getBySelector('#Form_ItemEditForm');
57
        $addformurl = (string) $addform[0]['action'];
58
59
        $response = $this->post(
60
            $addformurl,
61
            [
62
                'FirstName' => 'Jeremiah',
63
                'ajax' => 1,
64
                'action_doSave' => 1
65
            ]
66
        );
67
68
        $parser = new CSSContentParser($response->getBody());
69
        $errors = $parser->getBySelector('span.required');
70
        $this->assertEquals(1, count($errors ?? []));
71
72
        $response = $this->post(
73
            $addformurl,
74
            [
75
                'ajax' => 1,
76
                'action_doSave' => 1
77
            ]
78
        );
79
80
        $parser = new CSSContentParser($response->getBody());
81
        $errors = $parser->getBySelector('span.required');
82
        $this->assertEquals(2, count($errors ?? []));
83
    }
84
85
    public function testAddForm()
86
    {
87
        $this->logInWithPermission('ADMIN');
88
        $group = PeopleGroup::get()
89
            ->filter('Name', 'My Group')
90
            ->sort('Name')
91
            ->First();
92
        $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

92
        $count = $group->/** @scrutinizer ignore-call */ People()->Count();
Loading history...
93
94
        $response = $this->get('GridFieldDetailFormTest_Controller');
95
        $this->assertFalse($response->isError());
96
        $parser = new CSSContentParser($response->getBody());
97
        $addlinkitem = $parser->getBySelector('.grid-field .new-link');
98
        $addlink = (string) $addlinkitem[0]['href'];
99
100
        $response = $this->get($addlink);
101
        $this->assertFalse($response->isError());
102
103
        $parser = new CSSContentParser($response->getBody());
104
        $addform = $parser->getBySelector('#Form_ItemEditForm');
105
        $addformurl = (string) $addform[0]['action'];
106
107
        $response = $this->post(
108
            $addformurl,
109
            [
110
                'FirstName' => 'Jeremiah',
111
                'Surname' => 'BullFrog',
112
                'action_doSave' => 1
113
            ]
114
        );
115
        $this->assertFalse($response->isError());
116
117
        $group = PeopleGroup::get()
118
            ->filter('Name', 'My Group')
119
            ->sort('Name')
120
            ->First();
121
        $this->assertEquals($count + 1, $group->People()->Count());
122
    }
123
124
    public function testAddFormWithPolymorphicHasOne()
125
    {
126
        $group = PolymorphicPeopleGroup::get()
127
            ->filter('Name', 'My Group')
128
            ->sort('Name')
129
            ->First();
130
        $gridField = $group->getCMSFields()->dataFieldByName('People');
131
        $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

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

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

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

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

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