Completed
Push — fix-2494 ( 3153ee )
by Sam
07:19
created

CmsFormsContext::stepIFillInTheHtmlFieldWith()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 7

Duplication

Lines 11
Ratio 100 %

Importance

Changes 0
Metric Value
cc 1
eloc 7
nc 1
nop 2
dl 11
loc 11
rs 9.4285
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;
7
use Behat\Mink\Exception\ElementHtmlException;
8
use Behat\Gherkin\Node\TableNode;
9
use SilverStripe\BehatExtension\Context\MainContextAwareTrait;
10
use Symfony\Component\DomCrawler\Crawler;
11
use Behat\Mink\Element\NodeElement;
12
use SilverStripe\SiteConfig\SiteConfig;
13
14
/**
15
 * CmsFormsContext
16
 *
17
 * Context used to define steps related to forms inside CMS.
18
 */
19
class CmsFormsContext implements Context
20
{
21
    use MainContextAwareTrait;
22
23
    /**
24
     * Get Mink session from MinkContext
25
     */
26
    public function getSession($name = null)
27
    {
28
        return $this->getMainContext()->getSession($name);
29
    }
30
31
    /**
32
     * Returns fixed step argument (with \\" replaced back to ").
33
     * Copied from {@see MinkContext}
34
     *
35
     * @param string $argument
36
     * @return string
37
     */
38
    protected function fixStepArgument($argument)
39
    {
40
        return str_replace('\\"', '"', $argument);
41
    }
42
43
    /**
44
     * @Then /^I should( not? |\s*)see an edit page form$/
45
     */
46
    public function stepIShouldSeeAnEditPageForm($negative)
47
    {
48
        $page = $this->getSession()->getPage();
49
50
        $form = $page->find('css', '#Form_EditForm');
51
        if (trim($negative)) {
52
            assertNull($form, 'I should not see an edit page form');
53
        } else {
54
            assertNotNull($form, 'I should see an edit page form');
55
        }
56
    }
57
58
    /**
59
     * @When /^I fill in the "(?P<field>(?:[^"]|\\")*)" HTML field with "(?P<value>(?:[^"]|\\")*)"$/
60
     * @When /^I fill in "(?P<value>(?:[^"]|\\")*)" for the "(?P<field>(?:[^"]|\\")*)" HTML field$/
61
     */
62 View Code Duplication
    public function stepIFillInTheHtmlFieldWith($field, $value)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
63
    {
64
        $inputField = $this->getHtmlField($field);
65
        $value = $this->fixStepArgument($value);
66
67
        $this->getSession()->evaluateScript(sprintf(
68
            "jQuery('#%s').entwine('ss').getEditor().setContent('%s')",
69
            $inputField->getAttribute('id'),
70
            addcslashes($value, "'")
71
        ));
72
    }
73
74
    /**
75
     * @When /^I append "(?P<value>(?:[^"]|\\")*)" to the "(?P<field>(?:[^"]|\\")*)" HTML field$/
76
     */
77 View Code Duplication
    public function stepIAppendTotheHtmlField($field, $value)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
78
    {
79
        $inputField = $this->getHtmlField($field);
80
        $value = $this->fixStepArgument($value);
81
82
        $this->getSession()->evaluateScript(sprintf(
83
            "jQuery('#%s').entwine('ss').getEditor().insertContent('%s')",
84
            $inputField->getAttribute('id'),
85
            addcslashes($value, "'")
86
        ));
87
    }
88
89
    /**
90
     * @Then /^the "(?P<locator>(?:[^"]|\\")*)" HTML field should(?P<negative> not? |\s*)contain "(?P<html>.*)"$/
91
     */
92
    public function theHtmlFieldShouldContain($locator, $negative, $html)
93
    {
94
        $element = $this->getHtmlField($locator);
95
        $actual = $element->getValue();
96
        $regex = '/'.preg_quote($html, '/').'/ui';
97
        $failed = false;
98
99
        if (trim($negative)) {
100
            if (preg_match($regex, $actual)) {
101
                $failed = true;
102
            }
103
        } else {
104
            if (!preg_match($regex, $actual)) {
105
                $failed = true;
106
            }
107
        }
108
109
        if ($failed) {
110
            $message = sprintf(
111
                'The string "%s" should%sbe found in the HTML of the element matching name "%s". Actual content: "%s"',
112
                $html,
113
                $negative,
114
                $locator,
115
                $actual
116
            );
117
            throw new ElementHtmlException($message, $this->getSession(), $element);
0 ignored issues
show
Bug introduced by
It seems like $element defined by $this->getHtmlField($locator) on line 94 can be null; however, Behat\Mink\Exception\Ele...xception::__construct() 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...
118
        }
119
    }
120
121
	// @codingStandardsIgnoreStart
122
	/**
123
	 * Checks formatting in the HTML field, by analyzing the HTML node surrounding
124
	 * the text for certain properties.
125
	 *
126
	 * Example: Given "my text" in the "Content" HTML field should be right aligned
127
	 * Example: Given "my text" in the "Content" HTML field should not be bold
128
	 *
129
	 * @todo Use an actual DOM parser for more accurate assertions
130
	 *
131
	 * @Given /^"(?P<text>([^"]*))" in the "(?P<field>(?:[^"]|\\")*)" HTML field should(?P<negate>(?: not)?) be (?P<formatting>(.*))$/
132
	 */
133
	public function stepContentInHtmlFieldShouldHaveFormatting($text, $field, $negate, $formatting) {
134
		$inputField = $this->getHtmlField($field);
135
136
		$crawler = new Crawler($inputField->getValue());
137
		$matchedNode = null;
138
		foreach($crawler->filterXPath('//*') as $node) {
139
			if(
140
				$node->firstChild
141
				&& $node->firstChild->nodeType == XML_TEXT_NODE
142
				&& stripos($node->firstChild->nodeValue, $text) !== FALSE
143
			) {
144
				$matchedNode = $node;
145
			}
146
		}
147
		assertNotNull($matchedNode);
148
149
		$assertFn = $negate ? 'assertNotEquals' : 'assertEquals';
150
		if($formatting == 'bold') {
151
			call_user_func($assertFn, 'strong', $matchedNode->nodeName);
152
		} else if($formatting == 'left aligned') {
153
			if($matchedNode->getAttribute('style')) {
154
				call_user_func($assertFn, 'text-align: left;', $matchedNode->getAttribute('style'));
155
			}
156
		} else if($formatting == 'right aligned') {
157
			call_user_func($assertFn, 'text-align: right;', $matchedNode->getAttribute('style'));
158
		}
159
	}
160
	// @codingStandardsIgnoreEnd
161
162
    /**
163
     * Selects the first textual match in the HTML editor. Does not support
164
     * selection across DOM node boundaries.
165
     *
166
     * @When /^I select "(?P<text>([^"]*))" in the "(?P<field>(?:[^"]|\\")*)" HTML field$/
167
     */
168
    public function stepIHighlightTextInHtmlField($text, $field)
169
    {
170
        $inputField = $this->getHtmlField($field);
171
        $inputFieldId = $inputField->getAttribute('id');
172
        $text = addcslashes($text, "'");
173
174
        $js = <<<JS
175
// TODO <IE9 support
176
// TODO Allow text matches across nodes
177
var editor = jQuery('#$inputFieldId').entwine('ss').getEditor(),
178
	doc = editor.getInstance().getDoc(),
179
	sel = editor.getInstance().selection,
180
	rng = document.createRange(),
181
	matched = false;
182
183
jQuery(doc).find('body *').each(function() {
184
	if(!matched) {
185
		for(var i=0;i<this.childNodes.length;i++) {
186
			if(!matched && this.childNodes[i].nodeValue && this.childNodes[i].nodeValue.match('$text')) {
187
				rng.setStart(this.childNodes[i], this.childNodes[i].nodeValue.indexOf('$text'));
188
				rng.setEnd(this.childNodes[i], this.childNodes[i].nodeValue.indexOf('$text') + '$text'.length);
189
				sel.setRng(rng);
190
				editor.getInstance().nodeChanged();
191
				matched = true;
192
				break;
193
			}
194
		}
195
	}
196
});
197
JS;
198
199
        $this->getSession()->executeScript($js);
200
    }
201
202
    /**
203
     * @Given /^I should( not? |\s*)see a "([^"]*)" field$/
204
     */
205
    public function iShouldSeeAField($negative, $text)
206
    {
207
        $page = $this->getSession()->getPage();
208
        $els = $page->findAll('named', array('field', "'$text'"));
209
        $matchedEl = null;
210
        foreach ($els as $el) {
211
            if ($el->isVisible()) {
212
                $matchedEl = $el;
213
            }
214
        }
215
216
        if (trim($negative)) {
217
            assertNull($matchedEl);
218
        } else {
219
            assertNotNull($matchedEl);
220
        }
221
    }
222
223
    /**
224
     * Click on the element with the provided CSS Selector
225
     *
226
     * @When /^I press the "([^"]*)" HTML field button$/
227
     */
228
    public function iClickOnTheHtmlFieldButton($button)
229
    {
230
        $xpath = "//*[@aria-label='".$button."']";
231
        $session = $this->getSession();
232
        $element = $session->getPage()->find('xpath', $xpath);
233
        if (null === $element) {
234
            throw new \InvalidArgumentException(sprintf('Could not find element with xpath %s', $xpath));
235
        }
236
237
        $element->click();
238
    }
239
240
    /*
241
	 * @example Given the CMS settings has the following data
242
	 *	| Title | My site title |
243
	 *	| Theme | My site theme |
244
	 * @Given /^the CMS settings have the following data$/
245
	 */
246
    public function theCmsSettingsHasData(TableNode $fieldsTable)
247
    {
248
        $fields = $fieldsTable->getRowsHash();
249
        $siteConfig = SiteConfig::get()->first();
250
        foreach ($fields as $field => $value) {
251
            $siteConfig->$field = $value;
252
        }
253
        $siteConfig->write();
254
        $siteConfig->flushCache();
255
    }
256
257
    /**
258
     * Locate an HTML editor field
259
     *
260
     * @param string $locator Raw html field identifier as passed from
261
     * @return NodeElement
262
     */
263
    protected function getHtmlField($locator)
264
    {
265
        $locator = $this->fixStepArgument($locator);
266
        $page = $this->getSession()->getPage();
267
        $element = $page->find('css', 'textarea.htmleditor[name=\'' . $locator . '\']');
268
        assertNotNull($element, sprintf('HTML field "%s" not found', $locator));
269
        return $element;
270
    }
271
272
    /**
273
     * @Given /^the "([^"]*)" field ((?:does not have)|(?:has)) property "([^"]*)"$/
274
     */
275
    public function assertTheFieldHasProperty($name, $cond, $property)
276
    {
277
        $name = $this->fixStepArgument($name);
278
        $property = $this->fixStepArgument($property);
279
280
        $context = $this->getMainContext();
281
        $fieldObj = $context->assertSession()->fieldExists($name);
282
283
        // Check property
284
        $hasProperty = $fieldObj->hasAttribute($property);
285
        switch ($cond) {
286
            case 'has':
287
                assert($hasProperty, "Field $name does not have property $property");
288
                break;
289
            case 'does not have':
290
                assert(!$hasProperty, "Field $name should not have property $property");
291
                break;
292
            default:
293
                throw new BadMethodCallException("Invalid condition");
294
        }
295
    }
296
}
297