3 namespace Pelago\Tests\Unit\Emogrifier\HtmlProcessor;
5 use Pelago\Emogrifier\HtmlProcessor\AbstractHtmlProcessor;
6 use Pelago\Tests\Unit\Emogrifier\HtmlProcessor\Fixtures\TestingHtmlProcessor;
11 * @author Oliver Klee <github@oliverklee.de>
13 class AbstractHtmlProcessorTest extends \PHPUnit_Framework_TestCase
18 public function fixtureIsAbstractHtmlProcessor()
20 static::assertInstanceOf(AbstractHtmlProcessor::class, new TestingHtmlProcessor('<html></html>'));
26 public function reformatsHtml()
28 $rawHtml = '<!DOCTYPE HTML>' .
30 '<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head>' .
33 $formattedHtml = "<!DOCTYPE HTML>\n" .
35 '<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head>' . "\n" .
39 $subject = new TestingHtmlProcessor($rawHtml);
41 static::assertSame($formattedHtml, $subject->render());
47 public function nonHtmlDataProvider()
50 'empty string' => [''],
54 'object' => [new \stdClass()],
60 * @expectedException \InvalidArgumentException
64 * @dataProvider nonHtmlDataProvider
66 public function constructorWithNoHtmlDataThrowsException($html)
68 new TestingHtmlProcessor($html);
74 public function invalidHtmlDataProvider()
77 'broken nesting gets nested' => ['<b><i></b></i>', '<b><i></i></b>'],
78 'partial opening tag gets closed' => ['<b', '<b></b>'],
79 'only opening tag gets closed' => ['<b>', '<b></b>'],
80 'only closing tag gets removed' => ['foo</b> bar', 'foo bar'],
87 * @param string $input
88 * @param string $expectedHtml
90 * @dataProvider invalidHtmlDataProvider
92 public function renderRepairsBrokenHtml($input, $expectedHtml)
94 $subject = new TestingHtmlProcessor($input);
95 $result = $subject->render();
97 static::assertContains($expectedHtml, $result);
103 public function contentWithoutHtmlTagDataProvider()
106 'doctype only' => ['<!DOCTYPE html>'],
107 'body content only' => ['<p>Hello</p>'],
108 'HEAD element' => ['<head></head>'],
109 'BODY element' => ['<body></body>'],
110 'HEAD AND BODY element' => ['<head></head><body></body>'],
117 * @param string $html
119 * @dataProvider contentWithoutHtmlTagDataProvider
121 public function addsMissingHtmlTag($html)
123 $subject = new TestingHtmlProcessor($html);
125 $result = $subject->render();
127 static::assertContains('<html>', $result);
133 public function contentWithoutHeadTagDataProvider()
136 'doctype only' => ['<!DOCTYPE html>'],
137 'body content only' => ['<p>Hello</p>'],
138 'BODY element' => ['<body></body>'],
145 * @param string $html
147 * @dataProvider contentWithoutHeadTagDataProvider
149 public function addsMissingHeadTag($html)
151 $subject = new TestingHtmlProcessor($html);
153 $result = $subject->render();
155 static::assertContains('<head>', $result);
161 public function contentWithoutBodyTagDataProvider()
164 'doctype only' => ['<!DOCTYPE html>'],
165 'HEAD element' => ['<head></head>'],
166 'body content only' => ['<p>Hello</p>'],
173 * @param string $html
175 * @dataProvider contentWithoutBodyTagDataProvider
177 public function addsMissingBodyTag($html)
179 $subject = new TestingHtmlProcessor($html);
181 $result = $subject->render();
183 static::assertContains('<body>', $result);
189 public function putsMissingBodyElementAroundBodyContent()
191 $subject = new TestingHtmlProcessor('<p>Hello</p>');
193 $result = $subject->render();
195 static::assertContains('<body><p>Hello</p></body>', $result);
201 public function specialCharactersDataProvider()
204 'template markers with dollar signs & square brackets' => ['$[USER:NAME]$'],
205 'UTF-8 umlauts' => ['Küss die Hand, schöne Frau.'],
206 'HTML entities' => ['a & b > c'],
213 * @param string $codeNotToBeChanged
215 * @dataProvider specialCharactersDataProvider
217 public function keepsSpecialCharacters($codeNotToBeChanged)
219 $html = '<html><p>' . $codeNotToBeChanged . '</p></html>';
220 $subject = new TestingHtmlProcessor($html);
222 $result = $subject->render();
224 static::assertContains($codeNotToBeChanged, $result);
230 public function addsMissingHtml5DocumentType()
232 $subject = new TestingHtmlProcessor('<html></html>');
234 $result = $subject->render();
236 static::assertContains('<!DOCTYPE html>', $result);
242 public function documentTypeDataProvider()
245 'HTML5' => ['<!DOCTYPE html>'],
246 'XHTML 1.0 strict' => [
247 '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ' .
248 '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
250 'XHTML 1.0 transitional' => [
251 '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ' .
252 '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
254 'HTML 4 transitional' => [
255 '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" ' .
256 '"http://www.w3.org/TR/REC-html40/loose.dtd">',
264 * @param string $documentType
266 * @dataProvider documentTypeDataProvider
268 public function keepsExistingDocumentType($documentType)
270 $html = $documentType . '<html></html>';
271 $subject = new TestingHtmlProcessor($html);
273 $result = $subject->render();
275 static::assertContains($documentType, $result);
281 public function addsMissingContentTypeMetaTag()
283 $subject = new TestingHtmlProcessor('<p>Hello</p>');
285 $result = $subject->render();
287 static::assertContains('<meta http-equiv="Content-Type" content="text/html; charset=utf-8">', $result);
293 public function notAddsSecondContentTypeMetaTag()
295 $html = '<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head>';
296 $subject = new TestingHtmlProcessor($html);
298 $result = $subject->render();
300 $numberOfContentTypeMetaTags = \substr_count($result, 'Content-Type');
301 static::assertSame(1, $numberOfContentTypeMetaTags);
307 * @param string $documentType
309 * @dataProvider documentTypeDataProvider
311 public function convertsXmlSelfClosingTagsToNonXmlSelfClosingTag($documentType)
313 $subject = new TestingHtmlProcessor($documentType . '<html><body><br/></body></html>');
315 $result = $subject->render();
317 static::assertContains('<body><br></body>', $result);
323 * @param string $documentType
325 * @dataProvider documentTypeDataProvider
327 public function keepsNonXmlSelfClosingTags($documentType)
329 $subject = new TestingHtmlProcessor($documentType . '<html><body><br></body></html>');
331 $result = $subject->render();
333 static::assertContains('<body><br></body>', $result);
339 public function renderBodyContentForEmptyBodyReturnsEmptyString()
341 $subject = new TestingHtmlProcessor('<html><body></body></html>');
343 $result = $subject->renderBodyContent();
345 static::assertSame('', $result);
351 public function renderBodyContentReturnsBodyContent()
353 $bodyContent = '<p>Hello world</p>';
354 $subject = new TestingHtmlProcessor('<html><body>' . $bodyContent . '</body></html>');
356 $result = $subject->renderBodyContent();
358 static::assertSame($bodyContent, $result);
364 public function getDomDocumentReturnsDomDocument()
366 $subject = new TestingHtmlProcessor('<html></html>');
368 static::assertInstanceOf(\DOMDocument::class, $subject->getDomDocument());
374 public function getDomDocumentWithNormalizedHtmlRepresentsTheGivenHtml()
376 $html = "<!DOCTYPE html>\n<html>\n<head>" .
377 '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">' .
378 "</head>\n<body>\n<br>\n</body>\n</html>\n";
379 $subject = new TestingHtmlProcessor($html);
381 $domDocument = $subject->getDomDocument();
383 self::assertSame($html, $domDocument->saveHTML());