Completed
Push — 1.0.x ( 7e12c5...da53ed )
by Antonio
66:08 queued 64:19
created

EmailContext::assertEmailSentWithProperties()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 7
c 1
b 0
f 0
rs 9.4285
cc 2
eloc 5
nc 2
nop 1
1
<?php
2
3
namespace NuvoleWeb\Drupal\DrupalExtension\Context;
4
5
use Behat\Behat\Hook\Scope\AfterScenarioScope;
6
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
7
use Behat\Gherkin\Node\TableNode;
8
use NuvoleWeb\Drupal\DrupalExtension\Context\RawDrupalContext;
9
use function bovigo\assert\assert;
10
use function bovigo\assert\predicate\hasKey;
11
use function bovigo\assert\predicate\equals;
12
13
/**
14
 * Email step definitions.
15
 *
16
 * To use the email steps you need to have the mailsystem module enabled.
17
 */
18
class EmailContext extends RawDrupalContext {
19
20
  /**
21
   * Current mailsystem settings.
22
   *
23
   * @var string
24
   *    Email address.
25
   *
26
   * @see FeatureContext::beforeScenarioEmail()
27
   * @see FeatureContext::afterScenarioEmail()
28
   */
29
  protected $mailsystem = '';
30
31
  /**
32
   * Current contact settings.
33
   *
34
   * @var array
35
   *    Contact settings.
36
   *
37
   * @see FeatureContext::beforeScenarioNoContactFlood()
38
   * @see FeatureContext::beforeScenarioNoContactFlood()
39
   */
40
  protected $contactSettings = [];
41
42
  /**
43
   * Assert that an email has been sent to the given recipient.
44
   *
45
   * @param string $recipient
46
   *   Email address.
47
   *
48
   * @throws \Exception
49
   *    Throws an exception if no email has been sent or email is invalid.
50
   *
51
   * @Then an email should be sent to :recipient
52
   */
53
  public function assertEmailSentToRecipient($recipient) {
54
    $last_mail = $this->getLastEmail();
55
    if ($last_mail['to'] != $recipient) {
56
      throw new \Exception("Unexpected recipient: " . $last_mail['to']);
57
    }
58
  }
59
60
  /**
61
   * Assert that the email that has been sent has the given properties.
62
   *
63
   * @Then an email with the following properties should have been sent:
64
   */
65
  public function assertEmailSentWithProperties(TableNode $table) {
66
    $last_mail = $this->getLastEmail();
67
    foreach ($table->getRowsHash() as $name => $value) {
68
      assert($last_mail, hasKey($name));
69
      assert($last_mail[$name], equals($value));
70
    }
71
  }
72
73
  /**
74
   * Switch to Drupal test mail system for scenarios tagged with @email.
75
   *
76
   * @BeforeScenario @email
77
   */
78
  public function beforeScenarioEmail(BeforeScenarioScope $scope) {
0 ignored issues
show
Unused Code introduced by
The parameter $scope is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
79
    $mailsystem = $this->getCore()->getEditableConfig('mailsystem.settings');
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Drupal\Driver\Cores\CoreInterface as the method getEditableConfig() does only exist in the following implementations of said interface: NuvoleWeb\Drupal\Driver\Cores\Drupal8.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
80
    $this->mailsystem = $mailsystem->get('defaults');
81
    $mailsystem->set('defaults.sender', 'test_mail_collector')->save();
82
    $this->getCore()->state()->set('system.test_mail_collector', []);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Drupal\Driver\Cores\CoreInterface as the method state() does only exist in the following implementations of said interface: NuvoleWeb\Drupal\Driver\Cores\Drupal8.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
83
  }
84
85
  /**
86
   * Switch back to original mail system for scenarios tagged with @email.
87
   *
88
   * @AfterScenario @email
89
   */
90
  public function afterScenarioEmail(AfterScenarioScope $scope) {
0 ignored issues
show
Unused Code introduced by
The parameter $scope is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
91
    $mailsystem = $this->getCore()->getEditableConfig('mailsystem.settings');
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Drupal\Driver\Cores\CoreInterface as the method getEditableConfig() does only exist in the following implementations of said interface: NuvoleWeb\Drupal\Driver\Cores\Drupal8.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
92
    $mailsystem->set('defaults.sender', $this->mailsystem['sender'])->save();
93
  }
94
95
  /**
96
   * Increase value of contact form flooding.
97
   *
98
   * @BeforeScenario @no_contact_flood
99
   */
100
  public function beforeScenarioNoContactFlood(BeforeScenarioScope $scope) {
0 ignored issues
show
Unused Code introduced by
The parameter $scope is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
101
    $config = $this->getCore()->getEditableConfig('contact.settings');
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Drupal\Driver\Cores\CoreInterface as the method getEditableConfig() does only exist in the following implementations of said interface: NuvoleWeb\Drupal\Driver\Cores\Drupal8.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
102
    $this->contactSettings = $config->getData();
103
    $config->set('flood.limit', 100000);
104
    $config->set('flood.interval', 100000);
105
    $config->save();
106
  }
107
108
  /**
109
   * Restore contact form flooding settings.
110
   *
111
   * @AfterScenario @no_contact_flood
112
   */
113
  public function afterScenarioNoContactFlood(AfterScenarioScope $scope) {
0 ignored issues
show
Unused Code introduced by
The parameter $scope is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
114
    $config = $this->getCore()->getEditableConfig('contact.settings');
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Drupal\Driver\Cores\CoreInterface as the method getEditableConfig() does only exist in the following implementations of said interface: NuvoleWeb\Drupal\Driver\Cores\Drupal8.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
115
    $config->setData($this->contactSettings)->save();
116
  }
117
118
  /**
119
   * Get collected emails.
120
   *
121
   * @return array
122
   *   Array of collected emails.
123
   */
124
  protected function getCollectedEmails() {
125
    $this->getCore()->state()->resetCache();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Drupal\Driver\Cores\CoreInterface as the method state() does only exist in the following implementations of said interface: NuvoleWeb\Drupal\Driver\Cores\Drupal8.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
126
    $test_mail_collector = $this->getCore()->state()->get('system.test_mail_collector');
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Drupal\Driver\Cores\CoreInterface as the method state() does only exist in the following implementations of said interface: NuvoleWeb\Drupal\Driver\Cores\Drupal8.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
127
    if (!$test_mail_collector) {
128
      $test_mail_collector = [];
129
    }
130
131
    return $test_mail_collector;
132
  }
133
134
  /**
135
   * Get last sent email.
136
   *
137
   * @return string
138
   *   Last sent email.
139
   *
140
   * @throws \Exception
141
   */
142
  protected function getLastEmail() {
143
    $emails = $this->getCollectedEmails();
144
    if (!$emails) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $emails of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
145
      throw new \Exception('No mail was sent.');
146
    }
147
148
    return end($emails);
149
  }
150
151
}
152