├── .phpstan-sources.neon
├── .gitignore
├── .phpstan-tests.neon
├── phpunit.xml
├── sources
├── Lib
│ ├── Base
│ │ ├── ComponentInterface.php
│ │ └── Component.php
│ └── MarkupValidator
│ │ ├── MarkupProviderInterface.php
│ │ ├── MarkupValidatorInterface.php
│ │ ├── MessagePrinterInterface.php
│ │ ├── MessageFilterInterface.php
│ │ ├── MarkupValidatorMessageInterface.php
│ │ ├── DefaultMessagePrinter.php
│ │ ├── DefaultMarkupProvider.php
│ │ ├── W3CMarkupValidatorMessage.php
│ │ ├── W3CMarkupValidator.php
│ │ ├── DefaultMessageFilter.php
│ │ └── MarkupValidatorMessage.php
└── Module
│ └── MarkupValidator.php
├── .php-cs-fixer.dist.php
├── tests
├── Base
│ └── TestCase.php
├── Lib
│ ├── Base
│ │ └── ComponentTest.php
│ └── MarkupValidator
│ │ ├── DefaultMarkupProviderTest.php
│ │ ├── W3CMarkupValidatorTest.php
│ │ ├── MarkupValidatorMessageTest.php
│ │ ├── W3CMarkupValidatorMessageTest.php
│ │ ├── DefaultMessagePrinterTest.php
│ │ └── DefaultMessageFilterTest.php
└── Module
│ └── MarkupValidatorTest.php
├── composer.json
├── .github
└── workflows
│ └── build.yml
├── README.md
└── LICENSE.txt
/.phpstan-sources.neon:
--------------------------------------------------------------------------------
1 | parameters:
2 | level: 5
3 | paths:
4 | - "sources"
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.php-cs-fixer.cache
2 | /.phpunit.cache
3 | /build/
4 | /composer.lock
5 | /vendor/
6 |
--------------------------------------------------------------------------------
/.phpstan-tests.neon:
--------------------------------------------------------------------------------
1 | parameters:
2 | level: 1
3 | paths:
4 | - "tests"
5 | ignoreErrors:
6 | - '#Call to an undefined method Kolyunya\\Codeception\\Tests\\Lib\\MarkupValidator\\DefaultMessageFilterTest::assertArraySubset#'
7 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 | tests
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/sources/Lib/Base/ComponentInterface.php:
--------------------------------------------------------------------------------
1 | in(sprintf('%s/sources', __DIR__))
8 | ->in(sprintf('%s/tests', __DIR__))
9 | ->name('*.php')
10 | ->files()
11 | ;
12 |
13 | $config = (new Config())
14 | ->setRules(array(
15 | '@PSR1' => true,
16 | '@PSR2' => true,
17 | 'array_syntax' => array(
18 | 'syntax' => 'long',
19 | ),
20 | 'no_trailing_whitespace' => true,
21 | 'ordered_imports' => array(
22 | 'imports_order' => null,
23 | ),
24 | 'single_blank_line_at_eof' => true,
25 | 'strict_param' => true,
26 | ))
27 | ->setRiskyAllowed(true)
28 | ->setFinder($finder)
29 | ;
30 |
31 | return $config;
32 |
--------------------------------------------------------------------------------
/sources/Lib/MarkupValidator/MarkupProviderInterface.php:
--------------------------------------------------------------------------------
1 | setConfiguration($configuration);
34 | }
35 |
36 | /**
37 | * {@inheritDoc}
38 | */
39 | public function setConfiguration(array $configuration)
40 | {
41 | $this->configuration = array_merge($this->configuration, $configuration);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/tests/Base/TestCase.php:
--------------------------------------------------------------------------------
1 | customSetExpectedException($arguments);
18 | break;
19 | }
20 | }
21 |
22 | private function customSetExpectedException($arguments)
23 | {
24 | $exceptionClass = $arguments[0];
25 | $this->expectException($exceptionClass);
26 |
27 | $exceptionMessage = $arguments[1];
28 | $this->expectExceptionMessage($exceptionMessage);
29 |
30 | if (isset($arguments[2]) === true) {
31 | $exceptionCode = $arguments[2];
32 | $this->expectExceptionCode($exceptionCode);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "kolyunya/codeception-markup-validator",
3 | "description": "Markup validator module for Codeception.",
4 | "type": "library",
5 | "license": "LGPL-3.0-or-later",
6 | "minimum-stability": "stable",
7 | "homepage": "https://github.com/Kolyunya/codeception-markup-validator",
8 | "keywords": [
9 | "acceptance-testing",
10 | "codeception",
11 | "codeception-module",
12 | "html-validator",
13 | "markup-validator",
14 | "w3c-validator"
15 | ],
16 | "authors": [
17 | {
18 | "name": "Kolyunya",
19 | "email": "oleynikovny@mail.ru",
20 | "homepage": "http://github.com/Kolyunya"
21 | }
22 | ],
23 | "require": {
24 | "php": ">=8.1 <9.0",
25 | "codeception/codeception": ">=2.0 <6.0",
26 | "guzzlehttp/guzzle": "^7.0"
27 | },
28 | "require-dev": {
29 | "friendsofphp/php-cs-fixer": "^3.0",
30 | "phpstan/phpstan": "^1.9",
31 | "phpunit/phpunit": "^10.0"
32 | },
33 | "autoload": {
34 | "psr-4": {
35 | "Kolyunya\\Codeception\\": "sources"
36 | }
37 | },
38 | "autoload-dev": {
39 | "psr-4": {
40 | "Kolyunya\\Codeception\\Tests\\": "tests"
41 | }
42 | },
43 | "config": {
44 | "sort-packages": true
45 | },
46 | "scripts": {
47 | "validate-style": "PHP_CS_FIXER_IGNORE_ENV=TRUE vendor/bin/php-cs-fixer fix --dry-run",
48 | "analyze-sources": "vendor/bin/phpstan analyze --configuration=.phpstan-sources.neon",
49 | "analyze-tests": "vendor/bin/phpstan analyze --configuration=.phpstan-tests.neon",
50 | "run-test": "vendor/bin/phpunit"
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/sources/Lib/MarkupValidator/MarkupValidatorMessageInterface.php:
--------------------------------------------------------------------------------
1 |
34 | docker run --volume $PWD:/sources --workdir /sources --env PHP_CS_FIXER_IGNORE_ENV=TRUE php:${{ matrix.php-version }}
35 | vendor/bin/php-cs-fixer fix --dry-run
36 | -
37 | name: Analyze sources
38 | run: >
39 | docker run --volume $PWD:/sources --workdir /sources php:${{ matrix.php-version }}
40 | vendor/bin/phpstan analyze --configuration=.phpstan-sources.neon
41 | -
42 | name: Analyze tests
43 | run: >
44 | docker run --volume $PWD:/sources --workdir /sources php:${{ matrix.php-version }}
45 | vendor/bin/phpstan analyze --configuration=.phpstan-tests.neon
46 | -
47 | name: Run tests
48 | run: >
49 | docker run --volume $PWD:/sources --workdir /sources php:${{ matrix.php-version }}
50 | vendor/bin/phpunit
51 |
--------------------------------------------------------------------------------
/tests/Lib/Base/ComponentTest.php:
--------------------------------------------------------------------------------
1 | assertEquals($classNameActual, $classNameExpected);
34 | }
35 |
36 | public static function dataProviderGetClassName()
37 | {
38 | return array(
39 | array(
40 | 'Kolyunya\Codeception\Lib\Base\Component',
41 | Component::getClassName(),
42 | ),
43 | array(
44 | 'Kolyunya\Codeception\Lib\MarkupValidator\DefaultMarkupProvider',
45 | DefaultMarkupProvider::getClassName(),
46 | ),
47 | array(
48 | 'Kolyunya\Codeception\Lib\MarkupValidator\DefaultMessageFilter',
49 | DefaultMessageFilter::getClassName(),
50 | ),
51 | array(
52 | 'Kolyunya\Codeception\Lib\MarkupValidator\DefaultMessagePrinter',
53 | DefaultMessagePrinter::getClassName(),
54 | ),
55 | array(
56 | 'Kolyunya\Codeception\Lib\MarkupValidator\W3CMarkupValidator',
57 | W3CMarkupValidator::getClassName(),
58 | ),
59 | );
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/sources/Lib/MarkupValidator/DefaultMessagePrinter.php:
--------------------------------------------------------------------------------
1 | getMessageStringTemplate(), array(
25 | $message->getType(),
26 | $message->getSummary() ?: self::UNAVAILABLE_DATA_PLACEHOLDER,
27 | $message->getDetails() ?: self::UNAVAILABLE_DATA_PLACEHOLDER,
28 | $message->getFirstLineNumber() ?: self::UNAVAILABLE_DATA_PLACEHOLDER,
29 | $message->getLastLineNumber() ?: self::UNAVAILABLE_DATA_PLACEHOLDER,
30 | $message->getMarkup() ?: self::UNAVAILABLE_DATA_PLACEHOLDER,
31 | ));
32 | }
33 |
34 | /**
35 | * {@inheritDoc}
36 | */
37 | public function getMessagesString(array $messages)
38 | {
39 | $messagesStrings = array_map(array($this, 'getMessageString'), $messages);
40 | $messagesString = implode("\n", $messagesStrings);
41 |
42 | return $messagesString;
43 | }
44 |
45 | /**
46 | * Returns message string representation template.
47 | *
48 | * @return string Message string representation template.
49 | */
50 | protected function getMessageStringTemplate()
51 | {
52 | return
53 | <<moduleContainer = $moduleContainer;
31 | }
32 |
33 | /**
34 | * {@inheritDoc}
35 | */
36 | public function getMarkup()
37 | {
38 | try {
39 | return $this->getMarkupFromPhpBrowser();
40 | } catch (Exception $exception) {
41 | // Wasn't able to get markup from the `PhpBrowser` module.
42 | }
43 |
44 | try {
45 | return $this->getMarkupFromWebDriver();
46 | } catch (Exception $exception) {
47 | // Wasn't able to get markup from the `WebDriver` module.
48 | }
49 |
50 | throw new Exception('Unable to obtain current page markup.');
51 | }
52 |
53 | /**
54 | * Returns current page markup form the `PhpBrowser` module.
55 | *
56 | * @return string Current page markup.
57 | */
58 | private function getMarkupFromPhpBrowser()
59 | {
60 | /* @var $phpBrowser PhpBrowser */
61 | $phpBrowser = $this->getModule('PhpBrowser');
62 | $markup = $phpBrowser->_getResponseContent();
63 |
64 | return $markup;
65 | }
66 |
67 | /**
68 | * Returns current page markup form the `WebDriver` module.
69 | *
70 | * @return string Current page markup.
71 | */
72 | private function getMarkupFromWebDriver()
73 | {
74 | /* @var $webDriver WebDriver */
75 | $webDriver = $this->getModule('WebDriver');
76 | $markup = $webDriver->webDriver->getPageSource();
77 |
78 | return $markup;
79 | }
80 |
81 | /**
82 | * Returns a module instance by its name.
83 | *
84 | * @param string $name Module name.
85 | * @return object Module instance.
86 | */
87 | private function getModule($name)
88 | {
89 | if (!$this->moduleContainer->hasModule($name)) {
90 | throw new Exception(sprintf('«%s» module is not available.', $name));
91 | }
92 |
93 | $module = $this->moduleContainer->getModule($name);
94 |
95 | return $module;
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/sources/Lib/MarkupValidator/W3CMarkupValidatorMessage.php:
--------------------------------------------------------------------------------
1 | initializeType($data);
24 | $this->initializeSummary($data);
25 | $this->initializeFirstLineNumber($data);
26 | $this->initializeLastLineNumber($data);
27 | $this->initializeMarkup($data);
28 | }
29 |
30 | /**
31 | * Initializes message type.
32 | *
33 | * @param array $data Message data.
34 | */
35 | private function initializeType(array $data)
36 | {
37 | if (isset($data['type']) === false) {
38 | return;
39 | }
40 |
41 | if ($data['type'] === 'error') {
42 | $this->type = self::TYPE_ERROR;
43 | } elseif ($data['type'] === 'info') {
44 | if (isset($data['subType']) === true &&
45 | $data['subType'] === 'warning'
46 | ) {
47 | $this->type = self::TYPE_WARNING;
48 | } else {
49 | $this->type = self::TYPE_INFO;
50 | }
51 | }
52 | }
53 |
54 | /**
55 | * Initializes message summary.
56 | *
57 | * @param array $data Message data.
58 | */
59 | private function initializeSummary(array $data)
60 | {
61 | if (isset($data['message']) === true) {
62 | $this->setSummary($data['message']);
63 | }
64 | }
65 |
66 | /**
67 | * Initializes first line number.
68 | *
69 | * @param array $data Message data.
70 | */
71 | private function initializeFirstLineNumber(array $data)
72 | {
73 | if (isset($data['firstLine']) === true) {
74 | $this->setFirstLineNumber($data['firstLine']);
75 | }
76 | }
77 |
78 | /**
79 | * Initializes last line number.
80 | *
81 | * @param array $data Message data.
82 | */
83 | private function initializeLastLineNumber(array $data)
84 | {
85 | if (isset($data['lastLine']) === true) {
86 | $this->setLastLineNumber($data['lastLine']);
87 | }
88 | }
89 |
90 | /**
91 | * Initializes message markup.
92 | *
93 | * @param array $data Message data.
94 | */
95 | private function initializeMarkup(array $data)
96 | {
97 | if (isset($data['extract']) === true) {
98 | $this->setMarkup($data['extract']);
99 | }
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/sources/Lib/MarkupValidator/W3CMarkupValidator.php:
--------------------------------------------------------------------------------
1 | 'https://validator.w3.org/',
24 | self::ENDPOINT_CONFIG_KEY => '/nu/',
25 | );
26 |
27 | /**
28 | * HTTP client used to communicate with the W3C Markup Validation Service.
29 | *
30 | * @var Client
31 | */
32 | private $httpClient;
33 |
34 | /**
35 | * Parameters of a HTTP request to the W3C Markup Validation Service.
36 | *
37 | * @var array
38 | */
39 | private $httpRequestParameters;
40 |
41 | /**
42 | * {@inheritDoc}
43 | */
44 | public function __construct(array $configuration = array())
45 | {
46 | parent::__construct($configuration);
47 |
48 | $this->initializeHttpClient();
49 | $this->initializeHttpRequestParameters();
50 | }
51 |
52 | /**
53 | * {@inheritDoc}
54 | */
55 | public function validate($markup)
56 | {
57 | $validationData = $this->getValidationData($markup);
58 | $validationMessages = $this->getValidationMessages($validationData);
59 |
60 | return $validationMessages;
61 | }
62 |
63 | /**
64 | * Initializes HTTP client used to communicate with the W3C Markup Validation Service.
65 | */
66 | private function initializeHttpClient()
67 | {
68 | $this->httpClient = new Client(array(
69 | 'base_uri' => $this->configuration[self::BASE_URI_CONFIG_KEY],
70 | ));
71 | }
72 |
73 | /**
74 | * Initializes parameters of a HTTP request to the W3C Markup Validation Service.
75 | */
76 | private function initializeHttpRequestParameters()
77 | {
78 | $this->httpRequestParameters = array(
79 | 'headers' => array(
80 | 'Content-Type' => 'text/html; charset=UTF-8;',
81 | ),
82 | 'query' => array(
83 | 'out' => 'json',
84 | ),
85 | );
86 | }
87 |
88 | /**
89 | * Sends a validation request to a W3C Markup Validation Service
90 | * and returns decoded validation data.
91 | *
92 | * @param string $markup Markup to get validation data for.
93 | * @return array Validation data for provided markup.
94 | */
95 | private function getValidationData($markup)
96 | {
97 | $this->httpRequestParameters['body'] = $markup;
98 |
99 | $reponse = $this->httpClient->post(
100 | $this->configuration[self::ENDPOINT_CONFIG_KEY],
101 | $this->httpRequestParameters
102 | );
103 | $responseData = $reponse->getBody()->getContents();
104 | $validationData = json_decode($responseData, true);
105 | if ($validationData === null) {
106 | throw new Exception('Unable to parse W3C Markup Validation Service response.');
107 | }
108 |
109 | return $validationData;
110 | }
111 |
112 | /**
113 | * Parses validation data and returns validation messages.
114 | *
115 | * @param array $validationData Validation data.
116 | * @return MarkupValidatorMessageInterface[] Validation messages.
117 | */
118 | private function getValidationMessages(array $validationData)
119 | {
120 | $messages = array();
121 | $messagesData = $validationData['messages'];
122 | foreach ($messagesData as $messageData) {
123 | $message = new W3CMarkupValidatorMessage($messageData);
124 | $messages[] = $message;
125 | }
126 |
127 | return $messages;
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/tests/Lib/MarkupValidator/DefaultMarkupProviderTest.php:
--------------------------------------------------------------------------------
1 | moduleContainer = $this
28 | ->getMockBuilder('Codeception\Lib\ModuleContainer')
29 | ->disableOriginalConstructor()
30 | ->getMock()
31 | ;
32 |
33 | $this->provider = new DefaultMarkupProvider($this->moduleContainer);
34 | }
35 |
36 | /**
37 | * {@inheritDoc}
38 | */
39 | public function tearDown(): void
40 | {
41 | }
42 |
43 | public function testWithNoPhpBrowserNoWebDriver()
44 | {
45 | $this->setExpectedException('Exception', 'Unable to obtain current page markup.');
46 | $this->provider->getMarkup();
47 | }
48 |
49 | public function testWithPhpBrowser()
50 | {
51 | $expectedMarkup =
52 | <<
54 |
55 |
56 |
57 | A valid page.
58 |
59 |
60 |
61 | HTML
62 | ;
63 |
64 | $phpBrowser = $this
65 | ->getMockBuilder('Codeception\Module')
66 | ->disableOriginalConstructor()
67 | ->addMethods(array(
68 | '_getResponseContent',
69 | ))
70 | ->getMock()
71 | ;
72 | $phpBrowser
73 | ->method('_getResponseContent')
74 | ->will($this->returnValue($expectedMarkup))
75 | ;
76 |
77 | $this->moduleContainer
78 | ->method('hasModule')
79 | ->will($this->returnValueMap(array(
80 | array('PhpBrowser', true)
81 | )))
82 | ;
83 | $this->moduleContainer
84 | ->method('getModule')
85 | ->will($this->returnValueMap(array(
86 | array('PhpBrowser', $phpBrowser)
87 | )))
88 | ;
89 |
90 | $actualMarkup = $this->provider->getMarkup();
91 | $this->assertEquals($expectedMarkup, $actualMarkup);
92 | }
93 |
94 | public function testWithWebDriver()
95 | {
96 | $expectedMarkup =
97 | <<
99 |
100 |
101 |
102 | A valid page.
103 |
104 |
105 |
106 | HTML
107 | ;
108 |
109 | $remoteWebDriver = $this
110 | ->getMockBuilder('Codeception\Module')
111 | ->disableOriginalConstructor()
112 | ->addMethods(array(
113 | 'getPageSource',
114 | ))
115 | ->getMock()
116 | ;
117 | $remoteWebDriver
118 | ->method('getPageSource')
119 | ->will($this->returnValue($expectedMarkup))
120 | ;
121 |
122 | $webDriver = $this
123 | ->getMockBuilder('Codeception\Module')
124 | ->disableOriginalConstructor()
125 | ->getMock()
126 | ;
127 | $webDriver->webDriver = $remoteWebDriver;
128 |
129 | $this->moduleContainer
130 | ->method('hasModule')
131 | ->will($this->returnValueMap(array(
132 | array('PhpBrowser', false),
133 | array('WebDriver', true)
134 | )))
135 | ;
136 | $this->moduleContainer
137 | ->method('getModule')
138 | ->will($this->returnValueMap(array(
139 | array('WebDriver', $webDriver)
140 | )))
141 | ;
142 |
143 | $actualMarkup = $this->provider->getMarkup();
144 | $this->assertEquals($expectedMarkup, $actualMarkup);
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/sources/Lib/MarkupValidator/DefaultMessageFilter.php:
--------------------------------------------------------------------------------
1 | 0,
28 | self::IGNORE_WARNINGS_CONFIG_KEY => true,
29 | self::IGNORED_ERRORS_CONFIG_KEY => array(),
30 | );
31 |
32 | /**
33 | * {@inheritDoc}
34 | */
35 | public function filterMessages(array $messages)
36 | {
37 | $filteredMessages = array();
38 |
39 | foreach ($messages as $message) {
40 | /* @var $message MarkupValidatorMessageInterface */
41 | $messageType = $message->getType();
42 |
43 | if ($messageType === MarkupValidatorMessageInterface::TYPE_UNDEFINED ||
44 | $messageType === MarkupValidatorMessageInterface::TYPE_INFO
45 | ) {
46 | continue;
47 | }
48 |
49 | if ($messageType === MarkupValidatorMessageInterface::TYPE_WARNING &&
50 | $this->ignoreWarnings() === true
51 | ) {
52 | continue;
53 | }
54 |
55 | if ($this->ignoreError($message->getSummary()) === true) {
56 | continue;
57 | }
58 |
59 | $filteredMessages[] = $message;
60 | }
61 |
62 | if ($this->belowErrorCountThreshold($filteredMessages) === true) {
63 | // Error count threshold was not reached.
64 | return array();
65 | }
66 |
67 | return $filteredMessages;
68 | }
69 |
70 | /**
71 | * Returns a boolean indicating whether messages count
72 | * is below the threshold or not.
73 | *
74 | * @param array $messages Messages to report about.
75 | *
76 | * @return boolean Whether messages count is below the threshold or not.
77 | */
78 | private function belowErrorCountThreshold(array $messages)
79 | {
80 | if (is_int($this->configuration[self::ERROR_COUNT_THRESHOLD_KEY]) === false) {
81 | throw new Exception(sprintf('Invalid «%s» config key.', self::ERROR_COUNT_THRESHOLD_KEY));
82 | }
83 |
84 | $threshold = $this->configuration[self::ERROR_COUNT_THRESHOLD_KEY];
85 | $belowThreshold = count($messages) <= $threshold;
86 |
87 | return $belowThreshold;
88 | }
89 |
90 | /**
91 | * Returns a boolean indicating whether the filter ignores warnings or not.
92 | *
93 | * @return bool Whether the filter ignores warnings or not.
94 | */
95 | private function ignoreWarnings()
96 | {
97 | if (is_bool($this->configuration[self::IGNORE_WARNINGS_CONFIG_KEY]) === false) {
98 | throw new Exception(sprintf('Invalid «%s» config key.', self::IGNORE_WARNINGS_CONFIG_KEY));
99 | }
100 |
101 | /* @var $ignoreWarnings bool */
102 | $ignoreWarnings = $this->configuration[self::IGNORE_WARNINGS_CONFIG_KEY];
103 |
104 | return $ignoreWarnings;
105 | }
106 |
107 | /**
108 | * Returns a boolean indicating whether an error is ignored or not.
109 | *
110 | * @param string|null $summary Error summary.
111 | * @return boolean Whether an error is ignored or not.
112 | */
113 | private function ignoreError($summary)
114 | {
115 | if (is_array($this->configuration[self::IGNORED_ERRORS_CONFIG_KEY]) === false) {
116 | throw new Exception(sprintf('Invalid «%s» config key.', self::IGNORED_ERRORS_CONFIG_KEY));
117 | }
118 |
119 | $ignoreError = false;
120 |
121 | if ($summary === null) {
122 | return $ignoreError;
123 | }
124 |
125 | $ignoredErrors = $this->configuration[self::IGNORED_ERRORS_CONFIG_KEY];
126 | foreach ($ignoredErrors as $ignoredError) {
127 | $erorIsIgnored = preg_match($ignoredError, $summary) === 1;
128 | if ($erorIsIgnored) {
129 | $ignoreError = true;
130 | break;
131 | }
132 | }
133 |
134 | return $ignoreError;
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/tests/Lib/MarkupValidator/W3CMarkupValidatorTest.php:
--------------------------------------------------------------------------------
1 | validator = new W3CMarkupValidator();
22 | }
23 |
24 | /**
25 | * {@inheritDoc}
26 | */
27 | public function tearDown(): void
28 | {
29 | }
30 |
31 | /**
32 | * @dataProvider dataProviderValidateMarkup
33 | */
34 | public function testValidateMarkup($markup, $messagesData)
35 | {
36 | $messages = $this->validator->validate($markup);
37 |
38 | $this->assertEquals(count($messagesData), count($messages));
39 |
40 | foreach ($messagesData as $messageIndex => $messageData) {
41 | $message = $messages[$messageIndex];
42 |
43 | $this->assertEquals($message->getType(), $messageData['type']);
44 | $this->assertEquals($message->getSummary(), $messageData['summary']);
45 | $this->assertEquals($message->getDetails(), $messageData['details']);
46 | $this->assertEquals($message->getFirstLineNumber(), $messageData['firstLineNumber']);
47 | $this->assertEquals($message->getLastLineNumber(), $messageData['lastLineNumber']);
48 | $this->assertStringContainsString($messageData['markup'], $message->getMarkup());
49 | }
50 | }
51 |
52 | public function testInvalidValidationServiceResponse()
53 | {
54 | $this->setExpectedException('Exception', 'Unable to parse W3C Markup Validation Service response.');
55 |
56 | $this->validator->setConfiguration(array(
57 | 'baseUri' => 'https://validator.w3.org/',
58 | 'endpoint' => '/',
59 | ));
60 | $this->validator->validate('');
61 | }
62 |
63 | public static function dataProviderValidateMarkup()
64 | {
65 | return array(
66 | array(
67 | <<
69 |
70 |
71 |
72 | A valid page.
73 |
74 |
75 |
76 | HTML
77 | ,
78 | array(
79 | ),
80 | ),
81 | array(
82 | <<
84 |
85 |
86 |
87 |
88 | HTML
89 | ,
90 | array(
91 | array(
92 | 'type' => MarkupValidatorMessageInterface::TYPE_ERROR,
93 | 'summary' => 'Element “head” is missing a required instance of child element “title”.',
94 | 'details' => null,
95 | 'markup' => '',
96 | 'firstLineNumber' => null,
97 | 'lastLineNumber' => 4,
98 | ),
99 | ),
100 | ),
101 | array(
102 | <<
104 |
105 |
106 |
107 |
108 |
112 |
113 |
114 | HTML
115 | ,
116 | array(
117 | array(
118 | 'type' => MarkupValidatorMessageInterface::TYPE_ERROR,
119 | 'summary' => 'Element “head” is missing a required instance of child element “title”.',
120 | 'details' => null,
121 | 'markup' => '',
122 | 'firstLineNumber' => null,
123 | 'lastLineNumber' => 4,
124 | ),
125 | array(
126 | 'type' => MarkupValidatorMessageInterface::TYPE_WARNING,
127 | 'summary' => 'The “button” role is unnecessary for element “button”.',
128 | 'details' => null,
129 | 'markup' => '