Completed
Pull Request — master (#100)
by Michał
01:25
created

BrowserTestCase::onNotSuccessfulTest()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1.0046

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 5
cts 6
cp 0.8333
rs 9.6666
c 0
b 0
f 0
cc 1
eloc 5
nc 1
nop 1
crap 1.0046
1
<?php
2
/**
3
 * This file is part of the phpunit-mink library.
4
 * For the full copyright and license information, please view
5
 * the LICENSE file that was distributed with this source code.
6
 *
7
 * @copyright Alexander Obuhovich <[email protected]>
8
 * @link      https://github.com/aik099/phpunit-mink
9
 */
10
11
namespace aik099\PHPUnit;
12
13
14
use aik099\PHPUnit\BrowserConfiguration\BrowserConfiguration;
15
use aik099\PHPUnit\BrowserConfiguration\IBrowserConfigurationFactory;
16
use aik099\PHPUnit\RemoteCoverage\RemoteCoverageHelper;
17
use aik099\PHPUnit\RemoteCoverage\RemoteCoverageTool;
18
use aik099\PHPUnit\Event\TestEndedEvent;
19
use aik099\PHPUnit\Event\TestEvent;
20
use aik099\PHPUnit\Event\TestFailedEvent;
21
use aik099\PHPUnit\Session\ISessionStrategy;
22
use aik099\PHPUnit\Session\SessionStrategyManager;
23
use aik099\PHPUnit\TestSuite\RegularTestSuite;
24
use Behat\Mink\Exception\DriverException;
25
use Behat\Mink\Session;
26
use PHPUnit\Framework\TestCase;
27
use PHPUnit\Framework\TestResult;
28
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
29
30
/**
31
 * Test Case class for writing browser-based tests.
32
 *
33
 * @method \Mockery\Expectation shouldReceive(string $name)
34
 */
35
abstract class BrowserTestCase extends TestCase implements IEventDispatcherAware
36
{
37
38
	const TEST_ENDED_EVENT = 'test.ended';
39
40
	const TEST_SUITE_ENDED_EVENT = 'test_suite.ended';
41
42
	const TEST_FAILED_EVENT = 'test.failed';
43
44
	const TEST_SETUP_EVENT = 'test.setup';
45
46
	/**
47
	 * Browser list to be used in tests.
48
	 *
49
	 * @var array
50
	 */
51
	public static $browsers = array();
52
53
	/**
54
	 * Event dispatcher.
55
	 *
56
	 * @var EventDispatcherInterface
57
	 */
58
	private $_eventDispatcher;
59
60
	/**
61
	 * Browser configuration factory.
62
	 *
63
	 * @var IBrowserConfigurationFactory
64
	 */
65
	private $_browserConfigurationFactory;
66
67
	/**
68
	 * Remote coverage collection url.
69
	 *
70
	 * @var string Override to provide code coverage data from the server
71
	 */
72
	private $_remoteCoverageScriptUrl;
73
74
	/**
75
	 * Current browser configuration.
76
	 *
77
	 * @var BrowserConfiguration
78
	 */
79
	private $_browser;
80
81
	/**
82
	 * Reference to Mink session.
83
	 *
84
	 * @var Session
85
	 */
86
	private $_session;
87
88
	/**
89
	 * Session strategy manager.
90
	 *
91
	 * @var SessionStrategyManager
92
	 */
93
	protected $sessionStrategyManager;
94
95
	/**
96
	 * Remote coverage helper.
97
	 *
98
	 * @var RemoteCoverageHelper
99
	 */
100
	protected $remoteCoverageHelper;
101
102
	/**
103
	 * Session strategy, used currently.
104
	 *
105
	 * @var ISessionStrategy
106
	 */
107
	protected $sessionStrategy;
108
109
	/**
110
	 * Test ID.
111
	 *
112
	 * @var string
113
	 */
114
	private $_testId;
115
116
	/**
117
	 * Sets application.
118
	 *
119
	 * @param IBrowserConfigurationFactory $browser_configuration_factory Browser configuration factory.
120
	 *
121
	 * @return void
122
	 */
123 15
	public function setBrowserConfigurationFactory(IBrowserConfigurationFactory $browser_configuration_factory)
124
	{
125 15
		$this->_browserConfigurationFactory = $browser_configuration_factory;
126 15
	}
127
128
	/**
129
	 * Sets event dispatcher.
130
	 *
131
	 * @param EventDispatcherInterface $event_dispatcher Event dispatcher.
132
	 *
133
	 * @return void
134
	 */
135 16
	public function setEventDispatcher(EventDispatcherInterface $event_dispatcher)
136
	{
137 16
		$this->_eventDispatcher = $event_dispatcher;
138 16
	}
139
140
	/**
141
	 * Sets session strategy manager.
142
	 *
143
	 * @param SessionStrategyManager $session_strategy_manager Session strategy manager.
144
	 *
145
	 * @return self
146
	 */
147 17
	public function setSessionStrategyManager(SessionStrategyManager $session_strategy_manager)
148
	{
149 17
		$this->sessionStrategyManager = $session_strategy_manager;
150
151 17
		return $this;
152
	}
153
154
	/**
155
	 * Sets remote coverage helper.
156
	 *
157
	 * @param RemoteCoverageHelper $remote_coverage_helper Remote coverage helper.
158
	 *
159
	 * @return void
160
	 */
161 5
	public function setRemoteCoverageHelper(RemoteCoverageHelper $remote_coverage_helper)
162
	{
163 5
		$this->remoteCoverageHelper = $remote_coverage_helper;
164 5
	}
165
166
	/**
167
	 * Sets base url for remote coverage information collection.
168
	 *
169
	 * @param string $url URL.
170
	 *
171
	 * @return void
172
	 */
173 1
	public function setRemoteCoverageScriptUrl($url)
174
	{
175 1
		$this->_remoteCoverageScriptUrl = $url;
176 1
	}
177
178
	/**
179
	 * Set session meta-info for "Sauce Labs".
180
	 *
181
	 * @return void
182
	 */
183 6
	protected function setUp()
184
	{
185 6
		parent::setUp();
186
187 6
		$this->_eventDispatcher->dispatch(
188 6
			self::TEST_SETUP_EVENT,
189 6
			new TestEvent($this)
190
		);
191 6
	}
192
193
	/**
194
	 * Sets browser configuration.
195
	 *
196
	 * @param BrowserConfiguration $browser Browser configuration.
197
	 *
198
	 * @return self
199
	 */
200 11
	public function setBrowser(BrowserConfiguration $browser)
201
	{
202 11
		$this->_browser = $browser->attachToTestCase($this);
203
204
		// Configure session strategy.
205 11
		return $this->setSessionStrategy($this->sessionStrategyManager->getSessionStrategy($browser));
206
	}
207
208
	/**
209
	 * Returns browser configuration.
210
	 *
211
	 * @return BrowserConfiguration
212
	 * @throws \RuntimeException When browser configuration isn't defined.
213
	 */
214 9
	public function getBrowser()
215
	{
216 9
		if ( !is_object($this->_browser) ) {
217 1
			throw new \RuntimeException('Browser configuration not defined');
218
		}
219
220 8
		return $this->_browser;
221
	}
222
223
	/**
224
	 * Initializes a browser with given configuration.
225
	 *
226
	 * @param array $browser_config Browser configuration.
227
	 *
228
	 * @return self
229
	 */
230 4
	public function setBrowserFromConfiguration(array $browser_config)
231
	{
232 4
		return $this->setBrowser($this->createBrowserConfiguration($browser_config));
233
	}
234
235
	/**
236
	 * Returns browser configuration instance.
237
	 *
238
	 * @param array $browser_config Browser.
239
	 *
240
	 * @return BrowserConfiguration
241
	 */
242 4
	protected function createBrowserConfiguration(array $browser_config)
243
	{
244 4
		return $this->_browserConfigurationFactory->createBrowserConfiguration($browser_config, $this);
245
	}
246
247
	/**
248
	 * Sets session strategy.
249
	 *
250
	 * @param ISessionStrategy $session_strategy Session strategy.
251
	 *
252
	 * @return self
253
	 */
254 14
	public function setSessionStrategy(ISessionStrategy $session_strategy = null)
255
	{
256 14
		$this->sessionStrategy = $session_strategy;
257
258 14
		return $this;
259
	}
260
261
	/**
262
	 * Returns session strategy used currently.
263
	 *
264
	 * @return ISessionStrategy
265
	 * @see    setSessionStrategy()
266
	 */
267 10
	public function getSessionStrategy()
268
	{
269 10
		if ( $this->sessionStrategy ) {
270 9
			return $this->sessionStrategy;
271
		}
272
273
		// Default session strategy (not session itself) shared across all test cases.
274 1
		return $this->sessionStrategyManager->getDefaultSessionStrategy();
275
	}
276
277
	/**
278
	 * Creates Mink session using current session strategy and returns it.
279
	 *
280
	 * @return Session
281
	 */
282 4
	public function getSession()
283
	{
284 4
		if ( $this->_session ) {
285 1
			return $this->_session;
286
		}
287
288 4
		$browser = $this->getBrowser();
289
290
		try {
291 4
			$this->_session = $this->getSessionStrategy()->session($browser);
292
293 3
			if ( $this->getCollectCodeCoverageInformation() ) {
294 3
				$this->_session->visit($browser->getBaseUrl());
295
			}
296
		}
297 1
		catch ( DriverException $e ) {
298 1
			$message = 'The Selenium Server is not active on host %s at port %s';
299 1
			$this->markTestSkipped(sprintf($message, $browser->getHost(), $browser->getPort()));
300
		}
301
302 3
		return $this->_session;
303
	}
304
305
	/**
306
	 * Runs the test case and collects the results in a TestResult object.
307
	 *
308
	 * If no TestResult object is passed a new one will be created.
309
	 *
310
	 * @param TestResult $result Test result.
311
	 *
312
	 * @return TestResult
313
	 */
314 6
	public function run(TestResult $result = null)
315
	{
316 6
		if ( $result === null ) {
317 1
			$result = $this->createResult();
318
		}
319
320 6
		parent::run($result);
321
322 6
		if ( $result->getCollectCodeCoverageInformation() ) {
323 2
			$result->getCodeCoverage()->append($this->getRemoteCodeCoverageInformation(), $this);
324
		}
325
326
		/*$this->setTestResultObject($result);*/
327
328
		// Do not call this before to give the time to the Listeners to run.
329 6
		$this->_eventDispatcher->dispatch(
330 6
			self::TEST_ENDED_EVENT,
331 6
			new TestEndedEvent($this, $result, $this->_session)
332
		);
333
334
		/*$this->setTestResultObject(null);*/
335
336 6
		return $result;
337
	}
338
339
	/**
340
	 * Whatever or not code coverage information should be gathered.
341
	 *
342
	 * @return boolean
343
	 * @throws \RuntimeException When used before test is started.
344
	 */
345 7
	public function getCollectCodeCoverageInformation()
346
	{
347 7
		$result = $this->getTestResultObject();
348
349 7
		if ( !is_object($result) ) {
350
			throw new \RuntimeException('Test must be started before attempting to collect coverage information');
351
		}
352
353 7
		return $result->getCollectCodeCoverageInformation();
354
	}
355
356
	/**
357
	 * Override to tell remote website, that code coverage information needs to be collected.
358
	 *
359
	 * @return mixed
360
	 */
361 6
	protected function runTest()
362
	{
363 6
		if ( $this->getCollectCodeCoverageInformation() ) {
364 2
			$this->_testId = get_class($this) . '__' . $this->getName();
365
366 2
			$session = $this->getSession();
367 2
			$session->setCookie(RemoteCoverageTool::TEST_ID_VARIABLE, null);
368 2
			$session->setCookie(RemoteCoverageTool::TEST_ID_VARIABLE, $this->_testId);
369
		}
370
371 6
		return parent::runTest();
372
	}
373
374
	/**
375
	 * Called, when last test in a test case has ended.
376
	 *
377
	 * @return self
378
	 */
379 3
	public function onTestSuiteEnded()
380
	{
381 3
		$this->_eventDispatcher->dispatch(
382 3
			self::TEST_SUITE_ENDED_EVENT,
383 3
			new TestEvent($this, $this->_session)
384
		);
385
386 3
		return $this;
387
	}
388
389
	/**
390
	 * Returns remote code coverage information, when enabled.
391
	 *
392
	 * @return array
393
	 */
394 2
	public function getRemoteCodeCoverageInformation()
395
	{
396 2
		if ( $this->_remoteCoverageScriptUrl ) {
397 1
			return $this->remoteCoverageHelper->get($this->_remoteCoverageScriptUrl, $this->_testId);
398
		}
399
400 1
		return array();
401
	}
402
403
	/**
404
	 * Creates test suite for usage with Mink.
405
	 *
406
	 * @param string $class_name Test case class name.
407
	 *
408
	 * @return RegularTestSuite
409
	 */
410 4
	public static function suite($class_name)
411
	{
412 4
		$application = Application::getInstance();
413
414 4
		return $application->getTestSuiteFactory()->createSuiteFromTestCase($class_name);
415
	}
416
417
	/**
418
	 * This method is called when a test method did not execute successfully.
419
	 *
420
	 * @param \Throwable $e Exception.
421
	 *
422
	 * @return void
423
	 */
424 2
	protected function onNotSuccessfulTest(\Throwable $e)
425
	{
426 2
		$this->_eventDispatcher->dispatch(
427 2
			self::TEST_FAILED_EVENT,
428 2
			new TestFailedEvent($e, $this, $this->_session)
429
		);
430
431 2
		parent::onNotSuccessfulTest($e);
432
	}
433
434
	/**
435
	 * Get test id (generated internally).
436
	 *
437
	 * @return string
438
	 */
439 2
	public function getTestId()
440
	{
441 2
		return $this->_testId;
442
	}
443
444
	/**
445
	 * Gets browser configuration aliases.
446
	 *
447
	 * Allows to decouple actual test server connection details from test cases.
448
	 *
449
	 * @return array
450
	 */
451 2
	public function getBrowserAliases()
452
	{
453 2
		return array();
454
	}
455
456
}
457