Skip to content

Commit 73d3997

Browse files
authored
Merge pull request #7602 from kenjis/fix-FeatureTestTrait-params-type
fix: FeatureTestTrait may change $params values passed to call(), and a few bug fixes
2 parents d7cda93 + f1509f1 commit 73d3997

5 files changed

Lines changed: 282 additions & 33 deletions

File tree

system/Test/FeatureTestTrait.php

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public function withBodyFormat(string $format)
110110
/**
111111
* Set the raw body for the request
112112
*
113-
* @param mixed $body
113+
* @param string $body
114114
*
115115
* @return $this
116116
*/
@@ -137,6 +137,8 @@ public function skipEvents()
137137
* Calls a single URI, executes it, and returns a TestResponse
138138
* instance that can be used to run many assertions against.
139139
*
140+
* @param string $method HTTP verb
141+
*
140142
* @return TestResponse
141143
*/
142144
public function call(string $method, string $path, ?array $params = null)
@@ -156,7 +158,7 @@ public function call(string $method, string $path, ?array $params = null)
156158
$request = $this->setupRequest($method, $path);
157159
$request = $this->setupHeaders($request);
158160
$request = $this->populateGlobals($method, $request, $params);
159-
$request = $this->setRequestBody($request);
161+
$request = $this->setRequestBody($request, $params);
160162

