Completed
Push — master ( 0f91be...305d74 )
by Kevin
02:48
created

AbstractTestCase::assertNotTitleEquals()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

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