Completed
Push — master ( f105fc...3abe44 )
by Sergii
02:30
created

RawTqContext::getTag()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
dl 0
loc 4
c 2
b 1
f 0
rs 10
cc 2
eloc 2
nc 2
nop 1
1
<?php
2
/**
3
 * @author Sergii Bondarenko, <[email protected]>
4
 */
5
namespace Drupal\TqExtension\Context;
6
7
// Contexts.
8
use Behat\Behat\Context\SnippetAcceptingContext;
9
use Drupal\DrupalExtension\Context as DrupalContexts;
10
11
// Exceptions.
12
use Behat\Behat\Context\Exception\ContextNotFoundException;
13
14
// Helpers.
15
use WebDriver\Session;
16
use Drupal\Driver\DrushDriver;
17
use Behat\Mink\Element\NodeElement;
18
use Behat\Mink\Driver\Selenium2Driver;
19
use Behat\Behat\Hook\Scope\StepScope;
20
use Behat\Behat\Context\Environment\InitializedContextEnvironment;
21
use Drupal\TqExtension\Utils as TqUtils;
22
23
/**
24
 * @see RawTqContext::__call()
25
 *
26
 * @method User\UserContext getUserContext()
27
 * @method Form\FormContext getFormContext()
28
 * @method Email\EmailContext getEmailContext()
29
 * @method Drush\DrushContext getDrushContext()
30
 * @method Wysiwyg\WysiwygContext getWysiwygContext()
31
 * @method Redirect\RedirectContext getRedirectContext()
32
 * @method TqContext getTqContext()
33
 * @method DrupalContexts\MinkContext getMinkContext()
34
 * @method DrupalContexts\DrupalContext getDrupalContext()
35
 * @method DrupalContexts\MessageContext getMessageContext()
36
 * @method \Drupal\Component\Utility\Random getRandom()
37
 */
