NovinkaZverejnili sme 50+ Laravel balíkov ako open source
Custom AI apps, agents and automation — Roundly ConsultingRoundly
Všetky balíky

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ódaPrejde, 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 dispute

Payloady 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 kryptomien

Odoslaní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.