Passed
Push — master ( afef6b...b42680 )
by Marc
03:21
created

assertHreflangCoherentXDefault()   B

Complexity

Conditions 8
Paths 18

Size

Total Lines 41
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 22
nc 18
nop 0
dl 0
loc 41
rs 8.4444
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace MOrtola\BehatSEOContexts\Context;
4
5
use Behat\Mink\Element\NodeElement;
6
use Exception;
7
use Matriphe\ISO639\ISO639;
8
use PHPUnit\Framework\Assert;
9
10
class LocalizationContext extends BaseContext
11
{
12
    /**
13
     * @throws Exception
14
     *
15
     * @Then the page hreflang markup should be valid
16
     */
17
    public function thePageHreflangMarkupShouldBeValid(): void
18
    {
19
        $this->assertHreflangExists();
20
        $this->assertHreflangValidSelfReference();
21
        $this->assertHreflangValidIsoCodes();
22
        $this->assertHreflangCoherentXDefault();
23
        $this->assertHreflangValidReciprocal();
24
    }
25
26
    private function assertHreflangExists(): void
27
    {
28
        Assert::assertNotEmpty(
29
            $this->getHreflangElements(),
30
            sprintf('No hreflang meta tags have been found in %s', $this->getCurrentUrl())
31
        );
32
    }
33
34
    /**
35
     * @return NodeElement[]
36
     */
37
    private function getHreflangElements(): array
38
    {
39
        return $this->getSession()->getPage()->findAll(
40
            'xpath',
41
            '//head/link[@rel="alternate" and @hreflang]'
42
        );
43
    }
44
45
    private function assertHreflangValidSelfReference(): void
46
    {
47
        $selfReferenceFound = false;
48
49
        foreach ($this->getHreflangElements() as $hreflangMetaTag) {
50
            $alternateLink = $hreflangMetaTag->getAttribute('href');
51
            if ($alternateLink === $this->getCurrentUrl()) {
52
                $selfReferenceFound = true;
53
            }
54
        }
55
56
        Assert::assertTrue(
57
            $selfReferenceFound,
58
            sprintf('No self-referencing hreflang meta tag has been found in %s', $this->getCurrentUrl())
59
        );
60
    }
61
62
    private function assertHreflangValidIsoCodes(): void
63
    {
64
        $localeIsoValidator = new ISO639();
65
        foreach ($this->getHreflangElements() as $hreflangMetaTag) {
66
            $alternateLocale = $hreflangMetaTag->getAttribute('hreflang');
67
68
            if ('x-default' === $alternateLocale) {
69
                continue;
70
            }
71
72
            Assert::assertNotEmpty(
73
                $alternateLocale,
74
                'hreflang locale should not be empty.'
75
            );
76
77
            Assert::assertNotEmpty(
78
                $localeIsoValidator->languageByCode1($alternateLocale),
79
                sprintf(
80
                    'Wrong locale ISO-639-1 code "%s" in hreflang meta tag in url %s: %s',
81
                    $alternateLocale,
82
                    $this->getCurrentUrl(),
83
                    $this->getOuterHtml($hreflangMetaTag)
84
                )
85
            );
86
        }
87
    }
88
89
    private function assertHreflangCoherentXDefault(): void
90
    {
91
        foreach ($this->getHreflangElements() as $hreflangMetaTag) {
92
            if ('x-default' === $hreflangMetaTag->getAttribute('hreflang')) {
93
                $xDefault = $hreflangMetaTag->getAttribute('href');
94
            }
95
        }
96
97
        if (!isset($xDefault)) {
98
            return;
99
        }
100
101
        foreach ($this->getHreflangElements() as $hreflangMetaTag) {
102
            if ('x-default' !== $hreflangMetaTag->getAttribute('hreflang')) {
103
                $href = $hreflangMetaTag->getAttribute('href');
104
105
                Assert::assertNotNull($href);
106
107
                if (null === $href) {
108
                    continue;
109
                }
110
111
                $this->getSession()->visit($href);
112
113
                $hreflangAltDefault = $this->getSession()->getPage()->find(
114
                    'xpath',
115
                    '//head/link[@rel="alternate" and @hreflang="x-default"]'
116
                );
117
118
                Assert::assertNotNull($hreflangAltDefault);
119
120
                if (null === $hreflangAltDefault) {
121
                    continue;
122
                }
123
124
                Assert::assertEquals(
125
                    $xDefault,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $xDefault does not seem to be defined for all execution paths leading up to this point.
Loading history...
126
                    $hreflangAltDefault->getAttribute('href')
127
                );
128
129
                $this->getSession()->back();
130
            }
131
        }
132
    }
133
134
    private function assertHreflangValidReciprocal(): void
135
    {
136
        $currentPageHreflangLinks = [];
137
        foreach ($this->getHreflangElements() as $hreflangElement) {
138
            $currentPageHreflangLinks[$hreflangElement->getAttribute('hreflang')] = $hreflangElement->getAttribute(
139
                'href'
140
            );
141
        }
142
143
        foreach ($currentPageHreflangLinks as $currentPageHreflangLink) {
144
            if ($currentPageHreflangLink === $this->getCurrentUrl()) {
145
                continue;
146
            }
147
148
            if ($currentPageHreflangLink) {
149
                $this->getSession()->visit($currentPageHreflangLink);
150
            }
151
152
            $referencedPageHreflangLinks = [];
153
154
            foreach ($this->getHreflangElements() as $hreflangElement) {
155
                $referencedPageHreflangLinks[$hreflangElement->getAttribute(
156
                    'hreflang'
157
                )] = $hreflangElement->getAttribute('href');
158
            }
159
160
            $this->getSession()->back();
161
162
            Assert::assertEquals(
163
                $currentPageHreflangLinks,
164
                $referencedPageHreflangLinks,
165
                'Missing or not coherent hreflang reciprocal links.'
166
            );
167
        }
168
    }
169
170
    /**
171
     * @throws Exception
172
     *
173
     * @Then the page hreflang markup should not be valid
174
     */
175
    public function thePageHreflangMarkupShouldNotBeValid(): void
176
    {
177
        $this->assertInverse(
178
            [$this, 'thePageHreflangMarkupShouldBeValid'],
179
            'hreflang markup should not be valid.'
180
        );
181
    }
182
}
183