Passed
Pull Request — 1.x (#1)
by Kevin
02:07
created

Browser::wrapMinkExpectation()   A

Complexity

Conditions 2
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 6
c 0
b 0
f 0
nc 3
nop 1
dl 0
loc 10
rs 10
1
<?php
2
3
namespace Zenstruck;
4
5
use Behat\Mink\Driver\DriverInterface;
6
use Behat\Mink\Element\DocumentElement;
7
use Behat\Mink\Mink;
8
use Behat\Mink\Session;
9
use Behat\Mink\WebAssert;
10
use Symfony\Component\Filesystem\Filesystem;
11
use Symfony\Component\VarDumper\VarDumper;
12
use Zenstruck\Browser\Assert;
13
use Zenstruck\Browser\Assert\Assertion\Url;
14
use Zenstruck\Browser\Component;
15
use Zenstruck\Browser\Response;
16
use Zenstruck\Browser\Util\FunctionExecutor;
17
18
/**
19
 * @author Kevin Bond <[email protected]>
20
 */
21
class Browser
22
{
23
    private const SESSION = 'app';
24
25
    private Mink $mink;
26
    private ?string $sourceDir = null;
27
28
    public function __construct(DriverInterface $driver)
29
    {
30
        $this->mink = new Mink([self::SESSION => new Session($driver)]);
31
    }
32
33
    /**
34
     * @return static
35
     */
36
    public static function create(callable $factory): self
37
    {
38
        $browser = $factory();
39
40
        if (!$browser instanceof self) {
41
            throw new \RuntimeException(\sprintf('The factory callable must return an instance of "%s".', self::class));
42
        }
43
44
        return $browser;
45
    }
46
47
    /**
48
     * @return static
49
     */
50
    final public function setSourceDir(string $dir): self
51
    {
52
        $this->sourceDir = $dir;
53
54
        return $this;
55
    }
56
57
    final public function minkSession(): Session
58
    {
59
        return $this->mink->getSession(self::SESSION);
60
    }
61
62
    final public function webAssert(): WebAssert
63
    {
64
        return $this->mink->assertSession(self::SESSION);
65
    }
66
67
    final public function documentElement(): DocumentElement
68
    {
69
        return $this->minkSession()->getPage();
70
    }
71
72
    /**
73
     * @return static
74
     */
75
    final public function visit(string $uri): self
76
    {
77
        $this->minkSession()->visit($uri);
78
79
        return $this;
80
    }
81
82
    /**
83
     * @param array $parts The url parts to check (@see parse_url)
84
     *
85
     * @return static
86
     */
87
    final public function assertOn(string $expected, array $parts = ['path', 'query', 'fragment']): self
88
    {
89
        Assert::that((new Url($this->minkSession()->getCurrentUrl(), $parts))->matches($expected));
90
91
        return $this;
92
    }
93
94
    /**
95
     * @param array $parts The url parts to check (@see parse_url)
96
     *
97
     * @return static
98
     */
99
    final public function assertNotOn(string $expected, array $parts = ['path', 'query', 'fragment']): self
100
    {
101
        Assert::that((new Url($this->minkSession()->getCurrentUrl(), $parts))->notMatches($expected));
102
103
        return $this;
104
    }
105
106
    /**
107
     * @return static
108
     */
109
    final public function assertContains(string $expected): self
110
    {
111
        Assert::wrapMinkExpectation(
112
            fn() => $this->webAssert()->responseContains($expected)
113
        );
114
115
        return $this;
116
    }
117
118
    /**
119
     * @return static
120
     */
121
    final public function assertNotContains(string $expected): self
122
    {
123
        Assert::wrapMinkExpectation(
124
            fn() => $this->webAssert()->responseNotContains($expected)
125
        );
126
127
        return $this;
128
    }
129
130
    /**
131
     * @return static
132
     */
133
    final public function use(callable $callback): self
134
    {
135
        FunctionExecutor::createFor($callback)
136
            ->replaceUntypedArgument($this)
137
            ->replaceTypedArgument(self::class, $this)
138
            ->replaceTypedArgument(Component::class, fn(string $class) => new $class($this))
139
            ->execute()
140
        ;
141
142
        return $this;
143
    }
144
145
    /**
146
     * @return static
147
     */
148
    final public function saveSource(string $filename): self
149
    {
150
        if ($this->sourceDir) {
151
            $filename = \sprintf('%s/%s', \rtrim($this->sourceDir, '/'), \ltrim($filename, '/'));
152
        }
153
154
        (new Filesystem())->dumpFile($filename, $this->response()->raw());
155
156
        return $this;
157
    }
158
159
    /**
160
     * @return static
161
     */
162
    final public function dump(?string $selector = null): self
163
    {
164
        VarDumper::dump($selector ? $this->response()->find($selector) : $this->response()->raw());
165
166
        return $this;
167
    }
168
169
    final public function dd(?string $selector = null): void
170
    {
171
        $this->dump($selector);
172
        exit(1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
173
    }
174
175
    public function dumpCurrentState(string $filename): void
176
    {
177
        $this->saveSource("{$filename}.txt");
178
    }
179
180
    protected function response(): Response
181
    {
182
        return Response::createFor($this->minkSession());
183
    }
184
}
185