Skip to content

Commit 01e0ce6

Browse files
SamMousaDavertMik
authored andcommitted
Yii2 rework, new PR same changes. (#4894)
* Reorganized travis jobs * Improved Yii2 module * Fixed issue and updated docs * Added notice about absence of $app. * Fixed weird sentence
1 parent c1298a8 commit 01e0ce6

File tree

2 files changed

+291
-164
lines changed

2 files changed

+291
-164
lines changed

src/Codeception/Lib/Connector/Yii2.php

Lines changed: 74 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@
22
namespace Codeception\Lib\Connector;
33

44
use Codeception\Lib\Connector\Yii2\Logger;
5-
use Codeception\Lib\Connector\Yii2\TestMailer;
5+
use Codeception\Lib\InnerBrowser;
66
use Codeception\Util\Debug;
77
use Symfony\Component\BrowserKit\Client;
88
use Symfony\Component\BrowserKit\Cookie;
99
use Symfony\Component\BrowserKit\Response;
1010
use Yii;
1111
use yii\base\ExitException;
12+
use yii\base\Security;
1213
use yii\web\HttpException;
14+
use yii\web\Request;
1315
use yii\web\Response as YiiResponse;
1416

1517
class Yii2 extends Client
@@ -21,71 +23,41 @@ class Yii2 extends Client
2123
*/
2224
public $configFile;
2325

24-
public $defaultServerVars = [];
25-
26-
/**
27-
* @var array
28-
*/
29-
public $headers;
30-
public $statusCode;
31-
32-
/**
33-
* @var \yii\web\Application
34-
*/
35-
private $app;
36-
37-
/**
38-
* @var \yii\db\Connection
39-
*/
40-
public static $db; // remember the db instance
41-
42-
/**
43-
* @var TestMailer
44-
*/
45-
public static $mailer;
46-
4726
/**
4827
* @return \yii\web\Application
4928
*/
5029
public function getApplication()
5130
{
52-
if (!isset($this->app)) {
31+
if (!isset(Yii::$app)) {
5332
$this->startApp();
5433
}
55-
return $this->app;
34+
return Yii::$app;
5635
}
5736

5837
public function resetApplication()
5938
{
60-
$this->app = null;
39+
codecept_debug('Destroying application');
40+
Yii::$app = null;
41+
\yii\web\UploadedFile::reset();
42+
if (method_exists(\yii\base\Event::className(), 'offAll')) {
43+
\yii\base\Event::offAll();
44+
}
45+
Yii::setLogger(null);
6146
}
6247

6348
public function startApp()
6449
{
50+
codecept_debug('Starting application');
6551
$config = require($this->configFile);
6652
if (!isset($config['class'])) {
6753
$config['class'] = 'yii\web\Application';
6854
}
69-
if (static::$db) {
70-
// If the DB conection already exists, make sure to pass it as early as possible
71-
// to prevent application from new connection creating during bootstrap
72-
$config['components']['db'] = static::$db;
73-
}
55+
56+
$config = $this->mockMailer($config);
7457
/** @var \yii\web\Application $app */
75-
$this->app = Yii::createObject($config);
76-
$this->persistDb();
77-
$this->mockMailer($config);
78-
\Yii::setLogger(new Logger());
79-
}
58+
Yii::$app = Yii::createObject($config);
8059

81-
public function resetPersistentVars()
82-
{
83-
static::$db = null;
84-
static::$mailer = null;
85-
\yii\web\UploadedFile::reset();
86-
if (method_exists(\yii\base\Event::className(), 'offAll')) {
87-
\yii\base\Event::offAll();
88-
}
60+
Yii::setLogger(new Logger());
8961
}
9062

9163
/**
@@ -98,7 +70,6 @@ public function doRequest($request)
9870
{
9971
$_COOKIE = $request->getCookies();
10072
$_SERVER = $request->getServer();
101-
$this->restoreServerVars();
10273
$_FILES = $this->remapFiles($request->getFiles());
10374
$_REQUEST = $this->remapRequestParameters($request->getParameters());
10475
$_POST = $_GET = [];
@@ -123,20 +94,28 @@ public function doRequest($request)
12394

12495
$app = $this->getApplication();
12596

126-
$app->getResponse()->on(YiiResponse::EVENT_AFTER_PREPARE, [$this, 'processResponse']);
97+
/**
98+
* Just before the request we set the response object so it is always fresh.
99+
* @todo Implement some kind of check to see if someone tried to change the objects' properties and expects
100+
* those changes to be reflected in the reponse.
101+
*/
102+
$app->set('response', $app->getComponents()['response']);
127103

128104
// disabling logging. Logs are slowing test execution down
129105
foreach ($app->log->targets as $target) {
130106
$target->enabled = false;
131107
}
132108

133-
$this->headers = [];
134-
$this->statusCode = null;
135-
136109
ob_start();
137110

138111
// recreating request object to reset headers and cookies collections
112+
/**
113+
* Just before the request we set the request object so it is always fresh.
114+
* @todo Implement some kind of check to see if someone tried to change the objects' properties and expects
115+
* those changes to be reflected in the reponse.
116+
*/
139117
$app->set('request', $app->getComponents()['request']);
118+
140119
$yiiRequest = $app->getRequest();
141120
if ($request->getContent() !== null) {
142121
$yiiRequest->setRawBody($request->getContent());
@@ -148,35 +127,42 @@ public function doRequest($request)
148127
$yiiRequest->setQueryParams($_GET);
149128

150129
try {
130+
/*
131+
* This is basically equivalent to $app->run() without sending the response.
132+
* Sending the response is problematic because it tries to send headers.
133+
*/
151134
$app->trigger($app::EVENT_BEFORE_REQUEST);
152-
153-
$app->handleRequest($yiiRequest)->send();
154-
135+
$response = $app->handleRequest($yiiRequest);
155136
$app->trigger($app::EVENT_AFTER_REQUEST);
137+
codecept_debug($response->isSent);
138+
$response->send();
156139
} catch (\Exception $e) {
157140
if ($e instanceof HttpException) {
158141
// Don't discard output and pass exception handling to Yii to be able
159142
// to expect error response codes in tests.
160143
$app->errorHandler->discardExistingOutput = false;
161144
$app->errorHandler->handleException($e);
145+
$response = $app->response;
146+
162147
} elseif (!$e instanceof ExitException) {
163148
// for exceptions not related to Http, we pass them to Codeception
164149
$this->resetApplication();
165150
throw $e;
166151
}
167152
}
168153

169-
$content = ob_get_clean();
154+
$this->encodeCookies($response, $yiiRequest, $app->security);
170155

171-
// catch "location" header and display it in debug, otherwise it would be handled
172-
// by symfony browser-kit and not displayed.
173-
if (isset($this->headers['location'])) {
174-
Debug::debug("[Headers] " . json_encode($this->headers));
156+
if ($response->isRedirection) {
157+
Debug::debug("[Redirect with headers]" . print_r($response->getHeaders()->toArray(), true));
175158
}
176159

177-
$this->resetApplication();
160+
$content = ob_get_clean();
161+
if (empty($content) && !empty($response->content)) {
162+
throw new \Exception('No content was sent from Yii application');
163+
}
178164

179-
return new Response($content, $this->statusCode, $this->headers);
165+
return new Response($content, $response->statusCode, $response->getHeaders()->toArray());
180166
}
181167

182168
protected function revertErrorHandler()
@@ -186,36 +172,28 @@ protected function revertErrorHandler()
186172
}
187173

188174

189-
public function restoreServerVars()
190-
{
191-
$this->server = $this->defaultServerVars;
192-
foreach ($this->server as $key => $value) {
193-
$_SERVER[$key] = $value;
194-
}
195-
}
196-
197-
public function processResponse($event)
198-
{
199-
/** @var \yii\web\Response $response */
200-
$response = $event->sender;
201-
$request = Yii::$app->getRequest();
202-
$this->headers = $response->getHeaders()->toArray();
203-
$response->getHeaders()->removeAll();
204-
$this->statusCode = $response->getStatusCode();
205-
$cookies = $response->getCookies();
206-
175+
/**
176+
* Encodes the cookies and adds them to the headers.
177+
* @param \yii\web\Response $response
178+
* @throws \yii\base\InvalidConfigException
179+
*/
180+
protected function encodeCookies(
181+
YiiResponse $response,
182+
Request $request,
183+
Security $security
184+
) {
207185
if ($request->enableCookieValidation) {
208186
$validationKey = $request->cookieValidationKey;
209187
}
210188

211-
foreach ($cookies as $cookie) {
189+
foreach ($response->getCookies() as $cookie) {
212190
/** @var \yii\web\Cookie $cookie */
213191
$value = $cookie->value;
214192
if ($cookie->expire != 1 && isset($validationKey)) {
215193
$data = version_compare(Yii::getVersion(), '2.0.2', '>')
216194
? [$cookie->name, $cookie->value]
217195
: $cookie->value;
218-
$value = Yii::$app->security->hashData(serialize($data), $validationKey);
196+
$value = $security->hashData(serialize($data), $validationKey);
219197
}
220198
$c = new Cookie(
221199
$cookie->name,
@@ -228,21 +206,15 @@ public function processResponse($event)
228206
);
229207
$this->getCookieJar()->set($c);
230208
}
231-
$cookies->removeAll();
232209
}
233210

234211
/**
235212
* Replace mailer with in memory mailer
236-
* @param $config
237-
* @param $app
213+
* @param array $config Original configuration
214+
* @return array New configuration
238215
*/
239-
protected function mockMailer($config)
216+
protected function mockMailer(array $config)
240217
{
241-
if (static::$mailer) {
242-
$this->app->set('mailer', static::$mailer);
243-
return;
244-
}
245-
246218
// options that make sense for mailer mock
247219
$allowedOptions = [
248220
'htmlLayout',
@@ -267,21 +239,24 @@ protected function mockMailer($config)
267239
}
268240
}
269241
}
242+
$config['components']['mailer'] = $mailerConfig;
270243

271-
$this->app->set('mailer', $mailerConfig);
272-
static::$mailer = $this->app->get('mailer');
244+
return $config;
273245
}
274246

275247
/**
276-
* @param $app
248+
* A new client is created for every test, it is destroyed after every test.
249+
* @see InnerBrowser::_after()
250+
*
277251
*/
278-
protected function persistDb()
252+
public function __destruct()
279253
{
280-
// always use the same DB connection
281-
if (static::$db) {
282-
$this->app->set('db', static::$db);
283-
} elseif ($this->app->has('db')) {
284-
static::$db = $this->app->get('db');
285-
}
254+
$this->resetApplication();
255+
}
256+
257+
public function restart()
258+
{
259+
parent::restart();
260+
$this->resetApplication();
286261
}
287262
}

0 commit comments

Comments
 (0)