Passed
Pull Request — 4.3 (#8621)
by Maxime
07:48
created

testTreeSearchJsonFlatlistWithLowNodeThreshold()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 30
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 17
nc 1
nop 0
dl 0
loc 30
rs 9.7
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\Forms\Tests;
4
5
use SilverStripe\Assets\File;
6
use SilverStripe\Assets\Folder;
7
use SilverStripe\Control\Session;
8
use SilverStripe\Dev\CSSContentParser;
9
use SilverStripe\Dev\SapphireTest;
10
use SilverStripe\Control\HTTPRequest;
11
use SilverStripe\Forms\TreeDropdownField;
12
use SilverStripe\ORM\Tests\HierarchyTest\TestObject;
13
14
class TreeDropdownFieldTest extends SapphireTest
15
{
16
17
    protected static $fixture_file = 'TreeDropdownFieldTest.yml';
18
19
    protected static $extra_dataobjects = [
20
        TestObject::class
21
    ];
22
23
    public function testSchemaStateDefaults()
24
    {
25
        $field = new TreeDropdownField('TestTree', 'Test tree', Folder::class);
26
        $folder = $this->objFromFixture(Folder::class, 'folder1-subfolder1');
27
28
        $schema = $field->getSchemaStateDefaults();
29
        $this->assertFalse(isset($schema['data']['valueObject']));
30
31
        $field->setValue($folder->ID);
32
33
        $schema = $field->getSchemaStateDefaults();
34
        $this->assertEquals($folder->ID, $schema['data']['valueObject']['id']);
35
        $this->assertTrue(isset($schema['data']['valueObject']));
36
        $this->assertFalse($schema['data']['showSelectedPath']);
37
        $this->assertEquals('', $schema['data']['valueObject']['titlePath']);
38
39
        $field->setShowSelectedPath(true);
40
        $schema = $field->getSchemaStateDefaults();
41
        $this->assertTrue($schema['data']['showSelectedPath']);
42
        $this->assertEquals(
43
            'FileTest-folder1/FileTest-folder1-subfolder1/',
44
            $schema['data']['valueObject']['titlePath']
45
        );
46
    }
47
48
    public function testTreeSearchJson()
49
    {
50
        $field = new TreeDropdownField('TestTree', 'Test tree', Folder::class);
51
52
        // case insensitive search against keyword 'sub' for folders
53
        $request = new HTTPRequest('GET', 'url', array('search'=>'sub', 'format' => 'json'));
54
        $request->setSession(new Session([]));
55
        $response = $field->tree($request);
56
        $tree = json_decode($response->getBody(), true);
57
58
        $folder1 = $this->objFromFixture(Folder::class, 'folder1');
59
        $folder1Subfolder1 = $this->objFromFixture(Folder::class, 'folder1-subfolder1');
60
61
        $this->assertContains(
62
            $folder1->Name,
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...
63
            array_column($tree['children'], 'title'),
64
            $folder1->Name . ' is found in the json'
65
        );
66
67
        $filtered = array_filter($tree['children'], function ($entry) use ($folder1) {
68
            return $folder1->Name === $entry['title'];
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...
69
        });
70
        $folder1Tree = array_pop($filtered);
71
72
        $this->assertContains(
73
            $folder1Subfolder1->Name,
74
            array_column($folder1Tree['children'], 'title'),
75
            $folder1Subfolder1->Name . ' is found in the folder1 entry in the json'
76
        );
77
    }
78
79
    public function testTreeSearchJsonFlatlist()
80
    {
81
        $field = new TreeDropdownField('TestTree', 'Test tree', Folder::class);
82
83
        // case insensitive search against keyword 'sub' for folders
84
        $request = new HTTPRequest('GET', 'url', array('search'=>'sub', 'format' => 'json', 'flatList' => '1'));
85
        $request->setSession(new Session([]));
86
        $response = $field->tree($request);
87
        $tree = json_decode($response->getBody(), true);
88
89
        $folder1 = $this->objFromFixture(Folder::class, 'folder1');
90
        $folder1Subfolder1 = $this->objFromFixture(Folder::class, 'folder1-subfolder1');
91
92
        $this->assertNotContains(
93
            $folder1->Name,
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...
94
            array_column($tree['children'], 'title'),
95
            $folder1->Name . ' is not found in the json'
96
        );
97
98
        $this->assertContains(
99
            $folder1Subfolder1->Name,
100
            array_column($tree['children'], 'title'),
101
            $folder1Subfolder1->Name . ' is found in the json'
102
        );
103
    }
104
105
    public function testTreeSearchJsonFlatlistWithLowNodeThreshold()
106
    {
107
        // Initialise our TreeDropDownField
108
        $field = new TreeDropdownField('TestTree', 'Test tree', TestObject::class);
109
        $field->config()->set('node_threshold_total', 2);
110
111
        // Search for all Test object matching our criteria
112
        $request = new HTTPRequest(
113
            'GET',
114
            'url',
115
            ['search' => 'MatchSearchCriteria', 'format' => 'json', 'flatList' => '1']
116
        );
117
        $request->setSession(new Session([]));
118
        $response = $field->tree($request);
119
        $tree = json_decode($response->getBody(), true);
120
        $actualNodeIDs = array_column($tree['children'], 'id');
121
122
123
        // Get the list of expected node IDs from the YML Fixture
124
        $expectedNodeIDs = array_map(
125
            function ($key) {
126
                return $this->objFromFixture(TestObject::class, $key)->ID;
127
            },
128
            ['zero', 'oneA', 'twoAi', 'three'] // Those are the identifiers of the object we expect our search to find
129
        );
130
131
        sort($actualNodeIDs);
132
        sort($expectedNodeIDs);
133
134
        $this->assertEquals($expectedNodeIDs, $actualNodeIDs);
135
    }
136
137
    public function testTreeSearch()
138
    {
139
        $field = new TreeDropdownField('TestTree', 'Test tree', Folder::class);
140
141
        // case insensitive search against keyword 'sub' for folders
142
        $request = new HTTPRequest('GET', 'url', array('search'=>'sub'));
143
        $request->setSession(new Session([]));
144
        $response = $field->tree($request);
145
        $tree = $response->getBody();
146
147
        $folder1 = $this->objFromFixture(Folder::class, 'folder1');
148
        $folder1Subfolder1 = $this->objFromFixture(Folder::class, 'folder1-subfolder1');
149
150
        $parser = new CSSContentParser($tree);
151
        $cssPath = 'ul.tree li#selector-TestTree-' . $folder1->ID . ' li#selector-TestTree-' . $folder1Subfolder1->ID . ' a span.item';
152
        $firstResult = $parser->getBySelector($cssPath);
153
        $this->assertEquals(
154
            $folder1Subfolder1->Name,
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...
155
            (string)$firstResult[0],
156
            $folder1Subfolder1->Name . ' is found, nested under ' . $folder1->Name
157
        );
158
159
        $subfolder = $this->objFromFixture(Folder::class, 'subfolder');
160
        $cssPath = 'ul.tree li#selector-TestTree-' . $subfolder->ID . ' a span.item';
161
        $secondResult = $parser->getBySelector($cssPath);
162
        $this->assertEquals(
163
            $subfolder->Name,
164
            (string)$secondResult[0],
165
            $subfolder->Name . ' is found at root level'
166
        );
167
168
        // other folders which don't contain the keyword 'sub' are not returned in search results
169
        $folder2 = $this->objFromFixture(Folder::class, 'folder2');
170
        $cssPath = 'ul.tree li#selector-TestTree-' . $folder2->ID . ' a span.item';
171
        $noResult = $parser->getBySelector($cssPath);
172
        $this->assertEmpty(
173
            $noResult,
174
            $folder2 . ' is not found'
175
        );
176
177
        $field = new TreeDropdownField('TestTree', 'Test tree', File::class);
178
179
        // case insensitive search against keyword 'sub' for files
180
        $request = new HTTPRequest('GET', 'url', array('search'=>'sub'));
181
        $request->setSession(new Session([]));
182
        $response = $field->tree($request);
183
        $tree = $response->getBody();
184
185
        $parser = new CSSContentParser($tree);
186
187
        // Even if we used File as the source object, folders are still returned because Folder is a File
188
        $cssPath = 'ul.tree li#selector-TestTree-' . $folder1->ID . ' li#selector-TestTree-' . $folder1Subfolder1->ID . ' a span.item';
189
        $firstResult = $parser->getBySelector($cssPath);
190
        $this->assertEquals(
191
            $folder1Subfolder1->Name,
192
            (string)$firstResult[0],
193
            $folder1Subfolder1->Name . ' is found, nested under ' . $folder1->Name
194
        );
195
196
        // Looking for two files with 'sub' in their name, both under the same folder
197
        $file1 = $this->objFromFixture(File::class, 'subfolderfile1');
198
        $file2 = $this->objFromFixture(File::class, 'subfolderfile2');
199
        $cssPath = 'ul.tree li#selector-TestTree-' . $subfolder->ID . ' li#selector-TestTree-' . $file1->ID . ' a';
200
        $firstResult = $parser->getBySelector($cssPath);
201
        $this->assertNotEmpty(
202
            $firstResult,
203
            $file1->Name . ' with ID ' . $file1->ID . ' is in search results'
204
        );
205
        $this->assertEquals(
206
            $file1->Name,
207
            (string)$firstResult[0],
208
            $file1->Name . ' is found nested under ' . $subfolder->Name
209
        );
210
211
        $cssPath = 'ul.tree li#selector-TestTree-' . $subfolder->ID . ' li#selector-TestTree-' . $file2->ID . ' a';
212
        $secondResult = $parser->getBySelector($cssPath);
213
        $this->assertNotEmpty(
214
            $secondResult,
215
            $file2->Name . ' with ID ' . $file2->ID . ' is in search results'
216
        );
217
        $this->assertEquals(
218
            $file2->Name,
219
            (string)$secondResult[0],
220
            $file2->Name . ' is found nested under ' . $subfolder->Name
221
        );
222
223
        // other files which don't include 'sub' are not returned in search results
224
        $file3 = $this->objFromFixture(File::class, 'asdf');
225
        $cssPath = 'ul.tree li#selector-TestTree-' . $file3->ID;
226
        $noResult = $parser->getBySelector($cssPath);
227
        $this->assertEmpty(
228
            $noResult,
229
            $file3->Name . ' is not found'
230
        );
231
    }
232
233
    public function testReadonly()
234
    {
235
        $field = new TreeDropdownField('TestTree', 'Test tree', File::class);
236
        $fileMock = $this->objFromFixture(File::class, 'asdf');
237
        $field->setValue($fileMock->ID);
238
        $readonlyField = $field->performReadonlyTransformation();
239
        $result = (string) $readonlyField->Field();
240
        $this->assertContains(
241
            '<span class="readonly" id="TestTree">&lt;Special &amp; characters&gt;</span>',
242
            $result
243
        );
244
        $this->assertContains(
245
            '<input type="hidden" name="TestTree" value="' . $fileMock->ID . '" />',
246
            $result
247
        );
248
    }
249
}
250