Completed
Pull Request — master (#6979)
by Daniel
15:30 queued 06:20
created

HTMLEditorFieldTest::testNullSaving()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 0
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\Forms\Tests\HTMLEditor;
4
5
use SilverStripe\Assets\File;
6
use SilverStripe\Assets\FileNameFilter;
7
use SilverStripe\Assets\Filesystem;
8
use SilverStripe\Assets\Folder;
9
use SilverStripe\Assets\Image;
10
use SilverStripe\Assets\Tests\Storage\AssetStoreTest\TestAssetStore;
11
use SilverStripe\Core\Config\Config;
12
use SilverStripe\Dev\CSSContentParser;
13
use SilverStripe\Dev\FunctionalTest;
14
use SilverStripe\Forms\HTMLEditor\HTMLEditorField;
15
use SilverStripe\Forms\HTMLReadonlyField;
16
use SilverStripe\Forms\Tests\HTMLEditor\HTMLEditorFieldTest\TestObject;
17
use SilverStripe\ORM\FieldType\DBHTMLText;
18
use SilverStripe\Forms\HTMLEditor\TinyMCEConfig;
19
20
class HTMLEditorFieldTest extends FunctionalTest
21
{
22
    protected static $fixture_file = 'HTMLEditorFieldTest.yml';
23
24
    protected static $use_draft_site = true;
25
26
    protected static $extra_dataobjects = [
27
        TestObject::class,
28
    ];
29
30
    protected function setUp()
31
    {
32
        parent::setUp();
33
34
        // Set backend root to /HTMLEditorFieldTest
35
        TestAssetStore::activate('HTMLEditorFieldTest');
36
37
        // Set the File Name Filter replacements so files have the expected names
38
        Config::modify()->set(
39
            FileNameFilter::class,
40
            'default_replacements',
41
            [
42
                '/\s/' => '-', // remove whitespace
43
                '/_/' => '-', // underscores to dashes
44
                '/[^A-Za-z0-9+.\-]+/' => '', // remove non-ASCII chars, only allow alphanumeric plus dash and dot
45
                '/[\-]{2,}/' => '-', // remove duplicate dashes
46
                '/^[\.\-_]+/' => '', // Remove all leading dots, dashes or underscores
47
            ]
48
        );
49
50
        // Create a test files for each of the fixture references
51
        $files = File::get()->exclude('ClassName', Folder::class);
52
        foreach ($files as $file) {
53
            $fromPath = __DIR__ . '/HTMLEditorFieldTest/images/' . $file->Name;
54
            $destPath = TestAssetStore::getLocalPath($file); // Only correct for test asset store
55
            Filesystem::makeFolder(dirname($destPath));
56
            copy($fromPath, $destPath);
57
        }
58
    }
59
60
    protected function tearDown()
61
    {
62
        TestAssetStore::reset();
63
        parent::tearDown();
64
    }
65
66
    public function testCasting()
67
    {
68
        // Shim TinyMCE so silverstripe/admin doesn't have to be installed
69
        TinyMCEConfig::config()->set('base_dir', 'test');
70
        HtmlEditorField::config()->set('use_gzip', false);
71
72
        // Test special characters
73
        $inputText = "These are some unicodes: ä, ö, & ü";
74
        $field = new HTMLEditorField("Test", "Test");
75
        $field->setValue($inputText);
76
        $this->assertContains('These are some unicodes: &auml;, &ouml;, &amp; &uuml;', $field->Field());
77
        // Test shortcodes
78
        $inputText = "Shortcode: [file_link id=4]";
79
        $field = new HTMLEditorField("Test", "Test");
80
        $field->setValue($inputText);
81
        $this->assertContains('Shortcode: [file_link id=4]', $field->Field());
82
    }
83
84
    public function testBasicSaving()
85
    {
86
        $obj = new TestObject();
87
        $editor   = new HTMLEditorField('Content');
88
89
        $editor->setValue('<p class="foo">Simple Content</p>');
90
        $editor->saveInto($obj);
91
        $this->assertEquals('<p class="foo">Simple Content</p>', $obj->Content, 'Attributes are preserved.');
92
93
        $editor->setValue('<p>Unclosed Tag');
94
        $editor->saveInto($obj);
95
        $this->assertEquals('<p>Unclosed Tag</p>', $obj->Content, 'Unclosed tags are closed.');
96
    }
97
98
    public function testNullSaving()
99
    {
100
        $obj = new TestObject();
101
        $editor = new HTMLEditorField('Content');
102
103
        $editor->setValue(null);
104
        $editor->saveInto($obj);
105
        $this->assertEquals('', $obj->Content, "Doesn't choke on empty/null values.");
106
    }
107
108
    public function testResizedImageInsertion()
109
    {
110
        $obj = new TestObject();
111
        $editor = new HTMLEditorField('Content');
112
113
        $fileID = $this->idFromFixture(Image::class, 'example_image');
114
        $editor->setValue(
115
            sprintf(
116
                '[image src="assets/example.jpg" width="10" height="20" id="%d"]',
117
                $fileID
118
            )
119
        );
120
        $editor->saveInto($obj);
121
122
        $parser = new CSSContentParser($obj->dbObject('Content')->forTemplate());
123
        $xml = $parser->getByXpath('//img');
124
        $this->assertEquals(
125
            'example',
126
            (string)$xml[0]['alt'],
127
            'Alt tags are added by default based on filename'
128
        );
129
        $this->assertEquals('', (string)$xml[0]['title'], 'Title tags are added by default.');
130
        $this->assertEquals(10, (int)$xml[0]['width'], 'Width tag of resized image is set.');
131
        $this->assertEquals(20, (int)$xml[0]['height'], 'Height tag of resized image is set.');
132
133
        $neededFilename
134
            = '/assets/HTMLEditorFieldTest/f5c7c2f814/example__ResizedImageWyIxMCIsIjIwIl0.jpg';
135
136
        $this->assertEquals($neededFilename, (string)$xml[0]['src'], 'Correct URL of resized image is set.');
137
        $this->assertTrue(file_exists(BASE_PATH.DIRECTORY_SEPARATOR.$neededFilename), 'File for resized image exists');
138
        $this->assertEquals(false, $obj->HasBrokenFile, 'Referenced image file exists.');
139
    }
140
141
    public function testMultiLineSaving()
142
    {
143
        $obj = $this->objFromFixture(TestObject::class, 'home');
144
        $editor   = new HTMLEditorField('Content');
145
        $editor->setValue('<p>First Paragraph</p><p>Second Paragraph</p>');
146
        $editor->saveInto($obj);
0 ignored issues
show
Bug introduced by
It seems like $obj defined by $this->objFromFixture(\S...tObject::class, 'home') on line 143 can be null; however, SilverStripe\Forms\HTMLE...EditorField::saveInto() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
147
        $this->assertEquals('<p>First Paragraph</p><p>Second Paragraph</p>', $obj->Content);
148
    }
149
150
    public function testSavingLinksWithoutHref()
151
    {
152
        $obj = $this->objFromFixture(TestObject::class, 'home');
153
        $editor   = new HTMLEditorField('Content');
154
155
        $editor->setValue('<p><a name="example-anchor"></a></p>');
156
        $editor->saveInto($obj);
0 ignored issues
show
Bug introduced by
It seems like $obj defined by $this->objFromFixture(\S...tObject::class, 'home') on line 152 can be null; however, SilverStripe\Forms\HTMLE...EditorField::saveInto() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
157
158
        $this->assertEquals(
159
            '<p><a name="example-anchor"></a></p>',
160
            $obj->Content,
161
            'Saving a link without a href attribute works'
162
        );
163
    }
164
165
    public function testReadonlyField()
166
    {
167
        $editor = new HTMLEditorField('Content');
168
        $fileID = $this->idFromFixture(Image::class, 'example_image');
169
        $editor->setValue(
170
            sprintf(
171
                '[image src="assets/example.jpg" width="10" height="20" id="%d"]',
172
                $fileID
173
            )
174
        );
175
        /** @var HTMLReadonlyField $readonly */
176
        $readonly = $editor->performReadonlyTransformation();
177
        /** @var DBHTMLText $readonlyContent */
178
        $readonlyContent = $readonly->Field();
179
180
        $this->assertEquals(
181
            <<<EOS
182
<span class="readonly typography" id="Content">
183
	<img src="/assets/HTMLEditorFieldTest/f5c7c2f814/example__ResizedImageWyIxMCIsIjIwIl0.jpg" alt="example" width="10" height="20">
184
</span>
185
186
187
EOS
188
            ,
189
            $readonlyContent->getValue()
190
        );
191
192
        // Test with include input tag
193
        $readonly = $editor->performReadonlyTransformation()
194
            ->setIncludeHiddenField(true);
195
        /** @var DBHTMLText $readonlyContent */
196
        $readonlyContent = $readonly->Field();
197
        $this->assertEquals(
198
            <<<EOS
199
<span class="readonly typography" id="Content">
200
	<img src="/assets/HTMLEditorFieldTest/f5c7c2f814/example__ResizedImageWyIxMCIsIjIwIl0.jpg" alt="example" width="10" height="20">
201
</span>
202
203
	<input type="hidden" name="Content" value="[image src=&quot;/assets/HTMLEditorFieldTest/f5c7c2f814/example.jpg&quot; width=&quot;10&quot; height=&quot;20&quot; id=&quot;{$fileID}&quot;]" />
204
205
206
EOS
207
            ,
208
            $readonlyContent->getValue()
209
        );
210
    }
211
}
212