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

testAddFormWithPolymorphicHasOne()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 13
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 17
rs 9.8333
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\TestController;
18
19
/**
20
 * @skipUpgrade
21
 */
22
class GridFieldDetailFormTest extends FunctionalTest
23
{
24
    protected static $fixture_file = 'GridFieldDetailFormTest.yml';
25
26
    protected static $extra_dataobjects = [
27
        Person::class,
28
        PeopleGroup::class,
29
        Category::class,
30
    ];
31
32
    protected static $extra_controllers = [
33
        CategoryController::class,
34
        TestController::class,
35
        GroupController::class,
36
    ];
37
38
    protected static $disable_themes = true;
39
40
    public function testValidator()
41
    {
42
        $this->logInWithPermission('ADMIN');
43
44
        $response = $this->get('GridFieldDetailFormTest_Controller');
45
        $this->assertFalse($response->isError());
46
        $parser = new CSSContentParser($response->getBody());
47
        $addlinkitem = $parser->getBySelector('.grid-field .new-link');
48
        $addlink = (string) $addlinkitem[0]['href'];
49
50
        $response = $this->get($addlink);
51
        $this->assertFalse($response->isError());
52
53
        $parser = new CSSContentParser($response->getBody());
54
        $addform = $parser->getBySelector('#Form_ItemEditForm');
55
        $addformurl = (string) $addform[0]['action'];
56
57
        $response = $this->post(
58
            $addformurl,
59
            [
60
                'FirstName' => 'Jeremiah',
61
                'ajax' => 1,
62
                'action_doSave' => 1
63
            ]
64
        );
65
66
        $parser = new CSSContentParser($response->getBody());
67
        $errors = $parser->getBySelector('span.required');
68
        $this->assertEquals(1, count($errors ?? []));
69
70
        $response = $this->post(
71
            $addformurl,
72
            [
73
                'ajax' => 1,
74
                'action_doSave' => 1
75
            ]
76
        );
77
78
        $parser = new CSSContentParser($response->getBody());
79
        $errors = $parser->getBySelector('span.required');
80
        $this->assertEquals(2, count($errors ?? []));
81
    }
82
83
    public function testAddForm()
84
    {
85
        $this->logInWithPermission('ADMIN');
86
        $group = PeopleGroup::get()
87
            ->filter('Name', 'My Group')
88
            ->sort('Name')
89
            ->First();
90
        $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

90
        $count = $group->/** @scrutinizer ignore-call */ People()->Count();
Loading history...
91
92
        $response = $this->get('GridFieldDetailFormTest_Controller');
93
        $this->assertFalse($response->isError());
94
        $parser = new CSSContentParser($response->getBody());
95
        $addlinkitem = $parser->getBySelector('.grid-field .new-link');
96
        $addlink = (string) $addlinkitem[0]['href'];
97
98
        $response = $this->get($addlink);
99
        $this->assertFalse($response->isError());
100
101
        $parser = new CSSContentParser($response->getBody());
102
        $addform = $parser->getBySelector('#Form_ItemEditForm');
103
        $addformurl = (string) $addform[0]['action'];
104
105
        $response = $this->post(
106
            $addformurl,
107
            [
108
                'FirstName' => 'Jeremiah',
109
                'Surname' => 'BullFrog',
110
                'action_doSave' => 1
111
            ]
112
        );
113
        $this->assertFalse($response->isError());
114
115
        $group = PeopleGroup::get()
116
            ->filter('Name', 'My Group')
117
            ->sort('Name')
118
            ->First();
119
        $this->assertEquals($count + 1, $group->People()->Count());
120
    }
121
122
    public function testAddFormWithPolymorphicHasOne()
123
    {
124
        $group = PolymorphicPeopleGroup::get()
0 ignored issues
show
Bug introduced by
The type SilverStripe\Forms\Tests...\PolymorphicPeopleGroup was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

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

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

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

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

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