Completed
Push — master ( a9ff6a...76c893 )
by Kevin
05:32 queued 02:44
created

AbstractTestCase::getInitializer()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace Magium;
4
5
use Facebook\WebDriver\Exception\NoSuchElementException;
6
use Facebook\WebDriver\Exception\WebDriverException;
7
use Magium\Assertions\Element\Clickable;
8
use Magium\Assertions\Element\Exists;
9
use Magium\Assertions\Element\NotClickable;
10
use Magium\Assertions\Element\NotDisplayed;
11
use Magium\Assertions\Element\NotExists;
12
use Magium\Assertions\LoggingAssertionExecutor;
13
use Magium\TestCase\Initializer;
14
use Magium\Themes\BaseThemeInterface;
15
use Magium\Themes\ThemeConfigurationInterface;
16
use Magium\Util\Api\Request;
17
use Magium\Util\Configuration\ClassConfigurationReader;
18
use Magium\Util\Configuration\ConfigurationCollector\DefaultPropertyCollector;
19
use Magium\Util\Configuration\ConfigurationReader;
20
use Magium\Util\Configuration\EnvironmentConfigurationReader;
21
use Magium\Util\Configuration\StandardConfigurationProvider;
22
use Magium\Util\Log\Logger;
23
use Magium\Util\Api\Clairvoyant\Clairvoyant;
24
use Magium\Util\Phpunit\MasterListener;
25
use Magium\Util\TestCase\RegistrationListener;
26
use Magium\WebDriver\LoggingRemoteExecuteMethod;
27
use Magium\WebDriver\WebDriver;
28
use PHPUnit_Framework_TestResult;
29
use Zend\Di\Config;
30
use Zend\Di\Di;
31
32
abstract class AbstractTestCase extends \PHPUnit_Framework_TestCase
33
{
34
35
    protected static $baseNamespaces = [];
36
37
    protected $baseThemeClass = 'Magium\Themes\ThemeConfigurationInterface';
38
39
    protected $postCallbacks = [];
40
41
    /**
42
     * @var MasterListener
43
     */
44
45
    protected static $masterListener;
46
47
    /**
48
     * @var \Magium\WebDriver\WebDriver
49
     */
50
    protected $webdriver;
51
52
    /**
53
     * @var Di
54
     */
55
56
    protected $di;
57
58
    protected $textElementNodeSearch = [
59
        'button', 'span', 'a', 'li', 'label', 'option', 'h1', 'h2', 'h3', 'td'
60
    ];
61
62
    protected $initializer;
63
    
64
    const BY_XPATH = 'byXpath';
65
    const BY_ID    = 'byId';
66
    const BY_CSS_SELECTOR = 'byCssSelector';
67
    const BY_TEXT = 'byText';
68
69
    protected static $registrationCallbacks;
70
71
    protected function setUp()
72
    {
73
        /*
74
         * Putting this in the setup and not in the property means that an extending class can inject itself easily
75
         * before the Magium namespace, thus, taking preference over the base namespace
76
         */
77
        self::addBaseNamespace('Magium');
78
        $init = new Initializer($this->testCaseConfiguration, $this->testCaseConfigurationObject);
0 ignored issues
show
Bug introduced by
The property testCaseConfiguration does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
Bug introduced by
The property testCaseConfigurationObject does not seem to exist. Did you mean testCaseConfiguration?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
79
        $init->initialize($this);
80
    }
81
82
    /**
83
     * @return Di
84
     */
85
    public function getDi()
86
    {
87
        return $this->di;
88
    }
89
90
    /**
91
     * @param Di $di
92
     */
93
    public function setDi($di)
94
    {
95
        $this->di = $di;
96
    }
97
98
    /**
99
     * @return WebDriver
100
     */
101
    public function getWebdriver()
102
    {
103
        return $this->webdriver;
104
    }
105
106
    /**
107
     * @param WebDriver $webdriver
108
     */
109
    public function setWebdriver(WebDriver $webdriver)
110
    {
111
        $this->webdriver = $webdriver;
112
    }
113
114
    public function getInitializer()
115
    {
116
        return $this->initializer;
117
    }
118
119
120
    public function __construct($name = null, array $data = [], $dataName = null, Initializer $initializer = null)
121
    {
122
        if (!$initializer instanceof Initializer) {
123
            $initializer = new Initializer();
124
        }
125
        $this->initializer = $initializer;
126
        self::getMasterListener();
127
        parent::__construct($name, $data, $dataName);
128
129
    }
130
131
    public function setTestResultObject(PHPUnit_Framework_TestResult $result)
132
    {
133
        // This odd little function is here because the first place where you can reliably add a listener without
134
        // having to make a phpunit.xml or program argument change
135
136
        self::getMasterListener()->bindToResult($result);
137
        parent::setTestResultObject($result);
138
    }
139
140
    /**
141
     * @return MasterListener
142
     */
143
144
    public static function getMasterListener()
145
    {
146
        if (!self::$masterListener instanceof MasterListener) {
147
            self::$masterListener = new MasterListener();
148
        }
149
        return self::$masterListener;
150
    }
151
152
    protected function tearDown()
153
    {
154
        foreach ($this->postCallbacks as $callback) {
155
            if (is_callable($callback)) {
156
                call_user_func($callback);
157
            }
158
        }
159
        parent::tearDown();
160
        if ($this->webdriver instanceof WebDriver) {
161
            $this->webdriver->quit();
162
            $this->webdriver = null;
163
        }
164
    }
165
166
167
    public function filterWebDriverAction($by)
168
    {
169
        switch ($by) {
170
            case WebDriver::BY_XPATH:
171
                return 'xpath';
172
            case WebDriver::BY_CSS_SELECTOR:
173
                return 'css_selector';
174
            case WebDriver::BY_ID:
175
                return 'id';
176
            default:
177
                return $by;
178
        }
179
    }
180
181
    public function assertElementClickable($selector, $by = WebDriver::BY_ID)
182
    {
183
        $this->elementAssertion($selector, $by, Clickable::ASSERTION);
184
    }
185
186
187
    public function assertElementNotClickable($selector, $by = WebDriver::BY_ID)
188
    {
189
        $this->elementAssertion($selector, $by, NotClickable::ASSERTION);
190
191
    }
192
193
    public function setTestCaseConfigurationClass($class)
194
    {
195
        $this->testCaseConfiguration = $class;
196
    }
197
198
    public static function addBaseNamespace($namespace)
199
    {
200
        if (!in_array($namespace, self::$baseNamespaces)) {
201
            self::$baseNamespaces[] = trim($namespace, '\\');
202
        }
203
    }
204
205
    public static function resolveClass( $class, $prefix = null)
206
    {
207
        $origClass = $class;
208
        if ($prefix !== null) {
209
            $class = "{$prefix}\\{$class}";
210
        }
211
        foreach (self::$baseNamespaces as $namespace) {
212
            if (strpos($namespace, $class) === 0) {
213
                // We have a fully qualified class name
214
                return $class;
215
            }
216
        }
217
218
        foreach (self::$baseNamespaces as $namespace) {
219
            $fqClass = $namespace . '\\' . $class;
220
            if (class_exists($fqClass)) {
221
                return $fqClass;
222
            }
223
        }
224
        return $origClass;
225
    }
226
227
    public function setTypePreference($type, $preference)
228
    {
229
        $type = self::resolveClass($type);
230
        $preference = self::resolveClass($preference);
231
        $this->di->instanceManager()->unsetTypePreferences($type);
232
        $this->di->instanceManager()->setTypePreference($type, [$preference]);
233
234
    }
235
236
    protected function normalizeClassRequest($class)
237
    {
238
        return str_replace('/', '\\', $class);
239
    }
240
241
    public function addPostTestCallback($callback)
242
    {
243
        if (!is_callable($callback)) {
244
            throw new InvalidConfigurationException('Callback is not callable');
245
        }
246
        $this->postCallbacks[] = $callback;
247
    }
248
249
    /**
250
251
     * @param string $theme
252
     * @return \Magium\Themes\ThemeConfigurationInterface
253
     */
254
255
    public function getTheme($theme = null)
256
    {
257
        if ($theme === null) {
258
            return $this->get($this->baseThemeClass);
259
        }
260
        $theme = self::resolveClass($theme, 'Themes');
261
        return $this->get($theme);
262
    }
263
264
    /**
265
     *
266
     * @param string $action
267
     * @return mixed
268
     */
269
270
    public function getAction($action)
271
    {
272
        $action = self::resolveClass($action, 'Actions');
273
274
        return $this->get($action);
275
    }
276
277
278
    /**
279
     * @param string $name
280
     * @return \Magium\Magento\Identities\AbstractEntity
281
     */
282
283
    public function getIdentity($name = 'Customer')
284
    {
285
        $name = self::resolveClass($name, 'Identities');
286
287
        return $this->get($name);
288
    }
289
290
    /**
291
     *
292
     * @param string $navigator
293
     * @return \Magium\Magento\Navigators\BaseMenuNavigator
294
     */
295
296
    public function getNavigator($navigator = 'BaseMenu')
297
    {
298
        $navigator = self::resolveClass($navigator, 'Navigators');
299
300
        return $this->get($navigator);
301
    }
302
303
    public function getAssertion($assertion)
304
    {
305
        $assertion = self::resolveClass($assertion, 'Assertions');
306
307
        return $this->get($assertion);
308
    }
309
310
    /**
311
     *
312
     * @param string $extractor
313
     * @return \Magium\Extractors\AbstractExtractor
314
     */
315
316
    public function getExtractor($extractor)
317
    {
318
        $extractor = self::resolveClass($extractor, 'Extractors');
319
320
        return $this->get($extractor);
321
    }
322
323
    /**
324
     * Sleep the specified amount of time.
325
     *
326
     * Options: 1s (1 second), 1ms (1 millisecond), 1us (1 microsecond), 1ns (1 nanosecond)
327
     *
328
     * @param $time
329
     */
330
331
    public function sleep($time)
332
    {
333
        $length = (int)$time;
334
335
        if (strpos($time, 'ms') !== false) {
336
            usleep($length * 1000);
337
        } else if (strpos($time, 'us') !== false) {
338
            usleep($length);
339
        } else if (strpos($time, 'ns') !== false) {
340
            time_nanosleep(0, $length);
341
        } else {
342
            sleep($length);
343
        }
344
    }
345
346
347
    public function commandOpen($url)
348
    {
349
        $this->get('Magium\Commands\Open')->open($url);
350
    }
351
352
353
    /**
354
     * @return \Magium\Util\Log\Logger
355
     */
356
357
    public function getLogger()
358
    {
359
        return $this->get('Magium\Util\Log\Logger');
360
    }
361
362
    public function get($class)
363
    {
364
        $class = $this->normalizeClassRequest($class);
365
        $preferredClass = $this->di->instanceManager()->getTypePreferences($class);
366
        if (is_array($preferredClass) && count($preferredClass) > 0) {
367
            $class = array_shift($preferredClass);
368
        }
369
        return $this->di->get($class);
370
    }
371
372
373
    public function assertElementExists($selector, $by = 'byId')
374
    {
375
        $this->elementAssertion($selector, $by, Exists::ASSERTION);
376
    }
377
378
    public function assertTitleEquals($title)
379
    {
380
        $webTitle = $this->webdriver->getTitle();
381
        self::assertEquals($title, $webTitle);
382
    }
383
384
385
    public function assertTitleContains($title)
386
    {
387
        $webTitle = $this->webdriver->getTitle();
388
        self::assertContains($title, $webTitle);
389
    }
390
391
392
    public function assertNotTitleEquals($title)
393
    {
394
        $webTitle = $this->webdriver->getTitle();
395
        self::assertNotEquals($title, $webTitle);
396
    }
397
398
399
    public function assertNotTitleContains($title)
400
    {
401
        $webTitle = $this->webdriver->getTitle();
402
        self::assertNotContains($title, $webTitle);
403
    }
404
405
    public function assertURLEquals($url)
406
    {
407
        $webUrl = $this->webdriver->getCurrentURL();
408
        self::assertEquals($url, $webUrl);
409
    }
410
411
    public function assertURLContains($url)
412
    {
413
        $webUrl = $this->webdriver->getCurrentURL();
414
        self::assertContains($url, $webUrl);
415
    }
416
417
418
    public function assertURLNotEquals($url)
419
    {
420
        $webUrl = $this->webdriver->getCurrentURL();
421
        self::assertNotEquals($url, $webUrl);
422
    }
423
424
    public function assertURLNotContains($url)
425
    {
426
        $webUrl = $this->webdriver->getCurrentURL();
427
        self::assertNotContains($url, $webUrl);
428
    }
429
430
    protected function elementAssertion($selector, $by, $name)
431
    {
432
        $executor = $this->getAssertion(LoggingAssertionExecutor::ASSERTION);
433
        $assertion = $this->getAssertion($name);
434
        $assertion->setSelector($selector)->setBy($by);
435
        $executor->execute($assertion);
436
    }
437
438
    public function assertElementDisplayed($selector, $by = 'byId')
439
    {
440
        $this->elementAssertion($selector, $by, NotDisplayed::ASSERTION);
441
    }
442
443
    public function assertElementNotDisplayed($selector, $by = 'byId')
444
    {
445
        try {
446
            $this->assertElementExists($selector, $by);
447
            self::assertFalse(
448
                $this->webdriver->$by($selector)->isDisplayed(),
449
                sprintf('The element: %s, is displayed and it should not have been', $selector)
450
            );
451
        } catch (\Exception $e) {
452
            $this->fail(sprintf('Element "%s" cannot be found using selector "%s"', $selector, $by));
453
        }
454
    }
455
456
    public function assertElementNotExists($selector, $by = 'byId')
457
    {
458
        $this->elementAssertion($selector, $by, NotExists::ASSERTION);
459
    }
460
461
    /**
462
     * @return LoggingAssertionExecutor
463
     */
464
465
    public function getAssertionLogger()
466
    {
467
        return $this->getAssertion(LoggingAssertionExecutor::ASSERTION);
468
    }
469
470
    public function switchThemeConfiguration($fullyQualifiedClassName)
471
    {
472
473
        $reflection = new \ReflectionClass($fullyQualifiedClassName);
474
475
        if ($reflection->implementsInterface('Magium\Themes\ThemeConfigurationInterface')) {
476
            $this->baseThemeClass = $fullyQualifiedClassName;
477
            $this->di->instanceManager()->unsetTypePreferences('Magium\Themes\ThemeConfigurationInterface');
478
            $this->di->instanceManager()->setTypePreference('Magium\Themes\ThemeConfigurationInterface', [$fullyQualifiedClassName]);
479
480
            if ($reflection->implementsInterface('Magium\Themes\BaseThemeInterface')) {
481
                $this->di->instanceManager()->unsetTypePreferences('Magium\Themes\BaseThemeInterface');
482
                $this->di->instanceManager()->setTypePreference('Magium\Themes\BaseThemeInterface', [$fullyQualifiedClassName]);
483
            }
484
            $theme = $this->getTheme();
485
            if ($theme instanceof BaseThemeInterface) {
486
                $theme->configure($this);
487
            }
488
        } else {
489
            throw new InvalidConfigurationException('The theme configuration implement Magium\Themes\ThemeConfigurationInterface');
490
        }
491
        $this->getLogger()->addCharacteristic(Logger::CHARACTERISTIC_THEME, $fullyQualifiedClassName);
492
    }
493
494
    public static function assertWebDriverElement($element)
495
    {
496
        self::assertInstanceOf('Facebook\WebDriver\WebDriverElement', $element);
497
    }
498
499
    public function assertElementHasText($node, $text)
500
    {
501
        try {
502
            $this->byXpath(sprintf('//%s[contains(., "%s")]', $node, addslashes($text)));
503
        } catch (\Exception $e) {
504
            $this->fail('The body did not contain the text: ' . $text);
505
        }
506
    }
507
508
    public function assertPageHasText($text)
509
    {
510
        try {
511
            $this->webdriver->byXpath(sprintf('//body[contains(., "%s")]', $text));
512
            // If the element is not found then an exception will be thrown
513
        } catch (\Exception $e) {
514
            $this->fail('The body did not contain the text: ' . $text);
515
        }
516
517
    }
518
519
    public function assertPageNotHasText($text)
520
    {
521
        try {
522
            $this->webdriver->byXpath(sprintf('//body[contains(., "%s")]', $text));
523
            $this->fail('The page contains the words: ' . $text);
524
        } catch (NoSuchElementException $e) {
525
            // Exception thrown is a success
526
        }
527
    }
528
529
    /**
530
     * @param $xpath
531
     * @return \Facebook\WebDriver\Remote\RemoteWebElement
532
     */
533
534
    public function byXpath($xpath)
535
    {
536
        return $this->webdriver->byXpath($xpath);
537
    }
538
539
    /**
540
     * @param $id
541
     * @return \Facebook\WebDriver\Remote\RemoteWebElement
542
     */
543
544
    public function byId($id)
545
    {
546
        return $this->webdriver->byId($id);
547
    }
548
549
    /**
550
     * @param $selector
551
     * @return \Facebook\WebDriver\Remote\RemoteWebElement
552
     */
553
554
    public function byCssSelector($selector)
555
    {
556
        return $this->webdriver->byCssSelector($selector);
557
    }
558
559
    protected function getElementByTextXpath($xpathTemplate, $text, $specificNodeType = null, $parentElementSelector = null)
560
    {
561
562
        if ($parentElementSelector !== null) {
563
            $xpathTemplate = $parentElementSelector . $xpathTemplate;
564
        }
565
        if ($specificNodeType !== null) {
566
            return $this->byXpath(sprintf($xpathTemplate, $specificNodeType, $this->getTranslator()->translatePlaceholders($text)));
567
        }
568
569
        foreach ($this->textElementNodeSearch as $nodeName) {
570
            $xpath = sprintf($xpathTemplate, $nodeName, $this->getTranslator()->translatePlaceholders($text));
571
            if ($this->webdriver->elementExists($xpath, WebDriver::BY_XPATH)) {
572
                return $this->webdriver->byXpath($xpath);
573
            }
574
        }
575
        // This is here for consistency with the other by* methods
576
        WebDriverException::throwException(7, 'Could not find element with text: ' . $this->getTranslator()->translatePlaceholders($text), []);
577
    }
578
579
    /**
580
     * @param string $text
581
     * @param string $specificNodeType
582
     * @param string $parentElementSelector
583
     * @return \Facebook\WebDriver\Remote\RemoteWebElement
584
     */
585
    public function byText($text, $specificNodeType = null, $parentElementSelector = null)
586
    {
587
        $xpathTemplate = '//%s[concat(" ",normalize-space(.)," ") = " %s "]';
588
        return $this->getElementByTextXpath($xpathTemplate, $text, $specificNodeType, $parentElementSelector);
589
    }
590
591
592
    /**
593
     * @param string $text
594
     * @param string $specificNodeType
595
     * @param string $parentElementSelector
596
     * @return \Facebook\WebDriver\Remote\RemoteWebElement
597
     */
598
    public function byContainsText($text, $specificNodeType = null, $parentElementSelector = null)
599
    {
600
        $xpathTemplate = '//%s[contains(., "%s")]';
601
        return $this->getElementByTextXpath($xpathTemplate, $text, $specificNodeType, $parentElementSelector);
602
    }
603
604
    /**
605
     * @return \Magium\Util\Translator\Translator
606
     */
607
608
    public function getTranslator()
609
    {
610
        return $this->get('Magium\Util\Translator\Translator');
611
    }
612
613
    public function addTranslationCsvFile($file, $locale)
614
    {
615
        $this->getTranslator()->addTranslationCsvFile($file, $locale);
616
    }
617
}
618