Completed
Pull Request — master (#16)
by Sergii
03:45
created

RawTqContext::setDrupalVariables()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 6
ccs 0
cts 5
cp 0
rs 9.4285
cc 2
eloc 3
nc 2
nop 1
crap 6
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
24
/**
25
 * @see RawTqContext::__call()
26
 *
27
 * @method User\UserContext getUserContext()
28
 * @method Node\NodeContext getNodeContext()
29
 * @method Form\FormContext getFormContext()
30
 * @method Email\EmailContext getEmailContext()
31
 * @method Drush\DrushContext getDrushContext()
32
 * @method Wysiwyg\WysiwygContext getWysiwygContext()
33
 * @method Message\MessageContext getMessageContext()
34
 * @method Redirect\RedirectContext getRedirectContext()
35
 * @method TqContext getTqContext()
36
 * @method DrupalContexts\MinkContext getMinkContext()
37
 * @method DrupalContexts\DrupalContext getDrupalContext()
38
 * @method Random getRandom()
39
 */
40
class RawTqContext extends RawPageContext implements TqContextInterface
41
{
42
    use Debugger;
43
    use Tags;
44
45
    /**
46
     * Parameters of TqExtension.
47
     *
48
     * @var array
49
     */
50
    private $parameters = [];
51
    /**
52
     * @var string
53
     */
54
    protected static $pageUrl = '';
55
56
    /**
57
     * @param string $method
58
     * @param array $arguments
59
     *
60
     * @throws \Exception
61
     * @throws ContextNotFoundException
62
     *   When context class cannot be loaded.
63
     *
64
     * @return SnippetAcceptingContext
65
     */
66
    public function __call($method, array $arguments)
67
    {
68
        $environment = $this->getEnvironment();
69
        // @example
70
        // The "getFormContext" method is not declared and his name will be split by capital
71
        // letters, creating an array with three items: "get", "Form" and "Context".
72
        list(, $base, $context) = preg_split('/(?=[A-Z])/', $method);
73
74
        foreach ([
75
            [$this->getTqParameter('namespace'), 'Context', $base],
76
            ['Drupal', 'DrupalExtension', 'Context'],
77
        ] as $class) {
78
            $class[] = "$base$context";
79
            $class = implode('\\', $class);
80
81
            if ($environment->hasContextClass($class)) {
82
                return $environment->getContext($class);
83
            }
84
        }
85
86
        throw new \Exception(sprintf('Method "%s" does not exist', $method));
87
    }
88
89
    /**
90
     * Get selector by name.
91
     *
92
     * @param string $name
93
     *   Selector name from the configuration file.
94
     *
95
     * @return string
96
     *   CSS selector.
97
     *
98
     * @throws \Exception
99
     *   If selector does not exits.
100
     */
101
    public function getDrupalSelector($name)
102
    {
103
        $selectors = $this->getDrupalParameter('selectors');
104
105
        if (!isset($selectors[$name])) {
106
            throw new \Exception(sprintf('No such selector configured: %s', $name));
107
        }
108
109
        return $selectors[$name];
110
    }
111
112
    /**
113
     * {@inheritdoc}
114
     */
115
    public function getDrupalText($name)
116
    {
117
        // Make text selectors translatable.
118
        return \DrupalKernelPlaceholder::t(parent::getDrupalText($name));
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 = \DrupalKernelPlaceholder::formatString($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 self::hasTag('javascript') && 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
        $script = "!window.__behatAjax && !$(':animated').length && !$.active";
251
252
        static::processJavaScript($script);
253
254
        $this->getSession()->wait(1000, $script);
255
    }
256
257
    /**
258
     * {@inheritdoc}
259
     */
260
    public function setTqParameters(array $parameters)
261
    {
262
        if (empty($this->parameters)) {
263
            $this->parameters = $parameters;
264
        }
265
    }
266
267
    /**
268
     * {@inheritdoc}
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(strtolower($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