JsonEditorTest   A
last analyzed

Complexity

Total Complexity 17

Size/Duplication

Total Lines 287
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 17
eloc 136
c 3
b 0
f 0
dl 0
loc 287
rs 10

12 Methods

Rating   Name   Duplication   Size   Complexity  
A assetDevelopmentProvider() 0 4 1
A assetProvider() 0 4 1
A testAsset() 0 18 1
A testEditorActiveWidgetPrecedence() 0 29 1
A editorWidgetAndDefaultValueProvider() 0 7 1
A testEditorActiveWidgetWithAttributeExpression() 0 17 1
A editorActiveWidgetPrecedenceProvider() 0 42 1
A testEditorWidgetWithScriptInJson() 0 12 1
A testAssetDevelopment() 0 20 6
A testEditorActiveWidgetAndDefaults() 0 15 1
A testEditorWidgetAndDefaultValue() 0 9 1
A testEditorWidget() 0 21 1
1
<?php
2
3
namespace kdn\yii2;
4
5
use kdn\yii2\mocks\ModelMock;
6
use Yii;
7
use yii\widgets\ActiveForm;
8
9
/**
10
 * Class JsonEditorTest.
11
 * @package kdn\yii2
12
 */
13
class JsonEditorTest extends TestCase
14
{
15
    public static function assetProvider()
16
    {
17
        return [
18
            'production' => ['jsoneditor.min.css', 'jsoneditor-minimalist.min.js', 'jsoneditor.min.js'],
19
        ];
20
    }
21
22
    /**
23
     * @param string $css
24
     * @param string $minimalistJs
25
     * @param string $fullJs
26
     * @covers       \kdn\yii2\assets\JsonEditorAsset
27
     * @covers       \kdn\yii2\JsonEditor
28
     * @dataProvider assetProvider
29
     * @medium
30
     */
31
    public function testAsset($css, $minimalistJs, $fullJs)
32
    {
33
        $testWidgetAsset = function ($config, $assetName, $css, $js) {
34
            JsonEditor::widget($config);
35
            $bundles = Yii::$app->assetManager->bundles;
36
            $this->assertArrayHasKey($assetName, $bundles);
37
            $this->assertEquals([$css], $bundles[$assetName]->css);
38
            $this->assertEquals([$js], $bundles[$assetName]->js);
39
        };
40
41
        $fullAssetName = 'kdn\yii2\assets\JsonEditorFullAsset';
42
        $minimalistAssetName = 'kdn\yii2\assets\JsonEditorMinimalistAsset';
43
44
        $testWidgetAsset(['name' => 'data'], $minimalistAssetName, $css, $minimalistJs);
45
        static::mockWebApplication();
46
        $testWidgetAsset(['name' => 'data', 'clientOptions' => ['mode' => 'code']], $fullAssetName, $css, $fullJs);
47
        static::mockWebApplication();
48
        $testWidgetAsset(['name' => 'data', 'clientOptions' => ['modes' => ['code']]], $fullAssetName, $css, $fullJs);
49
    }
50
51
    public static function assetDevelopmentProvider()
52
    {
53
        return [
54
            'development' => ['jsoneditor.css', 'jsoneditor-minimalist.js', 'jsoneditor.js'],
55
        ];
56
    }
57
58
    /**
59
     * @param string $css
60
     * @param string $minimalistJs
61
     * @param string $fullJs
62
     * @covers       \kdn\yii2\assets\JsonEditorAsset
63
     * @covers       \kdn\yii2\JsonEditor
64
     * @dataProvider assetDevelopmentProvider
65
     * @medium
66
     * @throws \Exception
67
     */
68
    public function testAssetDevelopment($css, $minimalistJs, $fullJs)
69
    {
70
        $runkitFunctionName = null;
71
        if (function_exists('runkit7_constant_redefine')) {
72
            $runkitFunctionName = 'runkit7_constant_redefine';
73
        } elseif (function_exists('runkit_constant_redefine')) {
74
            $runkitFunctionName = 'runkit_constant_redefine';
75
        }
76
77
        if ($runkitFunctionName === null) {
78
            $this->markTestSkipped('runkit extension required.');
79
        }
80
81
        $yiiEnvDev = YII_ENV_DEV;
82
        if (!$runkitFunctionName('YII_ENV_DEV', true)) {
83
            $this->markTestSkipped('Cannot redefine constant "YII_ENV_DEV".');
84
        }
85
        $this->testAsset($css, $minimalistJs, $fullJs);
86
        if (!$runkitFunctionName('YII_ENV_DEV', $yiiEnvDev)) {
87
            throw new \Exception('Cannot restore value of constant "YII_ENV_DEV".');
88
        }
89
    }
90
91
    /**
92
     * @covers \kdn\yii2\JsonEditor
93
     * @uses   \kdn\yii2\assets\JsonEditorAsset
94
     * @medium
95
     */
96
    public function testEditorWidget()
97
    {
98
        $html = JsonEditor::widget(
99
            [
100
                'clientOptions' => [
101
                    'modes' => ['code', 'form', 'preview', 'text', 'tree', 'view'],
102
                    'mode' => 'view',
103
                    'onChange' => 'function () {console.log(this);}',
104
                    'onError' => 'function (error) {console.log(error);}',
105
                    'onModeChange' => 'function (nMode, oMode) {console.log(this, nMode, oMode);}',
106
                ],
107
                'collapseAll' => ['view'],
108
                'containerOptions' => ['class' => 'container'],
109
                'expandAll' => ['tree', 'form'],
110
                'name' => 'data',
111
                'options' => ['id' => 'data'],
112
            ]
113
        );
114
        $this->assertStringEqualsHtmlFile(__FUNCTION__, $html);
115
        $jsCodeBlock = reset(Yii::$app->view->js);
116
        $this->assertStringEqualsJsFile(__FUNCTION__, reset($jsCodeBlock));
117
    }
118
119
    /**
120
     * @covers \kdn\yii2\JsonEditor
121
     * @uses   \kdn\yii2\assets\JsonEditorAsset
122
     * @medium
123
     */
124
    public function testEditorWidgetWithScriptInJson()
125
    {
126
        $html = JsonEditor::widget(
127
            [
128
                'id' => 'data',
129
                'name' => 'data',
130
                'value' => '{"script":"<script>alert(\"XSS\");</script>"}',
131
            ]
132
        );
133
        $this->assertStringEqualsHtmlFile(__FUNCTION__, $html);
134
        $jsCodeBlock = reset(Yii::$app->view->js);
135
        $this->assertStringEqualsJsFile(__FUNCTION__, reset($jsCodeBlock));
136
    }
137
138
    public static function editorWidgetAndDefaultValueProvider()
139
    {
140
        return [
141
            '0' => ['0', '0'],
142
            'null' => ['null', 'null'],
143
            '""' => ['""', 'empty_json_string'],
144
            'empty string' => ['', 'default'],
145
        ];
146
    }
147
148
    /**
149
     * @param string $value
150
     * @param string $expectedResult
151
     * @covers       \kdn\yii2\JsonEditor
152
     * @uses         \kdn\yii2\assets\JsonEditorAsset
153
     * @dataProvider editorWidgetAndDefaultValueProvider
154
     * @medium
155
     */
156
    public function testEditorWidgetAndDefaultValue($value, $expectedResult)
157
    {
158
        $html = JsonEditor::widget(
159
            ['id' => 'data', 'name' => 'data', 'value' => $value, 'defaultValue' => '{"foo":"bar"}']
160
        );
161
        $fileRoot = __FUNCTION__ . '_' . $expectedResult;
162
        $this->assertStringEqualsHtmlFile($fileRoot, $html);
163
        $jsCodeBlock = reset(Yii::$app->view->js);
164
        $this->assertStringEqualsJsFile($fileRoot, reset($jsCodeBlock));
165
    }
166
167
    /**
168
     * @covers \kdn\yii2\JsonEditor
169
     * @uses   \kdn\yii2\assets\JsonEditorAsset
170
     * @medium
171
     */
172
    public function testEditorActiveWidgetAndDefaults()
173
    {
174
        $html = OutputHelper::catchOutput(
175
            function () {
176
                $form = ActiveForm::begin(['id' => 'data-form', 'action' => 'test', 'options' => ['csrf' => false]]);
177
                echo $form->field(new ModelMock(), 'data')->widget(
178
                    'kdn\yii2\JsonEditor',
179
                    ['expandAll' => ['tree'], 'options' => ['class' => false]]
180
                );
181
                ActiveForm::end();
182
            }
183
        )['output'];
184
        $this->assertStringEqualsHtmlFile(__FUNCTION__, $html);
185
        $jsCodeBlock = reset(Yii::$app->view->js);
186
        $this->assertStringEqualsJsFile(__FUNCTION__, reset($jsCodeBlock));
187
    }
188
189
    /**
190
     * @covers \kdn\yii2\JsonEditor
191
     * @uses   \kdn\yii2\assets\JsonEditorAsset
192
     * @medium
193
     */
194
    public function testEditorActiveWidgetWithAttributeExpression()
195
    {
196
        $html = OutputHelper::catchOutput(
197
            function () {
198
                $model = new ModelMock();
199
                $model->data = ['{}', '{"foo":"bar"}'];
200
                $form = ActiveForm::begin(['id' => 'data-form', 'action' => 'test', 'options' => ['csrf' => false]]);
201
                echo $form->field($model, '[1]data[1]')->widget(
202
                    'kdn\yii2\JsonEditor',
203
                    ['options' => ['class' => false]]
204
                );
205
                ActiveForm::end();
206
            }
207
        )['output'];
208
        $this->assertStringEqualsHtmlFile(__FUNCTION__, $html);
209
        $jsCodeBlock = reset(Yii::$app->view->js);
210
        $this->assertStringEqualsJsFile(__FUNCTION__, reset($jsCodeBlock));
211
    }
212
213
    public static function editorActiveWidgetPrecedenceProvider()
214
    {
215
        return [
216
            'decoded value' => [
217
                ['precedence' => 1],
218
                '{"precedence":2}',
219
                '{"precedence":3}',
220
                '{"precedence":4}',
221
                '{"precedence":5}',
222
                1,
223
            ],
224
            'value' => [
225
                null,
226
                '{"precedence":2}',
227
                '{"precedence":3}',
228
                '{"precedence":4}',
229
                '{"precedence":5}',
230
                2,
231
            ],
232
            "options['inputOptions']['value']" => [
233
                null,
234
                '',
235
                '{"precedence":3}',
236
                '{"precedence":4}',
237
                '{"precedence":5}',
238
                3,
239
            ],
240
            'model data' => [
241
                null,
242
                '',
243
                null,
244
                '{"precedence":4}',
245
                '{"precedence":5}',
246
                4,
247
            ],
248
            'default value' => [
249
                null,
250
                '',
251
                null,
252
                null,
253
                '{"precedence":5}',
254
                5,
255
            ],
256
        ];
257
    }
258
259
    /**
260
     * @param mixed $decodedValue
261
     * @param null|string $value
262
     * @param null|string $inputOptionsValue
263
     * @param null|string $modelData
264
     * @param null|string $defaultValue
265
     * @param int $expectedResult
266
     * @covers       \kdn\yii2\JsonEditor
267
     * @uses         \kdn\yii2\assets\JsonEditorAsset
268
     * @dataProvider editorActiveWidgetPrecedenceProvider
269
     * @medium
270
     */
271
    public function testEditorActiveWidgetPrecedence(
272
        $decodedValue,
273
        $value,
274
        $inputOptionsValue,
275
        $modelData,
276
        $defaultValue,
277
        $expectedResult
278
    ) {
279
        $html = OutputHelper::catchOutput(
280
            function () use ($decodedValue, $value, $inputOptionsValue, $modelData, $defaultValue) {
281
                $model = new ModelMock();
282
                $model->data = ['{"foo":"bar"}', $modelData];
283
                $form = ActiveForm::begin(['id' => 'data-form', 'action' => 'test', 'options' => ['csrf' => false]]);
284
                echo $form->field($model, '[1]data[1]', ['inputOptions' => ['value' => $inputOptionsValue]])->widget(
285
                    'kdn\yii2\JsonEditor',
286
                    [
287
                        'decodedValue' => $decodedValue,
288
                        'value' => $value,
289
                        'defaultValue' => $defaultValue,
290
                        'options' => ['class' => false],
291
                    ]
292
                );
293
                ActiveForm::end();
294
            }
295
        )['output'];
296
        $fileRoot = __FUNCTION__ . '_' . $expectedResult;
297
        $this->assertStringEqualsHtmlFile($fileRoot, $html);
298
        $jsCodeBlock = reset(Yii::$app->view->js);
299
        $this->assertStringEqualsJsFile($fileRoot, reset($jsCodeBlock));
300
    }
301
}
302