Passed
Push — master ( b4f0a0...3f9085 )
by
unknown
04:22 queued 10s
created

TagFieldTest::testSchemaIsAddedToAttributes()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace SilverStripe\TagField\Tests;
4
5
use PHPUnit_Framework_TestCase;
6
use SilverStripe\Control\HTTPRequest;
7
use SilverStripe\Dev\SapphireTest;
8
use SilverStripe\Forms\FieldList;
9
use SilverStripe\Forms\Form;
10
use SilverStripe\ORM\DataList;
11
use SilverStripe\ORM\DataObject;
12
use SilverStripe\TagField\ReadonlyTagField;
13
use SilverStripe\TagField\TagField;
14
use SilverStripe\TagField\Tests\Stub\TagFieldTestBlogPost;
15
use SilverStripe\TagField\Tests\Stub\TagFieldTestBlogTag;
16
use SilverStripe\TagField\Tests\Stub\TagFieldTestController;
17
18
/**
19
 * @mixin PHPUnit_Framework_TestCase
20
 */
21
class TagFieldTest extends SapphireTest
22
{
23
    /**
24
     * @var string
25
     */
26
    protected static $fixture_file = 'TagFieldTest.yml';
27
28
    /**
29
     * @var array
30
     */
31
    protected static $extra_dataobjects = [
32
        TagFieldTestBlogTag::class,
33
        TagFieldTestBlogPost::class,
34
    ];
35
36
    public function testItSavesLinksToNewTagsOnNewRecords()
37
    {
38
        $record = $this->getNewTagFieldTestBlogPost('BlogPost1');
39
        $field = new TagField('Tags', '', new DataList(TagFieldTestBlogTag::class));
40
        $field->setValue(['Tag3', 'Tag4']);
41
        $field->saveInto($record);
42
        $record->write();
43
        $this->compareExpectedAndActualTags(
44
            ['Tag3', 'Tag4'],
45
            $record
46
        );
47
    }
48
49
    /**
50
     * @param string $name
51
     *
52
     * @return TagFieldTestBlogPost
53
     */
54
    protected function getNewTagFieldTestBlogPost($name)
55
    {
56
        return $this->objFromFixture(
57
            TagFieldTestBlogPost::class,
58
            $name
59
        );
60
    }
61
62
    /**
63
     * @param array $expected
64
     * @param TagFieldTestBlogPost $record
65
     */
66
    protected function compareExpectedAndActualTags(array $expected, TagFieldTestBlogPost $record)
67
    {
68
        $this->compareTagLists($expected, $record->Tags());
0 ignored issues
show
Bug introduced by
The method Tags() does not exist on SilverStripe\TagField\Te...ub\TagFieldTestBlogPost. 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

68
        $this->compareTagLists($expected, $record->/** @scrutinizer ignore-call */ Tags());
Loading history...
69
    }
70
71
    /**
72
     * Ensure a source of tags matches the given string tag names
73
     *
74
     * @param array $expected
75
     * @param DataList $actualSource
76
     */
77
    protected function compareTagLists(array $expected, DataList $actualSource)
78
    {
79
        $actual = array_values($actualSource->map('ID', 'Title')->toArray());
80
        sort($expected);
81
        sort($actual);
82
83
        $this->assertEquals(
84
            $expected,
85
            $actual
86
        );
87
    }
88
89
    public function testItSavesLinksToNewTagsOnExistingRecords()
90
    {
91
        $record = $this->getNewTagFieldTestBlogPost('BlogPost1');
92
        $record->write();
93
94
        $field = new TagField('Tags', '', new DataList(TagFieldTestBlogTag::class));
95
        $field->setValue(['Tag3', 'Tag4']);
96
        $field->saveInto($record);
97
98
        $this->compareExpectedAndActualTags(
99
            array('Tag3', 'Tag4'),
100
            $record
101
        );
102
    }
103
104
    public function testItSavesLinksToExistingTagsOnNewRecords()
105
    {
106
        $record = $this->getNewTagFieldTestBlogPost('BlogPost1');
107
108
        $field = new TagField('Tags', '', new DataList(TagFieldTestBlogTag::class));
109
        $field->setValue(['Tag1', 'Tag2']);
110
        $field->saveInto($record);
111
112
        $record->write();
113
114
        $this->compareExpectedAndActualTags(
115
            ['Tag1', 'Tag2'],
116
            $record
117
        );
118
    }
119
120
    public function testItSavesLinksToExistingTagsOnExistingRecords()
121
    {
122
        $record = $this->getNewTagFieldTestBlogPost('BlogPost1');
123
        $record->write();
124
125
        $field = new TagField('Tags', '', new DataList(TagFieldTestBlogTag::class));
126
        $field->setValue(['Tag1', 'Tag2']);
127
        $field->saveInto($record);
128
129
        $this->compareExpectedAndActualTags(
130
            ['Tag1', 'Tag2'],
131
            $record
132
        );
133
    }
134
135
    /**
136
     * Ensure that {@see TagField::saveInto} respects existing tags
137
     */
138
    public function testSaveDuplicateTags()
139
    {
140
        $record = $this->getNewTagFieldTestBlogPost('BlogPost2');
141
        $record->write();
142
        $tag2ID = $this->idFromFixture(TagFieldTestBlogTag::class, 'Tag2');
143
144
        // Check tags before write
145
        $this->compareExpectedAndActualTags(
146
            ['Tag1', '222'],
147
            $record
148
        );
149
        $this->compareTagLists(
150
            ['Tag1', '222'],
151
            TagFieldTestBlogTag::get()
152
        );
153
        $this->assertContains($tag2ID, TagFieldTestBlogTag::get()->column('ID'));
154
155
        // Write new tags
156
        $field = new TagField('Tags', '', new DataList(TagFieldTestBlogTag::class));
157
        $field->setValue(['222', 'Tag3']);
158
        $field->saveInto($record);
159
160
        // Check only one new tag was added
161
        $this->compareExpectedAndActualTags(
162
            ['222', 'Tag3'],
163
            $record
164
        );
165
166
        // Ensure that only one new dataobject was added and that tag2s id has not changed
167
        $this->compareTagLists(
168
            ['Tag1', '222', 'Tag3'],
169
            TagFieldTestBlogTag::get()
170
        );
171
        $this->assertContains($tag2ID, TagFieldTestBlogTag::get()->column('ID'));
172
    }
173
174
    public function testItSuggestsTags()
175
    {
176
        $field = new TagField('Tags', '', new DataList(TagFieldTestBlogTag::class));
177
178
        /**
179
         * Partial tag title match.
180
         */
181
        $request = $this->getNewRequest(['term' => 'Tag']);
182
183
        $this->assertEquals(
184
            '{"items":[{"id":"Tag1","text":"Tag1"}]}',
185
            $field->suggest($request)->getBody()
186
        );
187
188
        /**
189
         * Exact tag title match.
190
         */
191
        $request = $this->getNewRequest(['term' => '222']);
192
193
        $this->assertEquals(
194
            '{"items":[{"id":"222","text":"222"}]}',
195
            $field->suggest($request)->getBody()
196
        );
197
198
        /**
199
         * Case-insensitive tag title match.
200
         */
201
        $request = $this->getNewRequest(['term' => 'TAG1']);
202
203
        $this->assertEquals(
204
            '{"items":[{"id":"Tag1","text":"Tag1"}]}',
205
            $field->suggest($request)->getBody()
206
        );
207
208
        /**
209
         * No tag title match.
210
         */
211
        $request = $this->getNewRequest(['term' => 'unknown']);
212
213
        $this->assertEquals(
214
            '{"items":[]}',
215
            $field->suggest($request)->getBody()
216
        );
217
    }
218
219
    /**
220
     * Tests that TagField supports pre-filtered data sources
221
     */
222
    public function testRestrictedSuggestions()
223
    {
224
        $source = TagFieldTestBlogTag::get()->exclude('Title', 'Tag2');
225
        $field = new TagField('Tags', '', $source);
226
227
        /**
228
         * Partial tag title match.
229
         */
230
        $request = $this->getNewRequest(['term' => 'Tag']);
231
232
        $this->assertEquals(
233
            '{"items":[{"id":"Tag1","text":"Tag1"}]}',
234
            $field->suggest($request)->getBody()
235
        );
236
237
        /**
238
         * Exact tag title match.
239
         */
240
        $request = $this->getNewRequest(['term' => 'Tag1']);
241
242
        $this->assertEquals(
243
            '{"items":[{"id":"Tag1","text":"Tag1"}]}',
244
            $field->suggest($request)->getBody()
245
        );
246
247
        /**
248
         * Excluded item doesn't appear in matches
249
         */
250
        $request = $this->getNewRequest(['term' => 'Tag2']);
251
252
        $this->assertEquals(
253
            '{"items":[]}',
254
            $field->suggest($request)->getBody()
255
        );
256
    }
257
258
    /**
259
     * @param array $parameters
260
     *
261
     * @return HTTPRequest
262
     */
263
    protected function getNewRequest(array $parameters)
264
    {
265
        return new HTTPRequest(
266
            'get',
267
            'TagFieldTestController/TagFieldTestForm/fields/Tags/suggest',
268
            $parameters
269
        );
270
    }
271
272
    public function testItDisplaysValuesFromRelations()
273
    {
274
        $record = $this->getNewTagFieldTestBlogPost('BlogPost1');
275
        $record->write();
276
277
        $form = new Form(
278
            new TagFieldTestController(),
279
            'Form',
280
            new FieldList(
281
                $field = new TagField('Tags', '', new DataList(TagFieldTestBlogTag::class))
282
            ),
283
            new FieldList()
284
        );
285
286
        $form->loadDataFrom(
287
            $this->objFromFixture(TagFieldTestBlogPost::class, 'BlogPost2')
288
        );
289
290
        $ids = TagFieldTestBlogTag::get()->column('Title');
291
292
        $this->assertEquals($field->Value(), $ids);
293
    }
294
295
    public function testItIgnoresNewTagsIfCannotCreate()
296
    {
297
        $this->markTestSkipped(
298
            'This test has not been updated yet.'
299
        );
300
301
        $record = new TagFieldTestBlogPost();
302
        $record->write();
303
304
        $tag = TagFieldTestBlogTag::get()->filter('Title', 'Tag1')->first();
305
306
        $field = new TagField('Tags', '', new DataList(TagFieldTestBlogTag::class), [$tag->Title, 'Tag3']);
307
        $field->setCanCreate(false);
308
        $field->saveInto($record);
309
310
        /**
311
         * @var TagFieldTestBlogPost $record
312
         */
313
        $record = DataObject::get_by_id(TagFieldTestBlogPost::class, $record->ID);
314
315
        $this->compareExpectedAndActualTags(
316
            ['Tag1'],
317
            $record
318
        );
319
    }
320
321
    /**
322
     * Test you can save without a source set
323
     */
324
    public function testSaveEmptySource()
325
    {
326
        $record = new TagFieldTestBlogPost();
327
        $record->write();
328
329
        // Clear database of tags
330
        TagFieldTestBlogTag::get()->removeAll();
331
332
        $field = new TagField('Tags', '', TagFieldTestBlogTag::get());
333
        $field->setValue(['New Tag']);
334
        $field->setCanCreate(true);
335
        $field->saveInto($record);
336
337
        $tag = TagFieldTestBlogTag::get()->first();
338
        $this->assertNotEmpty($tag);
339
        $this->assertEquals('New Tag', $tag->Title);
340
        $record = TagFieldTestBlogPost::get()->byID($record->ID);
341
        $this->assertEquals(
342
            $tag->ID,
343
            $record->Tags()->first()->ID
344
        );
345
    }
346
347
    /**
348
     * Test read only fields are returned
349
     */
350
    public function testReadonlyTransformation()
351
    {
352
        $field = new TagField('Tags', '', TagFieldTestBlogTag::get());
353
        $readOnlyField = $field->performReadonlyTransformation();
354
        $this->assertInstanceOf(ReadonlyTagField::class, $readOnlyField);
355
    }
356
357
    public function testGetSchemaDataDefaults()
358
    {
359
        $form = new Form(null, 'Form', new FieldList(), new FieldList());
360
        $field = new TagField('TestField', 'Test Field', TagFieldTestBlogTag::get());
361
        $field->setForm($form);
362
363
        $field
364
            ->setShouldLazyLoad(false)
365
            ->setCanCreate(false);
366
367
        $schema = $field->getSchemaDataDefaults();
368
        $this->assertSame('TestField[]', $schema['name']);
369
        $this->assertFalse($schema['lazyLoad']);
370
        $this->assertFalse($schema['creatable']);
371
        $this->assertEquals([
372
            ['Title' => 'Tag1', 'Value' => 'Tag1'],
373
            ['Title' => '222', 'Value' => '222'],
374
        ], $schema['options']);
375
376
        $field
377
            ->setShouldLazyLoad(true)
378
            ->setCanCreate(true);
379
380
        $schema = $field->getSchemaDataDefaults();
381
        $this->assertTrue($schema['lazyLoad']);
382
        $this->assertTrue($schema['creatable']);
383
        $this->assertContains('suggest', $schema['optionUrl']);
384
    }
385
386
    public function testSchemaIsAddedToAttributes()
387
    {
388
        $field = new TagField('TestField');
389
        $attributes = $field->getAttributes();
390
        $this->assertNotEmpty($attributes['data-schema']);
391
    }
392
}
393