forked from Codeception/Codeception
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathSnapshot.php
More file actions
177 lines (149 loc) · 4.39 KB
/
Copy pathSnapshot.php
File metadata and controls
177 lines (149 loc) · 4.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
<?php
declare(strict_types=1);
namespace Codeception;
use Codeception\Exception\ContentNotFound;
use Codeception\Util\Debug;
use Codeception\Util\Shared\Asserts;
use PHPUnit\Framework\AssertionFailedError;
abstract class Snapshot
{
use Asserts;
protected ?string $fileName = null;
/**
* @var string|false
*/
protected $dataSet;
protected ?bool $refresh = null;
protected bool $showDiff = false;
protected bool $saveAsJson = true;
protected string $extension = 'json';
/**
* Should return data from current test run
*
* @return string|false
*/
abstract protected function fetchData();
/**
* Performs assertion on saved data set against current dataset.
* Can be overridden to implement custom assertion
*
* @param mixed $data
*/
protected function assertData($data): void
{
$this->assertSame($this->dataSet, $data, "Snapshot doesn't match real data");
}
/**
* Loads data set from file.
*/
protected function load(): void
{
if (!file_exists($this->getFileName())) {
return;
}
$fileContents = file_get_contents($this->getFileName());
if ($this->saveAsJson) {
$fileContents = json_decode($fileContents, false, 512, JSON_THROW_ON_ERROR);
}
$this->dataSet = $fileContents;
if (!$this->dataSet) {
throw new ContentNotFound("Loaded snapshot is empty");
}
}
/**
* Saves data set to file
*/
protected function save(): void
{
$fileContents = $this->dataSet;
if ($this->saveAsJson) {
$fileContents = json_encode($fileContents, JSON_THROW_ON_ERROR);
}
file_put_contents($this->getFileName(), $fileContents);
}
/**
* If no filename is defined, generates one from class name
*/
protected function getFileName(): string
{
if (!$this->fileName) {
$this->fileName = preg_replace('#\W#', '.', get_class($this)) . '.' . $this->extension;
}
return codecept_data_dir() . $this->fileName;
}
/**
* Performs assertion for data sets
*/
public function assert(): void
{
// fetch data
$data = $this->fetchData();
if (!$data) {
throw new ContentNotFound("Fetched snapshot is empty.");
}
$this->load();
if (!$this->dataSet) {
$this->printDebug('Snapshot is empty. Updating snapshot...');
$this->dataSet = $data;
$this->save();
return;
}
try {
$this->assertData($data);
$this->printDebug('Data matches snapshot');
} catch (AssertionFailedError $exception) {
$this->printDebug('Snapshot assertion failed');
if (!is_bool($this->refresh)) {
$confirm = Debug::confirm('Should we update snapshot with fresh data? (Y/n) ');
} else {
$confirm = $this->refresh;
}
if ($confirm) {
$this->dataSet = $data;
$this->save();
$this->printDebug('Snapshot data updated');
return;
}
if ($this->showDiff) {
throw $exception;
}
$this->fail($exception->getMessage());
}
}
/**
* Force update snapshot data.
*/
public function shouldRefreshSnapshot(bool $refresh = true): void
{
$this->refresh = $refresh;
}
/**
* Show detailed diff if snapshot test fails
*/
public function shouldShowDiffOnFail(bool $showDiff = true): void
{
$this->showDiff = $showDiff;
}
/**
* json_encode/json_decode the snapshot data on storing/reading.
*/
public function shouldSaveAsJson(bool $saveAsJson = true): void
{
$this->saveAsJson = $saveAsJson;
}
/**
* Set the snapshot file extension.
* By default it will be stored as `.json`.
*
* The file extension will not perform any formatting in the data,
* it is only used as the snapshot file extension.
*/
public function setSnapshotFileExtension(string $fileExtension = 'json'): void
{
$this->extension = $fileExtension;
}
private function printDebug(string $message): void
{
Debug::debug(get_class($this) . ': ' . $message);
}
}