diff --git a/demos/_unit-test/late-output-error.php b/demos/_unit-test/late-output-error.php index 4b9b371008..f9628205e6 100644 --- a/demos/_unit-test/late-output-error.php +++ b/demos/_unit-test/late-output-error.php @@ -4,25 +4,27 @@ namespace Atk4\Ui\Demos; +use Atk4\Ui\Button; +use Atk4\Ui\Callback; use Atk4\Ui\CallbackLater; +use Atk4\Ui\Header; +use Atk4\Ui\Modal; /** @var \Atk4\Ui\App $app */ require_once __DIR__ . '/../init-app.php'; -$cb = CallbackLater::addTo($app); -$cb->setUrlTrigger('err_headers_already_sent'); - -$modal = \Atk4\Ui\Modal::addTo($app, ['cb' => $cb]); -$modal->set(function () { +$cbH1 = Callback::addTo($app); +$cbH1->setUrlTrigger('err_headers_already_sent_1'); +$modalH1 = Modal::addTo($app, ['cb' => $cbH1]); +$modalH1->set(function () { header('x-unmanaged-header: test'); flush(); }); -$cb2 = CallbackLater::addTo($app); -$cb2->setUrlTrigger('err_unexpected_output_detected'); - -$modal2 = \Atk4\Ui\Modal::addTo($app, ['cb' => $cb2]); -$modal2->set(function () { +$cbO1 = Callback::addTo($app); +$cbO1->setUrlTrigger('err_unexpected_output_detected_1'); +$modalO1 = Modal::addTo($app, ['cb' => $cbO1]); +$modalO1->set(function () { // unexpected output can be detected only when output buffering is enabled and not flushed if (ob_get_level() === 0) { ob_start(); @@ -30,8 +32,28 @@ echo 'unmanaged output'; }); -$button = \Atk4\Ui\Button::addTo($app, ['Test LateOutputError: Headers already sent']); -$button->on('click', $modal->show()); +$cbH2 = CallbackLater::addTo($app); +$cbH2->setUrlTrigger('err_headers_already_sent_2'); +$modalH2 = Modal::addTo($app, ['cb' => $cbH2]); +$modalH2->set($modalH1->fx); + +$cbO2 = CallbackLater::addTo($app); +$cbO2->setUrlTrigger('err_unexpected_output_detected_2'); +$modalO2 = Modal::addTo($app, ['cb' => $cbO2]); +$modalO2->set($modalO1->fx); + +Header::addTo($app, ['content' => 'Before render (/w Callback)']); + +$buttonH1 = Button::addTo($app, ['Test LateOutputError I: Headers already sent']); +$buttonH1->on('click', $modalH1->show()); + +$buttonO1 = Button::addTo($app, ['Test LateOutputError I: Unexpected output detected']); +$buttonO1->on('click', $modalO1->show()); + +Header::addTo($app, ['content' => 'After render (/w CallbackLater)']); + +$buttonH2 = Button::addTo($app, ['Test LateOutputError II: Headers already sent']); +$buttonH2->on('click', $modalH2->show()); -$button2 = \Atk4\Ui\Button::addTo($app, ['Test LateOutputError: Unexpected output detected']); -$button2->on('click', $modal2->show()); +$buttonO2 = Button::addTo($app, ['Test LateOutputError II: Unexpected output detected']); +$buttonO2->on('click', $modalO2->show()); diff --git a/src/App.php b/src/App.php index ccf8ff6939..82ac2709d3 100644 --- a/src/App.php +++ b/src/App.php @@ -407,7 +407,7 @@ public function terminate($output = '', array $headers = []): void $this->outputResponse($output, $headers); } - $this->runCalled = true; // prevent shutdown function from triggering. + $this->runCalled = true; // prevent shutdown function from triggering $this->callExit(); } @@ -1116,6 +1116,8 @@ protected function outputLateOutputError(LateOutputError $exception): void $this->outputResponseUnsafe($plainTextMessage, $headersNew); + $this->runCalled = true; // prevent shutdown function from triggering + exit(1); // should be never reached from phpunit because we set catchExceptions = false } diff --git a/tests/DemosHttpTest.php b/tests/DemosHttpTest.php index 4d95b1118c..1b4810ea35 100644 --- a/tests/DemosHttpTest.php +++ b/tests/DemosHttpTest.php @@ -114,32 +114,30 @@ protected function getPathWithAppVars(string $path): string return parent::getPathWithAppVars($path); } - private function getLateOutputErrorPath(string $trigger): string + /** + * @dataProvider demoLateOutputErrorProvider + */ + public function testDemoLateOutputError(string $urlTrigger, string $expectedOutput): void { - return '_unit-test/late-output-error.php?' . Callback::URL_QUERY_TRIGGER_PREFIX . $trigger . '=ajax&' - . Callback::URL_QUERY_TARGET . '=' . $trigger . '&__atk_json=1'; - } + $path = '_unit-test/late-output-error.php?' . Callback::URL_QUERY_TRIGGER_PREFIX . $urlTrigger . '=ajax&' + . Callback::URL_QUERY_TARGET . '=' . $urlTrigger . '&__atk_json=1'; - public function testDemoLateOutputErrorHeadersAlreadySent(): void - { - $response = $this->getResponseFromRequest5xx($this->getLateOutputErrorPath('err_headers_already_sent')); + $response = $this->getResponseFromRequest5xx($path); $this->assertSame(500, $response->getStatusCode()); - $this->assertSame( - "\n" . '!! FATAL UI ERROR: Headers already sent, more headers cannot be set at this stage !!' . "\n", - $response->getBody()->getContents() - ); + $this->assertSame($expectedOutput, $response->getBody()->getContents()); } - public function testDemoLateOutputErrorUnexpectedOutputDetected(): void + public function demoLateOutputErrorProvider(): array { - $response = $this->getResponseFromRequest5xx($this->getLateOutputErrorPath('err_unexpected_output_detected')); - - $this->assertSame(500, $response->getStatusCode()); - $this->assertSame( - 'unmanaged output' - . "\n" . '!! FATAL UI ERROR: Unexpected output detected !!' . "\n", - $response->getBody()->getContents() - ); + $hOutput = "\n" . '!! FATAL UI ERROR: Headers already sent, more headers cannot be set at this stage !!' . "\n"; + $oOutput = 'unmanaged output' . "\n" . '!! FATAL UI ERROR: Unexpected output detected !!' . "\n"; + + return [ + ['err_headers_already_sent_2', $hOutput], + ['err_unexpected_output_detected_2', $oOutput], + ['err_headers_already_sent_1', $hOutput], + ['err_unexpected_output_detected_1', $oOutput], + ]; } }