Completed
Pull Request — master (#7)
by Haralan
03:02
created

Saveonfailure::save_driver_content()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 26
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 3.0032

Importance

Changes 0
Metric Value
dl 0
loc 26
ccs 13
cts 14
cp 0.9286
rs 8.8571
c 0
b 0
f 0
cc 3
eloc 14
nc 4
nop 3
crap 3.0032
1
<?php
2
3
namespace Openbuildings\PHPUnitSpiderling;
4
5
6
/**
7
 * Phpunit_Saveonfailure definition
8
 *
9
 * @package    Openbuildings\PHPUnitSpiderling
10
 * @author     Ivan Kerin
11
 * @copyright  (c) 2013 OpenBuildings Ltd.
12
 * @license    http://spdx.org/licenses/BSD-3-Clause
13
 */
14
class Saveonfailure implements \PHPUnit\Framework\TestListener {
15
16
	/**
17
	 * Convert an attribute strigng from a relative to absolute, by providing a base_url
18
	 * @param  string $attribute name of the attribute, e.g. src, href
19
	 * @param  string $content   the string where to do the change
20
	 * @param  string $base_url
21
	 * @return string
22
	 */
23 8
	public static function to_absolute_attribute($attribute, $content, $base_url = NULL)
24
	{
25 8
		return preg_replace('/('.$attribute.'=[\'"])\//', '$1'.rtrim($base_url, '/').'/', $content);
26
	}
27
28
	/**
29
	 * Check if a directory does not exist, create it, otherwise check if it is writable
30
	 * @param  string $directory
31
	 * @throws Exception If directory is not writable
32
	 */
33 2
	public static function autocreate_directory($directory)
34
	{
35 2
		if ( ! file_exists($directory))
36
		{
37 2
			mkdir($directory, 0777, TRUE);
38
		}
39
40 2
		if ( ! is_writable($directory))
41
			throw new \Exception("Directory \"{$directory}\" is not writable");
42 2
	}
43
44
	/**
45
	 * Delete all the files from a directory
46
	 * @param  string $directory
47
	 */
48 2
	public static function clear_directory($directory)
49
	{
50 2
		foreach (scandir($directory) as $file)
51
		{
52 2
			if ($file !== '.' AND $file !== '..')
53
			{
54 1
				unlink($directory.$file);
55
			}
56
		}
57 2
	}
58
59
	/**
60
	 * Execute a php script and get the output of that script as a string, optionally pass variables as an associative array to be converted to local variables inside of the file
61
	 * @param  string $filename
62
	 * @param  array  $data
63
	 * @return string
64
	 */
65 1
	public static function render_file($filename, array $data = array())
66
	{
67 1
		extract($data, EXTR_SKIP);
68
69 1
		ob_start();
70 1
		include $filename;
71 1
		return ob_get_clean();
72
	}
73
74
	protected $_directory;
75
	protected $_base_url;
76
77 1
	function __construct($directory, $base_url)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
78
	{
79 1
		if ( ! $directory)
80
			throw new Exception('You must set a directory to output errors to');
81
82 1
		$this->_directory = rtrim($directory, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR;
83 1
		$this->_base_url = $base_url;
84
85 1
		self::autocreate_directory($directory);
86 1
		self::clear_directory($directory);
87 1
	}
88
89
	/**
90
	 * Save the current content of the driver into an html file. Add javascript errors, messages and a title to the html content
91
	 * @param  \Openbuildings\Spiderling\Driver $driver
92
	 * @param  string                           $filename
93
	 * @param  string                           $title
94
	 */
95 1
	public function save_driver_content(\Openbuildings\Spiderling\Driver $driver, $filename, $title)
96
	{
97 1
		$content = $driver->content();
98
99 1
		foreach (array('href', 'action', 'src') as $attribute)
100
		{
101 1
			$content = self::to_absolute_attribute($attribute, $content, $this->_base_url);
102
		}
103
104 1
		$testview = self::render_file(__DIR__.DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'error-page.php', array(
105 1
			'url' => $driver->current_url(),
106 1
			'title' => $title,
107 1
			'javascript_errors' => $driver->javascript_errors(),
108 1
			'javascript_messages' => $driver->javascript_messages(),
109
		));
110
111 1
		$page_content = str_replace('</body>', $testview.'</body>', $content);
112
113 1
		file_put_contents($this->_directory."/$filename.html", $page_content);
114
115
		try
116
		{
117 1
			$driver->screenshot($this->_directory."/$filename.png");
118
		}
119
		catch (\Openbuildings\Spiderling\Exception_Notimplemented $e){}
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
120 1
	}
121
122
	/**
123
	 * Implement PHPUnit\Framework\TestListener, save driver content if there was an error
124
	 * @param \PHPUnit\Framework\Test $test
125
	 * @param \Exception              $exception
126
	 * @param integer                  $time
127
	 */
128 1
	public function addError(\PHPUnit\Framework\Test $test, \Exception $exception, $time)
129
	{
130 1
		if ($test instanceof Testcase_Spiderling AND $test->is_driver_active() AND $test->driver()->is_page_active())
131
		{
132 1
			$this->save_driver_content(
133 1
				$test->driver(),
134 1
				get_class($test).'_'.$test->getName(FALSE),
135 1
				$exception->getMessage()
136
			);
137
		}
138 1
	}
139
140
	/**
141
	 * Implement PHPUnit\Framework\TestListener, save driver content if there was an error
142
	 * @param \PHPUnit\Framework\Test                 $test
143
	 * @param \PHPUnit\Framework\AssertionFailedError $failure
144
	 * @param integer                                 $time
145
	 */
146 1
	public function addFailure(\PHPUnit\Framework\Test $test, \PHPUnit\Framework\AssertionFailedError $failure, $time)
147
	{
148 1
		if ($test instanceof Testcase_Spiderling AND $test->is_driver_active() AND $test->driver()->is_page_active())
149
		{
150
151 1
			$this->save_driver_content(
152 1
				$test->driver(),
153 1
				get_class($test).'_'.$test->getName(FALSE),
154 1
				$failure->getMessage()
155
			);
156
		}
157 1
	}
158
159
	// @codeCoverageIgnoreStart
160
	public function addWarning(\PHPUnit\Framework\Test $test, \PHPUnit\Framework\Warning $e, $time) {}
161
	public function addRiskyTest(\PHPUnit\Framework\Test $test, \Exception $e, $time) {}
162
	public function addIncompleteTest(\PHPUnit\Framework\Test $test, \Exception $e, $time) {}
163
	public function addSkippedTest(\PHPUnit\Framework\Test $test, \Exception $e, $time) {}
164
	public function startTest(\PHPUnit\Framework\Test $test) {}
165
	public function endTest(\PHPUnit\Framework\Test $test, $time) {}
166
	public function startTestSuite(\PHPUnit\Framework\TestSuite $suite) {}
167
	public function endTestSuite(\PHPUnit\Framework\TestSuite $suite) {}
168
	// @codeCoverageIgnoreEnd
169
}
170