Chapters
35 Chapters
|
3:22:53
|
This course is archived!
This tutorial uses an older version of Symfony of the stripe-php SDK. The majority of the concepts are still valid, though there *are* differences. We've done our best to add notes & comments that describe these changes.
Login to bookmark this video
-
Course Code
Subscribe to download the code!Compatible PHP versions: >=5.5.9, <7.4
Subscribe to download the code!Compatible PHP versions: >=5.5.9, <7.4
-
This Video
Subscribe to download the video!
Subscribe to download the video!
-
Course Script
Subscribe to download the script!
Subscribe to download the script!
18.
Testing Part 2: Faking the Event Lookup
Scroll down to the script below, click on any sentence (including terminal blocks) to jump to that spot in the video!
Subscribe to jump to this part in the video!
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
This tutorial uses an older version of Symfony of the stripe-php SDK. The majority of the concepts are still valid, though there *are* differences. We've done our best to add notes & comments that describe these changes.
What PHP libraries does this tutorial use?
// composer.json
{
"require": {
"php": ">=5.5.9, <7.4",
"symfony/symfony": "3.1.*", // v3.1.10
"doctrine/orm": "^2.5", // v2.7.2
"doctrine/doctrine-bundle": "^1.6", // 1.6.8
"doctrine/doctrine-cache-bundle": "^1.2", // 1.3.0
"symfony/swiftmailer-bundle": "^2.3", // v2.6.2
"symfony/monolog-bundle": "^2.8", // v2.12.1
"symfony/polyfill-apcu": "^1.0", // v1.3.0
"sensio/distribution-bundle": "^5.0", // v5.0.22
"sensio/framework-extra-bundle": "^3.0.2", // v3.0.26
"incenteev/composer-parameter-handler": "^2.0", // v2.1.2
"friendsofsymfony/user-bundle": "~2.0.1", // v2.0.1
"stof/doctrine-extensions-bundle": "^1.2", // v1.2.2
"stripe/stripe-php": "^3.15", // v3.23.0
"doctrine/doctrine-migrations-bundle": "^1.1", // v1.2.1
"phpunit/phpunit": "^5.5", // 5.7.20
"composer/package-versions-deprecated": "^1.11" // 1.11.99
},
"require-dev": {
"sensio/generator-bundle": "^3.0", // v3.1.4
"symfony/phpunit-bridge": "^3.0", // v3.3.0
"hautelook/alice-bundle": "^1.3", // v1.4.1
"doctrine/data-fixtures": "^1.2" // v1.2.2
}
}
17 Comments
Hello, I try to make the test on Symfony 4.
My WebhookControllerTest seems https://pastebin.com/kGTXLXPG
But when I run test with
php bin/phpunit --filter testStripeCustomerSubscriptionDeletedI've this error :
Fatal error: Cannot redeclare static Symfony\Bundle\FrameworkBundle\Test\WebTestCase::$container as non static App\Tests\Controller\WebhookControllerTest::$container in C:\Users\user\Desktop\StripeFormation2\tests\Controller\WebhookControllerTest.php on <br />line 11Hey Kiuega
Your problem is at line 20. You are trying to re-define the
$containerproperty or your test class. Instead of using a property use a local variable and it should workCheers!
Okay, I have analyzed the problems I encounter.
https://pastebin.com/j0k8KPTC
[2020-01-23 15:16:16] request.CRITICAL: Uncaught PHP Exception Exception: "There seems to be no subscription ID sub_00000000000000"
On the one hand, it seems that I can't get the manager, because he couldn't flush the subscription if I can't get it back.
Is my way to get the manager correct in my setUp () function? Besides, I noticed that when I dump after the self :: bootKernel (), it doesn't display. But if I do it before, it works. Similarly in the other functions of the class, my dumps do not pass
Hey Kiuega!
The way you're doing it should be correct. However, you shouldn't need to have the
public static $containeron your class. This property is already implemented on a parent class as a protected static property - so the code should work the same without it. And setting the$emon a property might be ok... but it's a bit safer to get this property (fromself::$container->get('doctrine')->getManager()) whenever you needed it. In some cases, after making a request with the Client, you'll need to ask for the entity manager again. Otherwise, you'll (kind of) still be using the "old" one from the "previous request" and you can get some odd results.I'm familiar with this too :). When Symfony boots, it does some magic with dump(). This is usually cool magic, but in the case of tests, I find that it often means that the dump is hidden, which I don't actually want. I often use var_dump() in tests to make sure that I see my dumped output. That should help you debug.
Let us know how it's going!
Cheers!
Thank you for your reply ! I have made good progress on debugging. I still have a few concerns, well, especially a big one.
Since I'm on Symfony 4, the way to handle environment variables is not the same.
To be able to use the variable<b> "VERIFY_STRIPE_EVENT",</b> I therefore did simply like this:
In my <b>.env</b>, I set it to <b>true</b>.
In my <b>.env.test</b>, I set it to <b>false</b>.
That's all i did. And in my controller, if I do a
<b>$logger->info(getenv("VERIFY_STRIPE_EVENT"));</b>I've always an empty result.PS: Sorry for my bad english, I'm French
Hey Kiuega !
You did perfectly with setting up the environment variable. Nice job!
So, I would expect it to work. And... it might be working - the problem with logging is that the "true" and "false" values will both print as empty strings. You could try this:
That should print "true" or "false". There is one other detail. I don't think this is causing the issue, but it is something I want to mention. You typically don't reference environment variables in your code with
getenv. It's not a huge deal, but you're supposed to inject these as normal variables. The easiest way to do this is with a "bind":With this, you can now have a
$shouldVerifyStripeEventargument to any controller or as an argument to any service constructor and Symfony will pass you the environment variable.Let us know if this helps!
Cheers!
Okay ! So, the good line, I think; was :
$logger->info(var_export(getenv("VERIFY_STRIPE_EVENT"), true));It's okay, I've now the good thing in my log !
Next, for the bind, great! However, I did not understand how I can retrieve the variable from my controller?
With this code
Hey Kiuega!
You can add it as an argument to any controller method in your system:
That's it! The variable must be called
$shouldVerifyStripeEventbecause that's what you set up in your bind.Ah, actually, I think there is a problem with how you're setting the env var - and I missed it before. In
.envand.env.testuse the values "0" and "1" instead of true and false. Environment variables are always strings - that's just the nature of how they work. So using true/false will be the strings true/false, which both should actually look "true".Yea, it's super ugly :p. For
inline code like this, surround the code with <code> and </code>. For multiline code, you need to almost do the same thing, but you need to use both <pre><code> in the beginning and </code></pre> at the end... which is ugly (but then the code looks great!).Cheers!
Perfect man! I was just writing a comment on using 0 and 1 instead of true and false!
And yes it worked!
I'll take care of putting everything back in order and I'll tell you about some things to worry about (but safe it would seem)!
EDIT : Perfect man ! We are done ! Thanks ! So, the final output : https://zupimages.net/up/20/04/vqro.png
There are some errors, but which do not seem to bother. One of which concerns Doctrine and the method -> flush (). But in the test, at no time did I give an argument, so it's weird. (And by the way, very annoying that this way of doing things is deprecated)
Next, I have the answer, so perfect it confirms that the test is a success compared to our expectations.
Now, the final files, but which certainly contain a few lines that I could have done better:
<b>WebhookController.php :</b> https://pastebin.com/VgSMHg8z
<b>WebhookControllerTest.php :</b> https://pastebin.com/8icisnj8
<b>.env :</b>
VERIFY_STRIPE_EVENT=1<b>.env.test :</b>
VERIFY_STRIPE_EVENT=0<b>services.yaml:</b>
I try to rework this in Flex and Symfony 4.
At the end of this leg when I run ./vendor/bin/simple-phpunit --filter testStripeCustomerSubscriptionDeleted I should have green colors. But test doesn't pass. I still have 500 status code instead of 200 status code failure.
I have the repo at address https://github.com/petre-sy.... As far as I can see ./vendor/bin/simple-phpunit --filter testStripeCustomerSubscriptionDeleted doesn't hit https://localhost:8000. I think that's the problem. Probably I must set some parameter base-url or something like that somewhere but I can't really grasp where this setting must be put.
Cheers
Hey Diaconescu,
Look at logs! You can tail them with:
$ tail -f var/log/test.log
Most probably you just set up Stripe credentials wrong or forget to set up them at all :)
Cheers!
tail -f var/log/test.log produce something like this:
request.CRITICAL: Uncaught PHP Exception Symfony\Component\DependencyInjection\Exception\EnvNotFoundException: "Environment variable not found: "STRIPE_SECRET_KEY"." at /home/petrero/www/Stripe_Subscriptions_Discounts_Webhooks/vendor/symfony/dependency-injection/EnvVarProcessor.php line 96 {"exception":"[object] (Symfony\\Component\\DependencyInjection\\Exception\\EnvNotFoundException(code: 0): Environment variable not found: \"STRIPE_SECRET_KEY\". at /home/petrero/www/Stripe_Subscriptions_Discounts_Webhooks/vendor/symfony/dependency-injection/EnvVarProcessor.php:96)"} []
I have in .env.local something like so:
STRIPE_PUBLIC_KEY=.*****************
STRIPE_SECRET_KEY=*****************
In services.yaml:
# This file is the entry point to configure your own services.
# Files in the packages/ subdirectory configure your dependencies.
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/cur...
parameters:
locale: 'en'
stripe_public_key: '%env(STRIPE_PUBLIC_KEY)%'
stripe_secret_key: '%env(STRIPE_SECRET_KEY)%'
verify_stripe_event: '%env(VERIFY_STRIPE_EVENT)%'
In StripeClient.php I have:
class StripeClient {
/**
* @var EntityManagerInterface
*/
private $em;
public function __construct($secretKey, EntityManagerInterface $em){
$this->em = $em;
\Stripe\Stripe::setApiKey($secretKey);
}
public function createCustomer(User $user, $paymentToken){
$customer = \Stripe\Customer::create([
"email" => $user->getEmail(),
"source" => $paymentToken // obtained with Stripe.js
]);
Acordingly to tail -f var/log/test.log you seem to be right. But why this settings doesn't present any problem in web interface? Because in web interface I could charge the credit card, I could update the credit card, I could cancel a subscription, I could reactivate a subscription, I could apply for a subscription. Why all of this work? They are dependent on STRIPE_SECRET_KEY too
Hey Diaconescu
This happens only when running your tests, right? That's because env vars are isolated from environmets. You will have to create a new
.env.testfile and duplicate your env vars thereYou was right about duplicating env. vars in env.test file. Errors about STRIPE_SECRET_KEY disappeared, but I can't get rid of 'No such event: evt_00000000000000' critical error.
I have in .env.test:
VERIFY_STRIPE_EVENT=false
STRIPE_PUBLIC_KEY=********************************
STRIPE_SECRET_KEY=********************************
I have in .env.local:
STRIPE_PUBLIC_KEY=***************************************
STRIPE_SECRET_KEY=***************************************
VERIFY_STRIPE_EVENT=true
I have in services.yaml:
parameters:
locale: 'en'
stripe_public_key: '%env(STRIPE_PUBLIC_KEY)%'
stripe_secret_key: '%env(STRIPE_SECRET_KEY)%'
verify_stripe_event: '%env(VERIFY_STRIPE_EVENT)%'
In WebhookController I have:
if($this->getParameter('verify_stripe_event')){
$stripeEvent = $this->stripeClient->findEvent($eventId);
} else {
//fake the stripe event in the test environment
$stripeEvent = json_decode($request->getContent());
}
Hmm, that's weird, is there a stack trace? I would like to see it
Anyway, try adding this env vars to your
.env.testfileFirst 2 lines were already there. i added the last 1.
The complete result of tail -f var/log/test.log is:
[2019-06-11 17:41:20] doctrine.DEBUG: "START TRANSACTION" [] []
[2019-06-11 17:41:20] doctrine.DEBUG: INSERT INTO user (stripe_customer_id, email, roles, password, card_brand, card_last4) VALUES (?, ?, ?, ?, ?, ?) {"1":null,"2":"fluffy1878526223@sheep.com","3":[],"4":"$2y$13$7nBZfmwsPQNjSImNJQS [...]","5":null,"6":null} []
[2019-06-11 17:41:20] doctrine.DEBUG: INSERT INTO subscription (stripe_subscription_id, stripe_plan_id, ends_at, billing_period_ends_at, user_id) VALUES (?, ?, ?, ?, ?) {"1":"sub_STRIPE_TEST_XYZ1183136485","2":"plan_STRIPE_TEST_ABC499083006","3":null,"4":"2019-07-11 17:41:20","5":22} []
[2019-06-11 17:41:20] doctrine.DEBUG: "COMMIT" [] []
[2019-06-11 17:41:21] request.INFO: Matched route "webhook_stripe". {"route":"webhook_stripe","route_parameters":{"_route":"webhook_stripe","_controller":"App\\Controller\\WebhookController::stripeWebhookAction"},"request_uri":"http://localhost/webhooks/stripe","method":"POST"} []
[2019-06-11 17:41:21] security.DEBUG: Checking for guard authentication credentials. {"firewall_key":"main","authenticators":1} []
[2019-06-11 17:41:21] security.DEBUG: Checking support on guard authenticator. {"firewall_key":"main","authenticator":"App\\Security\\LoginAuthenticator"} []
[2019-06-11 17:41:21] security.DEBUG: Guard authenticator does not support the request. {"firewall_key":"main","authenticator":"App\\Security\\LoginAuthenticator"} []
[2019-06-11 17:41:21] security.INFO: Populated the TokenStorage with an anonymous Token. [] []
[2019-06-11 17:41:22] request.CRITICAL: Uncaught PHP Exception Stripe\Error\InvalidRequest: "No such event: evt_00000000000000" at /home/petrero/www/Stripe_Subscriptions_Discounts_Webhooks/vendor/stripe/stripe-php/lib/ApiRequestor.php line 210 {"exception":"[object] (Stripe\\Error\\InvalidRequest(code: 0): No such event: evt_00000000000000 at /home/petrero/www/Stripe_Subscriptions_Discounts_Webhooks/vendor/stripe/stripe-php/lib/ApiRequestor.php:210)"} []
Ok, so it's hitting Stripe's API the thing is such event does not exist on your Stripe account. Check your test code, probably the subscription id doesn't exist
"Houston: no signs of life"
Start the conversation!