|
| 1 | +# Testing |
| 2 | + |
| 3 | +::: tip INFO |
| 4 | +This page documents the new Testing API. If you use the legacy one, please refer to [Testing (legacy)](../legacy/testing.md). |
| 5 | +::: |
| 6 | + |
| 7 | +Sharp provides a fluent testing API to help you test your Sharp code. These assertions and helpers are designed to be used in Feature tests. |
| 8 | + |
| 9 | +## The `SharpAssertions` trait |
| 10 | + |
| 11 | +To use Sharp's testing helpers, include the `Code16\Sharp\Utils\Testing\SharpAssertions` trait in your TestCase class: |
| 12 | + |
| 13 | +```php |
| 14 | +use Code16\Sharp\Utils\Testing\SharpAssertions; |
| 15 | + |
| 16 | +abstract class TestCase extends BaseTestCase |
| 17 | +{ |
| 18 | + use SharpAssertions; |
| 19 | + |
| 20 | + // ... |
| 21 | +} |
| 22 | +``` |
| 23 | + |
| 24 | +or in `Pest.php`: |
| 25 | + |
| 26 | +```php |
| 27 | +use Code16\Sharp\Utils\Testing\SharpAssertions; |
| 28 | + |
| 29 | +pest() |
| 30 | + ->extend(\Tests\TestCase::class) |
| 31 | + ->use(SharpAssertions::class); |
| 32 | +``` |
| 33 | + |
| 34 | +## Authentication |
| 35 | + |
| 36 | +### `loginAsSharpUser($user)` |
| 37 | + |
| 38 | +Sharp provides a helper to log in a user. By default, it will use the `SharpAssertions` internal logic to ensure the user is authorized to access Sharp. |
| 39 | + |
| 40 | +```php |
| 41 | +it('allows the user to access the list', function () { |
| 42 | + $user = User::factory()->create(); |
| 43 | + |
| 44 | + $this |
| 45 | + ->loginAsSharpUser($user) |
| 46 | + ->sharpList(Post::class) |
| 47 | + ->get() |
| 48 | + ->assertOk(); |
| 49 | +}); |
| 50 | +``` |
| 51 | + |
| 52 | +## Testing Entity Lists |
| 53 | + |
| 54 | +Use `sharpList()` to test your Entity Lists. |
| 55 | + |
| 56 | +### `sharpList(string $entityKey)` |
| 57 | + |
| 58 | +Starts a fluent interaction with an Entity List. |
| 59 | + |
| 60 | +```php |
| 61 | +$this->sharpList(Post::class) |
| 62 | + ->get() |
| 63 | + ->assertOk() |
| 64 | + ->assertListData(fn (AssertableJson $data) => $data |
| 65 | + ->count(3) |
| 66 | + ->has('0.title', 'My first post') |
| 67 | + ->etc() |
| 68 | + ); |
| 69 | +``` |
| 70 | + |
| 71 | +### Filtering the list |
| 72 | + |
| 73 | +You can use `withFilter()` to apply filters to the list before calling `get()` or a command. |
| 74 | + |
| 75 | +```php |
| 76 | +$this->sharpList(Post::class) |
| 77 | + ->withFilter(CategoryFilter::class, 1) |
| 78 | + ->get() |
| 79 | + ->assertOk(); |
| 80 | +``` |
| 81 | + |
| 82 | +### Entity Commands |
| 83 | + |
| 84 | +You can call an Entity Command directly from the list: |
| 85 | + |
| 86 | +```php |
| 87 | +$this->sharpList(Post::class) |
| 88 | + ->entityCommand(ExportPosts::class) |
| 89 | + ->post() |
| 90 | + ->assertOk() |
| 91 | + ->assertReturnsDownload('posts.csv'); |
| 92 | +``` |
| 93 | + |
| 94 | +If the command has a form, you can test it: |
| 95 | + |
| 96 | +```php |
| 97 | +$this->sharpList(Post::class) |
| 98 | + ->entityCommand(ExportPosts::class) |
| 99 | + ->getForm() |
| 100 | + ->assertFormData(fn (AssertableJson $data) => $data |
| 101 | + ->where('format', 'xls') |
| 102 | + ->etc() |
| 103 | + ) |
| 104 | + ->post(['format' => 'csv']) |
| 105 | + ->assertOk(); |
| 106 | +``` |
| 107 | + |
| 108 | +### Instance Commands |
| 109 | + |
| 110 | +Similarly, you can call an Instance Command: |
| 111 | + |
| 112 | +```php |
| 113 | +$this->sharpList(Post::class) |
| 114 | + ->instanceCommand(PublishPost::class, 1) |
| 115 | + ->post() |
| 116 | + ->assertOk() |
| 117 | + ->assertReturnsReload(); |
| 118 | +``` |
| 119 | + |
| 120 | +### Multi-step Commands (Wizards) |
| 121 | + |
| 122 | +For commands that have multiple steps, you can use `getNextStepForm()`: |
| 123 | + |
| 124 | +```php |
| 125 | +$this->sharpList(Post::class) |
| 126 | + ->entityCommand(MyWizardCommand::class) |
| 127 | + ->getForm() |
| 128 | + ->post(['step1_data' => 'value']) |
| 129 | + ->assertReturnsStep('step2') |
| 130 | + ->getNextStepForm() |
| 131 | + ->assertFormData(fn (AssertableJson $data) => $data |
| 132 | + ->where('step2_field', 'default') |
| 133 | + ->etc() |
| 134 | + ) |
| 135 | + ->post(['step2_data' => 'value']) |
| 136 | + ->assertOk(); |
| 137 | +``` |
| 138 | + |
| 139 | +## Testing Show Pages |
| 140 | + |
| 141 | +Use `sharpShow()` to test your Show Pages. |
| 142 | + |
| 143 | +### `sharpShow(string $entityKey, $instanceId)` |
| 144 | + |
| 145 | +Starts a fluent interaction with a Show Page. |
| 146 | + |
| 147 | +```php |
| 148 | +$this->sharpShow(Post::class, 1) |
| 149 | + ->get() |
| 150 | + ->assertOk() |
| 151 | + ->assertShowData(fn (AssertableJson $data) => $data |
| 152 | + ->where('title', 'My first post') |
| 153 | + ->where('author', 'John Doe') |
| 154 | + ->etc() |
| 155 | + ); |
| 156 | +``` |
| 157 | + |
| 158 | +### Instance Commands from Show |
| 159 | + |
| 160 | +```php |
| 161 | +$this->sharpShow(Post::class, 1) |
| 162 | + ->instanceCommand(PublishPost::class) |
| 163 | + ->post() |
| 164 | + ->assertOk(); |
| 165 | +``` |
| 166 | + |
| 167 | +### List & dashboard fields |
| 168 | + |
| 169 | +Show Pages can contain embedded Entity Lists or Dashboards. You can test them using `sharpListField()` and `sharpDashboardField()`. |
| 170 | + |
| 171 | +#### `sharpListField(string $entityKey)` |
| 172 | + |
| 173 | +```php |
| 174 | +$this->sharpShow(Post::class, 1) |
| 175 | + ->sharpListField(Comment::class) |
| 176 | + ->get() |
| 177 | + ->assertOk() |
| 178 | + ->assertListData(fn (AssertableJson $data) => $data |
| 179 | + ->count(5) |
| 180 | + ); |
| 181 | +``` |
| 182 | + |
| 183 | +#### `sharpDashboardField(string $entityKey)` |
| 184 | + |
| 185 | +```php |
| 186 | +$this->sharpShow(User::class, 1) |
| 187 | + ->sharpDashboardField(UserStatsDashboard::class) |
| 188 | + ->get() |
| 189 | + ->assertOk(); |
| 190 | +``` |
| 191 | + |
| 192 | +### Nested shows |
| 193 | + |
| 194 | +There are some cases where you have nested shows by navigating through Show List fields. You can chain `sharpShow()` calls to simulate the correct breadcrumb : |
| 195 | + |
| 196 | +```php |
| 197 | +$this->sharpList(Post::class) |
| 198 | + ->sharpShow(Post::class, 1) |
| 199 | + ->sharpListField(Comment::class) |
| 200 | + ->sharpShow(Comment::class, 1) |
| 201 | + ->assertOk(); |
| 202 | +``` |
| 203 | + |
| 204 | +## Testing Forms |
| 205 | + |
| 206 | +Use `sharpForm()` to test your Forms. |
| 207 | + |
| 208 | +### `sharpForm(string $entityKey, $instanceId = null)` |
| 209 | + |
| 210 | +Starts a fluent interaction with a Form. If `$instanceId` is provided, it targets an edit form; otherwise, it targets a creation form. |
| 211 | + |
| 212 | +### Creating and Updating |
| 213 | + |
| 214 | +```php |
| 215 | +// Create |
| 216 | +$this->sharpForm(Post::class) |
| 217 | + ->store(['title' => 'New Post']) |
| 218 | + ->assertValid() |
| 219 | + ->assertRedirect(); |
| 220 | + |
| 221 | +// Update |
| 222 | +$this->sharpForm(Post::class, 1) |
| 223 | + ->update(['title' => 'Updated Post']) |
| 224 | + ->assertValid() |
| 225 | + ->assertRedirect(); |
| 226 | +``` |
| 227 | + |
| 228 | +### Testing the "Creation" or "Edit" request itself |
| 229 | + |
| 230 | +If you want to test that the form displays correctly: |
| 231 | + |
| 232 | +```php |
| 233 | +$this->sharpForm(Post::class, 1) |
| 234 | + ->edit() |
| 235 | + ->assertOk() |
| 236 | + ->assertFormData(fn (AssertableJson $data) => $data |
| 237 | + ->where('title', 'Existing Post') |
| 238 | + ->etc() |
| 239 | + ); |
| 240 | +``` |
| 241 | + |
| 242 | +From an `AssertableForm` (the result of `edit()` or `create()`), you can also call `update()` or `store()`: |
| 243 | + |
| 244 | +```php |
| 245 | +$this->sharpForm(Post::class, 1) |
| 246 | + ->edit() |
| 247 | + ->update(['title' => 'New title']) |
| 248 | + ->assertValid(); |
| 249 | +``` |
| 250 | + |
| 251 | +## Testing Dashboards |
| 252 | + |
| 253 | +Use `sharpDashboard()` to test your Dashboards. |
| 254 | + |
| 255 | +### `sharpDashboard(string $entityKey)` |
| 256 | + |
| 257 | +Starts a fluent interaction with a Dashboard. |
| 258 | + |
| 259 | +```php |
| 260 | +$this->sharpDashboard(MyDashboard::class) |
| 261 | + ->get() |
| 262 | + ->assertOk(); |
| 263 | +``` |
| 264 | + |
| 265 | +### Filtering the dashboard |
| 266 | + |
| 267 | +```php |
| 268 | +$this->sharpDashboard(MyDashboard::class) |
| 269 | + ->withFilter(PeriodFilter::class, ['start' => '2023-01-01', 'end' => '2023-01-31']) |
| 270 | + ->get() |
| 271 | + ->assertOk(); |
| 272 | +``` |
| 273 | + |
| 274 | +### Dashboard Commands |
| 275 | + |
| 276 | +```php |
| 277 | +$this->sharpDashboard(MyDashboard::class) |
| 278 | + ->dashboardCommand(RefreshStats::class) |
| 279 | + ->post() |
| 280 | + ->assertOk(); |
| 281 | +``` |
0 commit comments