Skip to content

Commit

Permalink
MNT Add tests for using GridField with arbitrary data
Browse files Browse the repository at this point in the history
Note that the main tests are added as behat tests in the admin module
  • Loading branch information
GuySartorelli committed Dec 10, 2023
1 parent 72607ae commit aa5a151
Show file tree
Hide file tree
Showing 11 changed files with 680 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace SilverStripe\Forms\Tests\GridField;

use LogicException;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Core\Convert;
use SilverStripe\Dev\CSSContentParser;
Expand Down Expand Up @@ -167,6 +168,90 @@ function ($item) {
);
}

public function provideMustHaveDataObject()
{
return [
[
'method' => 'getHTMLFragments',
'args' => ['__GRIDFIELD__'],
'throwsException' => true,
],
[
'method' => 'getManipulatedData',
'args' => ['__GRIDFIELD__', '__LIST__'],
'throwsException' => true,
],
[
'method' => 'doSearch',
'args' => ['__GRIDFIELD__', '__REQUEST__'],
'throwsException' => true,
],
[
'method' => 'scaffoldSearchFields',
'args' => ['__DATACLASS__'],
'throwsException' => true,
],
[
'method' => 'getPlaceholderText',
'args' => ['__DATACLASS__'],
'throwsException' => true,
],
[
'method' => 'setPlaceholderText',
'args' => [''],
'throwsException' => false,
],
];
}

/**
* @dataProvider provideMustHaveDataObject
*/
public function testMustHaveDataObject(string $method, array $args, bool $throwsException)
{
$component = new GridFieldAddExistingAutocompleter();
$gridField = $this->getGridFieldForComponent($component);
$list = new ArrayList();
$dataClass = ArrayData::class;
$list->setDataClass($dataClass);
$gridField->setList($list);

foreach ($args as $key => $value) {
switch ($value) {
case '__GRIDFIELD__':
$args[$key] = $gridField;
break;
case '__LIST__':
$args[$key] = $list;
break;
case '__REQUEST__':
$args[$key] = new HTTPRequest('GET', '');
break;
case '__DATACLASS__':
$args[$key] = $dataClass;
break;
default:
// no-op
}
}

if ($throwsException) {
$this->expectException(LogicException::class);
$this->expectExceptionMessage(
GridFieldAddExistingAutocompleter::class
. " must be used with DataObject subclasses. Found '$dataClass'"
);
} else {
// Prevent from being marked risky.
// This test passes if there's no exception thrown.
$this->expectNotToPerformAssertions();
}

// Calling the method will either throw an exception or not.
// The test pass/failure is explicitly about whether an exception is thrown.
$component->$method(...$args);
}

