Completed
Push — master ( 615c0c...a84d4b )
by Marcel
01:37
created

VisualDiffTester::getComparisonFilename()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace BeyondCode\VisualDiff;
4
5
use PHPUnit\Framework\Assert;
6
use Spatie\Browsershot\Browsershot;
7
use PHPUnit\Framework\ExpectationFailedException;
8
9
class VisualDiffTester
10
{
11
    protected $html;
12
13
    protected $name;
14
15
    protected $currentResolution = null;
16
17
    protected $resolutions;
18
19
    protected $diffOutputPath = null;
20
21
    protected $screenshotOutputPath = null;
22
23
    public function __construct(string $html, string $name, array $resolutions)
24
    {
25
        $this->html = $html;
26
        $this->name = $name;
27
        $this->resolutions = $resolutions;
28
        $this->screenshotOutputPath = config('visualdiff.screenshot_path');
29
        $this->diffOutputPath = config('visualdiff.diff_path');
30
    }
31
32
    public function setDiffOutputPath(string $diffOutputPath)
33
    {
34
        $this->diffOutputPath = $diffOutputPath;
35
36
        return $this;
37
    }
38
39
    public function setScreenshotOutputPath(string $screenshotOutputPath)
40
    {
41
        $this->screenshotOutputPath = $screenshotOutputPath;
42
43
        return $this;
44
    }
45
46
    public function createDiffs()
47
    {
48
        $this->preparePaths();
49
50
        foreach ($this->resolutions as $resolution) {
51
52
            $this->currentResolution = $resolution;
53
54
            $createDiff = $this->shouldCreateDiff();
55
56
            $this->createScreenshot();
57
58
            if ($createDiff) {
59
                $this->createDiff();
60
            }
61
62
        }
63
    }
64
65
    protected function preparePaths()
66
    {
67
        @mkdir($this->screenshotOutputPath, 0755, true);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
68
        @mkdir($this->diffOutputPath, 0755, true);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
69
    }
70
71
    protected function shouldCreateDiff(): bool
72
    {
73
        return file_exists($this->screenshotOutputPath . DIRECTORY_SEPARATOR . $this->currentResolution['width'] . '_x_' . $this->currentResolution['height'] . '_' . $this->name . '.png');
74
    }
75
76
    protected function getDiffFilename()
77
    {
78
        return $this->currentResolution['width'] . '_x_' . $this->currentResolution['height'] . '_diff_' . $this->name . '.png';
79
    }
80
81
    protected function getComparisonFilename()
82
    {
83
        return $this->currentResolution['width'] . '_x_' . $this->currentResolution['height'] . '_' . $this->name . '.png';
84
    }
85
86
    protected function getNewFilename()
87
    {
88
        return $this->currentResolution['width'] . '_x_' . $this->currentResolution['height'] . '_new_' . $this->name . '.png';
89
    }
90
91
    protected function getFilename()
92
    {
93
        if (!$this->shouldCreateDiff()) {
94
            return $this->getComparisonFilename();
95
        }
96
97
        return $this->getNewFilename();
98
    }
99
100
    /**
101
     * @throws \Spatie\Browsershot\Exceptions\CouldNotTakeBrowsershot
102
     */
103
    protected function createScreenshot()
104
    {
105
        $filename = $this->getFilename();
106
107
        $browsershot = Browsershot::html($this->html);
108
        $browsershot->noSandbox();
109
110
        if (! is_null(config('visualdiff.node_binary'))) {
111
            $browsershot->setNodeBinary(config('visualdiff.node_binary'));
112
        }
113
114
        if (! is_null(config('visualdiff.npm_binary'))) {
115
            $browsershot->setNpmBinary(config('visualdiff.npm_binary'));
116
        }
117
118
        $browsershot->windowSize($this->currentResolution['width'], $this->currentResolution['height'])
119
            ->save($this->screenshotOutputPath . DIRECTORY_SEPARATOR . $filename);
120
    }
121
    /**
122
     * Determines whether or not the screenshots should be updated instead of
123
     * matched.
124
     *
125
     * @return bool
126
     */
127
    protected function shouldUpdateScreenshots(): bool
128
    {
129
        return in_array('--update-screenshots', $_SERVER['argv'], true);
130
    }
131
132
    protected function createDiff()
133
    {
134
        $diff = VisualDiff::diff(
135
            $this->screenshotOutputPath . DIRECTORY_SEPARATOR . $this->getNewFilename(),
136
            $this->screenshotOutputPath . DIRECTORY_SEPARATOR . $this->getComparisonFilename()
137
        );
138
139
        if (! is_null(config('visualdiff.node_binary'))) {
140
            $diff->setNodeBinary(config('visualdiff.node_binary'));
141
        }
142
143
        if (! is_null(config('visualdiff.npm_binary'))) {
144
            $diff->setNpmBinary(config('visualdiff.npm_binary'));
145
        }
146
147
        $diff->setAntialias(config('visualdiff.antialias'))
148
            ->setThreshold(config('visualdiff.threshold'));
149
150
        $result = $diff->save($this->diffOutputPath . DIRECTORY_SEPARATOR . $this->getDiffFilename());
151
152
        if (! is_null($result)) {
153
            try {
154
                Assert::assertLessThanOrEqual(
155
                    config('visualdiff.maximum_error_percentage'),
156
                    $result->error_percentage,
157
                    "The visual diff for " . $this->name . " has a higher pixel diff than the allowed maximum." . PHP_EOL .
158
                    "See: " . $this->diffOutputPath . $this->getDiffFilename()
159
                );
160
            } catch (ExpectationFailedException $e) {
161
                if ($this->shouldUpdateScreenshots()) {
162
                    $this->renameScreenshots();
163
                    return;
164
                } else {
165
                    echo exec(__DIR__ . '/../bin/imgcat ' . escapeshellarg($this->diffOutputPath . DIRECTORY_SEPARATOR . $this->getDiffFilename()));
166
167
                    throw $e;
168
                }
169
            }
170
        }
171
172
        // Rename new image for next comparison
173
        $this->renameScreenshots();
174
    }
175
176
    protected function renameScreenshots()
177
    {
178
        rename(
179
            $this->screenshotOutputPath . DIRECTORY_SEPARATOR . $this->getNewFilename(),
180
            $this->screenshotOutputPath . DIRECTORY_SEPARATOR . $this->getComparisonFilename()
181
        );
182
    }
183
184
}