Testovanie
Purchases::fake() nahradí manažéra — za fasádou aj všade, kde sa injektuje PurchasesManager (webhook controller, purchases:replay, vaše vlastné služby) — spy objektom PurchasesFake a vráti ho. Zaznamená každé volanie handle(), sync() a replay() a pritom stále beží skutočný pipeline ukladania, takže sa zapíšu riadky a spustia vaše listenery (ak ich nechcete, pridajte Event::fake()). Výsledky zaradené cez push() preskočia overenie podpisu; handle() vo fake navyše vynechá auditný log aj frontu, kým sync() a replay() bežia presne ako v produkcii:
use Illuminate\Http\Request;
use RoundlyConsulting\Purchases\Facades\Purchases;
use RoundlyConsulting\Purchases\Models\Subscription;
use RoundlyConsulting\Purchases\Testing\FakeResult;
it('starts a subscription from a Stripe webhook', function () {
$fake = Purchases::fake();
$fake->push('stripe', FakeResult::subscription('stripe', 'sub_1'));
$model = Purchases::handle('stripe', Request::create('/', 'POST'));
Purchases::sync(FakeResult::purchase('apple', 'txn_1'));
expect($model)->toBeInstanceOf(Subscription::class);
$fake->assertHandled('stripe');
$fake->assertHandledCount(1);
$fake->assertSubscriptionStarted('stripe');
$fake->assertSynced('apple');
$fake->assertPurchaseRecorded('apple');
});Asercie
| Metóda | Prejde, keď / vracia |
|---|---|
push($provider, $result) | Zaradí výsledok, ktorý vráti najbližšie result() / handle() pre daného poskytovateľa — bez overenia podpisu. |
handledResults() / syncedResults() | Kolekcia všetkých výsledkov z handle() / sync() pre vlastné asercie. |
assertHandled($provider) | handle() dostalo výsledok pre daného poskytovateľa. |
assertHandledCount($count) | handle() dostalo presne $count výsledkov. |
assertNothingHandled() | handle() sa nikdy nezavolalo. |
assertSynced(?$provider) | sync() dostalo výsledok (pre daného poskytovateľa). |
assertNothingSynced() | sync() sa nikdy nezavolalo. |
assertReplayed(?$notification) | Niečo sa znova spracovalo — alebo práve táto notifikácia (model alebo id). |
assertNothingReplayed() | Nič sa znova nespracovalo. |
assertPurchaseRecorded(?$provider) | Nákup prišiel cez handle(), sync() alebo replay(). |
assertSubscriptionStarted(?$provider) | Výsledok typu predplatné prišiel ktoroukoľvek z nich. |
assertRefundRecorded(?$provider) | Refundácia alebo chargeback prišli ktoroukoľvek z nich. |
Zaznamenajú sa aj opätovné spracovania, vrátane tých, ktoré spustí príkaz:
$fake = Purchases::fake();
$this->artisan('purchases:replay', ['id' => $notification->id]); // the command injects PurchasesManager
$fake->assertReplayed($notification); // or its id; assertReplayed() alone = anything replayed
$fake->assertNothingHandled();
$fake->assertNothingSynced();Odmietnuté opätovné spracovanie sa nezaznamená. Pomocníky z HasPurchases iba čítajú, takže nezaznamenajú nič — delegujú však na manažéra, a preto používajú fake.
FakeResult
FakeResult vytvára hotové GenericResult s rozumnými predvolenými hodnotami:
use RoundlyConsulting\Purchases\Enum\Status;
use RoundlyConsulting\Purchases\Testing\FakeResult;
FakeResult::purchase('stripe', 'pi_1'); // Completed, 9.99 USD
FakeResult::purchase('apple', status: Status::Failed);
FakeResult::subscription('google', 'sub_1', Status::InGracePeriod, 'pro'); // 19.99 USD, ends in a month
FakeResult::refund('stripe', 're_1'); // reason requested_by_customer
FakeResult::refund('stripe', 'dp_1', chargeback: true); // a disputePayloady poskytovateľov
PayloadFactory vytvára surové payloady v tvare obchodov — appleNotification(), googleEnvelope(), googleSubscriptionNotification(), googleVoidedNotification() a stripeEvent() — na end-to-end testy skutočných poskytovateľov. Notifikácia Google sa po vypnutí autentifikácie pushov dekóduje bez siete; uloženie RTDN o predplatnom navyše číta subscriptionsv2, preto toto volanie nahraďte cez Http::fake():
use Illuminate\Http\Request;
use RoundlyConsulting\Purchases\Providers\Google\Google;
use RoundlyConsulting\Purchases\Testing\PayloadFactory;
it('decodes a Google renewal notification', function () {
// Proving the push came from Google is not this test's job.
config()->set('purchases.settings.google.push.authenticate', false);
$request = new Request(PayloadFactory::googleEnvelope(
PayloadFactory::googleSubscriptionNotification(type: 2, token: 'token-1'), // 2 = renewed
));
$notification = app(Google::class)->notification($request);
expect($notification->subscriptionNotification?->purchaseToken)->toBe('token-1');
});Pri Stripe podpíšte payload testovacím webhook kľúčom presne tak, ako to robí Stripe. Objektu payment_intent.* dajte výslovné pole invoice — bez neho sa balík pýta Invoice Payments API v Stripe, ktorú faktúru uhrádza:
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Event;
use RoundlyConsulting\Purchases\Events\PurchaseCompleted;
use RoundlyConsulting\Purchases\Facades\Purchases;
use RoundlyConsulting\Purchases\Testing\PayloadFactory;
it('records a signed Stripe payment', function () {
Event::fake([PurchaseCompleted::class]);
config()->set('purchases.settings.stripe.webhook_secret', 'whsec_test');
$payload = (string) json_encode(PayloadFactory::stripeEvent('payment_intent.succeeded', [
'id' => 'pi_1', 'status' => 'succeeded', 'amount' => 1000, 'currency' => 'usd',
'invoice' => null, // pays no invoice — no Invoice Payments lookup needed
]));
$timestamp = now()->getTimestamp();
$signature = hash_hmac('sha256', "{$timestamp}.{$payload}", 'whsec_test');
$request = Request::create('/', 'POST', content: $payload);
$request->headers->set('Stripe-Signature', "t={$timestamp},v1={$signature}");
$purchase = Purchases::handle('stripe', $request);
expect($purchase->price->minor())->toBe('1000');
Event::assertDispatched(PurchaseCompleted::class);
});Testy spúšťajte s načítanými publikovanými migráciami (RefreshDatabase).
Prejavte lásku k open source
Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.
Ďalšie spôsoby podpory vrátane kryptomienOdoslaním daru súhlasíte s našimi podmienkami prijímania darov.
Chcete to zabudovať do svojho produktu?
Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.