Passed
Push — master ( b42680...426658 )
by Marc
02:40
created

assertHreflangCoherentXDefault()   A

Complexity

Conditions 6
Paths 12

Size

Total Lines 33
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

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