ViewTest.php 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. <?php
  2. namespace Illuminate\Tests\View;
  3. use ArrayAccess;
  4. use BadMethodCallException;
  5. use Closure;
  6. use Illuminate\Contracts\Support\Arrayable;
  7. use Illuminate\Contracts\Support\Renderable;
  8. use Illuminate\Contracts\View\Engine;
  9. use Illuminate\Support\MessageBag;
  10. use Illuminate\Support\ViewErrorBag;
  11. use Illuminate\View\Factory;
  12. use Illuminate\View\View;
  13. use Mockery as m;
  14. use PHPUnit\Framework\TestCase;
  15. class ViewTest extends TestCase
  16. {
  17. protected function tearDown(): void
  18. {
  19. m::close();
  20. }
  21. public function testDataCanBeSetOnView()
  22. {
  23. $view = $this->getView();
  24. $view->with('foo', 'bar');
  25. $view->with(['baz' => 'boom']);
  26. $this->assertEquals(['foo' => 'bar', 'baz' => 'boom'], $view->getData());
  27. $view = $this->getView();
  28. $view->withFoo('bar')->withBaz('boom');
  29. $this->assertEquals(['foo' => 'bar', 'baz' => 'boom'], $view->getData());
  30. }
  31. public function testRenderProperlyRendersView()
  32. {
  33. $view = $this->getView(['foo' => 'bar']);
  34. $view->getFactory()->shouldReceive('incrementRender')->once()->ordered();
  35. $view->getFactory()->shouldReceive('callComposer')->once()->ordered()->with($view);
  36. $view->getFactory()->shouldReceive('getShared')->once()->andReturn(['shared' => 'foo']);
  37. $view->getEngine()->shouldReceive('get')->once()->with('path', ['foo' => 'bar', 'shared' => 'foo'])->andReturn('contents');
  38. $view->getFactory()->shouldReceive('decrementRender')->once()->ordered();
  39. $view->getFactory()->shouldReceive('flushStateIfDoneRendering')->once();
  40. $callback = function (View $rendered, $contents) use ($view) {
  41. $this->assertEquals($view, $rendered);
  42. $this->assertSame('contents', $contents);
  43. };
  44. $this->assertSame('contents', $view->render($callback));
  45. }
  46. public function testRenderHandlingCallbackReturnValues()
  47. {
  48. $view = $this->getView();
  49. $view->getFactory()->shouldReceive('incrementRender');
  50. $view->getFactory()->shouldReceive('callComposer');
  51. $view->getFactory()->shouldReceive('getShared')->andReturn(['shared' => 'foo']);
  52. $view->getEngine()->shouldReceive('get')->andReturn('contents');
  53. $view->getFactory()->shouldReceive('decrementRender');
  54. $view->getFactory()->shouldReceive('flushStateIfDoneRendering');
  55. $this->assertSame('new contents', $view->render(function () {
  56. return 'new contents';
  57. }));
  58. $this->assertEmpty($view->render(function () {
  59. return '';
  60. }));
  61. $this->assertSame('contents', $view->render(function () {
  62. //
  63. }));
  64. }
  65. public function testRenderSectionsReturnsEnvironmentSections()
  66. {
  67. $view = m::mock(View::class.'[render]', [
  68. m::mock(Factory::class),
  69. m::mock(Engine::class),
  70. 'view',
  71. 'path',
  72. [],
  73. ]);
  74. $view->shouldReceive('render')->with(m::type(Closure::class))->once()->andReturn($sections = ['foo' => 'bar']);
  75. $this->assertEquals($sections, $view->renderSections());
  76. }
  77. public function testSectionsAreNotFlushedWhenNotDoneRendering()
  78. {
  79. $view = $this->getView(['foo' => 'bar']);
  80. $view->getFactory()->shouldReceive('incrementRender')->twice();
  81. $view->getFactory()->shouldReceive('callComposer')->twice()->with($view);
  82. $view->getFactory()->shouldReceive('getShared')->twice()->andReturn(['shared' => 'foo']);
  83. $view->getEngine()->shouldReceive('get')->twice()->with('path', ['foo' => 'bar', 'shared' => 'foo'])->andReturn('contents');
  84. $view->getFactory()->shouldReceive('decrementRender')->twice();
  85. $view->getFactory()->shouldReceive('flushStateIfDoneRendering')->twice();
  86. $this->assertSame('contents', $view->render());
  87. $this->assertSame('contents', (string) $view);
  88. }
  89. public function testViewNestBindsASubView()
  90. {
  91. $view = $this->getView();
  92. $view->getFactory()->shouldReceive('make')->once()->with('foo', ['data']);
  93. $result = $view->nest('key', 'foo', ['data']);
  94. $this->assertInstanceOf(View::class, $result);
  95. }
  96. public function testViewAcceptsArrayableImplementations()
  97. {
  98. $arrayable = m::mock(Arrayable::class);
  99. $arrayable->shouldReceive('toArray')->once()->andReturn(['foo' => 'bar', 'baz' => ['qux', 'corge']]);
  100. $view = $this->getView($arrayable);
  101. $this->assertSame('bar', $view->foo);
  102. $this->assertEquals(['qux', 'corge'], $view->baz);
  103. }
  104. public function testViewGettersSetters()
  105. {
  106. $view = $this->getView(['foo' => 'bar']);
  107. $this->assertSame('view', $view->name());
  108. $this->assertSame('path', $view->getPath());
  109. $data = $view->getData();
  110. $this->assertSame('bar', $data['foo']);
  111. $view->setPath('newPath');
  112. $this->assertSame('newPath', $view->getPath());
  113. }
  114. public function testViewArrayAccess()
  115. {
  116. $view = $this->getView(['foo' => 'bar']);
  117. $this->assertInstanceOf(ArrayAccess::class, $view);
  118. $this->assertTrue($view->offsetExists('foo'));
  119. $this->assertSame('bar', $view->offsetGet('foo'));
  120. $view->offsetSet('foo', 'baz');
  121. $this->assertSame('baz', $view->offsetGet('foo'));
  122. $view->offsetUnset('foo');
  123. $this->assertFalse($view->offsetExists('foo'));
  124. }
  125. public function testViewConstructedWithObjectData()
  126. {
  127. $view = $this->getView(new DataObjectStub);
  128. $this->assertInstanceOf(ArrayAccess::class, $view);
  129. $this->assertTrue($view->offsetExists('foo'));
  130. $this->assertSame('bar', $view->offsetGet('foo'));
  131. $view->offsetSet('foo', 'baz');
  132. $this->assertSame('baz', $view->offsetGet('foo'));
  133. $view->offsetUnset('foo');
  134. $this->assertFalse($view->offsetExists('foo'));
  135. }
  136. public function testViewMagicMethods()
  137. {
  138. $view = $this->getView(['foo' => 'bar']);
  139. $this->assertTrue(isset($view->foo));
  140. $this->assertSame('bar', $view->foo);
  141. $view->foo = 'baz';
  142. $this->assertSame('baz', $view->foo);
  143. $this->assertEquals($view['foo'], $view->foo);
  144. unset($view->foo);
  145. $this->assertFalse(isset($view->foo));
  146. $this->assertFalse($view->offsetExists('foo'));
  147. }
  148. public function testViewBadMethod()
  149. {
  150. $this->expectException(BadMethodCallException::class);
  151. $this->expectExceptionMessage('Method Illuminate\View\View::badMethodCall does not exist.');
  152. $view = $this->getView();
  153. $view->badMethodCall();
  154. }
  155. public function testViewGatherDataWithRenderable()
  156. {
  157. $view = $this->getView();
  158. $view->getFactory()->shouldReceive('incrementRender')->once()->ordered();
  159. $view->getFactory()->shouldReceive('callComposer')->once()->ordered()->with($view);
  160. $view->getFactory()->shouldReceive('getShared')->once()->andReturn(['shared' => 'foo']);
  161. $view->getEngine()->shouldReceive('get')->once()->andReturn('contents');
  162. $view->getFactory()->shouldReceive('decrementRender')->once()->ordered();
  163. $view->getFactory()->shouldReceive('flushStateIfDoneRendering')->once();
  164. $view->renderable = m::mock(Renderable::class);
  165. $view->renderable->shouldReceive('render')->once()->andReturn('text');
  166. $this->assertSame('contents', $view->render());
  167. }
  168. public function testViewRenderSections()
  169. {
  170. $view = $this->getView();
  171. $view->getFactory()->shouldReceive('incrementRender')->once()->ordered();
  172. $view->getFactory()->shouldReceive('callComposer')->once()->ordered()->with($view);
  173. $view->getFactory()->shouldReceive('getShared')->once()->andReturn(['shared' => 'foo']);
  174. $view->getEngine()->shouldReceive('get')->once()->andReturn('contents');
  175. $view->getFactory()->shouldReceive('decrementRender')->once()->ordered();
  176. $view->getFactory()->shouldReceive('flushStateIfDoneRendering')->once();
  177. $view->getFactory()->shouldReceive('getSections')->once()->andReturn(['foo', 'bar']);
  178. $sections = $view->renderSections();
  179. $this->assertSame('foo', $sections[0]);
  180. $this->assertSame('bar', $sections[1]);
  181. }
  182. public function testWithErrors()
  183. {
  184. $view = $this->getView();
  185. $errors = ['foo' => 'bar', 'qu' => 'ux'];
  186. $this->assertSame($view, $view->withErrors($errors));
  187. $this->assertInstanceOf(ViewErrorBag::class, $view->errors);
  188. $foo = $view->errors->get('foo');
  189. $this->assertSame('bar', $foo[0]);
  190. $qu = $view->errors->get('qu');
  191. $this->assertSame('ux', $qu[0]);
  192. $data = ['foo' => 'baz'];
  193. $this->assertSame($view, $view->withErrors(new MessageBag($data)));
  194. $foo = $view->errors->get('foo');
  195. $this->assertSame('baz', $foo[0]);
  196. $foo = $view->errors->getBag('default')->get('foo');
  197. $this->assertSame('baz', $foo[0]);
  198. $this->assertSame($view, $view->withErrors(new MessageBag($data), 'login'));
  199. $foo = $view->errors->getBag('login')->get('foo');
  200. $this->assertSame('baz', $foo[0]);
  201. }
  202. protected function getView($data = [])
  203. {
  204. return new View(
  205. m::mock(Factory::class),
  206. m::mock(Engine::class),
  207. 'view',
  208. 'path',
  209. $data
  210. );
  211. }
  212. }
  213. class DataObjectStub
  214. {
  215. public $foo = 'bar';
  216. }