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