Passed
Push — consistent-limit ( 2d3f1d...474034 )
by Sam
05:57
created

CmsFormsContext::stepIClickTheListBoxOption()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

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