Completed
Pull Request — master (#16)
by Sergii
04:34
created

RawTqContext::processJavaScript()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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