38
class RawTqContext extends RawPageContext implements TqContextInterface
39
{
40
    use TqUtils\Interaction;
41
42
    /**
43
     * Parameters of TqExtension.
44
     *
45
     * @var array
46
     */
47
    private $parameters = [];
48
    /**
49
     * @var string
50
     */
51
    protected static $pageUrl = '';
52
53
    /**
54
     * @param string $method
55
     * @param array $arguments
56
     *
57
     * @throws \Exception
58
     * @throws ContextNotFoundException
59
     *   When context class cannot be loaded.
60
     *
61
     * @return SnippetAcceptingContext
62
     */
63
    public function __call($method, array $arguments)
64
    {
65
        $environment = $this->getEnvironment();
66
        // @example
67
        // The "getFormContext" method is not declared and his name will be split by capital
68
        // letters, creating an array with three items: "get", "Form" and "Context".
69
        list(, $base, $context) = preg_split('/(?=[A-Z])/', $method);
70
71
        foreach ([
72
            [$this->getTqParameter('context_namespace'), $base],
73
            ['Drupal', 'DrupalExtension', 'Context'],
74
        ] as $class) {
75
            $class[] = "$base$context";
76
            $class = implode('\\', $class);
77
78
            if ($environment->hasContextClass($class)) {
79
                return $environment->getContext($class);
80
            }
81
        }
82
83
        throw new \Exception(sprintf('Method %s does not exist', $method));
84
    }
85
86
    /**
87
     * @param array $variables
88
     *   An associative array where key is a variable name and a value - value.
89
     */
90
    public static function setDrupalVariables(array $variables)
91
    {
92
        foreach ($variables as $name => $value) {
93
            variable_set($name, $value);
94
        }
95
    }
96
97
    /**
98
     * Get selector by name.
99
     *
100
     * @param string $name
101
     *   Selector name from the configuration file.
102
     *
103
     * @return string
104
     *   CSS selector.
105
     *
106
     * @throws \Exception
107
     *   If selector does not exits.
108
     */
109
    public function getDrupalSelector($name)
110
    {
111
        $selectors = $this->getDrupalParameter('selectors');
112
113
        if (!isset($selectors[$name])) {
114
            throw new \Exception(sprintf('No such selector configured: %s', $name));
115
        }
116
117
        return $selectors[$name];
118
    }
119
120
121
    /**
122
     * @param string $site
123
     *   Drupal site folder.
124
     *
125
     * @return string
126
     *   URL to files directory.
127
     */
128
    public function getFilesUrl($site = 'default')
129
    {
130
        return $this->locatePath("sites/$site/files");
131
    }
132
133
    /**
134
     * @param string $text
135
     *   JS code for processing.
136
     *
137
     * @return self
138
     */
139
    protected function processJavaScript(&$text)
140
    {
141
        $text = str_replace(['$'], ['jQuery'], $text);
142
143
        return $this;
144
    }
145
146
    /**
147
     * @return InitializedContextEnvironment
148
     */
149
    public function getEnvironment()
150
    {
151
        return $this->getDrupal()->getEnvironment();
152
    }
153
154
    /**
155
     * @return Selenium2Driver
156
     */
157
    public function getSessionDriver()
158
    {
159
        return $this->getSession()->getDriver();
160
    }
161
162
    /**
163
     * @return Session
164
     */
165
    public function getWebDriverSession()
166
    {
167
        return $this->getSessionDriver()->getWebDriverSession();
168
    }
169
170
    /**
171
     * @todo Remove this when DrupalExtension will be used Mink >=1.6 and use $this->getSession->getWindowNames();
172
     *
173
     * @return string[]
174
     */
175
    public function getWindowNames()
176
    {
177
        return $this->getWebDriverSession()->window_handles();
178
    }
179
180
    /**
181
     * @param NodeElement $element
182
     * @param string $script
183
     *
184
     * @example
185
     * $this->executeJsOnElement($this->element('*', 'Meta tags'), 'return jQuery({{ELEMENT}}).text();');
186
     * $this->executeJsOnElement($this->element('*', '#menu'), '{{ELEMENT}}.focus();');
187
     *
188
     * @throws \Exception
189
     *
190
     * @return mixed
191
     */
192
    public function executeJsOnElement(NodeElement $element, $script)
193
    {
194
        $session = $this->getWebDriverSession();
195
        // We need to trigger something with "withSyn" method, because, otherwise an element won't be found.
196
        $element->focus();
197
198
        $this->processJavaScript($script);
199
        self::debug([$script]);
200
201
        return $session->execute([
202
            'script' => str_replace('{{ELEMENT}}', 'arguments[0]', $script),
203
            'args' => [['ELEMENT' => $session->element('xpath', $element->getXpath())->getID()]],
204
        ]);
205
    }
206
207
    /**
208
     * @param string $javascript
209
     *   JS code for execution.
210
     * @param array $args
211
     *   Placeholder declarations.
212
     *
213
     * @return mixed
214
     */
215
    public function executeJs($javascript, array $args = [])
216
    {
217
        $javascript = format_string($javascript, $args);
218
219
        $this->processJavaScript($javascript);
220
        self::debug([$javascript]);
221
222
        return $this->getSession()->evaluateScript($javascript);
223
    }
224
225
    /**
226
     * Check JS events in step definition.
227
     *
228
     * @param StepScope $event
229
     *
230
     * @return int
231
     */
232
    public static function isStepImpliesJsEvent(StepScope $event)
233
    {
234
        return preg_match('/(follow|press|click|submit)/i', $event->getStep()->getText());
235
    }
236
237
    /**
238
     * @return DrushDriver
239
     */
240
    public function getDrushDriver()
241
    {
242
        return $this->getDriver('drush');
243
    }
244
245
    /**
246
     * Wait for all AJAX requests and jQuery animations.
247
     */
248
    public function waitAjaxAndAnimations()
249
    {
250
        $this->getSession()
251
             ->wait(1000, "window.__behatAjax === false && !jQuery(':animated').length && !jQuery.active");
252
    }
253
254
    /**
255
     * {@inheritdoc}
256
     */
257
    public function setTqParameters(array $parameters)
258
    {
259
        if (empty($this->parameters)) {
260
            $this->parameters = $parameters;
261
        }
262
    }
263
264
    /**
265
     * @param string $name
266
     *   The name of parameter from behat.yml.
267
     *
268
     * @return mixed
269
     */
270
    public function getTqParameter($name)
271
    {
272
        return isset($this->parameters[$name]) ? $this->parameters[$name] : false;
273
    }
274
275
    /**
276
     * {@inheritdoc}
277
     */
278
    public function locatePath($path = '')
279
    {
280
        // Obtain base URL when path is empty, or not starts from "//" or "http".
281
        if (empty($path) || strpos($path, '//') !== 0 && strpos($path, 'http') !== 0) {
282
            $path = rtrim($this->getMinkParameter('base_url'), '/') . '/' . ltrim($path, '/');
283
        }
284
285
        $url = parse_url($path);
286
287
        if (!isset($url['host'])) {
288
            throw new \InvalidArgumentException(sprintf('Incorrect URL: %s', func_get_arg(0)));
289
        }
290
291
        // When URL starts from "//" the "scheme" key will not exists.
292
        if (isset($url['scheme'])) {
293
            // Check scheme.
294
            if (!in_array($url['scheme'], ['http', 'https'])) {
295
                throw new \InvalidArgumentException(sprintf('%s is not valid scheme.', $url['scheme']));
296
            }
297
298
            $path = $url['scheme'] . ':';
299
        } else {
300
            // Process "//" at the start.
301
            $path = '';
302
        }
303
304
        $path .= '//';
305
306
        if (isset($url['user'], $url['pass'])) {
307
            // Encode special characters in username and password. Useful
308
            // when some item contain something like "@" symbol.
309
            foreach (['user' => ':', 'pass' => '@'] as $part => $suffix) {
310
                $path .= rawurlencode($url[$part]) . $suffix;
311
            }
312
        }
313
314
        $path .= $url['host'];
315
316
        // Append additional URL components.
317
        foreach (['port' => ':', 'path' => '', 'query' => '?', 'fragment' => '#'] as $part => $prefix) {
318
            if (isset($url[$part])) {
319
                $path .= $prefix . $url[$part];
320
            }
321
        }
322
323
        return $path;
324
    }
325
326
    /**
327
     * @return string
328
     */
329
    public function getCurrentUrl()
330
    {
331
        return $this->locatePath($this->getSession()->getCurrentUrl());
332
    }
333
}
334