Flexible matching for eg SubjectSpecification
I have a site which sends emails with subject like "Your order 123 is confirmed" and would like to test for presence of the order confirmation email using rpkamp/mailhog-behat-extension; in order to simplify tests, I'd like to use a loose match such as "Your order * is confirmed".
Current behaviour for the following appears to be:
Then I should see an email with subject "subject" and body "body" to "[email protected]"
- subject match is exact (
===) - body match uses strpos to test for string presence
- recipient match is any (contains)
I see that matching implementations vary:
https://github.com/rpkamp/mailhog-client/blob/a93d089d2d88aeb5b3095ae61987da609d8ed940/src/Specification/SubjectSpecification.php#L20-L23
https://github.com/rpkamp/mailhog-client/blob/a93d089d2d88aeb5b3095ae61987da609d8ed940/src/Specification/SenderSpecification.php#L21-L24
https://github.com/rpkamp/mailhog-client/blob/a93d089d2d88aeb5b3095ae61987da609d8ed940/src/Specification/BodySpecification.php#L22-L25
https://github.com/rpkamp/mailhog-client/blob/a93d089d2d88aeb5b3095ae61987da609d8ed940/src/Specification/RecipientSpecification.php#L21-L24
https://github.com/rpkamp/mailhog-client/blob/a93d089d2d88aeb5b3095ae61987da609d8ed940/src/Specification/AttachmentSpecification.php#L20-L29
One approach would be that the looser specification apply (eg subject, recipient, body all are "contains" type implementations). Alternatively we could introduce a way to flag specification matches for the new looser behaviour, to preserve BC better.
I've opened this in rpkamp/mailhog-client as I believe that's the right place for it, but let me know if I'm missing a trick over in rpkamp/mailhog-behat-extension!
That's a good point and something to be expanded upon in the future! I don't want to add that now in haste, but rather chew on it a bit to get it right.
In the meantime you could quite easily add your own Specification and Behat Context.
SubjectMatchesSpecification
final class SubjectMatchesSpecification implements Specification
{
/**
* @var string
*/
private $regex;
public function __construct(string $regex)
{
$this->regex = $regex;
}
public function isSatisfiedBy(Message $message): bool
{
return preg_match($this->regex, $message->subject);
}
}
MessageMatchingContext.php
<?php
declare(strict_types=1);
use rpkamp\Mailhog\MailhogClient;
use rpkamp\Behat\MailhogExtension\Context\MailhogAwareContext;
class FeatureContext implements MailhogAwareContext
{
private $mailhog;
public function setMailhog(MailhogClient $client)
{
$this->mailhog = $client;
}
/**
* @Then /^I should see an email where subject matches "([^"]+)"$/
*/
public function iShouldSeeAnEmailWhereSubjectMatches(string $regex): void
{
$messages = $this->mailhogClient->findMessagesSatisfying(new SubjectMatchesSpecification($regex));
if (count($message) > 0) {
return;
}
// throw exception
}
}
With that you can use the step like so
Then I should see an email where subject matches "Your order \d is confirmed"
As a general approach though, I would always suggest wiping the database before any actions like these, so the number in the email becomes predictable and you can directly check against it.