protected function getGridFieldForComponent($component)
{
$config = GridFieldConfig::create()->addComponents(
Expand Down
22 changes: 22 additions & 0 deletions tests/php/Forms/GridField/GridFieldAddNewButtonTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,22 @@

namespace SilverStripe\Forms\Tests\GridField;

use LogicException;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\Form;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridFieldAddNewButton;
use SilverStripe\Forms\GridField\GridFieldConfig;
use SilverStripe\Forms\GridField\GridFieldConfig_Base;
use SilverStripe\Forms\Tests\GridField\GridFieldDetailFormTest\Person;
use SilverStripe\Forms\Tests\GridField\GridFieldDetailFormTest\PeopleGroup;
use SilverStripe\Forms\Tests\GridField\GridFieldDetailFormTest\Category;
use SilverStripe\Forms\Tests\GridField\GridFieldDetailFormTest\TestController;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\SS_List;
use SilverStripe\View\ArrayData;

class GridFieldAddNewButtonTest extends SapphireTest
{
Expand Down Expand Up @@ -76,6 +80,24 @@ public function testButtonPassesNoParentContextToSingletonWhenNoParentRecordExis
$this->mockButtonFragments($list, null);
}

public function testGetHTMLFragmentsThrowsException()
{
$component = new GridFieldAddNewButton();
$config = new GridFieldConfig_Base();
$config->addComponent($component);
$gridField = new GridField('dummy', 'dummy', new ArrayList(), $config);
$modelClass = ArrayData::class;
$gridField->setModelClass($modelClass);

$this->expectException(LogicException::class);
$this->expectExceptionMessage(
GridFieldAddNewButton::class . ' cannot be used with models that do not implement canCreate().'
. " Remove this component from your GridField or implement canCreate() on $modelClass"
);

$component->getHTMLFragments($gridField);
}

protected function mockButtonFragments(SS_List $list, $parent = null)
{
$form = Form::create(
Expand Down
22 changes: 22 additions & 0 deletions tests/php/Forms/GridField/GridFieldDataColumnsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@
namespace SilverStripe\Forms\Tests\GridField;

use InvalidArgumentException;
use LogicException;
use SilverStripe\Forms\GridField\GridFieldDataColumns;
use SilverStripe\Security\Member;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridFieldConfig_Base;
use SilverStripe\ORM\ArrayList;
use SilverStripe\View\ArrayData;
use stdClass;

class GridFieldDataColumnsTest extends SapphireTest
Expand Down Expand Up @@ -76,4 +80,22 @@ public function testFieldFormatting()
$columns->getFieldFormatting()
);
}

public function testGetDisplayFieldsThrowsException()
{
$component = new GridFieldDataColumns();
$config = new GridFieldConfig_Base();
$config->addComponent($component);
$gridField = new GridField('dummy', 'dummy', new ArrayList(), $config);
$modelClass = ArrayData::class;
$gridField->setModelClass($modelClass);

$this->expectException(LogicException::class);
$this->expectExceptionMessage(
'Cannot dynamically determine columns. Pass the column names to setDisplayFields()'
. " or implement a summaryFields() method on $modelClass"
);

$component->getDisplayFields($gridField);
}
}
71 changes: 71 additions & 0 deletions tests/php/Forms/GridField/GridFieldDeleteActionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace SilverStripe\Forms\Tests\GridField;

use LogicException;
use ReflectionMethod;
use SilverStripe\Control\Controller;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse_Exception;
Expand All @@ -12,6 +14,7 @@
use SilverStripe\Forms\Form;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridFieldConfig;
use SilverStripe\Forms\GridField\GridFieldConfig_Base;
use SilverStripe\Forms\GridField\GridFieldDeleteAction;
use SilverStripe\Forms\Tests\GridField\GridFieldTest\Cheerleader;
use SilverStripe\Forms\Tests\GridField\GridFieldTest\Permissions;
Expand All @@ -22,6 +25,7 @@
use SilverStripe\ORM\ValidationException;
use SilverStripe\Security\Security;
use SilverStripe\Security\SecurityToken;
use SilverStripe\View\ArrayData;

class GridFieldDeleteActionTest extends SapphireTest
{
Expand Down Expand Up @@ -230,4 +234,71 @@ public function testMenuGroup()
$group = $action->getGroup($gridField, $this->list->first(), 'dummy');
$this->assertNull($group, 'A menu group does not exist when the user cannot delete');
}

public function provideComponentThrowsException()
{
return [
[
'method' => 'handleAction',
'args' => ['__GRIDFIELD__', 'deleterecord', ['RecordID' => 1], []],
'requiredMethod' => 'canDelete',
],
[
'method' => 'handleAction',
'args' => ['__GRIDFIELD__', 'unlinkrelation', ['RecordID' => 1], []],
'requiredMethod' => 'canEdit',
],
[
'method' => 'getRemoveAction',
'args' => ['__GRIDFIELD__', new ArrayData(), ''],
'requiredMethod' => 'canEdit',
'prerequisiteMethodCalls' => ['setRemoveRelation' => [true]],
],
[
'method' => 'getRemoveAction',
'args' => ['__GRIDFIELD__', new ArrayData(), ''],
'requiredMethod' => 'canDelete',
'prerequisiteMethodCalls' => ['setRemoveRelation' => [false]],
],
];
}

/**
* @dataProvider provideComponentThrowsException
*/
public function testComponentThrowsException(string $method, array $args, string $requiredMethod, array $prerequisiteMethodCalls = [])
{
$component = new GridFieldDeleteAction();
$config = new GridFieldConfig_Base();
$config->addComponent($component);
$gridField = new GridField('dummy', 'dummy', new ArrayList([new ArrayData(['ID' => 1])]), $config);
$modelClass = ArrayData::class;
$gridField->setModelClass($modelClass);

foreach ($prerequisiteMethodCalls as $methodToCall => $toCallArgs) {
$component->$methodToCall(...$toCallArgs);
}

foreach ($args as $key => $value) {
if ($value === '__GRIDFIELD__') {
$args[$key] = $gridField;
}
}

$this->expectException(LogicException::class);
$this->expectExceptionMessage(
GridFieldDeleteAction::class . " cannot be used with models that don't implement {$requiredMethod}()."
. " Remove this component from your GridField or implement {$requiredMethod}() on $modelClass"
);

// Calling the method will either throw an exception or not.
// The test pass/failure is explicitly about whether an exception is thrown.
$reflectionMethod = new ReflectionMethod($component, $method);
if ($reflectionMethod->isPublic()) {
$component->$method(...$args);
} else {
$reflectionMethod->setAccessible(true);
$reflectionMethod->invokeArgs($component, $args);
}
}
}
33 changes: 33 additions & 0 deletions tests/php/Forms/GridField/GridFieldDetailForm_ItemRequestTest .php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace SilverStripe\Forms\Tests\GridField;

