Completed
Pull Request — master (#16)
by Sergii
07:11
created

RawTqContext::locatePath()   D

Complexity

Conditions 10
Paths 16

Size

Total Lines 44
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 110

Importance

Changes 0
Metric Value
dl 0
loc 44
ccs 0
cts 14
cp 0
rs 4.8196
c 0
b 0
f 0
cc 10
eloc 19
nc 16
nop 1
crap 110

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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