Skip to content

Commit 807c0b6

Browse files
SamMousaDavertMik
authored andcommitted
Yii2: Move implementations to connector (#5173)
* Refactor functions from module to connector, keeping the module interface the same but moving implementations to the connector. * Fixed nitpick CS * Attempt to use Guzzle MockHandler instead of external service * Fixed issues with test & phpbrowser configurability
1 parent a599b5c commit 807c0b6

File tree

2 files changed

+172
-71
lines changed

2 files changed

+172
-71
lines changed

src/Codeception/Lib/Connector/Yii2.php

Lines changed: 152 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
<?php
22
namespace Codeception\Lib\Connector;
33

4+
use Codeception\Exception\ConfigurationException;
45
use Codeception\Lib\Connector\Yii2\Logger;
6+
use Codeception\Lib\Connector\Yii2\TestMailer;
57
use Codeception\Lib\InnerBrowser;
68
use Codeception\Util\Debug;
79
use Symfony\Component\BrowserKit\Client;
@@ -79,7 +81,7 @@ class Yii2 extends Client
7981
/**
8082
* @return \yii\web\Application
8183
*/
82-
public function getApplication()
84+
protected function getApplication()
8385
{
8486
if (!isset(Yii::$app)) {
8587
$this->startApp();
@@ -90,6 +92,7 @@ public function getApplication()
9092
public function resetApplication()
9193
{
9294
codecept_debug('Destroying application');
95+
$this->closeSession();
9396
Yii::$app = null;
9497
\yii\web\UploadedFile::reset();
9598
if (method_exists(\yii\base\Event::className(), 'offAll')) {
@@ -100,6 +103,144 @@ public function resetApplication()
100103
gc_collect_cycles();
101104
}
102105

106+
/**
107+
* Finds and logs in a user
108+
* @param $user
109+
* @throws ConfigurationException
110+
*/
111+
public function findAndLoginUser($user)
112+
{
113+
$app = $this->getApplication();
114+
if (!$app->has('user')) {
115+
throw new ConfigurationException('The user component is not configured');
116+
}
117+
118+
if ($user instanceof \yii\web\IdentityInterface) {
119+
$identity = $user;
120+
} else {
121+
// class name implementing IdentityInterface
122+
$identityClass = $app->user->identityClass;
123+
$identity = call_user_func([$identityClass, 'findIdentity'], $user);
124+
}
125+
$app->user->login($identity);
126+
}
127+
128+
/**
129+
* Masks a value
130+
* @param string $val
131+
* @return string
132+
* @see \yii\base\Security::maskToken
133+
*/
134+
public function maskToken($val)
135+
{
136+
return $this->getApplication()->security->maskToken($val);
137+
}
138+
139+
/**
140+
* @param string $name The name of the cookie
141+
* @param string $value The value of the cookie
142+
* @return string The value to send to the browser
143+
*/
144+
public function hashCookieData($name, $value)
145+
{
146+
$app = $this->getApplication();
147+
if (!$app->request->enableCookieValidation) {
148+
return $value;
149+
}
150+
return $app->security->hashData(serialize([$name, $value]), $app->request->cookieValidationKey);
151+
}
152+
153+
/**
154+
* @return array List of regex patterns for recognized domain names
155+
*/
156+
public function getInternalDomains()
157+
{
158+
/** @var \yii\web\UrlManager $urlManager */
159+
$urlManager = $this->getApplication()->urlManager;
160+
$domains = [$this->getDomainRegex($urlManager->hostInfo)];
161+
if ($urlManager->enablePrettyUrl) {
162+
foreach ($urlManager->rules as $rule) {
163+
/** @var \yii\web\UrlRule $rule */
164+
if (isset($rule->host)) {
165+
$domains[] = $this->getDomainRegex($rule->host);
166+
}
167+
}
168+
}
169+
return array_unique($domains);
170+
}
171+
172+
/**
173+
* @return array List of sent emails
174+
*/
175+
public function getEmails()
176+
{
177+
$app = $this->getApplication();
178+
if ($app->has('mailer', true)) {
179+
$mailer = $app->get('mailer');
180+
if ($mailer instanceof TestMailer) {
181+
return $app->get('mailer')->getSentMessages();
182+
} else {
183+
throw new ConfigurationException("Mailer module is not mocked, can't test emails");
184+
}
185+
}
186+
return [];
187+
}
188+
189+
public function getComponent($name)
190+
{
191+
$app = $this->getApplication();
192+
if (!$app->has($name)) {
193+
throw new ConfigurationException("Component $name is not available in current application");
194+
}
195+
return $app->get($name);
196+
}
197+
198+
/**
199+
* Getting domain regex from rule host template
200+
*
201+
* @param string $template
202+
* @return string
203+
*/
204+
private function getDomainRegex($template)
205+
{
206+
if (preg_match('#https?://(.*)#', $template, $matches)) {
207+
$template = $matches[1];
208+
}
209+
$parameters = [];
210+
if (strpos($template, '<') !== false) {
211+
$template = preg_replace_callback(
212+
'/<(?:\w+):?([^>]+)?>/u',
213+
function ($matches) use (&$parameters) {
214+
$key = '#' . count($parameters) . '#';
215+
$parameters[$key] = isset($matches[1]) ? $matches[1] : '\w+';
216+
return $key;
217+
},
218+
$template
219+
);
220+
}
221+
$template = preg_quote($template);
222+
$template = strtr($template, $parameters);
223+
return '/^' . $template . '$/u';
224+
}
225+
226+
/**
227+
* Gets the name of the CSRF param.
228+
* @return string
229+
*/
230+
public function getCsrfParamName()
231+
{
232+
return $this->getApplication()->request->csrfParam;
233+
}
234+
235+
/**
236+
* @param $params
237+
* @return mixed
238+
*/
239+
public function createUrl($params)
240+
{
241+
return is_array($params) ?$this->getApplication()->getUrlManager()->createUrl($params) : $params;
242+
}
243+
103244
public function startApp()
104245
{
105246
codecept_debug('Starting application');
@@ -292,6 +433,16 @@ public function restart()
292433
$this->resetApplication();
293434
}
294435

436+
/**
437+
* This functions closes the session of the application, if the application exists and has a session.
438+
*/
439+
public function closeSession()
440+
{
441+
if (isset(\Yii::$app) && \Yii::$app->has('session', true)) {
442+
\Yii::$app->session->close();
443+
}
444+
}
445+
295446
/**
296447
* Resets the applications' response object.
297448
* The method used depends on the module configuration.

src/Codeception/Module/Yii2.php

Lines changed: 20 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
namespace Codeception\Module;
33

44
use Codeception\Configuration;
5+
use Codeception\Exception\ConfigurationException;
56
use Codeception\Exception\ModuleConfigException;
67
use Codeception\Exception\ModuleException;
78
use Codeception\Lib\Connector\Yii2 as Yii2Connector;
@@ -356,10 +357,6 @@ public function _after(TestInterface $test)
356357
$this->loadedFixtures = [];
357358
}
358359

359-
if ($this->client !== null && $this->client->getApplication()->has('session', true)) {
360-
$this->client->getApplication()->session->close();
361-
}
362-
363360
$this->client->resetApplication();
364361
parent::_after($test);
365362
}
@@ -406,17 +403,11 @@ public function _parts()
406403
*/
407404
public function amLoggedInAs($user)
408405
{
409-
if (!$this->client->getApplication()->has('user')) {
410-
throw new ModuleException($this, 'User component is not loaded');
406+
try {
407+
$this->client->findAndLoginUser($user);
408+
} catch (ConfigurationException $e) {
409+
throw new ModuleException($this, $e->getMessage());
411410
}
412-
if ($user instanceof \yii\web\IdentityInterface) {
413-
$identity = $user;
414-
} else {
415-
// class name implementing IdentityInterface
416-
$identityClass = $this->client->getApplication()->user->identityClass;
417-
$identity = call_user_func([$identityClass, 'findIdentity'], $user);
418-
}
419-
$this->client->getApplication()->user->login($identity);
420411
}
421412

422413
/**
@@ -659,10 +650,7 @@ public function amOnRoute($route, array $params = [])
659650
*/
660651
protected function clientRequest($method, $uri, array $parameters = [], array $files = [], array $server = [], $content = null, $changeHistory = true)
661652
{
662-
if (is_array($uri)) {
663-
$uri = $this->client->getApplication()->getUrlManager()->createUrl($uri);
664-
}
665-
return parent::clientRequest($method, $uri, $parameters, $files, $server, $content, $changeHistory);
653+
return parent::clientRequest($method, $this->client->createUrl($uri), $parameters, $files, $server, $content, $changeHistory);
666654
}
667655

668656
/**
@@ -676,13 +664,15 @@ protected function clientRequest($method, $uri, array $parameters = [], array $f
676664
* @param $component
677665
* @return mixed
678666
* @throws ModuleException
667+
* @deprecated in your tests you can use \Yii::$app directly.
679668
*/
680669
public function grabComponent($component)
681670
{
682-
if (!$this->client->getApplication()->has($component)) {
683-
throw new ModuleException($this, "Component $component is not available in current application");
671+
try {
672+
return $this->client->getComponent($component);
673+
} catch (ConfigurationException $e) {
674+
throw new ModuleException($this, $e->getMessage());
684675
}
685-
return $this->client->getApplication()->get($component);
686676
}
687677

688678
/**
@@ -738,11 +728,11 @@ public function dontSeeEmailIsSent()
738728
*/
739729
public function grabSentEmails()
740730
{
741-
$mailer = $this->grabComponent('mailer');
742-
if (!$mailer instanceof Yii2Connector\TestMailer) {
743-
throw new ModuleException($this, "Mailer module is not mocked, can't test emails");
731+
try {
732+
return $this->client->getEmails();
733+
} catch (ConfigurationException $e) {
734+
throw new ModuleException($this, $e->getMessage());
744735
}
745-
return $mailer->getSentMessages();
746736
}
747737

748738
/**
@@ -763,33 +753,7 @@ public function grabLastSentEmail()
763753
return end($messages);
764754
}
765755

766-
/**
767-
* Getting domain regex from rule host template
768-
*
769-
* @param string $template
770-
* @return string
771-
*/
772-
private function getDomainRegex($template)
773-
{
774-
if (preg_match('#https?://(.*)#', $template, $matches)) {
775-
$template = $matches[1];
776-
}
777-
$parameters = [];
778-
if (strpos($template, '<') !== false) {
779-
$template = preg_replace_callback(
780-
'/<(?:\w+):?([^>]+)?>/u',
781-
function ($matches) use (&$parameters) {
782-
$key = '#' . count($parameters) . '#';
783-
$parameters[$key] = isset($matches[1]) ? $matches[1] : '\w+';
784-
return $key;
785-
},
786-
$template
787-
);
788-
}
789-
$template = preg_quote($template);
790-
$template = strtr($template, $parameters);
791-
return '/^' . $template . '$/u';
792-
}
756+
793757

794758
/**
795759
* Returns a list of regex patterns for recognized domain names
@@ -798,17 +762,7 @@ function ($matches) use (&$parameters) {
798762
*/
799763
public function getInternalDomains()
800764
{
801-
$domains = [$this->getDomainRegex($this->client->getApplication()->urlManager->hostInfo)];
802-
803-
if ($this->client->getApplication()->urlManager->enablePrettyUrl) {
804-
foreach ($this->client->getApplication()->urlManager->rules as $rule) {
805-
/** @var \yii\web\UrlRule $rule */
806-
if (isset($rule->host)) {
807-
$domains[] = $this->getDomainRegex($rule->host);
808-
}
809-
}
810-
}
811-
return array_unique($domains);
765+
return $this->client->getInternalDomains();
812766
}
813767

814768
private function defineConstants()
@@ -826,11 +780,7 @@ private function defineConstants()
826780
*/
827781
public function setCookie($name, $val, array $params = [])
828782
{
829-
// Sign the cookie.
830-
if ($this->client->getApplication()->request->enableCookieValidation) {
831-
$val = $this->client->getApplication()->security->hashData(serialize([$name, $val]), $this->client->getApplication()->request->cookieValidationKey);
832-
}
833-
parent::setCookie($name, $val, $params);
783+
parent::setCookie($name, $this->client->hashCookieData($name, $val), $params);
834784
}
835785

836786
/**
@@ -840,8 +790,8 @@ public function setCookie($name, $val, array $params = [])
840790
*/
841791
public function createAndSetCsrfCookie($val)
842792
{
843-
$masked = $this->client->getApplication()->security->maskToken($val);
844-
$name = $this->client->getApplication()->request->csrfParam;
793+
$masked = $this->client->maskToken($val);
794+
$name = $this->client->getCsrfParamName();
845795
$this->setCookie($name, $val);
846796
return [$name, $masked];
847797
}

0 commit comments

Comments
 (0)