use SilverStripe\Control\Controller;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridFieldConfig_Base;
use SilverStripe\Forms\GridField\GridFieldDetailForm;
use SilverStripe\Forms\GridField\GridFieldDetailForm_ItemRequest;
use SilverStripe\ORM\ArrayList;
use SilverStripe\View\ArrayData;

class GridFieldDetailForm_ItemRequestTest extends SapphireTest
{
protected $usesDatabase = false;

public function testItemEditFormThrowsException()
{
$gridField = new GridField('dummy', 'dummy', new ArrayList(), new GridFieldConfig_Base());
$modelClass = ArrayData::class;
$gridField->setModelClass($modelClass);
$itemRequest = new GridFieldDetailForm_ItemRequest($gridField, new GridFieldDetailForm(), new ArrayData(), new Controller(), '');

$this->expectException(LogicException::class);
$this->expectExceptionMessage(
'Cannot dynamically determine columns. Pass the fields to GridFieldDetailForm::setFields()'
. " or implement a getCMSFields() method on $modelClass"
);

$itemRequest->ItemEditForm();
}
}
30 changes: 28 additions & 2 deletions tests/php/Forms/GridField/GridFieldExportButtonTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
namespace SilverStripe\Forms\Tests\GridField;

use League\Csv\Reader;
use LogicException;
use ReflectionMethod;
use SilverStripe\Forms\Tests\GridField\GridFieldExportButtonTest\NoView;
use SilverStripe\Forms\Tests\GridField\GridFieldExportButtonTest\Team;
use SilverStripe\ORM\DataList;
Expand All @@ -12,8 +14,10 @@
use SilverStripe\Forms\GridField\GridFieldConfig;
use SilverStripe\Forms\GridField\GridFieldExportButton;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridFieldDataColumns;
use SilverStripe\Forms\GridField\GridFieldPaginator;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\View\ArrayData;

class GridFieldExportButtonTest extends SapphireTest
{
Expand Down Expand Up @@ -155,13 +159,16 @@ public function testNoCsvHeaders()
public function testArrayListInput()
{
$button = new GridFieldExportButton();
$columns = new GridFieldDataColumns();
$columns->setDisplayFields(['ID' => 'ID']);
$this->gridField->getConfig()->addComponent($columns);
$this->gridField->getConfig()->addComponent(new GridFieldPaginator());

//Create an ArrayList 1 greater the Paginator's default 15 rows
$arrayList = new ArrayList();
for ($i = 1; $i <= 16; $i++) {
$dataobject = new DataObject(['ID' => $i]);
$arrayList->add($dataobject);
$datum = new ArrayData(['ID' => $i]);
$arrayList->add($datum);
}
$this->gridField->setList($arrayList);

Expand Down Expand Up @@ -192,6 +199,25 @@ public function testZeroValue()
);
}

public function testGetExportColumnsForGridFieldThrowsException()
{
$component = new GridFieldExportButton();
$gridField = new GridField('dummy', 'dummy', new ArrayList());
$gridField->getConfig()->removeComponentsByType(GridFieldDataColumns::class);
$modelClass = ArrayData::class;
$gridField->setModelClass($modelClass);

$this->expectException(LogicException::class);
$this->expectExceptionMessage(
'Cannot dynamically determine columns. Add a GridFieldDataColumns component to your GridField'
. " or implement a summaryFields() method on $modelClass"
);

$reflectionMethod = new ReflectionMethod($component, 'getExportColumnsForGridField');
$reflectionMethod->setAccessible(true);
$reflectionMethod->invoke($component, $gridField);
}

protected function createReader($string)
{
$reader = Reader::createFromString($string);
Expand Down
Loading

0 comments on commit aa5a151

Please sign in to comment.