1. Go to this page and download the library: Download tyloo/atc library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
tyloo / atc example snippets
final class CreateUserTest extends ApiTestCase
{
use Factories;
use ResetDatabase;
use InteractsWithDatabase;
use InteractsWithMessenger;
#[Test]
public function admin_creates_a_user_and_queues_welcome_email(): void
{
$admin = AdminFactory::createOne();
$this->actingAs($admin)
->post('/api/users', json: [
'email' => '[email protected]',
'name' => 'Jean Bond',
])
->assertStatus(201)
->assertMatchesJsonSchema('users/create.json')
->assertJsonPath('data.email', '[email protected]')
->assertHeader('Location', '/api/users/42');
$this->assertDatabaseHas(User::class, ['email' => '[email protected]']);
$this->assertMessageDispatched(
SendWelcomeEmail::class,
fn (SendWelcomeEmail $m) => $m->email === '[email protected]',
);
}
}
use App\Factory\UserFactory;
use Tyloo\Atc\ApiTestCase;
use Zenstruck\Foundry\Test\Factories;
use Zenstruck\Foundry\Test\ResetDatabase;
final class ProfileTest extends ApiTestCase
{
use Factories;
use ResetDatabase;
#[Test]
public function returns_authenticated_users_profile(): void
{
$alice = UserFactory::createOne(['email' => '[email protected]']);
$this->actingAs($alice)
->get('/api/me')
->assertStatusOk()
->assertJsonPath('email', '[email protected]');
}
}
use Tyloo\Atc\ApiTestCase;
use Tyloo\Atc\Http\ApiClient;
abstract class BaseApiTestCase extends ApiTestCase
{
#[\Override]
protected function authenticate(object $user, ApiClient $client): ApiClient
{
$jwt = static::getContainer()->get(JWTTokenManagerInterface::class);
return $client->withToken($jwt->create($user));
}
}
$notifier = $this->partialMockService(NotifierService::class, ['send']);
$notifier->method('send')->willReturn(null);
// every other method on NotifierService keeps its real implementation.
$this->setService('app.feature_flags', new InMemoryFeatureFlags(['beta' => true]));
final class CreateUserTest extends ApiTestCase
{
use Factories;
use ResetDatabase;
use InteractsWithDatabase;
#[Test]
public function admin_creates_user_persists_row(): void
{
$admin = UserFactory::createOne(['role' => 'admin']);
$this->actingAs($admin)
->post('/api/users', json: ['email' => '[email protected]'])
->assertStatus(201);
$this->assertDatabaseHas(User::class, ['email' => '[email protected]']);
$this->assertDatabaseMissing(User::class, ['email' => '[email protected]']);
$this->assertDatabaseCount(User::class, 2);
}
}
use Tyloo\Atc\Trait\InteractsWithMessenger;
final class BulkImportTest extends ApiTestCase
{
use InteractsWithMessenger;
#[\PHPUnit\Framework\Attributes\Test]
public function csv_upload_queues_one_message_per_row(): void
{
$this->post('/api/imports', files: ['csv' => $this->uploadCsv('100-rows.csv')])
->assertStatus(202);
$this->assertMessagesDispatchedCount(100, ImportRow::class);
$this->assertMessageDispatched(
ImportRow::class,
fn (ImportRow $row) => $row->email === '[email protected]',
);
}
}
$this->assertNoMessagesDispatched(); // any class
$this->assertNoMessagesDispatched(SendEmail::class); // class-specific
$all = $this->dispatchedMessages(); // list<object>
$welcomes = $this->dispatchedMessages(SendWelcomeEmail::class);
use Tyloo\Atc\Trait\InteractsWithMailer;
final class PasswordResetTest extends ApiTestCase
{
use InteractsWithMailer;
#[\PHPUnit\Framework\Attributes\Test]
public function reset_request_sends_a_one_time_link(): void
{
$this->post('/api/password/reset', json: ['email' => '[email protected]'])
->assertStatusOk();
$this->assertEmailSent();
$this->assertEmailSentTo(
'[email protected]',
fn (Email $email) => str_contains((string) $email->getSubject(), 'Reset your password'),
);
$this->assertNoEmailsSent(); // for negative paths
}
}
use Tyloo\Atc\Trait\InteractsWithNotifier;
final class OutageAlertTest extends ApiTestCase
{
use InteractsWithNotifier;
#[\PHPUnit\Framework\Attributes\Test]
public function downstream_error_pages_the_oncall(): void
{
$this->mockService(StatusPageClient::class)
->method('latest')
->willThrowException(new \RuntimeException('upstream down'));
$this->get('/api/health')->assertStatus(503);
$this->assertNotificationSent();
$this->assertSame(1, $this->sentNotifications()->count());
}
}
use Symfony\Component\HttpClient\Response\MockResponse;
use Tyloo\Atc\Trait\InteractsWithHttpClient;
final class GeocodingTest extends ApiTestCase
{
use InteractsWithHttpClient;
#[\PHPUnit\Framework\Attributes\Test]
public function address_lookup_calls_geocoder_with_signed_query(): void
{
$this->mockHttpClient([
new MockResponse(json_encode(['lat' => 48.85, 'lng' => 2.35]), ['http_code' => 200]),
]);
$this->post('/api/addresses', json: ['street' => '1 rue de Rivoli'])
->assertStatus(201)
->assertJsonPath('lat', 48.85);
$this->assertHttpRequestSent('GET', 'https://api.example.com/geocode');
}
}
use Tyloo\Atc\Trait\InteractsWithCache;
final class RateLimitTest extends ApiTestCase
{
use InteractsWithCache;
#[\PHPUnit\Framework\Attributes\Test]
public function fourth_request_in_a_minute_is_throttled(): void
{
for ($i = 0; $i < 3; $i++) {
$this->get('/api/search?q=foo')->assertStatusOk();
}
$this->get('/api/search?q=foo')->assertStatus(429);
$this->clearCache(); // reset between sub-scenarios
$this->get('/api/search?q=foo')->assertStatusOk();
}
}
use Tyloo\Atc\Trait\InteractsWithProfiler;
final class ListUsersTest extends ApiTestCase
{
use InteractsWithProfiler;
#[\PHPUnit\Framework\Attributes\Test]
public function list_endpoint_uses_a_single_query_regardless_of_user_count(): void
{
UserFactory::createMany(50);
$this->withProfiling();
$this->get('/api/users')
->assertStatusOk()
->assertJsonCount(50, 'data');
$this->assertQueryCount(1); // exactly one SELECT
$this->assertQueryCountLessThan(3); // looser bound
$profile = $this->profile(); // raw Symfony Profile for deeper introspection
}
}
use Tyloo\Atc\ApiTestCase;
use Tyloo\Atc\Http\ApiClient;
abstract class BaseApiTestCase extends ApiTestCase
{
/** Default headers sent with every request. */
#[\Override]
protected function resolveDefaultHeaders(): array
{
return ['Accept' => 'application/json', 'X-Tenant' => 'acme'];
}
/** Where JSON Schema files live (`<project_dir>/tests/Schemas` by default). */
#[\Override]
protected function resolveJsonSchemaBaseDir(): string
{
return static::$kernel->getProjectDir() . '/tests/api-schemas';
}
/** Services replaced with default doubles for every test in this suite. */
#[\Override]
protected function defaultMocks(): array
{
return [
ShopifyService::class => fn () => $this->createMock(ShopifyService::class),
];
}
/** Auth strategy: map a user to an authenticated client. */
#[\Override]
protected function authenticate(object $user, ApiClient $client): ApiClient
{
return $client->withToken($this->jwt()->create($user));
}
/** Pin the in-memory messenger transports instead of auto-discovering. */
#[\Override]
protected function resolveMessengerTransports(): array
{
return ['async', 'failed'];
}
/** Let unmatched outbound HTTP requests pass through instead of failing. */
#[\Override]
protected function resolveHttpClientStrict(): bool
{
return false;
}
/** Swap additional cache pools (default: just `cache.app`). */
#[\Override]
protected function cachePoolIds(): array
{
return ['cache.app', 'cache.system'];
}
}
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.