From af17f7b868de4a449c71e8609f91ed2669e055e1 Mon Sep 17 00:00:00 2001 From: Joel Male Date: Sat, 11 Apr 2026 08:15:11 +1000 Subject: [PATCH] test: add Pest test suite for LaravelGoogleShoppingFeed --- tests/LaravelGoogleShoppingFeedTest.php | 147 ++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 tests/LaravelGoogleShoppingFeedTest.php diff --git a/tests/LaravelGoogleShoppingFeedTest.php b/tests/LaravelGoogleShoppingFeedTest.php new file mode 100644 index 0000000..af99f1b --- /dev/null +++ b/tests/LaravelGoogleShoppingFeedTest.php @@ -0,0 +1,147 @@ + 'prod-1', + 'link' => 'https://example.com/product', + 'title' => 'Test Product', + 'g:price' => '29.99 AUD', + 'g:image_link' => 'https://example.com/image.jpg', + ], $overrides); +} + +describe('init', function () { + it('stores title, description, and link', function () { + $feed = LaravelGoogleShoppingFeed::init('My Store', 'My Desc', 'https://example.com'); + + expect($feed->title)->toBe('My Store') + ->and($feed->description)->toBe('My Desc') + ->and($feed->link)->toBe('https://example.com'); + }); + + it('defaults to empty strings', function () { + $feed = LaravelGoogleShoppingFeed::init(); + + expect($feed->title)->toBe('') + ->and($feed->description)->toBe('') + ->and($feed->link)->toBe(''); + }); +}); + +describe('addItem', function () { + it('accepts a valid item without throwing', function () { + $feed = LaravelGoogleShoppingFeed::init(); + $feed->addItem(validProduct()); + + expect(true)->toBeTrue(); + }); + + it('throws for missing required field', function (string $field) { + $product = validProduct(); + unset($product[$field]); + + expect(fn () => LaravelGoogleShoppingFeed::init()->addItem($product)) + ->toThrow(MissingRequiredFieldException::class); + })->with(['id', 'link', 'title', 'g:price', 'g:image_link']); + + it('throws with a message containing the field name', function () { + $product = validProduct(); + unset($product['g:price']); + + expect(fn () => LaravelGoogleShoppingFeed::init()->addItem($product)) + ->toThrow(MissingRequiredFieldException::class, "g:price"); + }); +}); + +describe('toXml', function () { + it('returns a string', function () { + $feed = LaravelGoogleShoppingFeed::init('Store', 'Desc', 'https://example.com'); + + expect(is_string($feed->toXml()))->toBeTrue(); + }); + + it('contains the RSS xmlns:g attribute', function () { + $feed = LaravelGoogleShoppingFeed::init(); + $xml = $feed->toXml(); + + expect($xml)->toContain('xmlns:g="http://base.google.com/ns/1.0"'); + }); + + it('contains the RSS version attribute', function () { + $feed = LaravelGoogleShoppingFeed::init(); + $xml = $feed->toXml(); + + expect($xml)->toContain('version="2.0"'); + }); + + it('includes the channel title, description and link', function () { + $feed = LaravelGoogleShoppingFeed::init('My Store', 'My Description', 'https://example.com'); + $xml = $feed->toXml(); + + expect($xml) + ->toContain('My Store') + ->toContain('My Description') + ->toContain('https://example.com'); + }); + + it('includes product data', function () { + $feed = LaravelGoogleShoppingFeed::init('Store', 'Desc', 'https://example.com'); + $feed->addItem(validProduct()); + $xml = $feed->toXml(); + + expect($xml) + ->toContain('prod-1') + ->toContain('Test Product'); + }); + + it('wraps products in item tags', function () { + $feed = LaravelGoogleShoppingFeed::init('Store', 'Desc', 'https://example.com'); + $feed->addItem(validProduct()); + $xml = $feed->toXml(); + + expect($xml) + ->toContain('') + ->toContain(''); + }); + + it('handles multiple products', function () { + $feed = LaravelGoogleShoppingFeed::init('Store', 'Desc', 'https://example.com'); + $feed->addItem(validProduct(['id' => 'prod-1'])); + $feed->addItem(validProduct(['id' => 'prod-2'])); + $xml = $feed->toXml(); + + expect(substr_count($xml, ''))->toBe(2) + ->and($xml)->toContain('prod-1') + ->and($xml)->toContain('prod-2'); + }); +}); + +describe('generate', function () { + it('returns an HTTP 200 response', function () { + $feed = LaravelGoogleShoppingFeed::init('Store', 'Desc', 'https://example.com'); + $response = $feed->generate(); + + expect($response->getStatusCode())->toBe(200); + }); + + it('sets the content type to application/rss+xml', function () { + $feed = LaravelGoogleShoppingFeed::init('Store', 'Desc', 'https://example.com'); + $response = $feed->generate(); + + expect($response->headers->get('Content-Type'))->toContain('application/rss+xml'); + }); + + it('returns the xml in the response body', function () { + $feed = LaravelGoogleShoppingFeed::init('Store', 'Desc', 'https://example.com'); + $feed->addItem(validProduct()); + $response = $feed->generate(); + + expect($response->getContent())->toBe($feed->toXml()); + }); +});