Logo

dev-resources.site

for different kinds of informations.

Testing Temporary URLs in Laravel Storage

Published at
1/12/2025
Categories
laravel
testing
php
aws
Author
tegos
Categories
4 categories in total
laravel
open
testing
open
php
open
aws
open
Author
5 person written this
tegos
open
Testing Temporary URLs in Laravel Storage

How to Test Laravel's Storage::temporaryUrl()

Laravel provides a powerful and flexible Storage facade for file storage and manipulation. One notable feature is temporaryUrl(), which generates temporary URLs for files stored on services like Amazon S3 or DigitalOcean Spaces. However, Laravel's documentation does not cover how to test this method effectively. Testing it can pose challenges, particularly when using Storage::fake, as the fake storage driver does not support temporaryUrl() and throws the error:

This driver does not support creating temporary URLs.

In this article, weā€™ll demonstrate two approaches to testing Storage::temporaryUrl() using a practical example. These approaches involve mocking the filesystem and using fake storage. Both methods ensure your tests remain isolated and reliable.

Example Setup

Weā€™ll use a PriceExport model, a corresponding controller, and test cases to illustrate the testing process. Hereā€™s the setup:

Model

final class PriceExport extends Model
{
    protected $fillable = [
        'user_id',
        'supplier_id',
        'path',
        'is_auto',
        'is_ready',
        'is_send',
    ];

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    public function supplier(): BelongsTo
    {
        return $this->belongsTo(Supplier::class);
    }
}
Enter fullscreen mode Exit fullscreen mode

Controller

The controller generates a temporary URL for the file using the temporaryUrl method:

final class PriceExportController extends Controller
{
    /**
     * @throws ItemNotFoundException
     */
    public function download(PriceExport $priceExport): DownloadFileResource
    {
        if (!$priceExport->is_ready || empty($priceExport->path)) {
            throw new ItemNotFoundException('price export');
        }

        $fileName = basename($priceExport->path);
        $diskS3 = Storage::disk(StorageDiskName::DO_S3->value);

        $url = $diskS3->temporaryUrl($priceExport->path, Carbon::now()->addHour());

        $downloadFileDTO = new DownloadFileDTO($url, $fileName);

        return DownloadFileResource::make($downloadFileDTO);
    }
}
Enter fullscreen mode Exit fullscreen mode

Testing temporaryUrl()

Test Case 1: Using Storage::fake

While Storage::fake doesnā€™t natively support temporaryUrl, we can mock the fake storage to simulate the methodā€™s behavior. This approach ensures you can test without needing a real storage service.

final class PriceExportTest extends TestCase
{
    public function test_price_export_download_fake(): void
    {
        // Arrange
        $user = $this->getDefaultUser();
        $this->actingAsFrontendUser($user);

        $supplier = SupplierFactory::new()->create();
        $priceExport = PriceExportFactory::new()->for($user)->for($supplier)->create([
            'path' => 'price-export/price-2025.xlsx',
        ]);

        $expectedUrl = 'https://temporary-url.com/supplier-price-export-2025.xlsx';
        $expectedFileName = basename($priceExport->path);

        $fakeFilesystem = Storage::fake(StorageDiskName::DO_S3->value);

        // Mock the fake filesystem
        $proxyMockedFakeFilesystem = Mockery::mock($fakeFilesystem);
        $proxyMockedFakeFilesystem->shouldReceive('temporaryUrl')->andReturn($expectedUrl);
        Storage::set(StorageDiskName::DO_S3->value, $proxyMockedFakeFilesystem);

        // Act
        $response = $this->postJson(route('api-v2:price-export.price-exports.download', $priceExport));

        // Assert
        $response->assertOk()->assertJson([
            'data' => [
                'name' => $expectedFileName,
                'url' => $expectedUrl,
            ]
        ]);
    }
}
Enter fullscreen mode Exit fullscreen mode

Test Case 2: Using Storage::shouldReceive

