Completed
Pull Request — 3.3 (#6342)
by Damian
07:25
created

CmsFormsContext::getHtmlField()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 1
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 27 and the first side effect is on line 19.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
3
namespace SilverStripe\Framework\Test\Behaviour;
4
5
use Behat\Behat\Context\ClosuredContextInterface,
6
	Behat\Behat\Context\TranslatedContextInterface,
7
	Behat\Behat\Context\BehatContext,
8
	Behat\Behat\Context\Step,
9
	Behat\Behat\Exception\PendingException,
10
	Behat\Mink\Exception\ElementHtmlException,
11
	Behat\Gherkin\Node\PyStringNode,
12
	Behat\Gherkin\Node\TableNode,
13
	Behat\MinkExtension\Context\MinkContext as MinkContext;
14
15
use Behat\Mink\Element\NodeElement;
16
use Symfony\Component\DomCrawler\Crawler;
17
18
// PHPUnit
19
require_once 'PHPUnit/Autoload.php';
20
require_once 'PHPUnit/Framework/Assert/Functions.php';
21
22
/**
23
 * CmsFormsContext
24
 *
25
 * Context used to define steps related to forms inside CMS.
26
 */
27
class CmsFormsContext extends BehatContext {
28
	protected $context;
29
30
	/**
31
	 * Initializes context.
32
	 * Every scenario gets it's own context object.
33
	 *
34
	 * @param   array   $parameters     context parameters (set them up through behat.yml)
35
	 */
36
	public function __construct(array $parameters) {
37
		// Initialize your context here
38
		$this->context = $parameters;
39
	}
40
41
	/**
42
	 * Get Mink session from MinkContext
43
	 */
44
	public function getSession($name = null) {
45
		return $this->getMainContext()->getSession($name);
46
	}
47
48
	/**
49
	 * Returns fixed step argument (with \\" replaced back to ").
50
	 * Copied from {@see MinkContext}
51
	 *
52
	 * @param string $argument
53
	 * @return string
54
	 */
55
	protected function fixStepArgument($argument) {
56
		return str_replace('\\"', '"', $argument);
57
	}
58
59
	/**
60
	 * @Then /^I should( not? |\s*)see an edit page form$/
61
	 */
62
	public function stepIShouldSeeAnEditPageForm($negative) {
63
		$page = $this->getSession()->getPage();
64
65
		$form = $page->find('css', '#Form_EditForm');
66
		if(trim($negative)) {
67
			assertNull($form, 'I should not see an edit page form');
68
		} else {
69
			assertNotNull($form, 'I should see an edit page form');
70
		}
71
	}
72
73
	/**
74
	 * @When /^I fill in the "(?P<field>(?:[^"]|\\")*)" HTML field with "(?P<value>(?:[^"]|\\")*)"$/
75
	 * @When /^I fill in "(?P<value>(?:[^"]|\\")*)" for the "(?P<field>(?:[^"]|\\")*)" HTML field$/
76
	 */
77
	public function stepIFillInTheHtmlFieldWith($field, $value) {
78
		$inputField = $this->getHtmlField($field);
79
		$value = $this->fixStepArgument($value);
80
81
		$this->getSession()->evaluateScript(sprintf(
82
			"jQuery('#%s').entwine('ss').getEditor().setContent('%s')",
83
			$inputField->getAttribute('id'),
84
			addcslashes($value, "'")
85
		));
86
	}
87
88
	/**
89
	 * @When /^I append "(?P<value>(?:[^"]|\\")*)" to the "(?P<field>(?:[^"]|\\")*)" HTML field$/
90
	 */
91
	public function stepIAppendTotheHtmlField($field, $value) {
92
		$inputField = $this->getHtmlField($field);
93
		$value = $this->fixStepArgument($value);
94
95
		$this->getSession()->evaluateScript(sprintf(
96
			"jQuery('#%s').entwine('ss').getEditor().insertContent('%s')",
97
			$inputField->getAttribute('id'),
98
			addcslashes($value, "'")
99
		));
100
	}
101
102
	/**
103
	 * @Then /^the "(?P<locator>(?:[^"]|\\")*)" HTML field should(?P<negative> not? |\s*)contain "(?P<html>.*)"$/
104
	 */
105
	public function theHtmlFieldShouldContain($locator, $negative, $html) {
106
		$element = $this->getHtmlField($locator);
107
		$actual = $element->getValue();
108
		$regex = '/'.preg_quote($html, '/').'/ui';
109
		$failed = false;
110
111
		if(trim($negative)) {
112
			if (preg_match($regex, $actual)) {
113
				$failed = true;
114
			}
115
		} else {
116
			if (!preg_match($regex, $actual)) {
117
				$failed = true;
118
			}
119
		}
120
121
		if($failed) {
122
			$message = sprintf(
123
				'The string "%s" should%sbe found in the HTML of the element matching name "%s". Actual content: "%s"',
124
				$html,
125
				$negative,
126
				$locator,
127
				$actual
128
			);
129
			throw new ElementHtmlException($message, $this->getSession(), $element);
130
		}
131
	}
132
133
	// @codingStandardsIgnoreStart
134
	/**
135
	 * Checks formatting in the HTML field, by analyzing the HTML node surrounding
136
	 * the text for certain properties.
137
	 *
138
	 * Example: Given "my text" in the "Content" HTML field should be right aligned
139
	 * Example: Given "my text" in the "Content" HTML field should not be bold
140
	 *
141
	 * @todo Use an actual DOM parser for more accurate assertions
142
	 *
143
	 * @Given /^"(?P<text>([^"]*))" in the "(?P<field>(?:[^"]|\\")*)" HTML field should(?P<negate>(?: not)?) be (?P<formatting>(.*))$/
144
	 */
145
	public function stepContentInHtmlFieldShouldHaveFormatting($text, $field, $negate, $formatting) {
146
		$inputField = $this->getHtmlField($field);
147
148
		$crawler = new Crawler($inputField->getValue());
149
		$matchedNode = null;
150
		foreach($crawler->filterXPath('//*') as $node) {
151
			if(
152
				$node->firstChild
153
				&& $node->firstChild->nodeType == XML_TEXT_NODE
154
				&& stripos($node->firstChild->nodeValue, $text) !== FALSE
155
			) {
156
				$matchedNode = $node;
157
			}
158
		}
159
		assertNotNull($matchedNode);
160
161
		$assertFn = $negate ? 'assertNotEquals' : 'assertEquals';
162
		if($formatting == 'bold') {
163
			call_user_func($assertFn, 'strong', $matchedNode->nodeName);
164
		} else if($formatting == 'left aligned') {
165
			if($matchedNode->getAttribute('style')) {
166
				call_user_func($assertFn, 'text-align: left;', $matchedNode->getAttribute('style'));
167
			}
168
		} else if($formatting == 'right aligned') {
169
			call_user_func($assertFn, 'text-align: right;', $matchedNode->getAttribute('style'));
170
		}
171
	}
172
	// @codingStandardsIgnoreEnd
173
174
	/**
175
	 * Selects the first textual match in the HTML editor. Does not support
176
	 * selection across DOM node boundaries.
177
	 *
178
	 * @When /^I select "(?P<text>([^"]*))" in the "(?P<field>(?:[^"]|\\")*)" HTML field$/
179
	 */
180
	public function stepIHighlightTextInHtmlField($text, $field) {
181
		$inputField = $this->getHtmlField($field);
182
		$inputFieldId = $inputField->getAttribute('id');
183
		$text = addcslashes($text, "'");
184
185
		$js = <<<JS
186
// TODO <IE9 support
187
// TODO Allow text matches across nodes
188
var editor = jQuery('#$inputFieldId').entwine('ss').getEditor(),
189
	doc = editor.getDOM().doc,
190
	sel = editor.getInstance().selection,
191
	rng = document.createRange(),
192
	matched = false;
193
194
jQuery(doc).find('body *').each(function() {
195
	if(!matched) {
196
		for(var i=0;i<this.childNodes.length;i++) {
197
			if(!matched && this.childNodes[i].nodeValue && this.childNodes[i].nodeValue.match('$text')) {
198
				rng.setStart(this.childNodes[i], this.childNodes[i].nodeValue.indexOf('$text'));
199
				rng.setEnd(this.childNodes[i], this.childNodes[i].nodeValue.indexOf('$text') + '$text'.length);
200
				sel.setRng(rng);
201
				editor.getInstance().nodeChanged();
202
				matched = true;
203
				break;
204
			}
205
		}
206
	}
207
});
208
JS;
209
210
		$this->getSession()->executeScript($js);
211
	}
212
213
	/**
214
	 * Example: I should see a "Submit" button
215
	 * Example: I should not see a "Delete" button
216
	 *
217
	 * @Given /^I should( not? |\s*)see a "([^"]*)" button$/
218
	 */
219
	public function iShouldSeeAButton($negative, $text) {
220
		$page = $this->getSession()->getPage();
221
		$els = $page->findAll('named', array('link_or_button', "'$text'"));
222
		$matchedEl = null;
223
		foreach($els as $el) {
224
			if($el->isVisible()) $matchedEl = $el;
225
		}
226
227
		if(trim($negative)) {
228
			assertNull($matchedEl, sprintf('%s button found', $text));
229
		} else {
230
			assertNotNull($matchedEl, sprintf('%s button not found', $text));
231
		}
232
	}
233
234
	/**
235
	 * @Given /^I should( not? |\s*)see a "([^"]*)" field$/
236
	 */
237
	public function iShouldSeeAField($negative, $text) {
238
		$page = $this->getSession()->getPage();
239
		$els = $page->findAll('named', array('field', "'$text'"));
240
		$matchedEl = null;
241
		foreach($els as $el) {
242
			if($el->isVisible()) $matchedEl = $el;
243
		}
244
245
		if(trim($negative)) {
246
			assertNull($matchedEl);
247
		} else {
248
			assertNotNull($matchedEl);
249
		}
250
	}
251
252
	/**
253
	 * Locate a HTML editor field
254
	 *
255
	 * @param string $locator Raw html field identifier as passed from
256
	 * @return NodeElement
257
	 */
258
	protected function getHtmlField($locator)
259
	{
260
		$locator = $this->fixStepArgument($locator);
261
		$page = $this->getSession()->getPage();
262
		$element = $page->find('css', 'textarea.htmleditor[name=\'' . $locator . '\']');
263
		assertNotNull($element, sprintf('HTML field "%s" not found', $locator));
264
		return $element;
265
	}
266
267
}
268