diff --git a/.gitattributes b/.gitattributes
index 47b98cc..2b49341 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -4,9 +4,8 @@
# Ignore all test and documentation with "export-ignore".
/.gitattributes export-ignore
/.gitignore export-ignore
-/.travis.yml export-ignore
-/phpunit.xml.dist export-ignore
-/.scrutinizer.yml export-ignore
+/.github export-ignore
+/phpunit.xml export-ignore
/.styleci.yml export-ignore
/tests export-ignore
/.editorconfig export-ignore
\ No newline at end of file
diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml
new file mode 100644
index 0000000..e7bfd77
--- /dev/null
+++ b/.github/workflows/run-tests.yml
@@ -0,0 +1,48 @@
+name: Tests
+
+on:
+ push:
+ branches: [master]
+ pull_request:
+ branches: [master]
+
+jobs:
+ tests:
+ runs-on: ubuntu-latest
+
+ strategy:
+ fail-fast: false
+ matrix:
+ php: ['8.2', '8.3', '8.4']
+ laravel: [12, 13]
+ dependency-version: [prefer-lowest, prefer-stable]
+ include:
+ - laravel: 12
+ testbench: 10
+ - laravel: 13
+ testbench: 11
+ exclude:
+ # Laravel 13 requires PHP 8.3+
+ - laravel: 13
+ php: '8.2'
+
+ name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }} - ${{ matrix.dependency-version }}
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php }}
+ extensions: curl, json, mbstring
+ coverage: none
+
+ - name: Install dependencies
+ run: |
+ composer require "orchestra/testbench:^${{ matrix.testbench }}" --dev --no-interaction --no-update
+ composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-progress
+
+ - name: Run tests
+ run: vendor/bin/phpunit
diff --git a/.scrutinizer.yml b/.scrutinizer.yml
deleted file mode 100644
index ebf9543..0000000
--- a/.scrutinizer.yml
+++ /dev/null
@@ -1,23 +0,0 @@
-checks:
- php:
- remove_extra_empty_lines: true
- remove_php_closing_tag: true
- remove_trailing_whitespace: true
- fix_use_statements:
- remove_unused: true
- preserve_multiple: false
- preserve_blanklines: true
- order_alphabetically: true
- fix_php_opening_tag: true
- fix_linefeed: true
- fix_line_ending: true
- fix_identation_4spaces: true
- fix_doc_comments: true
-
-
-build:
- nodes:
- analysis:
- tests:
- override:
- - php-scrutinizer-run
diff --git a/changelog.md b/changelog.md
index 6b345bb..fb41bed 100644
--- a/changelog.md
+++ b/changelog.md
@@ -2,6 +2,24 @@
All notable changes to `AmazonGiftCode` will be documented in this file.
+## Version 2.0 - 2026-06-12
+
+### Added
+- Support for Laravel 13.
+- Test suite (PHPUnit + Orchestra Testbench) covering config, request signing, response parsing and the public API.
+- GitHub Actions CI matrix across Laravel 12/13 on PHP 8.2 to 8.4.
+
+### Changed
+- `AWS` and `AmazonGiftCode` now accept an optional `ClientInterface`, allowing the HTTP layer to be substituted (defaults to the existing cURL client, so behavior is unchanged).
+
+### Fixed
+- `CreateResponse` and `CreateBalanceResponse` no longer raise an undefined-key error when Amazon returns a body without the `cardInfo` / `availableFunds` keys (for example error responses).
+
+### Removed
+- Scrutinizer CI configuration (replaced by GitHub Actions).
+- `sempro/phpunit-pretty-print` dev dependency (incompatible with PHPUnit 10+).
+- Laravel 11 from the CI matrix and dev dependencies; it is past its security support window and is blocked by Composer's advisory policy. It remains installable for existing users via the `illuminate/support` constraint.
+
## Version 1.0
### Added
diff --git a/composer.json b/composer.json
index dce5423..68bfe9f 100644
--- a/composer.json
+++ b/composer.json
@@ -20,13 +20,14 @@
"Amazon Incentives API"
],
"require": {
- "illuminate/support": "~5|^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0"
+ "illuminate/support": "~5|^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0|^13.0"
},
"require-dev": {
- "phpunit/phpunit": "~7.0|~8.0|^10.5|^11.0",
- "mockery/mockery": "^1.1",
- "orchestra/testbench": "~3.0|^9.0",
- "sempro/phpunit-pretty-print": "^1.0"
+ "phpunit/phpunit": "^10.5|^11.0|^12.5.12",
+ "orchestra/testbench": "^10.0|^11.0"
+ },
+ "scripts": {
+ "test": "vendor/bin/phpunit"
},
"autoload": {
"psr-4": {
diff --git a/phpunit.xml b/phpunit.xml
index ce34605..b62cc30 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -1,22 +1,18 @@
-
+ failOnWarning="true"
+ failOnRisky="true">
- ./tests/
+ ./tests/
-
-
- src/
-
-
+
+
+ src/
+
+
diff --git a/readme.md b/readme.md
index f22f206..729f79e 100644
--- a/readme.md
+++ b/readme.md
@@ -3,9 +3,7 @@
-[](https://scrutinizer-ci.com/g/kamerk22/AmazonGiftCode/?branch=master)
-[](https://scrutinizer-ci.com/g/kamerk22/AmazonGiftCode/build-status/master)
-[](https://scrutinizer-ci.com/code-intelligence)
+[](https://github.com/kamerk22/AmazonGiftCode/actions/workflows/run-tests.yml)
[![Latest Version on Packagist][ico-version]][link-packagist]
[![Total Downloads][ico-downloads]][link-downloads]
@@ -14,6 +12,13 @@ AmazonGiftCode is Laravel package for Amazon Gift Codes On Demand (AGCOD). Integ
This package will give you a simplest APIs to Create/Cancel Amazon Gift Code On Demand.
+## Requirements
+
+- PHP 8.2 or higher (PHP 8.3+ for Laravel 13)
+- Laravel 12 or 13
+
+Older Laravel versions (5 to 11) remain installable, but the test suite and CI target 12 and 13. Laravel 11 and below are past their security support window.
+
## Installation
You can install this package via Composer.
@@ -215,6 +220,14 @@ Get the raw JSON response. (original response)
$rawJson = $aws->getRawJson();
```
+## Testing
+
+``` bash
+$ composer test
+```
+
+The test suite runs against Laravel 12 and 13 on PHP 8.2 to 8.4 (Laravel 13 requires PHP 8.3+).
+
## Change log
Please see the [changelog](changelog.md) for more information on what has changed recently.
diff --git a/src/AWS/AWS.php b/src/AWS/AWS.php
index 77de709..501dd3b 100644
--- a/src/AWS/AWS.php
+++ b/src/AWS/AWS.php
@@ -11,6 +11,7 @@
use kamerk22\AmazonGiftCode\Client\Client;
+use kamerk22\AmazonGiftCode\Client\ClientInterface;
use kamerk22\AmazonGiftCode\Config\Config;
use kamerk22\AmazonGiftCode\Exceptions\AmazonErrors;
use kamerk22\AmazonGiftCode\Response\CancelResponse;
@@ -35,14 +36,23 @@ class AWS
private $_config;
+ /**
+ * @var ClientInterface
+ */
+ private $_client;
+
/**
* AWS constructor.
+ *
* @param Config $config
+ * @param ClientInterface|null $client Optional HTTP client. Defaults to the
+ * cURL-based Client; inject a fake for testing.
*/
- public function __construct(Config $config)
+ public function __construct(Config $config, ?ClientInterface $client = null)
{
$this->_config = $config;
+ $this->_client = $client ?: new Client();
}
@@ -124,7 +134,7 @@ public function makeRequest($payload, $canonicalRequest, $serviceOperation, $dat
$url = 'https://' . $endpoint . '/' . $serviceOperation;
$headers = $this->buildHeaders($payload, $authorizationValue, $dateTimeString, $serviceTarget);
- return (new Client())->request($url, $headers, $payload);
+ return $this->_client->request($url, $headers, $payload);
}
/**
diff --git a/src/AmazonGiftCode.php b/src/AmazonGiftCode.php
index bfc696f..a339c09 100644
--- a/src/AmazonGiftCode.php
+++ b/src/AmazonGiftCode.php
@@ -3,6 +3,7 @@
namespace kamerk22\AmazonGiftCode;
use kamerk22\AmazonGiftCode\AWS\AWS;
+use kamerk22\AmazonGiftCode\Client\ClientInterface;
use kamerk22\AmazonGiftCode\Config\Config;
use kamerk22\AmazonGiftCode\Exceptions\AmazonErrors;
@@ -11,6 +12,11 @@ class AmazonGiftCode
private $_config;
+ /**
+ * @var ClientInterface|null
+ */
+ private $_client;
+
/**
* AmazonGiftCode constructor.
*
@@ -19,10 +25,13 @@ class AmazonGiftCode
* @param null $partner
* @param null $endpoint
* @param null $currency
+ * @param ClientInterface|null $client Optional HTTP client. Defaults to the
+ * cURL-based Client; inject a fake for testing.
*/
- public function __construct($key = null, $secret = null, $partner = null, $endpoint = null, $currency = null)
+ public function __construct($key = null, $secret = null, $partner = null, $endpoint = null, $currency = null, ?ClientInterface $client = null)
{
$this->_config = new Config($key, $secret, $partner, $endpoint, $currency);
+ $this->_client = $client;
}
/**
@@ -32,9 +41,9 @@ public function __construct($key = null, $secret = null, $partner = null, $endpo
*
* @throws AmazonErrors
*/
- public function buyGiftCard(Float $value, string $creationRequestId = null): Response\CreateResponse
+ public function buyGiftCard(Float $value, ?string $creationRequestId = null): Response\CreateResponse
{
- return (new AWS($this->_config))->getCode($value, $creationRequestId);
+ return (new AWS($this->_config, $this->_client))->getCode($value, $creationRequestId);
}
@@ -45,7 +54,7 @@ public function buyGiftCard(Float $value, string $creationRequestId = null): Res
*/
public function cancelGiftCard(string $creationRequestId, string $gcId): Response\CancelResponse
{
- return (new AWS($this->_config))->cancelCode($creationRequestId, $gcId);
+ return (new AWS($this->_config, $this->_client))->cancelCode($creationRequestId, $gcId);
}
/**
@@ -55,7 +64,7 @@ public function cancelGiftCard(string $creationRequestId, string $gcId): Respons
*/
public function getAvailableFunds(): Response\CreateBalanceResponse
{
- return (new AWS($this->_config))->getBalance();
+ return (new AWS($this->_config, $this->_client))->getBalance();
}
/**
diff --git a/src/Response/CreateBalanceResponse.php b/src/Response/CreateBalanceResponse.php
index 70c287b..1299d6f 100644
--- a/src/Response/CreateBalanceResponse.php
+++ b/src/Response/CreateBalanceResponse.php
@@ -105,10 +105,10 @@ public function parseJsonResponse($jsonResponse): self
if (!is_array($jsonResponse)) {
throw new \RuntimeException('Response must be a scalar value');
}
- if (array_key_exists('amount', $jsonResponse['availableFunds'])) {
+ if (isset($jsonResponse['availableFunds']['amount'])) {
$this->_amount = $jsonResponse['availableFunds']['amount'];
}
- if (array_key_exists('currencyCode', $jsonResponse['availableFunds'])) {
+ if (isset($jsonResponse['availableFunds']['currencyCode'])) {
$this->_currency = $jsonResponse['availableFunds']['currencyCode'];
}
if (array_key_exists('status', $jsonResponse)) {
diff --git a/src/Response/CreateResponse.php b/src/Response/CreateResponse.php
index d3f8d79..03c7f8b 100644
--- a/src/Response/CreateResponse.php
+++ b/src/Response/CreateResponse.php
@@ -176,16 +176,16 @@ public function parseJsonResponse($jsonResponse): self
if (array_key_exists('gcClaimCode', $jsonResponse)) {
$this->_claim_code = $jsonResponse['gcClaimCode'];
}
- if (array_key_exists('amount', $jsonResponse['cardInfo']['value'])) {
+ if (isset($jsonResponse['cardInfo']['value']['amount'])) {
$this->_value = $jsonResponse['cardInfo']['value']['amount'];
}
- if (array_key_exists('currencyCode', $jsonResponse['cardInfo']['value'])) {
+ if (isset($jsonResponse['cardInfo']['value']['currencyCode'])) {
$this->_currency = $jsonResponse['cardInfo']['value']['currencyCode'];
}
if (array_key_exists('gcExpirationDate', $jsonResponse)) {
$this->_expiration_date = $jsonResponse['gcExpirationDate'];
}
- if (array_key_exists('cardStatus', $jsonResponse['cardInfo'])) {
+ if (isset($jsonResponse['cardInfo']['cardStatus'])) {
$this->_card_status = $jsonResponse['cardInfo']['cardStatus'];
}
diff --git a/tests/AmazonGiftCodeTest.php b/tests/AmazonGiftCodeTest.php
new file mode 100644
index 0000000..bfebffa
--- /dev/null
+++ b/tests/AmazonGiftCodeTest.php
@@ -0,0 +1,76 @@
+ client -> response-parse path is exercised without network.
+ */
+class AmazonGiftCodeTest extends TestCase
+{
+ private function giftCode(FakeClient $client): AmazonGiftCode
+ {
+ return new AmazonGiftCode(null, null, null, null, null, $client);
+ }
+
+ public function test_buy_gift_card_returns_parsed_create_response(): void
+ {
+ $client = new FakeClient(json_encode([
+ 'cardInfo' => [
+ 'cardStatus' => 'Fulfilled',
+ 'value' => ['amount' => 25, 'currencyCode' => 'USD'],
+ ],
+ 'creationRequestId' => 'Examp_abc',
+ 'gcClaimCode' => 'WXYZ-123456-ABCD',
+ 'gcExpirationDate' => '2030-01-01T00:00:00Z',
+ 'gcId' => 'A2ZACI3RGNN4FB',
+ 'status' => 'SUCCESS',
+ ]));
+
+ $response = $this->giftCode($client)->buyGiftCard(25.0, 'Examp_abc');
+
+ $this->assertInstanceOf(CreateResponse::class, $response);
+ $this->assertSame('WXYZ-123456-ABCD', $response->getClaimCode());
+ $this->assertSame('25', $response->getValue());
+
+ // The request was signed and aimed at the configured endpoint/operation.
+ $this->assertSame('https://agcod-v2-gamma.amazon.com/CreateGiftCard', $client->lastUrl);
+ $this->assertSame('Examp_abc', json_decode($client->lastParams, true)['creationRequestId']);
+ }
+
+ public function test_cancel_gift_card_returns_parsed_cancel_response(): void
+ {
+ $client = new FakeClient(json_encode([
+ 'creationRequestId' => 'Examp_abc',
+ 'gcId' => 'A2ZACI3RGNN4FB',
+ 'status' => 'SUCCESS',
+ ]));
+
+ $response = $this->giftCode($client)->cancelGiftCard('Examp_abc', 'A2ZACI3RGNN4FB');
+
+ $this->assertInstanceOf(CancelResponse::class, $response);
+ $this->assertSame('A2ZACI3RGNN4FB', $response->getId());
+ $this->assertSame('https://agcod-v2-gamma.amazon.com/CancelGiftCard', $client->lastUrl);
+ }
+
+ public function test_get_available_funds_returns_parsed_balance_response(): void
+ {
+ $client = new FakeClient(json_encode([
+ 'availableFunds' => ['amount' => 5000, 'currencyCode' => 'USD'],
+ 'status' => 'SUCCESS',
+ 'timestamp' => '20240101T000000Z',
+ ]));
+
+ $response = $this->giftCode($client)->getAvailableFunds();
+
+ $this->assertInstanceOf(CreateBalanceResponse::class, $response);
+ $this->assertSame('5000', $response->getAmount());
+ $this->assertSame('https://agcod-v2-gamma.amazon.com/GetAvailableFunds', $client->lastUrl);
+ }
+}
diff --git a/tests/AwsSignatureTest.php b/tests/AwsSignatureTest.php
new file mode 100644
index 0000000..6bdba37
--- /dev/null
+++ b/tests/AwsSignatureTest.php
@@ -0,0 +1,97 @@
+assertSame($expectedRegion, $this->aws($endpoint)->getRegion());
+ }
+
+ public static function regionProvider(): array
+ {
+ return [
+ 'na production' => ['https://agcod-v2.amazon.com', 'us-east-1'],
+ 'na sandbox' => ['https://agcod-v2-gamma.amazon.com', 'us-east-1'],
+ 'eu production' => ['https://agcod-v2-eu.amazon.com', 'eu-west-1'],
+ 'eu sandbox' => ['https://agcod-v2-eu-gamma.amazon.com', 'eu-west-1'],
+ 'fe production' => ['https://agcod-v2-fe.amazon.com', 'us-west-2'],
+ 'fe sandbox' => ['https://agcod-v2-fe-gamma.amazon.com', 'us-west-2'],
+ ];
+ }
+
+ public function test_gift_card_payload_has_expected_shape(): void
+ {
+ $payload = json_decode($this->aws()->getGiftCardPayload('10.00', 'req-1'), true);
+
+ $this->assertSame('req-1', $payload['creationRequestId']);
+ $this->assertSame('Examp', $payload['partnerId']);
+ $this->assertSame('USD', $payload['value']['currencyCode']);
+ $this->assertEquals(10, $payload['value']['amount']);
+ }
+
+ public function test_gift_card_payload_generates_creation_id_when_missing(): void
+ {
+ $payload = json_decode($this->aws()->getGiftCardPayload('5'), true);
+
+ $this->assertStringStartsWith('Examp_', $payload['creationRequestId']);
+ }
+
+ public function test_cancel_payload_has_expected_shape(): void
+ {
+ $payload = json_decode($this->aws()->getCancelGiftCardPayload('req-1', 'gc-1'), true);
+
+ $this->assertSame('req-1', $payload['creationRequestId']);
+ $this->assertSame('Examp', $payload['partnerId']);
+ $this->assertSame('gc-1', $payload['gcId']);
+ }
+
+ public function test_available_funds_payload_has_expected_shape(): void
+ {
+ $payload = json_decode($this->aws()->getAvailableFundsPayload(), true);
+
+ $this->assertSame(['partnerId' => 'Examp'], $payload);
+ }
+
+ public function test_build_hash_is_sha256_hex(): void
+ {
+ $this->assertSame(hash('sha256', 'payload'), $this->aws()->buildHash('payload'));
+ }
+
+ public function test_hmac_matches_php_reference(): void
+ {
+ $aws = $this->aws();
+
+ $this->assertSame(hash_hmac('sha256', 'data', 'key', false), $aws->hmac('data', 'key', false));
+ $this->assertSame(hash_hmac('sha256', 'data', 'key', true), $aws->hmac('data', 'key', true));
+ }
+
+ public function test_canonical_request_targets_the_operation(): void
+ {
+ $canonical = $this->aws()->getCanonicalRequest('CreateGiftCard', '{}');
+
+ $this->assertStringStartsWith("POST\n/CreateGiftCard\n", $canonical);
+ $this->assertStringContainsString('host:agcod-v2-gamma.amazon.com', $canonical);
+ $this->assertStringEndsWith(hash('sha256', '{}'), $canonical);
+ }
+
+ public function test_string_to_sign_uses_sigv4_scope(): void
+ {
+ $stringToSign = $this->aws()->buildStringToSign('abc123');
+
+ $this->assertStringStartsWith("AWS4-HMAC-SHA256\n", $stringToSign);
+ $this->assertStringContainsString('us-east-1/AGCODService/aws4_request', $stringToSign);
+ $this->assertStringEndsWith("\nabc123", $stringToSign);
+ }
+}
diff --git a/tests/ConfigTest.php b/tests/ConfigTest.php
new file mode 100644
index 0000000..f1d9c2b
--- /dev/null
+++ b/tests/ConfigTest.php
@@ -0,0 +1,43 @@
+assertSame('key', $config->getAccessKey());
+ $this->assertSame('secret', $config->getSecret());
+ $this->assertSame('Partn', $config->getPartner());
+ $this->assertSame('EUR', $config->getCurrency());
+ }
+
+ public function test_it_falls_back_to_laravel_config_when_values_are_null(): void
+ {
+ $config = new Config(null, null, null, null, null);
+
+ $this->assertSame('AKIAIOSFODNN7EXAMPLE', $config->getAccessKey());
+ $this->assertSame('wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY', $config->getSecret());
+ $this->assertSame('Examp', $config->getPartner());
+ $this->assertSame('USD', $config->getCurrency());
+ }
+
+ public function test_set_endpoint_extracts_host_from_url(): void
+ {
+ $config = new Config('k', 's', 'p', 'https://agcod-v2-gamma.amazon.com', 'USD');
+
+ $this->assertSame('agcod-v2-gamma.amazon.com', $config->getEndpoint());
+ }
+
+ public function test_setters_are_fluent(): void
+ {
+ $config = new Config('k', 's', 'p', 'https://agcod-v2.amazon.com', 'USD');
+
+ $this->assertSame($config, $config->setCurrency('CAD'));
+ $this->assertSame('CAD', $config->getCurrency());
+ }
+}
diff --git a/tests/ResponseTest.php b/tests/ResponseTest.php
new file mode 100644
index 0000000..ba26660
--- /dev/null
+++ b/tests/ResponseTest.php
@@ -0,0 +1,96 @@
+ [
+ 'cardNumber' => null,
+ 'cardStatus' => 'Fulfilled',
+ 'value' => ['amount' => 10, 'currencyCode' => 'USD'],
+ ],
+ 'creationRequestId' => 'Examp_123',
+ 'gcClaimCode' => 'ABCD-EFGHIJ-KLMN',
+ 'gcExpirationDate' => '2030-01-01T00:00:00Z',
+ 'gcId' => 'A2ZACI3RGNN4FB',
+ 'status' => 'SUCCESS',
+ ];
+ }
+
+ public function test_create_response_exposes_card_details(): void
+ {
+ $response = new CreateResponse($this->createPayload());
+
+ $this->assertSame('A2ZACI3RGNN4FB', $response->getId());
+ $this->assertSame('Examp_123', $response->getCreationRequestId());
+ $this->assertSame('ABCD-EFGHIJ-KLMN', $response->getClaimCode());
+ $this->assertSame('10', $response->getValue());
+ $this->assertSame('USD', $response->getCurrency());
+ $this->assertSame('2030-01-01T00:00:00Z', $response->getExpirationDate());
+ $this->assertSame('Fulfilled', $response->getCardStatus());
+ $this->assertJson($response->getRawJson());
+ }
+
+ public function test_create_response_rejects_non_array_payload(): void
+ {
+ $this->expectException(\RuntimeException::class);
+ $this->expectExceptionMessage('Response must be a scalar value');
+
+ new CreateResponse('not-an-array');
+ }
+
+ public function test_create_response_tolerates_missing_card_info(): void
+ {
+ // Amazon may return an error-shaped body without cardInfo; parsing it
+ // must not raise an undefined-key error.
+ $response = new CreateResponse([
+ 'creationRequestId' => 'Examp_123',
+ 'status' => 'FAILURE',
+ ]);
+
+ $this->assertSame('Examp_123', $response->getCreationRequestId());
+ }
+
+ public function test_balance_response_tolerates_missing_available_funds(): void
+ {
+ $response = new CreateBalanceResponse([
+ 'status' => 'FAILURE',
+ ]);
+
+ $this->assertSame('FAILURE', $response->getStatus());
+ }
+
+ public function test_cancel_response_exposes_ids(): void
+ {
+ $response = new CancelResponse([
+ 'creationRequestId' => 'Examp_123',
+ 'gcId' => 'A2ZACI3RGNN4FB',
+ 'status' => 'SUCCESS',
+ ]);
+
+ $this->assertSame('A2ZACI3RGNN4FB', $response->getId());
+ $this->assertSame('Examp_123', $response->getCreationRequestId());
+ $this->assertJson($response->getRawJson());
+ }
+
+ public function test_balance_response_exposes_available_funds(): void
+ {
+ $response = new CreateBalanceResponse([
+ 'availableFunds' => ['amount' => 1000, 'currencyCode' => 'USD'],
+ 'status' => 'SUCCESS',
+ 'timestamp' => '20240101T000000Z',
+ ]);
+
+ $this->assertSame('1000', $response->getAmount());
+ $this->assertSame('USD', $response->getCurrency());
+ $this->assertSame('SUCCESS', $response->getStatus());
+ $this->assertSame('20240101T000000Z', $response->getTimestamp());
+ }
+}
diff --git a/tests/ServiceProviderTest.php b/tests/ServiceProviderTest.php
new file mode 100644
index 0000000..12dd0e8
--- /dev/null
+++ b/tests/ServiceProviderTest.php
@@ -0,0 +1,30 @@
+assertInstanceOf(AmazonGiftCode::class, $this->app->make('amazongiftcode'));
+ $this->assertSame($this->app->make('amazongiftcode'), $this->app->make('amazongiftcode'));
+ }
+
+ public function test_config_is_merged(): void
+ {
+ $this->assertSame('USD', config('amazongiftcode.currency'));
+ }
+
+ public function test_facade_resolves_to_the_service(): void
+ {
+ $this->assertInstanceOf(AmazonGiftCode::class, AmazonGiftCodeFacade::getFacadeRoot());
+ }
+
+ public function test_make_builds_a_fresh_instance(): void
+ {
+ $this->assertInstanceOf(AmazonGiftCode::class, AmazonGiftCode::make());
+ }
+}
diff --git a/tests/Support/FakeClient.php b/tests/Support/FakeClient.php
new file mode 100644
index 0000000..14d25b6
--- /dev/null
+++ b/tests/Support/FakeClient.php
@@ -0,0 +1,38 @@
+response = $response;
+ }
+
+ public function request($url, $headers, $params): string
+ {
+ $this->lastUrl = $url;
+ $this->lastHeaders = $headers;
+ $this->lastParams = $params;
+
+ return $this->response;
+ }
+}
diff --git a/tests/TestCase.php b/tests/TestCase.php
new file mode 100644
index 0000000..39d324f
--- /dev/null
+++ b/tests/TestCase.php
@@ -0,0 +1,41 @@
+
+ */
+ protected function getPackageProviders($app): array
+ {
+ return [AmazonGiftCodeServiceProvider::class];
+ }
+
+ /**
+ * @param \Illuminate\Foundation\Application $app
+ * @return array
+ */
+ protected function getPackageAliases($app): array
+ {
+ return ['AmazonGiftCode' => AmazonGiftCode::class];
+ }
+
+ /**
+ * @param \Illuminate\Foundation\Application $app
+ * @return void
+ */
+ protected function defineEnvironment($app): void
+ {
+ $app['config']->set('amazongiftcode.endpoint', 'https://agcod-v2-gamma.amazon.com');
+ $app['config']->set('amazongiftcode.key', 'AKIAIOSFODNN7EXAMPLE');
+ $app['config']->set('amazongiftcode.secret', 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY');
+ $app['config']->set('amazongiftcode.partner', 'Examp');
+ $app['config']->set('amazongiftcode.currency', 'USD');
+ }
+}