Passed
Pull Request — 4 (#10028)
by Steve
07:09
created

stepContentInHtmlFieldShouldHaveFormatting()   C

Complexity

Conditions 12
Paths 24

Size

Total Lines 35
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 26
nc 24
nop 4
dl 0
loc 35
rs 6.9666
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace SilverStripe\Framework\Tests\Behaviour;
4
5
use BadMethodCallException;
6
use Behat\Behat\Context\Context;
0 ignored issues
show
Bug introduced by
The type Behat\Behat\Context\Context was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
7
use Behat\Mink\Exception\ElementHtmlException;
0 ignored issues
show
Bug introduced by
The type Behat\Mink\Exception\ElementHtmlException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
8
use Behat\Gherkin\Node\TableNode;
0 ignored issues
show
Bug introduced by
The type Behat\Gherkin\Node\TableNode was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
9
use Behat\Mink\Session;
0 ignored issues
show
Bug introduced by
The type Behat\Mink\Session was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
10
use PHPUnit\Framework\Assert;
11
use SilverStripe\BehatExtension\Context\MainContextAwareTrait;
0 ignored issues
show
Bug introduced by
The type SilverStripe\BehatExtens...t\MainContextAwareTrait was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
12
use SilverStripe\BehatExtension\Utility\StepHelper;
0 ignored issues
show
Bug introduced by
The type SilverStripe\BehatExtension\Utility\StepHelper was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
13
use Symfony\Component\DomCrawler\Crawler;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\DomCrawler\Crawler was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
14
use Behat\Mink\Element\NodeElement;
0 ignored issues
show
Bug introduced by
The type Behat\Mink\Element\NodeElement was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
15
use SilverStripe\SiteConfig\SiteConfig;
0 ignored issues
show
Bug introduced by
The type SilverStripe\SiteConfig\SiteConfig was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
17
/**
18
 * CmsFormsContext
19
 *
20
 * Context used to define steps related to forms inside CMS.
21
 */
22
class CmsFormsContext implements Context
23
{
24
    use MainContextAwareTrait;
25
    use StepHelper;
26
27
    /**
28
     * Get Mink session from MinkContext
29
     *
30
     * @param string $name
31
     * @return Session
32
     */
33
    public function getSession($name = null)
34
    {
35
        return $this->getMainContext()->getSession($name);
36
    }
37
38
    /**
39
     * Returns fixed step argument (with \\" replaced back to ").
40
     * Copied from {@see MinkContext}
41
     *
42
     * @param string $argument
43
     * @return string
44
     */
45
    protected function fixStepArgument($argument)
46
    {
47
        return str_replace('\\"', '"', $argument);
48
    }
49
50
    /**
51
     * @Then /^I should( not? |\s*)see an edit page form$/
52
     */
53
    public function stepIShouldSeeAnEditPageForm($negative)
54
    {
55
        $page = $this->getSession()->getPage();
56
57
        $form = $page->find('css', '#Form_EditForm');
58
        if (trim($negative)) {
59
            Assert::assertNull($form, 'I should not see an edit page form');
60
        } else {
61
            Assert::assertNotNull($form, 'I should see an edit page form');
62
        }
63
    }
64
65
    /**
66
     * @When /^I fill in the "(?P<field>(?:[^"]|\\")*)" HTML field with "(?P<value>(?:[^"]|\\")*)"$/
67
     * @When /^I fill in "(?P<value>(?:[^"]|\\")*)" for the "(?P<field>(?:[^"]|\\")*)" HTML field$/
68
     */
69
    public function stepIFillInTheHtmlFieldWith($field, $value)
70
    {
71
        $inputField = $this->getHtmlField($field);
72
        $value = $this->fixStepArgument($value);
73
74
        $this->getSession()->evaluateScript(sprintf(
75
            "jQuery('#%s').entwine('ss').getEditor().setContent('%s')",
76
            $inputField->getAttribute('id'),
77
            addcslashes($value, "'")
78
        ));
79
        $this->getSession()->evaluateScript(sprintf(
80
            "jQuery('#%s').entwine('ss').getEditor().save()",
81
            $inputField->getAttribute('id')
82
        ));
83
    }
84
85
    /**
86
     * @When /^I append "(?P<value>(?:[^"]|\\")*)" to the "(?P<field>(?:[^"]|\\")*)" HTML field$/
87
     */
88
    public function stepIAppendTotheHtmlField($field, $value)
89
    {
90
        $inputField = $this->getHtmlField($field);
91
        $value = $this->fixStepArgument($value);
92
93
        $this->getSession()->evaluateScript(sprintf(
94
            "jQuery('#%s').entwine('ss').getEditor().insertContent('%s')",
95
            $inputField->getAttribute('id'),
96
            addcslashes($value, "'")
97
        ));
98
    }
99
100
    /**
101
     * @Then /^the "(?P<locator>(?:[^"]|\\")*)" HTML field should(?P<negative> not? |\s*)contain "(?P<html>.*)"$/
102
     */
103
    public function theHtmlFieldShouldContain($locator, $negative, $html)
104
    {
105
        $element = $this->getHtmlField($locator);
106
        $actual = $element->getValue();
107
        $regex = '/' . preg_quote($html, '/') . '/ui';
108
        $failed = false;
109
110
        if (trim($negative)) {
111
            if (preg_match($regex, $actual)) {
112
                $failed = true;
113
            }
114
        } else {
115
            if (!preg_match($regex, $actual)) {
116
                $failed = true;
117
            }
118
        }
119
120
        if ($failed) {
121
            $message = sprintf(
122
                'The string "%s" should%sbe found in the HTML of the element matching name "%s". Actual content: "%s"',
123
                $html,
124
                $negative,
125
                $locator,
126
                $actual
127
            );
128
            throw new ElementHtmlException($message, $this->getSession(), $element);
129
        }
130
    }
131
132
	// @codingStandardsIgnoreStart
133
	/**
134
	 * Checks formatting in the HTML field, by analyzing the HTML node surrounding
135
	 * the text for certain properties.
136
	 *
137
	 * Example: Given "my text" in the "Content" HTML field should be right aligned
138
	 * Example: Given "my text" in the "Content" HTML field should not be bold
139
	 *
140
	 * @todo Use an actual DOM parser for more accurate assertions
141
	 *
142
	 * @Given /^"(?P<text>([^"]*))" in the "(?P<field>(?:[^"]|\\")*)" HTML field should(?P<negate>(?: not)?) be (?P<formatting>(.*))$/
143
	 */
144
	public function stepContentInHtmlFieldShouldHaveFormatting($text, $field, $negate, $formatting) {
145
		$inputField = $this->getHtmlField($field);
146
147
		$crawler = new Crawler($inputField->getValue());
148
		$matchedNode = null;
149
		foreach($crawler->filterXPath('//*') as $node) {
150
			if(
151
				$node->firstChild
152
				&& $node->firstChild->nodeType == XML_TEXT_NODE
153
				&& stripos($node->firstChild->nodeValue, $text) !== FALSE
154
			) {
155
				$matchedNode = $node;
156
			}
157
		}
158
        Assert::assertNotNull($matchedNode);
159
160
        if ($formatting == 'bold') {
161
            if ($negate) {
162
                Assert::assertNotEquals('strong', $matchedNode->nodeName);
163
            } else {
164
                Assert::assertEquals('strong', $matchedNode->nodeName);
165
            }
166
        } else if ($formatting == 'left aligned') {
167
            if ($matchedNode->getAttribute('class')) {
168
                if ($negate) {
169
                    Assert::assertNotEquals('text-left', $matchedNode->getAttribute('class'));
170
                } else {
171
                    Assert::assertEquals('text-left', $matchedNode->getAttribute('class'));
172
                }
173
            }
174
        } else if ($formatting == 'right aligned') {
175
            if ($negate) {
176
                Assert::assertNotEquals('text-right', $matchedNode->getAttribute('class'));
177
            } else {
178
                Assert::assertEquals('text-right', $matchedNode->getAttribute('class'));
179
            }
180
        }
181
    }
182
    // @codingStandardsIgnoreEnd
183
184
    /**
185
     * Selects the first textual match in the HTML editor. Does not support
186
     * selection across DOM node boundaries.
187
     *
188
     * @When /^I select "(?P<text>([^"]*))" in the "(?P<field>(?:[^"]|\\")*)" HTML field$/
189
     */
190
    public function stepIHighlightTextInHtmlField($text, $field)
191
    {
192
        $inputField = $this->getHtmlField($field);
193
        $inputFieldId = $inputField->getAttribute('id');
194
        $text = addcslashes($text, "'");
195
196
        $js = <<<JS
197
// TODO <IE9 support
198
// TODO Allow text matches across nodes
199
var editor = jQuery('#$inputFieldId').entwine('ss').getEditor(),
200
	doc = editor.getInstance().getDoc(),
201
	sel = editor.getInstance().selection,
202
	rng = document.createRange(),
203
	matched = false;
204
205
editor.getInstance().focus();
206
jQuery(doc).find('body *').each(function() {
207
	if(!matched) {
208
		for(var i=0;i<this.childNodes.length;i++) {
209
			if(!matched && this.childNodes[i].nodeValue && this.childNodes[i].nodeValue.match('$text')) {
210
				rng.setStart(this.childNodes[i], this.childNodes[i].nodeValue.indexOf('$text'));
211
				rng.setEnd(this.childNodes[i], this.childNodes[i].nodeValue.indexOf('$text') + '$text'.length);
212
				sel.setRng(rng);
213
				editor.getInstance().nodeChanged();
214
				matched = true;
215
				break;
216
			}
217
		}
218
	}
219
});
220
JS;
221
222
        $this->getSession()->executeScript($js);
223
    }
224
225
    /**
226
     * @Given /^I should( not? |\s*)see a "([^"]*)" field$/
227
     */
228
    public function iShouldSeeAField($negative, $text)
229
    {
230
        $page = $this->getSession()->getPage();
231
        $els = $page->findAll('named', ['field', "'$text'"]);
232
        $matchedEl = null;
233
        /** @var NodeElement $el */
234
        foreach ($els as $el) {
235
            if ($el->isVisible()) {
236
                $matchedEl = $el;
237
            }
238
        }
239
240
        if (trim($negative)) {
241
            Assert::assertNull($matchedEl);
242
        } else {
243
            Assert::assertNotNull($matchedEl);
244
        }
245
    }
246
247
    /**
248
     * Click on the element with the provided CSS Selector
249
     *
250
     * @When /^I press the "([^"]*)" HTML field button$/
251
     */
252
    public function iClickOnTheHtmlFieldButton($button)
253
    {
254
        $xpath = "//*[@aria-label='" . $button . "']";
255
        $session = $this->getSession();
256
        $element = $session->getPage()->find('xpath', $xpath);
257
        if (null === $element) {
258
            // If it can't find the exact name, find one that starts with the phrase
259
            // Helpful for "Insert link" which has a conditional label for keyboard shortcut
260
            $xpath = "//*[starts-with(@aria-label, '" . $button . "')]";
261
            $element = $session->getPage()->find('xpath', $xpath);
262
263
            if (null === $element) {
264
                throw new \InvalidArgumentException(sprintf('Could not find element with xpath %s', $xpath));
265
            };
266
        }
267
268
        $element->click();
269
    }
270
271
    /*
272
     * @example Given the CMS settings has the following data
273
     *  | Title | My site title |
274
     *  | Theme | My site theme |
275
     * @Given /^the CMS settings have the following data$/
276
     */
277
    public function theCmsSettingsHasData(TableNode $fieldsTable)
278
    {
279
        $fields = $fieldsTable->getRowsHash();
280
        $siteConfig = SiteConfig::get()->first();
281
        foreach ($fields as $field => $value) {
282
            $siteConfig->$field = $value;
283
        }
284
        $siteConfig->write();
285
        $siteConfig->flushCache();
286
    }
287
288
    /**
289
     * Select a value in the tree dropdown field
290
     *
291
     * NOTE: This is react specific, may need to move to its own react section later
292
     *
293
     * @When /^I select "([^"]*)" in the "([^"]*)" tree dropdown$/
294
     */
295
    public function iSelectValueInTreeDropdown($text, $selector)
296
    {
297
        $page = $this->getSession()->getPage();
298
        /** @var NodeElement $parentElement */
299
        $parentElement = null;
300
        $this->retryThrowable(function () use (&$parentElement, &$page, $selector) {
301
            $parentElement = $page->find('css', $selector);
302
            Assert::assertNotNull($parentElement, sprintf('"%s" element not found', $selector));
303
            $page = $this->getSession()->getPage();
304
        });
305
306
        $this->retryThrowable(function () use ($parentElement, $selector) {
307
            $dropdown = $parentElement->find('css', '.Select-arrow');
308
            Assert::assertNotNull($dropdown, sprintf('Unable to find the dropdown in "%s"', $selector));
309
            $dropdown->click();
310
        });
311
312
        $this->retryThrowable(function () use ($text, $parentElement, $selector) {
313
            $element = $parentElement->find('xpath', sprintf('//*[count(*)=0 and contains(.,"%s")]', $text));
314
            Assert::assertNotNull($element, sprintf('"%s" not found in "%s"', $text, $selector));
315
            $element->click();
316
        });
317
    }
318
319
    /**
320
     * Locate an HTML editor field
321
     *
322
     * @param string $locator Raw html field identifier as passed from
323
     * @return NodeElement
324
     */
325
    protected function getHtmlField($locator)
326
    {
327
        $locator = $this->fixStepArgument($locator);
328
        $page = $this->getSession()->getPage();
329
        
330
        // Searching by name is usually good...
331
        $element = $page->find('css', 'textarea.htmleditor[name=\'' . $locator . '\']');
332
        
333
        if ($element === null) {
334
            $element = $this->findInputByLabelContent($locator);
335
        }
336
        
337
        Assert::assertNotNull($element, sprintf('HTML field "%s" not found', $locator));
338
        return $element;
339
    }
340
341
    protected function findInputByLabelContent($locator)
342
    {
343
        $page = $this->getSession()->getPage();
344
        $label = $page->findAll('xpath', sprintf('//label[contains(text(), \'%s\')]', $locator));
345
346
        if (empty($label)) {
347
            return null;
348
        }
349
350
        Assert::assertCount(1, $label, sprintf(
351
            'Found more than one element containing the phrase "%s".',
352
            $locator
353
        ));
354
355
        $label = array_shift($label);
356
357
        $fieldId = $label->getAttribute('for');
358
        return $page->find('css', '#' . $fieldId);
359
    }
360
361
    /**
362
     * @Given /^the "([^"]*)" field ((?:does not have)|(?:has)) property "([^"]*)"$/
363
     */
364
    public function assertTheFieldHasProperty($name, $cond, $property)
365
    {
366
        $name = $this->fixStepArgument($name);
367
        $property = $this->fixStepArgument($property);
368
369
        $context = $this->getMainContext();
370
        $fieldObj = $context->assertSession()->fieldExists($name);
371
372
        // Check property
373
        $hasProperty = $fieldObj->hasAttribute($property);
374
        switch ($cond) {
375
            case 'has':
376
                assert($hasProperty, "Field $name does not have property $property");
377
                break;
378
            case 'does not have':
379
                assert(!$hasProperty, "Field $name should not have property $property");
380
                break;
381
            default:
382
                throw new BadMethodCallException("Invalid condition");
383
        }
384
    }
385
386
    /**
387
     * @When /^I switch to the "([^"]*)" iframe$/
388
     * @param string $id iframe id property
389
     */
390
    public function stepSwitchToTheFrame($id)
391
    {
392
        $this->getMainContext()->getSession()->getDriver()->switchToIFrame($id);
393
    }
394
395
    /**
396
     * @When /^I am not in an iframe$/
397
     */
398
    public function stepSwitchToParentFrame()
399
    {
400
        $this->getMainContext()->getSession()->getDriver()->switchToIFrame(null);
401
    }
402
403
    /**
404
     * @When /^my session expires$/
405
     */
406
    public function stepMySessionExpires()
407
    {
408
        // Destroy cookie to detach session
409
        $this->getMainContext()->getSession()->setCookie('PHPSESSID', null);
410
    }
411
412
    /**
413
     * @When /^I should see the "([^"]*)" button in the "([^"]*)" gridfield for the "([^"]*)" row$/
414
     * @param string $buttonLabel
415
     * @param string $gridFieldName
416
     * @param string $rowName
417
     */
418
    public function assertIShouldSeeTheGridFieldButtonForRow($buttonLabel, $gridFieldName, $rowName)
419
    {
420
        $button = $this->getGridFieldButton($gridFieldName, $rowName, $buttonLabel);
421
        Assert::assertNotNull($button, sprintf('Button "%s" not found', $buttonLabel));
422
    }
423
424
    /**
425
     * @When /^I should not see the "([^"]*)" button in the "([^"]*)" gridfield for the "([^"]*)" row$/
426
     * @param string $buttonLabel
427
     * @param string $gridFieldName
428
     * @param string $rowName
429
     */
430
    public function assertIShouldNotSeeTheGridFieldButtonForRow($buttonLabel, $gridFieldName, $rowName)
431
    {
432
        $button = $this->getGridFieldButton($gridFieldName, $rowName, $buttonLabel);
433
        Assert::assertNull($button, sprintf('Button "%s" found', $buttonLabel));
434
    }
435
436
    /**
437
     * @When /^I click the "([^"]*)" button in the "([^"]*)" gridfield for the "([^"]*)" row$/
438
     * @param string $buttonLabel
439
     * @param string $gridFieldName
440
     * @param string $rowName
441
     */
442
    public function stepIClickTheGridFieldButtonForRow($buttonLabel, $gridFieldName, $rowName)
443
    {
444
        $button = $this->getGridFieldButton($gridFieldName, $rowName, $buttonLabel);
445
        Assert::assertNotNull($button, sprintf('Button "%s" not found', $buttonLabel));
446
447
        $button->click();
448
    }
449
450
    /**
451
     * Finds a button in the gridfield row
452
     *
453
     * @param $gridFieldName
454
     * @param $rowName
455
     * @param $buttonLabel
456
     * @return $button
0 ignored issues
show
Documentation Bug introduced by
The doc comment $button at position 0 could not be parsed: Unknown type name '$button' at position 0 in $button.
Loading history...
457
     */
458
    protected function getGridFieldButton($gridFieldName, $rowName, $buttonLabel)
459
    {
460
        $page = $this->getSession()->getPage();
461
        $gridField = $page->find('xpath', sprintf('//*[@data-name="%s"]', $gridFieldName));
462
        Assert::assertNotNull($gridField, sprintf('Gridfield "%s" not found', $gridFieldName));
463
464
        $name = $gridField->find('xpath', sprintf('//*[count(*)=0 and contains(.,"%s")]', $rowName));
465
        if (!$name) {
466
            return null;
467
        }
468
469
        if ($dropdownButton = $name->getParent()->find('css', '.action-menu__toggle')) {
470
            $dropdownButton->click();
471
        }
472
473
        $button = $name->getParent()->find('named', ['link_or_button', $buttonLabel]);
474
475
        return $button;
476
    }
477
478
    /**
479
     * @When /^I click the "([^"]*)" option in the "([^"]*)" listbox$/
480
     * @param $optionLabel
481
     * @param $fieldName
482
     */
483
    public function stepIClickTheListBoxOption($optionLabel, $fieldName)
484
    {
485
        $page = $this->getSession()->getPage();
486
        $listBox = $page->find('xpath', sprintf('//*[@name="%s[]"]', $fieldName));
487
        Assert::assertNotNull($listBox, sprintf('The listbox %s is not found', $fieldName));
488
489
        $option = $listBox->getParent()
490
            ->find('css', '.chosen-choices')
491
            ->find('xpath', sprintf('//*[count(*)=0 and contains(.,"%s")]', $optionLabel));
492
        Assert::assertNotNull($option, sprintf('Option %s is not found', $optionLabel));
493
494
        $button = $option->getParent()->find('css', 'a');
495
496
        $button->click();
497
    }
498
}
499