Passed
Push — master ( 5fa21f...f08728 )
by Caen
03:34 queued 15s
created

TestableHtmlElement::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 13
Bugs 0 Features 0
Metric Value
cc 2
eloc 10
c 13
b 0
f 0
nc 2
nop 4
dl 0
loc 16
rs 9.9332
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Hyde\Testing\Support\HtmlTesting;
6
7
use DOMElement;
8
use Illuminate\Support\Arr;
9
use Illuminate\Support\Collection;
10
use Illuminate\Contracts\Support\Arrayable;
11
use Illuminate\Testing\Assert as PHPUnit;
12
13
use function trim;
14
use function filled;
15
use function strlen;
16
use function explode;
17
use function preg_match;
18
use function strip_tags;
19
use function array_filter;
20
21
/**
22
 * A wrapper for an HTML element node, parsed into an assertable and queryable object.
23
 */
24
class TestableHtmlElement implements Arrayable
25
{
26
    use HtmlTestingAssertions;
27
28
    public readonly string $html;
29
    public readonly string $tag;
30
    public readonly string $text;
31
    public readonly ?string $id;
32
33
    /** @var array<string> */
34
    public readonly array $classes;
35
36
    /** @var array<array<string, scalar>> */
37
    public readonly array $attributes;
38
39
    /** @var \Illuminate\Support\Collection<\Hyde\Testing\Support\HtmlTesting\TestableHtmlElement> The element's child nodes. */
40
    public readonly Collection $nodes;
41
42
    public readonly DOMElement $element;
43
44
    protected ?TestableHtmlElement $parent = null;
45
46
    public function __construct(string $html, DOMElement $element, ?TestableHtmlElement $parent = null, ?Collection $nodes = null)
47
    {
48
        $this->html = $html;
49
        $this->element = $element;
50
51
        if ($parent) {
52
            $this->parent = $parent;
53
        }
54
55
        $this->nodes = $nodes ?? new Collection();
56
57
        $this->tag = $this->parseTag($html);
58
        $this->text = $this->parseText($html);
59
        $this->id = $this->parseId($element);
60
        $this->classes = $this->parseClasses($element);
61
        $this->attributes = $this->parseAttributes($element);
62
    }
63
64
    /** @return array{id: ?string, tag: string, text: string, classes: ?array, attributes: ?array, nodes: \Illuminate\Support\Collection<\Hyde\Testing\Support\HtmlTesting\TestableHtmlElement>} */
65
    public function toArray(): array
66
    {
67
        return array_filter([
68
            'id' => $this->id,
69
            'tag' => $this->tag,
70
            'text' => $this->text,
71
            'classes' => $this->classes,
72
            'attributes' => $this->attributes,
73
            'nodes' => $this->nodes,
74
        ], fn ($value): bool => filled($value));
75
    }
76
77
    public function hasClass(string $class): static
78
    {
79
        return $this->doAssert(fn () => PHPUnit::assertContains($class, $this->classes, "The class '$class' was not found in the element."));
80
    }
81
82
    public function doesNotHaveClass(string $class): static
83
    {
84
        return $this->doAssert(fn () => PHPUnit::assertNotContains($class, $this->classes, "The class '$class' was found in the element."));
85
    }
86
87
    protected function parseTag(string $html): string
88
    {
89
        preg_match('/^<([a-z0-9-]+)/i', $html, $matches);
90
91
        return $matches[1] ?? '';
92
    }
93
94
    protected function parseText(string $html): string
95
    {
96
        preg_match('/>([^<]+)</', $html, $matches);
97
98
        $text = trim(strip_tags($matches[1] ?? ''));
99
100
        if (($this->tag === 'style' || $this->tag === 'script') && (strlen($text) > 200)) {
101
            return "(Inline $this->tag content)";
102
        }
103
104
        return $text;
105
    }
106
107
    protected function parseId(DOMElement $element): ?string
108
    {
109
        return $element->getAttribute('id') ?: null;
110
    }
111
112
    protected function parseClasses(DOMElement $element): array
113
    {
114
        return array_filter(explode(' ', $element->getAttribute('class')));
115
    }
116
117
    protected function parseAttributes(DOMElement $element): array
118
    {
119
        $attributes = [];
120
121
        foreach ($element->attributes as $attribute) {
122
            $attributes[$attribute->name] = $attribute->value;
123
        }
124
125
        return Arr::except($attributes, ['id', 'class']);
126
    }
127
}
128