161163
// Initialize the RouteCollection
162164
if (! $routes = $this->routes) {
@@ -281,6 +283,8 @@ public function options(string $path, ?array $params = null)
281283
/**
282284
* Setup a Request object to use so that CodeIgniter
283285
* won't try to auto-populate some of the items.
286+
*
287+
* @param string $method HTTP verb
284288
*/
285289
protected function setupRequest(string $method, ?string $path = null): IncomingRequest
286290
{
@@ -325,6 +329,8 @@ protected function setupHeaders(IncomingRequest $request)
325329
*
326330
* Always populate the GET vars based on the URI.
327331
*
332+
* @param string $method HTTP verb
333+
*
328334
* @return Request
329335
*
330336
* @throws ReflectionException
@@ -333,16 +339,23 @@ protected function populateGlobals(string $method, Request $request, ?array $par
333339
{
334340
// $params should set the query vars if present,
335341
// otherwise set it from the URL.
336-
$get = ! empty($params) && $method === 'get'
342+
$get = (! empty($params) && $method === 'get')
337343
? $params
338344
: $this->getPrivateProperty($request->getUri(), 'query');
339345

340346
$request->setGlobal('get', $get);
341-
if ($method !== 'get') {
342-
$request->setGlobal($method, $params);
347+
348+
if ($method === 'get') {
349+
$request->setGlobal('request', $request->fetchGlobal('get'));
343350
}
344351

345-
$request->setGlobal('request', $params);
352+
if ($method === 'post') {
353+
$request->setGlobal($method, $params);
354+
$request->setGlobal(
355+
'request',
356+
$request->fetchGlobal('post') + $request->fetchGlobal('get')
357+
);
358+
}
346359

347360
$_SESSION = $this->session ?? [];
348361

@@ -354,31 +367,30 @@ protected function populateGlobals(string $method, Request $request, ?array $par
354367
* This allows the body to be formatted in a way that the controller is going to
355368
* expect as in the case of testing a JSON or XML API.
356369
*
357-
* @param array|null $params The parameters to be formatted and put in the body. If this is empty, it will get the
358-
* what has been loaded into the request global of the request class.
370+
* @param array|null $params The parameters to be formatted and put in the body.
359371
*/
360372
protected function setRequestBody(Request $request, ?array $params = null): Request
361373
{
362-
if (isset($this->requestBody) && $this->requestBody !== '') {
374+
if ($this->requestBody !== '') {
363375
$request->setBody($this->requestBody);
364-
365-
return $request;
366376
}
367377

368-
if (isset($this->bodyFormat) && $this->bodyFormat !== '') {
369-
if (empty($params)) {
370-
$params = $request->fetchGlobal('request');
371-
}
378+
if ($this->bodyFormat !== '') {
372379
$formatMime = '';
373380
if ($this->bodyFormat === 'json') {
374381
$formatMime = 'application/json';
375382
} elseif ($this->bodyFormat === 'xml') {
376383
$formatMime = 'application/xml';
377384
}
378-
if (! empty($formatMime) && ! empty($params)) {
385+
386+
if ($formatMime !== '') {
387+
$request->setHeader('Content-Type', $formatMime);
388+
}
389+
390+
if ($params !== null && $formatMime !== '') {
379391
$formatted = Services::format()->getFormatter($formatMime)->format($params);
392+
// "withBodyFormat() and $params of call()" has higher priority than withBody().
380393
$request->setBody($formatted);
381-
$request->setHeader('Content-Type', $formatMime);
382394
}
383395
}
384396

tests/system/Test/FeatureTestTraitTest.php

Lines changed: 195 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,162 @@ public function testIsOkWithRedirects()
358358
$this->assertTrue($response->isOK());
359359
}
360360

361+
public function testCallGetWithParams()
362+
{
363+
$this->withRoutes([
364+
[
365+
'get',
366+
'home',
367+
static fn () => json_encode(Services::request()->getGet()),
368+
],
369+
]);
370+
$data = [
371+
'true' => true,
372+
'false' => false,
373+
'int' => 2,
374+
'null' => null,
375+
'float' => 1.23,
376+
'string' => 'foo',
377+
];
378+
$response = $this->get('home', $data);
379+
380+
$response->assertOK();
381+
$this->assertStringContainsString(
382+
// All GET values will be strings.
383+
'{"true":"1","false":"","int":"2","null":"","float":"1.23","string":"foo"}',
384+
$response->getBody()
385+
);
386+
}
387+
388+
public function testCallGetWithParamsAndREQUEST()
389+
{
390+
$this->withRoutes([
391+
[
392+
'get',
393+
'home',
394+
static fn () => json_encode(Services::request()->fetchGlobal('request')),
395+
],
396+
]);
397+
$data = [
398+
'true' => true,
399+
'false' => false,
400+
'int' => 2,
401+
'null' => null,
402+
'float' => 1.23,
403+
'string' => 'foo',
404+
];
405+
$response = $this->get('home', $data);
406+
407+
$response->assertOK();
408+
$this->assertStringContainsString(
409+
// All GET values will be strings.
410+
'{"true":"1","false":"","int":"2","null":"","float":"1.23","string":"foo"}',
411+
$response->getBody()
412+
);
413+
}
414+
415+
public function testCallPostWithParams()
416+
{
417+
$this->withRoutes([
418+
[
419+
'post',
420+
'home',
421+
static fn () => json_encode(Services::request()->getPost()),
422+
],
423+
]);
424+
$data = [
425+
'true' => true,
426+
'false' => false,
427+
'int' => 2,
428+
'null' => null,
429+
'float' => 1.23,
430+
'string' => 'foo',
431+
];
432+
$response = $this->post('home', $data);
433+
434+
$response->assertOK();
435+
$this->assertStringContainsString(
436+
// All POST values will be strings.
437+
'{"true":"1","false":"","int":"2","null":"","float":"1.23","string":"foo"}',
438+
$response->getBody()
439+
);
440+
}
441+
442+
public function testCallPostWithParamsAndREQUEST()
443+
{
444+
$this->withRoutes([
445+
[
446+
'post',
447+
'home',
448+
static fn () => json_encode(Services::request()->fetchGlobal('request')),
449+
],
450+
]);
451+
$data = [
452+
'true' => true,
453+
'false' => false,
454+
'int' => 2,
455+
'null' => null,
456+
'float' => 1.23,
457+
'string' => 'foo',
458+
];
459+
$response = $this->post('home', $data);
460+
461+
$response->assertOK();
462+
$this->assertStringContainsString(
463+
// All POST values will be strings.
464+
'{"true":"1","false":"","int":"2","null":"","float":"1.23","string":"foo"}',
465+
$response->getBody()
466+
);
467+
}
468+
469+
public function testCallPutWithJsonRequest()
470+
{
471+
$this->withRoutes([
472+
[
473+
'put',
474+
'home',
475+
'\Tests\Support\Controllers\Popcorn::echoJson',
476+
],
477+
]);
478+
$data = [
479+
'true' => true,
480+
'false' => false,
481+
'int' => 2,
482+
'null' => null,
483+
'float' => 1.23,
484+
'string' => 'foo',
485+
];
486+
$response = $this->withBodyFormat('json')
487+
->call('put', 'home', $data);
488+
489+
$response->assertOK();
490+
$response->assertJSONExact($data);
491+
}
492+
493+
public function testCallPutWithJsonRequestAndREQUEST()
494+
{
495+
$this->withRoutes([
496+
[
497+
'put',
498+
'home',
499+
static fn () => json_encode(Services::request()->fetchGlobal('request')),
500+
],
501+
]);
502+
$data = [
503+
'true' => true,
504+
'false' => false,
505+
'int' => 2,
506+
'null' => null,
507+
'float' => 1.23,
508+
'string' => 'foo',
509+
];
510+
$response = $this->withBodyFormat('json')
511+
->call('put', 'home', $data);
512+
513+
$response->assertOK();
514+
$this->assertStringContainsString('[]', $response->getBody());
515+
}
516+
361517
public function testCallWithJsonRequest()
362518
{
363519
$this->withRoutes([
@@ -367,9 +523,19 @@ public function testCallWithJsonRequest()
367523
'\Tests\Support\Controllers\Popcorn::echoJson',
368524
],
369525
]);
370-
$response = $this->withBodyFormat('json')->call('post', 'home', ['foo' => 'bar']);
526+
$data = [
527+
'true' => true,
528+
'false' => false,
529+
'int' => 2,
530+
'null' => null,
531+
'float' => 1.23,
532+
'string' => 'foo',
533+
];
534+
$response = $this->withBodyFormat('json')
535+
->call('post', 'home', $data);
536+
371537
$response->assertOK();
372-
$response->assertJSONExact(['foo' => 'bar']);
538+
$response->assertJSONExact($data);
373539
}
374540

375541
public function testSetupRequestBodyWithParams()
@@ -382,14 +548,39 @@ public function testSetupRequestBodyWithParams()
382548
$this->assertSame('application/json', $request->header('Content-Type')->getValue());
383549
}
384550

551+
public function testSetupJSONRequestBodyWithBody()
552+
{
553+
$request = $this->setupRequest('post', 'home');
554+
$request = $this->withBodyFormat('json')
555+
->withBody(json_encode(['foo1' => 'bar1']))
556+
->setRequestBody($request);
557+
558+
$this->assertJsonStringEqualsJsonString(
559+
json_encode(['foo1' => 'bar1']),
560+
$request->getBody()
561+
);
562+
$this->assertSame(
563+
'application/json',
564+
$request->header('Content-Type')->getValue()
565+
);
566+
}
567+
385568
public function testSetupRequestBodyWithXml()
386569
{
387570
$request = $this->setupRequest('post', 'home');
388571

389-
$request = $this->withBodyFormat('xml')->setRequestBody($request, ['foo' => 'bar']);
572+
$data = [
573+
'true' => true,
574+
'false' => false,
575+
'int' => 2,
576+
'null' => null,
577+
'float' => 1.23,
578+
'string' => 'foo',
579+
];
580+
$request = $this->withBodyFormat('xml')->setRequestBody($request, $data);
390581

391582
$expectedXml = '<?xml version="1.0"?>
392-
<response><foo>bar</foo></response>
583+
<response><true>1</true><false/><int>2</int><null/><float>1.23</float><string>foo</string></response>
393584
';
394585

395586
$this->assertSame($expectedXml, $request->getBody());

user_guide_src/source/changelogs/v4.3.7.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ Release Date: Unreleased
1212
BREAKING
1313
********
1414

15+
- **FeatureTestTrait:** When using :ref:`withBodyFormat() <feature-formatting-the-request>`,
16+
the priority of the request body has been changed.
17+
See :ref:`Upgrading Guide <upgrade-437-feature-testing>` for details.
18+
1519
Message Changes
1620
***************
1721

user_guide_src/source/installation/upgrade_437.rst

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,27 @@ Mandatory File Changes
1818
Breaking Changes
1919
****************
2020

21+
.. _upgrade-437-feature-testing:
22+
23+
Feature Testing Request Body
24+
============================
25+
26+
If you call:
27+
28+
1. :ref:`withBody() <feature-setting-the-body>`
29+
2. and :ref:`withBodyFormat() <feature-formatting-the-request>`
30+
3. and pass the ``$params`` to :ref:`call() <feature-requesting-a-page>` (or shorthand methods)
31+
32+
the priority for a Request body has been changed. In the unlikely event that you
33+
have test code affected by this change, modify it.
34+
35+
For example, now the ``$params`` is used to build the request body, and the ``$body``
36+
is not used::
37+
38+
$this->withBody($body)->withBodyFormat('json')->call('post', $params)
39+
40+
Previously, the ``$body`` was used for the request body.
41+
2142
Breaking Enhancements
2243
*********************
2344

0 commit comments

Comments
 (0)