New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix 5244: Removed Email Subclasses #5271
Fix 5244: Removed Email Subclasses #5271
Conversation
@@ -4,14 +4,14 @@ | |||
* @subpackage email | |||
*/ | |||
class TestMailer extends Mailer { | |||
protected $emailsSent = array(); | |||
protected static $emailsSent = array(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is going to be problematic if running across multiple tests... creating and re-setting a new TestMailer won't flush all old emails.
I suggest keeping these as non-static if you can.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's what clearEmails
is for (flushing emails, that is)? Since TestMailer isn't enforced to be a singleton during a test, you can get multiple instances of it, where one will have Emails stored and another one doesn't. This was the case for me when I triggered an Email via FunctionalTest::post
(see my testForgotPasswordEmaling
test). There seem to be two different instances of TestMailer being instantiated in that case and the Mailer used within the tests itself won't contain any mails, unless $emailsSent
is a static member.
I think overall a static member makes sense, since you can't enforce the mailer instance via Mailer::set_mailer
. Tests that send Emails should use $this->clearEmails
at the start… I don't see any issues with this, unless you're starting to run tests in parallel (and even then, you can find your sent Email using the existing API).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I investigated a bit further. It seems like using Email::mailer()
will get you the correct instance, while SapphireTest::$mailer
will return another (unpopulated) instance. That's really strange, since SapphireTest sets Injector::inst()->registerService($this->mailer, 'Mailer');
in the startup, which should make them the same instance.
I guess it's time to start the debugger to see what's going on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, the issue wasn't related to FunctionalTest::post
at all (I thought it might have something to do with Injector nesting that happens within Director::test
).
The SapphireTest->mailer
instance gets already overridden/canceled-out within the setUp
method whenever self::create_temp_db()
is being called (which in turn calls SapphireTest::resetDBSchema
that clears the service cache, via Injector::unregisterAllObjects
).
Solving the problem is relatively simple, by just setting up the Mailer at the end of the setUp
method. Will amend this PR with these changes and revert the changes made to TestMailer
(eg. not using static members).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fantastic fix - I had this problem the other day and just gave up testing emails, I think there's even an issue open about this
Thanks, very good overall! Just a comment on the member variables. |
e1ef3d2
to
01731cc
Compare
urldecode($response->getHeader('Location'))); | ||
|
||
// Check existance of reset link | ||
$this->assertEmailSent("sam@silverstripe.com", null, 'Your password reset link', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, just one more thing... can you please change this to not be a real email address? I just want to avoid the case where someday down the line sam ends up with 10000 test emails from travis.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haha, sure thing. Maybe it would be a good idea to generally replace all "real" E-Mail Addresses from fixture-files?
…ordEmail and Member_ForgotPasswordEmail). Added a test for the forgot password email. Improved the test for the change-password email. Fixed issue where `SapphireTest::mailer` was cleared during `setUp` by moving instantiation of the mailer at the end of the `setUp` method. No longer use deprecated i18n method in test-setup. Replace potentially real Email Address with a fake one.
01731cc
to
ca4036b
Compare
OK - I'm not particularly happy with this because it actually makes these emails much more rigid than they used to be. I'd assume the reason they are their own subclasses is because it allows better customisation, however there's no way here to change their behaviour (ie: no use of config or extension hooks)? This is more a problem with the injector that should be fixed IMO rather than this (see #4774 where it's been decided that we shouldn't override all child classes). This means it's on the dev to override all subclasses individually if needed. |
related: #5000 |
What kind of customizations did you have in mind? The most common one is obviously overriding the template which is still possible. We could add an Injector "placeholder", something like this: Injector:
Member_ChangePasswordEmail:
class: Email And then use And: Yeah, it seems like the issue #5000 is the same I encountered when writing tests for this fix. |
You're right. But that doesn't mean the devs aren't doing it and without providing other means to allow them to, makes it more rigid. Your placeholder solution compounds the problem in #5000, surely? Unless the injector looks for the class that replaces email when insttantiating this? |
And a note regarding Email subclasses: I think these exist, because in earlier versions of SilverStripe (2.2 and prior) there wasn't a The shop module also deprecated Email subclasses in favor of using My point is: These subclasses are here because of legacy reasons and no longer represent best-practice. I'll leave it up to you ( @dhensby , @tractorcow anyone else? ) to decide if you want to keep these subclasses or not. Please let me know, so that I can amend this PR, because I think it would contain other useful improvements (such as improving Email testing). Cheers. |
@bummzack OK - I've spoken to @kinglozzer and I think it's worth merging I do think this is more rigid that it was before, but allowing custom templates should do away with most of the customisations people will need. |
thanks |
Great. From my point of view, issue #5000 could also be closed now. Should I create a separate PR for 3.x to fix the Email testing issue there as well?
|
@bummzack yes, please patch 3.x for that issue (even patching 3.2.x would make sense) |
Updated/added tests for changed- and forgot-password Emails. Updated fixture and tests to no longer use a real Email address.
Updated/added tests for changed- and forgot-password Emails. Updated fixture and tests to no longer use a real Email address.
Fix Email test issue discovered in #5271.
Removed Email Subclasses used by the Member class (
Member_ChangePasswordEmail
andMember_ForgotPasswordEmail
).Added a test for the forgot password email.
Improved the test for the change-password email.
It's not guaranteed that the
TestMailer
instance will remain the same across a unit-test, made$emailsSent
a static member to fix this issue.