Completed
Push — master ( f9afae...e8d24b )
by Sergii
05:27
created

RawTqContext::getDrupalText()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 5
rs 9.4285
cc 1
eloc 2
nc 1
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
     * {@inheritdoc}
122
     */
123
    public function getDrupalText($name)
124
    {
125
        // Make text selectors translatable.
126
        return t(parent::getDrupalText($name));
127
    }
128
129
    /**
130
     * @param string $site
131
     *   Drupal site folder.
132
     *
133
     * @return string
134
     *   URL to files directory.
135
     */
136
    public function getFilesUrl($site = 'default')
137
    {
138
        return $this->locatePath("sites/$site/files");
139
    }
140
141
    /**
142
     * @param string $text
143
     *   JS code for processing.
144
     *
145
     * @return self
146
     */
147
    protected function processJavaScript(&$text)
148
    {
149
        $text = str_replace(['$'], ['jQuery'], $text);
150
151
        return $this;
152
    }
153
154
    /**
155
     * @return InitializedContextEnvironment
156
     */
157
    public function getEnvironment()
158
    {
159
        return $this->getDrupal()->getEnvironment();
160
    }
161
162
    /**
163
     * @return Selenium2Driver
164
     */
165
    public function getSessionDriver()
166
    {
167
        return $this->getSession()->getDriver();
168
    }
169
170
    /**
171
     * @return Session
172
     */
173
    public function getWebDriverSession()
174
    {
175
        return $this->getSessionDriver()->getWebDriverSession();
176
    }
177
178
    /**
179
     * @todo Remove this when DrupalExtension will be used Mink >=1.6 and use $this->getSession->getWindowNames();
180
     *
181
     * @return string[]
182
     */
183
    public function getWindowNames()
184
    {
185
        return $this->getWebDriverSession()->window_handles();
186
    }
187
188
    /**
189
     * @param NodeElement $element
190
     * @param string $script
191
     *
192
     * @example
193
     * $this->executeJsOnElement($this->element('*', 'Meta tags'), 'return jQuery({{ELEMENT}}).text();');
194
     * $this->executeJsOnElement($this->element('*', '#menu'), '{{ELEMENT}}.focus();');
195
     *
196
     * @throws \Exception
197
     *
198
     * @return mixed
199
     */
200
    public function executeJsOnElement(NodeElement $element, $script)
201
    {
202
        $session = $this->getWebDriverSession();
203
        // We need to trigger something with "withSyn" method, because, otherwise an element won't be found.
204
        $element->focus();
205
206
        $this->processJavaScript($script);
207
        self::debug([$script]);
208
209
        return $session->execute([
210
            'script' => str_replace('{{ELEMENT}}', 'arguments[0]', $script),
211
            'args' => [['ELEMENT' => $session->element('xpath', $element->getXpath())->getID()]],
212
        ]);
213
    }
214
215
    /**
216
     * @param string $javascript
217
     *   JS code for execution.
218
     * @param array $args
219
     *   Placeholder declarations.
220
     *
221
     * @return mixed
222
     */
223
    public function executeJs($javascript, array $args = [])
224
    {
225
        $javascript = format_string($javascript, $args);
226
227
        $this->processJavaScript($javascript);
228
        self::debug([$javascript]);
229
230
        return $this->getSession()->evaluateScript($javascript);
231
    }
232
233
    /**
234
     * Check JS events in step definition.
235
     *
236
     * @param StepScope $event
237
     *
238
     * @return int
239
     */
240
    public static function isStepImpliesJsEvent(StepScope $event)
241
    {
242
        return preg_match('/(follow|press|click|submit)/i', $event->getStep()->getText());
243
    }
244
245
    /**
246
     * @return DrushDriver
247
     */
248
    public function getDrushDriver()
249
    {
250
        return $this->getDriver('drush');
251
    }
252
253
    /**
254
     * Wait for all AJAX requests and jQuery animations.
255
     */
256
    public function waitAjaxAndAnimations()
257
    {
258
        $this->getSession()
259
             ->wait(1000, "window.__behatAjax === false && !jQuery(':animated').length && !jQuery.active");
260
    }
261
262
    /**
263
     * {@inheritdoc}
264
     */
265
    public function setTqParameters(array $parameters)
266
    {
267
        if (empty($this->parameters)) {
268
            $this->parameters = $parameters;
269
        }
270
    }
271
272
    /**
273
     * @param string $name
274
     *   The name of parameter from behat.yml.
275
     *
276
     * @return mixed
277
     */
278
    public function getTqParameter($name)
279
    {
280
        return isset($this->parameters[$name]) ? $this->parameters[$name] : false;
281
    }
282
283
    /**
284
     * {@inheritdoc}
285
     */
286
    public function locatePath($path = '')
287
    {
288
        // Obtain base URL when path is empty, or not starts from "//" or "http".
289
        if (empty($path) || strpos($path, '//') !== 0 && strpos($path, 'http') !== 0) {
290
            $path = rtrim($this->getMinkParameter('base_url'), '/') . '/' . ltrim($path, '/');
291
        }
292
293
        $url = parse_url($path);
294
295
        if (!isset($url['host'])) {
296
            throw new \InvalidArgumentException(sprintf('Incorrect URL: %s', func_get_arg(0)));
297
        }
298
299
        // When URL starts from "//" the "scheme" key will not exists.
300
        if (isset($url['scheme'])) {
301
            // Check scheme.
302
            if (!in_array($url['scheme'], ['http', 'https'])) {
303
                throw new \InvalidArgumentException(sprintf('%s is not valid scheme.', $url['scheme']));
304
            }
305
306
            $path = $url['scheme'] . ':';
307
        } else {
308
            // Process "//" at the start.
309
            $path = '';
310
        }
311
312
        $path .= '//';
313
314
        if (isset($url['user'], $url['pass'])) {
315
            // Encode special characters in username and password. Useful
316
            // when some item contain something like "@" symbol.
317
            foreach (['user' => ':', 'pass' => '@'] as $part => $suffix) {
318
                $path .= rawurlencode($url[$part]) . $suffix;
319
            }
320
        }
321
322
        $path .= $url['host'];
323
324
        // Append additional URL components.
325
        foreach (['port' => ':', 'path' => '', 'query' => '?', 'fragment' => '#'] as $part => $prefix) {
326
            if (isset($url[$part])) {
327
                $path .= $prefix . $url[$part];
328
            }
329
        }
330
331
        return $path;
332
    }
333
334
    /**
335
     * @return string
336
     */
337
    public function getCurrentUrl()
338
    {
339
        return $this->locatePath($this->getSession()->getCurrentUrl());
340
    }
341
}
342