RestTest.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. <?php
  2. use Codeception\Util\Stub as Stub;
  3. /**
  4. * Class RestTest
  5. * @group appveyor
  6. */
  7. class RestTest extends \PHPUnit_Framework_TestCase
  8. {
  9. /**
  10. * @var \Codeception\Module\REST
  11. */
  12. protected $module;
  13. public function setUp()
  14. {
  15. $connector = new \Codeception\Lib\Connector\Universal();
  16. $connector->setIndex(\Codeception\Configuration::dataDir() . '/rest/index.php');
  17. $connectionModule = new \Codeception\Module\UniversalFramework(make_container());
  18. $connectionModule->client = $connector;
  19. $connectionModule->_initialize();
  20. $this->module = Stub::make('\Codeception\Module\REST');
  21. $this->module->_inject($connectionModule);
  22. $this->module->_initialize();
  23. $this->module->_before(Stub::makeEmpty('\Codeception\Test\Test'));
  24. $this->module->client->setServerParameters([
  25. 'SCRIPT_FILENAME' => 'index.php',
  26. 'SCRIPT_NAME' => 'index',
  27. 'SERVER_NAME' => 'localhost',
  28. 'SERVER_PROTOCOL' => 'http'
  29. ]);
  30. }
  31. public function testConflictsWithAPI()
  32. {
  33. $this->assertInstanceOf('Codeception\Lib\Interfaces\ConflictsWithModule', $this->module);
  34. $this->assertEquals('Codeception\Lib\Interfaces\API', $this->module->_conflicts());
  35. }
  36. private function setStubResponse($response)
  37. {
  38. $connectionModule = Stub::make('\Codeception\Module\UniversalFramework', ['_getResponseContent' => $response]);
  39. $this->module->_inject($connectionModule);
  40. $this->module->_initialize();
  41. $this->module->_before(Stub::makeEmpty('\Codeception\Test\Test'));
  42. }
  43. public function testBeforeHookResetsVariables()
  44. {
  45. $this->module->haveHttpHeader('Origin', 'http://www.example.com');
  46. $this->module->sendGET('/rest/user/');
  47. $server = $this->module->client->getInternalRequest()->getServer();
  48. $this->assertArrayHasKey('HTTP_ORIGIN', $server);
  49. $this->module->_before(Stub::makeEmpty('\Codeception\Test\Test'));
  50. $this->module->sendGET('/rest/user/');
  51. $server = $this->module->client->getInternalRequest()->getServer();
  52. $this->assertArrayNotHasKey('HTTP_ORIGIN', $server);
  53. }
  54. public function testGet()
  55. {
  56. $this->module->sendGET('/rest/user/');
  57. $this->module->seeResponseIsJson();
  58. $this->module->seeResponseContains('davert');
  59. $this->module->seeResponseContainsJson(['name' => 'davert']);
  60. $this->module->seeResponseCodeIs(200);
  61. $this->module->dontSeeResponseCodeIs(404);
  62. }
  63. public function testPost()
  64. {
  65. $this->module->sendPOST('/rest/user/', ['name' => 'john']);
  66. $this->module->seeResponseContains('john');
  67. $this->module->seeResponseContainsJson(['name' => 'john']);
  68. }
  69. public function testPut()
  70. {
  71. $this->module->sendPUT('/rest/user/', ['name' => 'laura']);
  72. $this->module->seeResponseContains('davert@mail.ua');
  73. $this->module->seeResponseContainsJson(['name' => 'laura']);
  74. $this->module->dontSeeResponseContainsJson(['name' => 'john']);
  75. }
  76. public function testGrabDataFromResponseByJsonPath()
  77. {
  78. $this->module->sendGET('/rest/user/');
  79. // simple assoc array
  80. $this->assertEquals(['davert@mail.ua'], $this->module->grabDataFromResponseByJsonPath('$.email'));
  81. // nested assoc array
  82. $this->assertEquals(['Kyiv'], $this->module->grabDataFromResponseByJsonPath('$.address.city'));
  83. // nested index array
  84. $this->assertEquals(['DavertMik'], $this->module->grabDataFromResponseByJsonPath('$.aliases[0]'));
  85. // empty if data not found
  86. $this->assertEquals([], $this->module->grabDataFromResponseByJsonPath('$.address.street'));
  87. }
  88. public function testValidJson()
  89. {
  90. $this->setStubResponse('{"xxx": "yyy"}');
  91. $this->module->seeResponseIsJson();
  92. $this->setStubResponse('{"xxx": "yyy", "zzz": ["a","b"]}');
  93. $this->module->seeResponseIsJson();
  94. $this->module->seeResponseEquals('{"xxx": "yyy", "zzz": ["a","b"]}');
  95. }
  96. public function testInvalidJson()
  97. {
  98. $this->setExpectedException('PHPUnit_Framework_ExpectationFailedException');
  99. $this->setStubResponse('{xxx = yyy}');
  100. $this->module->seeResponseIsJson();
  101. }
  102. public function testValidXml()
  103. {
  104. $this->setStubResponse('<xml></xml>');
  105. $this->module->seeResponseIsXml();
  106. $this->setStubResponse('<xml><name>John</name></xml>');
  107. $this->module->seeResponseIsXml();
  108. $this->module->seeResponseEquals('<xml><name>John</name></xml>');
  109. }
  110. public function testInvalidXml()
  111. {
  112. $this->setExpectedException('PHPUnit_Framework_ExpectationFailedException');
  113. $this->setStubResponse('<xml><name>John</surname></xml>');
  114. $this->module->seeResponseIsXml();
  115. }
  116. public function testSeeInJsonResponse()
  117. {
  118. $this->setStubResponse(
  119. '{"ticket": {"title": "Bug should be fixed", "user": {"name": "Davert"}, "labels": null}}'
  120. );
  121. $this->module->seeResponseIsJson();
  122. $this->module->seeResponseContainsJson(['name' => 'Davert']);
  123. $this->module->seeResponseContainsJson(['user' => ['name' => 'Davert']]);
  124. $this->module->seeResponseContainsJson(['ticket' => ['title' => 'Bug should be fixed']]);
  125. $this->module->seeResponseContainsJson(['ticket' => ['user' => ['name' => 'Davert']]]);
  126. $this->module->seeResponseContainsJson(['ticket' => ['labels' => null]]);
  127. }
  128. public function testSeeInJsonCollection()
  129. {
  130. $this->setStubResponse(
  131. '[{"user":"Blacknoir","age":"42","tags":["wed-dev","php"]},'
  132. . '{"user":"John Doe","age":27,"tags":["web-dev","java"]}]'
  133. );
  134. $this->module->seeResponseIsJson();
  135. $this->module->seeResponseContainsJson(['tags' => ['web-dev', 'java']]);
  136. $this->module->seeResponseContainsJson(['user' => 'John Doe', 'age' => 27]);
  137. $this->module->seeResponseContainsJson([['user' => 'John Doe', 'age' => 27]]);
  138. $this->module->seeResponseContainsJson(
  139. [['user' => 'Blacknoir', 'age' => 42], ['user' => 'John Doe', 'age' => "27"]]
  140. );
  141. }
  142. public function testArrayJson()
  143. {
  144. $this->setStubResponse(
  145. '[{"id":1,"title": "Bug should be fixed"},{"title": "Feature should be implemented","id":2}]'
  146. );
  147. $this->module->seeResponseContainsJson(['id' => 1]);
  148. }
  149. public function testDontSeeInJson()
  150. {
  151. $this->setStubResponse('{"ticket": {"title": "Bug should be fixed", "user": {"name": "Davert"}}}');
  152. $this->module->seeResponseIsJson();
  153. $this->module->dontSeeResponseContainsJson(['name' => 'Davet']);
  154. $this->module->dontSeeResponseContainsJson(['user' => ['name' => 'Davet']]);
  155. $this->module->dontSeeResponseContainsJson(['user' => ['title' => 'Bug should be fixed']]);
  156. }
  157. public function testApplicationJsonIncludesJsonAsContent()
  158. {
  159. $this->module->haveHttpHeader('Content-Type', 'application/json');
  160. $this->module->sendPOST('/', ['name' => 'john']);
  161. /** @var $request \Symfony\Component\BrowserKit\Request **/
  162. $request = $this->module->client->getRequest();
  163. $this->assertContains('application/json', $request->getServer());
  164. $server = $request->getServer();
  165. $this->assertEquals('application/json', $server['HTTP_CONTENT_TYPE']);
  166. $this->assertJson($request->getContent());
  167. $this->assertEmpty($request->getParameters());
  168. }
  169. public function testApplicationJsonIncludesObjectSerialized()
  170. {
  171. $this->module->haveHttpHeader('Content-Type', 'application/json');
  172. $this->module->sendPOST('/', new JsonSerializedItem());
  173. /** @var $request \Symfony\Component\BrowserKit\Request **/
  174. $request = $this->module->client->getRequest();
  175. $this->assertContains('application/json', $request->getServer());
  176. $this->assertJson($request->getContent());
  177. }
  178. public function testGetApplicationJsonNotIncludesJsonAsContent()
  179. {
  180. $this->module->haveHttpHeader('Content-Type', 'application/json');
  181. $this->module->sendGET('/', ['name' => 'john']);
  182. /** @var $request \Symfony\Component\BrowserKit\Request **/
  183. $request = $this->module->client->getRequest();
  184. $this->assertNull($request->getContent());
  185. $this->assertContains('john', $request->getParameters());
  186. }
  187. public function testUrlIsFull()
  188. {
  189. $this->module->sendGET('/api/v1/users');
  190. /** @var $request \Symfony\Component\BrowserKit\Request **/
  191. $request = $this->module->client->getRequest();
  192. $this->assertEquals('http://localhost/api/v1/users', $request->getUri());
  193. }
  194. public function testSeeHeaders()
  195. {
  196. $response = new \Symfony\Component\BrowserKit\Response("", 200, [
  197. 'Cache-Control' => ['no-cache', 'no-store'],
  198. 'Content_Language' => 'en-US'
  199. ]);
  200. $this->module->client->mockResponse($response);
  201. $this->module->sendGET('/');
  202. $this->module->seeHttpHeader('Cache-Control');
  203. $this->module->seeHttpHeader('content_language', 'en-US');
  204. $this->module->seeHttpHeader('Content-Language', 'en-US');
  205. $this->module->dontSeeHttpHeader('Content-Language', 'en-RU');
  206. $this->module->dontSeeHttpHeader('Content-Language1');
  207. $this->module->seeHttpHeaderOnce('Content-Language');
  208. $this->assertEquals('en-US', $this->module->grabHttpHeader('Content-Language'));
  209. $this->assertEquals('no-cache', $this->module->grabHttpHeader('Cache-Control'));
  210. $this->assertEquals(['no-cache', 'no-store'], $this->module->grabHttpHeader('Cache-Control', false));
  211. }
  212. public function testSeeHeadersOnce()
  213. {
  214. $this->shouldFail();
  215. $response = new \Symfony\Component\BrowserKit\Response("", 200, [
  216. 'Cache-Control' => ['no-cache', 'no-store'],
  217. ]);
  218. $this->module->client->mockResponse($response);
  219. $this->module->sendGET('/');
  220. $this->module->seeHttpHeaderOnce('Cache-Control');
  221. }
  222. public function testSeeResponseJsonMatchesXpath()
  223. {
  224. $this->setStubResponse(
  225. '[{"user":"Blacknoir","age":27,"tags":["wed-dev","php"]},'
  226. . '{"user":"John Doe","age":27,"tags":["web-dev","java"]}]'
  227. );
  228. $this->module->seeResponseIsJson();
  229. $this->module->seeResponseJsonMatchesXpath('//user');
  230. }
  231. public function testSeeResponseJsonMatchesJsonPath()
  232. {
  233. $this->setStubResponse(
  234. '[{"user":"Blacknoir","age":27,"tags":["wed-dev","php"]},'
  235. . '{"user":"John Doe","age":27,"tags":["web-dev","java"]}]'
  236. );
  237. $this->module->seeResponseJsonMatchesJsonPath('$[*].user');
  238. $this->module->seeResponseJsonMatchesJsonPath('$[1].tags');
  239. }
  240. public function testDontSeeResponseJsonMatchesJsonPath()
  241. {
  242. $this->setStubResponse(
  243. '[{"user":"Blacknoir","age":27,"tags":["wed-dev","php"]},'
  244. . '{"user":"John Doe","age":27,"tags":["web-dev","java"]}]'
  245. );
  246. $this->module->dontSeeResponseJsonMatchesJsonPath('$[*].profile');
  247. }
  248. public function testDontSeeResponseJsonMatchesXpath()
  249. {
  250. $this->setStubResponse(
  251. '[{"user":"Blacknoir","age":27,"tags":["wed-dev","php"]},'
  252. . '{"user":"John Doe","age":27,"tags":["web-dev","java"]}]'
  253. );
  254. $this->module->dontSeeResponseJsonMatchesXpath('//status');
  255. }
  256. public function testDontSeeResponseJsonMatchesXpathFails()
  257. {
  258. $this->shouldFail();
  259. $this->setStubResponse(
  260. '[{"user":"Blacknoir","age":27,"tags":["wed-dev","php"]},'
  261. . '{"user":"John Doe","age":27,"tags":["web-dev","java"]}]'
  262. );
  263. $this->module->dontSeeResponseJsonMatchesXpath('//user');
  264. }
  265. /**
  266. * @Issue https://github.com/Codeception/Codeception/issues/2775
  267. */
  268. public function testSeeResponseJsonMatchesXPathWorksWithAmpersand()
  269. {
  270. $this->setStubResponse('{ "product":[ { "category":[ { "comment":"something & something" } ] } ] }');
  271. $this->module->seeResponseIsJson();
  272. $this->module->seeResponseJsonMatchesXpath('//comment');
  273. }
  274. public function testSeeResponseJsonMatchesJsonPathFails()
  275. {
  276. $this->shouldFail();
  277. $this->setStubResponse(
  278. '[{"user":"Blacknoir","age":27,"tags":["wed-dev","php"]},'
  279. . '{"user":"John Doe","age":27,"tags":["web-dev","java"]}]'
  280. );
  281. $this->module->seeResponseIsJson();
  282. $this->module->seeResponseJsonMatchesJsonPath('$[*].profile');
  283. }
  284. public function testStructuredJsonPathAndXPath()
  285. {
  286. $this->setStubResponse(
  287. '{ "store": {"book": [{ "category": "reference", "author": "Nigel Rees", '
  288. . '"title": "Sayings of the Century", "price": 8.95 }, { "category": "fiction", "author": "Evelyn Waugh", '
  289. . '"title": "Sword of Honour", "price": 12.99 }, { "category": "fiction", "author": "Herman Melville", '
  290. . '"title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99 }, { "category": "fiction", '
  291. . '"author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", '
  292. . '"price": 22.99 } ], "bicycle": {"color": "red", "price": 19.95 } } }'
  293. );
  294. $this->module->seeResponseIsJson();
  295. $this->module->seeResponseJsonMatchesXpath('//book/category');
  296. $this->module->seeResponseJsonMatchesJsonPath('$..book');
  297. $this->module->seeResponseJsonMatchesJsonPath('$.store.book[2].author');
  298. $this->module->dontSeeResponseJsonMatchesJsonPath('$.invalid');
  299. $this->module->dontSeeResponseJsonMatchesJsonPath('$.store.book.*.invalidField');
  300. }
  301. public function testApplicationJsonSubtypeIncludesObjectSerialized()
  302. {
  303. $this->module->haveHttpHeader('Content-Type', 'application/resource+json');
  304. $this->module->sendPOST('/', new JsonSerializedItem());
  305. /** @var $request \Symfony\Component\BrowserKit\Request **/
  306. $request = $this->module->client->getRequest();
  307. $this->assertContains('application/resource+json', $request->getServer());
  308. $this->assertJson($request->getContent());
  309. }
  310. public function testJsonTypeMatches()
  311. {
  312. $this->setStubResponse('{"xxx": "yyy", "user_id": 1}');
  313. $this->module->seeResponseMatchesJsonType(['xxx' => 'string', 'user_id' => 'integer:<10']);
  314. $this->module->dontSeeResponseMatchesJsonType(['xxx' => 'integer', 'user_id' => 'integer:<10']);
  315. }
  316. public function testJsonTypeMatchesWithJsonPath()
  317. {
  318. $this->setStubResponse('{"users": [{ "name": "davert"}, {"id": 1}]}');
  319. $this->module->seeResponseMatchesJsonType(['name' => 'string'], '$.users[0]');
  320. $this->module->seeResponseMatchesJsonType(['id' => 'integer'], '$.users[1]');
  321. $this->module->dontSeeResponseMatchesJsonType(['id' => 'integer'], '$.users[0]');
  322. }
  323. public function testMatchJsonTypeFailsWithNiceMessage()
  324. {
  325. $this->setStubResponse('{"xxx": "yyy", "user_id": 1}');
  326. try {
  327. $this->module->seeResponseMatchesJsonType(['zzz' => 'string']);
  328. $this->fail('it had to throw exception');
  329. } catch (PHPUnit_Framework_AssertionFailedError $e) {
  330. $this->assertEquals('Key `zzz` doesn\'t exist in {"xxx":"yyy","user_id":1}', $e->getMessage());
  331. }
  332. }
  333. public function testDontMatchJsonTypeFailsWithNiceMessage()
  334. {
  335. $this->setStubResponse('{"xxx": "yyy", "user_id": 1}');
  336. try {
  337. $this->module->dontSeeResponseMatchesJsonType(['xxx' => 'string']);
  338. $this->fail('it had to throw exception');
  339. } catch (PHPUnit_Framework_AssertionFailedError $e) {
  340. $this->assertEquals('Unexpectedly response matched: {"xxx":"yyy","user_id":1}', $e->getMessage());
  341. }
  342. }
  343. public function testSeeResponseIsJsonFailsWhenResponseIsEmpty()
  344. {
  345. $this->shouldFail();
  346. $this->setStubResponse('');
  347. $this->module->seeResponseIsJson();
  348. }
  349. public function testSeeResponseIsJsonFailsWhenResponseIsInvalidJson()
  350. {
  351. $this->shouldFail();
  352. $this->setStubResponse('{');
  353. $this->module->seeResponseIsJson();
  354. }
  355. public function testSeeResponseJsonMatchesXpathCanHandleResponseWithOneElement()
  356. {
  357. $this->setStubResponse('{"success": 1}');
  358. $this->module->seeResponseJsonMatchesXpath('//success');
  359. }
  360. public function testSeeResponseJsonMatchesXpathCanHandleResponseWithTwoElements()
  361. {
  362. $this->setStubResponse('{"success": 1, "info": "test"}');
  363. $this->module->seeResponseJsonMatchesXpath('//success');
  364. }
  365. public function testSeeResponseJsonMatchesXpathCanHandleResponseWithOneSubArray()
  366. {
  367. $this->setStubResponse('{"array": {"success": 1}}');
  368. $this->module->seeResponseJsonMatchesXpath('//array/success');
  369. }
  370. protected function shouldFail()
  371. {
  372. $this->setExpectedException('PHPUnit_Framework_AssertionFailedError');
  373. }
  374. }
  375. class JsonSerializedItem implements JsonSerializable
  376. {
  377. public function jsonSerialize()
  378. {
  379. return array("hello" => "world");
  380. }
  381. }