Search code examples
phpsymfonyswiftmailer

Functional test fails due to corrupted token extracted from email


In a Symfony 5 project, a functional test of user registration fails when the confirmation token is corrupted when extracted from an email. (Email is done with SwiftMailer due to its ability to send logs.)

The test begins with completing a form with a user name and email address. On Save the email is sent. Because the test includes $this->client->followRedirects(false); the test has access to the email's contents. When the token is extracted from the email it includes extra characters. So when the test tries to $this->client->request('GET', '/register/reset/' . $token); the test fails due to invalid registration data.

Here's a version of the test:

    public function testReplacementEmail() {
        $this->client->clickLink('Staff');
        $this->client->clickLink('Replace');
        $this->client->followRedirects(false);
        $this->client->submitForm('Save', [
            'user[fname]' => 'Useless',
            'user[sname]' => 'Garbage',
            'user[email]' => 'ugar@bogus.info'
        ]);
        $mailCollector = $this->client->getProfile()->getCollector('swiftmailer');

        $this->assertSame(1, $mailCollector->getMessageCount());
        $collectedMessages = $mailCollector->getMessages();
        $message = $collectedMessages[0];
        $this->assertStringContainsString('has been asked to designate', $message);

        $string = 'register/reset/';
        $offset = strlen($string);
        $pos = strpos($message, $string) + $offset;
        $token = substr($message, $pos, 32);
        var_dump($token);

        $this->client->followRedirects(true);
        $this->client->request('GET', '/logout');
        $this->client->request('GET', '/register/reset/' . $token);
        $this->client->submitForm('Save', [
            'new_password[plainPassword][first]' => '123Abc',
            'new_password[plainPassword][second]' => '123Abc',
        ]);

        $this->assertStringContainsString('You are now the registered representative', $this->client->getResponse()->getContent());
    }

I have included in the controller that handles the Replace link the lines $token = md5(uniqid(rand(), true));var_dump($token); in order to get an unadulterated token. When the test is run, those lines produce something like this:

string(32) "ad47260162194f9ab6deb55eb4f38178"

If I use var_dump($message); in the test to access the contents of the email I can see something like this:

href="http://localhost/register/reset/ad47260162194f9ab6deb55eb4f38178"

Yet where the test includes var_dump($token); I instead see something like this:

string(32) "7260162194f9ab6d=
eb55eb4f38178"

The presence of =\r\n (on a Windows system) causes the link to fail.

I would like to know why these extra characters occur and how to avoid them if at all possible.


Solution

  • The presence of =\r\n in your string suggests that the message is MIME-encoded with quoted printable and your link spans a line end. The SwiftMailer message object appears to have a magic __toString() method that (oddly, IMO) yields the encoded form of the message. If you want the original raw message string, you can call the getBody() method of the message object, and then just use your strpos() test on the result of that.