assertHreflangValidReciprocal()   A
last analyzed

Complexity

Conditions 6
Paths 12

Size

Total Lines 32
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 19
nc 12
nop 0
dl 0
loc 32
rs 9.0111
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
        $xDefault = '';
89
90
        foreach ($this->getHreflangElements() as $hreflangMetaTag) {
91
            if ('x-default' === $hreflangMetaTag->getAttribute('hreflang')) {
92
                $xDefault = $hreflangMetaTag->getAttribute('href');
93
            }
94
        }
95
96
        if ('' === $xDefault) {
97
            return;
98
        }
99
100
        foreach ($this->getHreflangElements() as $hreflangMetaTag) {
101
            if ('x-default' !== $hreflangMetaTag->getAttribute('hreflang')) {
102
                $href = $hreflangMetaTag->getAttribute('href');
103
104
                Assert::notNull($href);
105
106
                $this->getSession()->visit($href);
107
108
                $hreflangAltDefault = $this->getSession()->getPage()->find(
109
                    'xpath',
110
                    '//head/link[@rel="alternate" and @hreflang="x-default"]'
111
                );
112
113
                Assert::notNull($hreflangAltDefault);
114
115
                Assert::eq(
116
                    $xDefault,
117
                    $hreflangAltDefault->getAttribute('href')
118
                );
119
120
                $this->getSession()->back();
121
            }
122
        }
123
    }
124
125
    private function assertHreflangValidReciprocal(): void
126
    {
127
        $currentPageHreflangLinks = [];
128
        foreach ($this->getHreflangElements() as $hreflangElement) {
129
            $currentPageHreflangLinks[$hreflangElement->getAttribute('hreflang')] = $hreflangElement->getAttribute(
130
                'href'
131
            );
132
        }
133
134
        foreach ($currentPageHreflangLinks as $currentPageHreflangLink) {
135
            if ($currentPageHreflangLink === $this->getCurrentUrl()) {
136
                continue;
137
            }
138
139
            if ($currentPageHreflangLink) {
140
                $this->getSession()->visit($currentPageHreflangLink);
141
            }
142
143
            $referencedPageHreflangLinks = [];
144
145
            foreach ($this->getHreflangElements() as $hreflangElement) {
146
                $referencedPageHreflangLinks[$hreflangElement->getAttribute(
147
                    'hreflang'
148
                )] = $hreflangElement->getAttribute('href');
149
            }
150
151
            $this->getSession()->back();
152
153
            Assert::eq(
154
                $currentPageHreflangLinks,
155
                $referencedPageHreflangLinks,
156
                'Missing or not coherent hreflang reciprocal links.'
157
            );
158
        }
159
    }
160
161
    /**
162
     * @Then the page hreflang markup should not be valid
163
     */
164
    public function thePageHreflangMarkupShouldNotBeValid(): void
165
    {
166
        $this->assertInverse(
167
            [$this, 'thePageHreflangMarkupShouldBeValid'],
168
            'hreflang markup should not be valid.'
169
        );
170
    }
171
}
172