This method leverages Laravelā€™s built-in mocking capabilities to mock the temporaryUrl behavior directly.

final class PriceExportTest extends TestCase
{
    public function test_price_export_download_mock(): void
    {
        // Arrange
        $user = $this->getDefaultUser();
        $this->actingAsFrontendUser($user);

        $supplier = SupplierFactory::new()->create();
        $priceExport = PriceExportFactory::new()->for($user)->for($supplier)->create([
            'path' => 'price-export/price-2025.xlsx',
        ]);

        $expectedUrl = 'https://temporary-url.com/supplier-price-export-2025.xlsx';
        $expectedFileName = basename($priceExport->path);

        // Mock the storage behavior
        Storage::shouldReceive('disk')->with(StorageDiskName::DO_S3->value)->andReturnSelf();
        Storage::shouldReceive('temporaryUrl')->andReturn($expectedUrl);

        // Act
        $response = $this->postJson(route('api-v2:price-export.price-exports.download', $priceExport));

        // Assert
        $response->assertOk()->assertJson([
            'data' => [
                'name' => $expectedFileName,
                'url' => $expectedUrl,
            ]
        ]);
    }
}
Enter fullscreen mode Exit fullscreen mode

Key Takeaways

  1. Storage::fake Limitation: The fake storage driver does not support temporaryUrl. Use a mocked version of the fake storage to work around this.
  2. Mocking Storage: Laravelā€™s Storage::shouldReceive simplifies mocking methods like temporaryUrl when testing controllers.
  3. Isolation: Both approaches ensure your tests donā€™t depend on external services, maintaining fast and reliable tests.

By combining these techniques, you can effectively test Storage::temporaryUrl() and ensure your applicationā€™s functionality is well-verified.

php Article's
30 articles in total
Favicon
The Importance of Writing Meaningful Code and Documentation
Favicon
Filling a 10 Million Image Grid with PHP for Internet History
Favicon
Code Smell 286 - Overlapping Methods
Favicon
Example of using Late Static Binding in PHP.
Favicon
How to Resolve the 'Permission Denied' Error in PHP File Handling
Favicon
2429. Minimize XOR
Favicon
The Ultimate PHP QR Code Library
Favicon
Understanding PHP Development and Why Itā€™s Still Relevant Today
Favicon
2657. Find the Prefix Common Array of Two Arrays
Favicon
Php Base64 encode/decode ā€“ best practices and use cases
Favicon
Laravel 11.30: A Leap Forward in Testing, Model IDs, and Authorization
Favicon
How to Effectively Manage Laravel Request Validation?
Favicon
3223. Minimum Length of String After Operations
Favicon
Author Bio Box CSS in WordPress
Favicon
[Boost]
Favicon
How to Image Upload with CKeditor in Laravel 11 Tutorial
Favicon
How to Install and Use Trix Editor in Laravel 11
Favicon
Testing Temporary URLs in Laravel Storage
Favicon
2116. Check if a Parentheses String Can Be Valid
Favicon
API Vulnerabilities in Laravel: Identify & Secure Your Endpoints
Favicon
Enforcing Strong Passwords in Laravel
Favicon
"PHP is deadāš°ļø" .. what's next? Is Laravel worth it? šŸ˜Ž
Favicon
LTS as a Business: How an Old Project Can Become the Foundation for a New Business Model
Favicon
Php
Favicon
How to Fix the "PHP Not Found" Error on macOS After Installing XAMPP
Favicon
The Hidden Bug That Crashed a Satellite: Lessons for Every Developer šŸš€
Favicon
Sending logs to Telegram. Module for Laravel
Favicon
Reflecting on 2024: From CodeIgniter to Laravel and Building Integrated Solutions
Favicon
Host Header Injection in Laravel: Risks and Prevention
Favicon
CodeIgniter Monitoring Library ā€“ Born from Understanding Real Developer Needs

Featured ones: