clearPlugins(); $this->loadPlugins(['TestPlugin', 'TestTheme']); $request = new ServerRequest(); $response = new Response(); $this->View = new View($request, $response); } /** * tearDown method */ public function tearDown(): void { parent::tearDown(); unset($this->View); } /** * Tests basic cell rendering. */ public function testCellRender(): void { $cell = $this->View->cell('Articles::teaserList'); $render = "{$cell}"; $this->assertSame('teaser_list', $cell->viewBuilder()->getTemplate()); $this->assertStringContainsString('

Lorem ipsum

', $render); $this->assertStringContainsString('

Usectetur adipiscing eli

', $render); $this->assertStringContainsString('

Topis semper blandit eu non

', $render); $this->assertStringContainsString('

Suspendisse gravida neque

', $render); $cell = $this->View->cell('Cello'); $this->assertInstanceOf(CelloCell::class, $cell); $this->assertSame("Cellos\n", $cell->render()); } /** * Tests debug output. */ public function testDebugInfo(): void { $cell = $this->View->cell('Articles::teaserList'); $data = $cell->__debugInfo(); $this->assertArrayHasKey('request', $data); $this->assertArrayHasKey('response', $data); $this->assertSame('teaserList', $data['action']); $this->assertEquals([], $data['args']); } /** * Test __toString() hitting an error when rendering views. */ public function testCellImplictRenderWithError(): void { $capture = function ($errno, $msg): void { restore_error_handler(); $this->assertSame(E_USER_WARNING, $errno); $this->assertStringContainsString('Could not render cell - Cell template file', $msg); }; set_error_handler($capture); $cell = $this->View->cell('Articles::teaserList'); $cell->viewBuilder()->setTemplate('nope'); (string)$cell; } /** * Tests that we are able pass multiple arguments to cell methods. * * This test sets its own error handler, as PHPUnit won't convert * errors into exceptions when the caller is a __toString() method. */ public function testCellWithArguments(): void { $cell = $this->View->cell('Articles::doEcho', ['dummy', ' message']); $render = "{$cell}"; $this->assertStringContainsString('dummy message', $render); } public function testCellWithNamedArguments(): void { $cell = $this->View->cell('Articles::doEcho', ['msg1' => 'dummy', 'msg2' => ' message']); $render = "{$cell}"; $this->assertStringContainsString('dummy message', $render); $cell = $this->View->cell('Articles::doEcho', ['msg2' => ' dummy', 'msg1' => 'message']); $render = "{$cell}"; $this->assertStringContainsString('message dummy', $render); } /** * Tests that cell runs default action when none is provided. */ public function testDefaultCellAction(): void { $appCell = $this->View->cell('Articles'); $this->assertSame('display', $appCell->viewBuilder()->getTemplate()); $this->assertStringContainsString('dummy', "{$appCell}"); $pluginCell = $this->View->cell('TestPlugin.Dummy'); $this->assertStringContainsString('dummy', "{$pluginCell}"); $this->assertSame('display', $pluginCell->viewBuilder()->getTemplate()); } /** * Tests that cell action setting the templatePath */ public function testSettingCellTemplatePathFromAction(): void { $appCell = $this->View->cell('Articles::customTemplatePath'); $this->assertStringContainsString('Articles subdir custom_template_path template', "{$appCell}"); $this->assertSame('custom_template_path', $appCell->viewBuilder()->getTemplate()); $this->assertSame(Cell::TEMPLATE_FOLDER . '/Articles/Subdir', $appCell->viewBuilder()->getTemplatePath()); } /** * Tests that cell action setting the template using the ViewBuilder renders the correct template */ public function testSettingCellTemplateFromActionViewBuilder(): void { $appCell = $this->View->cell('Articles::customTemplateViewBuilder'); $this->assertStringContainsString('This is the alternate template', "{$appCell}"); $this->assertSame('alternate_teaser_list', $appCell->viewBuilder()->getTemplate()); } /** * Tests manual render() invocation. */ public function testCellManualRender(): void { /** @var \TestApp\View\Cell\ArticlesCell $cell */ $cell = $this->View->cell('Articles::doEcho', ['msg1' => 'dummy', 'msg2' => ' message']); $this->assertStringContainsString('dummy message', $cell->render()); $cell->teaserList(); $this->assertStringContainsString('

Lorem ipsum

', $cell->render('teaser_list')); } /** * Tests manual render() invocation with error */ public function testCellManualRenderError(): void { $cell = $this->View->cell('Articles'); $e = null; try { $cell->render('fooBar'); } catch (MissingCellTemplateException $e) { } $this->assertNotNull($e); $message = $e->getMessage(); $this->assertStringContainsString( str_replace('/', DS, 'Cell template file `cell/Articles/foo_bar.php` could not be found.'), $message ); $this->assertStringContainsString('The following paths', $message); $this->assertStringContainsString(ROOT . DS . 'templates', $message); $this->assertInstanceOf(MissingTemplateException::class, $e->getPrevious()); } /** * Test rendering a cell with a theme. */ public function testCellRenderThemed(): void { $this->View->setTheme('TestTheme'); $cell = $this->View->cell('Articles'); $this->assertEquals($this->View->getTheme(), $cell->viewBuilder()->getTheme()); $this->assertStringContainsString('Themed cell content.', $cell->render()); } /** * Test that a cell can render a plugin view. */ public function testCellRenderPluginTemplate(): void { $cell = $this->View->cell('Articles'); $this->assertStringContainsString( 'TestPlugin Articles/display', $cell->render('TestPlugin.display') ); $cell = $this->View->cell('Articles'); $cell->viewBuilder()->setPlugin('TestPlugin'); $this->assertStringContainsString( 'TestPlugin Articles/display', $cell->render('display') ); } /** * Tests that using plugin's cells works. */ public function testPluginCell(): void { $cell = $this->View->cell('TestPlugin.Dummy::echoThis', ['msg' => 'hello world!']); $this->assertStringContainsString('hello world!', "{$cell}"); } /** * Tests that using namespaced cells works. */ public function testNamespacedCell(): void { $cell = $this->View->cell('Admin/Menu'); $this->assertStringContainsString('Admin Menu Cell', $cell->render()); } /** * Tests that using namespaced cells in plugins works */ public function testPluginNamespacedCell(): void { $cell = $this->View->cell('TestPlugin.Admin/Menu'); $this->assertStringContainsString('Test Plugin Admin Menu Cell', $cell->render()); } /** * Test that plugin cells can render other view templates. */ public function testPluginCellAlternateTemplate(): void { $cell = $this->View->cell('TestPlugin.Dummy::echoThis', ['msg' => 'hello world!']); $cell->viewBuilder()->setTemplate('../../element/translate'); $this->assertStringContainsString('This is a translatable string', "{$cell}"); } /** * Test that plugin cells can render other view templates. */ public function testPluginCellAlternateTemplateRenderParam(): void { $cell = $this->View->cell('TestPlugin.Dummy::echoThis', ['msg' => 'hello world!']); $result = $cell->render('../../element/translate'); $this->assertStringContainsString('This is a translatable string', $result); } /** * Tests that using an nonexistent cell throws an exception. */ public function testNonExistentCell(): void { $this->expectException(MissingCellException::class); $this->View->cell('Void::echoThis', ['arg1' => 'v1', 'arg2' => 'v2']); } /** * Tests missing method errors */ public function testCellMissingMethod(): void { $this->expectException(BadMethodCallException::class); $this->expectExceptionMessage('Class `TestApp\View\Cell\ArticlesCell` does not have a `nope` method.'); $cell = $this->View->cell('Articles::nope'); $cell->render(); } /** * Test that cell options are passed on. */ public function testCellOptions(): void { /** @var \TestApp\View\Cell\ArticlesCell $cell */ $cell = $this->View->cell('Articles', [], ['limit' => 10, 'nope' => 'nope']); $this->assertSame(10, $cell->limit); $this->assertTrue(!isset($cell->nope), 'Not a valid option'); } /** * Test that cells get the helper configuration from the view that created them. */ public function testCellInheritsHelperConfig(): void { $request = new ServerRequest(); $response = new Response(); $helpers = ['Url', 'Form', 'Banana']; $view = new View($request, $response, null, ['helpers' => $helpers]); $cell = $view->cell('Articles'); $expected = array_combine($helpers, [[], [], []]); $this->assertSame($expected, $cell->viewBuilder()->getHelpers()); } /** * Test that cells the view class name of a custom view passed on. */ public function testCellInheritsCustomViewClass(): void { $request = new ServerRequest(); $response = new Response(); $view = new CustomJsonView($request, $response); $view->setTheme('Pretty'); $cell = $view->cell('Articles'); $this->assertSame(CustomJsonView::class, $cell->viewBuilder()->getClassName()); $this->assertSame('Pretty', $cell->viewBuilder()->getTheme()); } /** * Test that cells the view class name of a controller passed on. */ public function testCellInheritsController(): void { $request = new ServerRequest(); $controller = new CellTraitTestController($request); $controller->viewBuilder()->setTheme('Pretty'); $controller->viewBuilder()->setClassName('Json'); $cell = $controller->cell('Articles'); $this->assertSame('Json', $cell->viewBuilder()->getClassName()); $this->assertSame('Pretty', $cell->viewBuilder()->getTheme()); } /** * Test cached render. */ public function testCachedRenderSimple(): void { Cache::setConfig('default', ['className' => 'Array']); $cell = $this->View->cell('Articles', [], ['cache' => true]); $result = $cell->render(); $expected = "dummy\n"; $this->assertSame($expected, $result); $result = Cache::read('cell_test_app_view_cell_articles_cell_display_default', 'default'); $this->assertSame($expected, $result); Cache::drop('default'); } /** * Test read cached cell. */ public function testReadCachedCell(): void { Cache::setConfig('default', ['className' => 'Array']); Cache::write('cell_test_app_view_cell_articles_cell_display_default', 'from cache'); $cell = $this->View->cell('Articles', [], ['cache' => true]); $result = $cell->render(); $this->assertSame('from cache', $result); Cache::drop('default'); } /** * Test cached render array config */ public function testCachedRenderArrayConfig(): void { Cache::setConfig('cell', ['className' => 'Array']); Cache::write('my_key', 'from cache', 'cell'); $cell = $this->View->cell('Articles', [], [ 'cache' => ['key' => 'my_key', 'config' => 'cell'], ]); $result = $cell->render(); $this->assertSame('from cache', $result); Cache::drop('cell'); } /** * Test cached render when using an action changing the template used */ public function testCachedRenderSimpleCustomTemplate(): void { Cache::setConfig('default', ['className' => 'Array']); $cell = $this->View->cell('Articles::customTemplateViewBuilder', [], ['cache' => true]); $result = $cell->render(); $expected = 'This is the alternate template'; $this->assertStringContainsString($expected, $result); $result = Cache::read('cell_test_app_view_cell_articles_cell_customTemplateViewBuilder_default'); $this->assertStringContainsString($expected, $result); Cache::drop('default'); } /** * Test that when the cell cache is enabled, the cell action is only invoke the first * time the cell is rendered */ public function testCachedRenderSimpleCustomTemplateViewBuilder(): void { Cache::setConfig('default', ['className' => 'Array']); /** @var \TestApp\View\Cell\ArticlesCell $cell */ $cell = $this->View->cell('Articles::customTemplateViewBuilder', [], ['cache' => ['key' => 'celltest']]); $result = $cell->render(); $this->assertSame(1, $cell->counter); $cell->render(); $this->assertSame(1, $cell->counter); $this->assertStringContainsString('This is the alternate template', $result); Cache::drop('default'); } /** * Test that when the cell cache is enabled, the cell action is only invoke the first * time the cell is rendered */ public function testACachedViewCellReRendersWhenGivenADifferentTemplate(): void { Cache::setConfig('default', ['className' => 'Array']); $cell = $this->View->cell('Articles::customTemplateViewBuilder', [], ['cache' => true]); $result = $cell->render('alternate_teaser_list'); $result2 = $cell->render('not_the_alternate_teaser_list'); $this->assertStringContainsString('This is the alternate template', $result); $this->assertStringContainsString('This is NOT the alternate template', $result2); Cache::delete('celltest'); Cache::drop('default'); } /** * Tests events are dispatched correctly */ public function testCellRenderDispatchesEvents(): void { $args = ['msg1' => 'dummy', 'msg2' => ' message']; /** @var \TestApp\View\Cell\ArticlesCell $cell */ $cell = $this->View->cell('Articles::doEcho', $args); $beforeEventIsCalled = false; $afterEventIsCalled = false; $manager = $this->View->getEventManager(); $manager->on('Cell.beforeAction', function ($event, $eventCell, $action, $eventArgs) use ($cell, $args, &$beforeEventIsCalled): void { $this->assertSame($eventCell, $cell); $this->assertEquals('doEcho', $action); $this->assertEquals($args, $eventArgs); $beforeEventIsCalled = true; }); $manager->on('Cell.afterAction', function ($event, $eventCell, $action, $eventArgs) use ($cell, $args, &$afterEventIsCalled): void { $this->assertSame($eventCell, $cell); $this->assertEquals('doEcho', $action); $this->assertEquals($args, $eventArgs); $afterEventIsCalled = true; }); $cell->render(); $this->assertTrue($beforeEventIsCalled); $this->assertTrue($afterEventIsCalled); } }