mailhog-client icon indicating copy to clipboard operation
mailhog-client copied to clipboard

Flexible matching for eg SubjectSpecification

Open xurizaemon opened this issue 4 years ago • 1 comments

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!

xurizaemon avatar Jun 19 '21 21:06 xurizaemon

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.

rpkamp avatar Jun 20 '21 12:06 rpkamp