Skip to content

Commit

Permalink
Fast testing without webserver (#1277)
Browse files Browse the repository at this point in the history
* Refactor layout demos

* Refactor before testing without builtin webserver

* Add demos testing without HTTP

* Fix for PHP 7.2: Cannot determine time at which the request started

* Set more $_SERVER superglobals

* Run tests in single phpunit but still slow/http tests at the end

* Remove debug code

* Refactor/cleanup

* Run with coverage.php only if copied manually

* Load coverage.php only if not run with phpunit directly

* Convert props to nonstatic if possible
  • Loading branch information
mvorisek committed Jun 18, 2020
1 parent 5801cb3 commit 1da7b58
Show file tree
Hide file tree
Showing 22 changed files with 625 additions and 475 deletions.
6 changes: 4 additions & 2 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,12 @@ jobs:
if: matrix.type == 'Phpunit'
run: |
if [ -n "$LOG_COVERAGE" ]; then
vendor/bin/phpunit --coverage-text -v
cp tools/coverage.php demos
mkdir coverage
vendor/bin/phpunit --exclude-group none --coverage-text -v
ls -l coverage | wc -l && mv coverage/* build/logs
else
vendor/bin/phpunit --no-coverage -v
vendor/bin/phpunit --exclude-group none --no-coverage -v
fi
# - name: "Run tests: Behat (only for Behat)"
Expand Down
2 changes: 1 addition & 1 deletion codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ coverage:
project:
default:
target: auto
threshold: 0.1
threshold: 0.025
patch: false
changes: false
1 change: 1 addition & 0 deletions demos/db.default.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@
throw new \Exception('Sqlite database does not exist, create it first.');
}
$db = new \atk4\data\Persistence\SQL('sqlite:' . $sqliteFile);
unset($sqliteFile);
4 changes: 2 additions & 2 deletions demos/init-app.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
unset($isRootProject, $loader);

// collect coverage for HTTP tests 1/2
if (file_exists(__DIR__ . '/coverage.php')) {
if (file_exists(__DIR__ . '/coverage.php') && !class_exists(\PHPUnit\Framework\TestCase::class, false)) {
require_once __DIR__ . '/coverage.php';
\CoverageUtil::start();
}
Expand All @@ -36,7 +36,7 @@
}

// collect coverage for HTTP tests 2/2
if (file_exists(__DIR__ . '/coverage.php')) {
if (file_exists(__DIR__ . '/coverage.php') && !class_exists(\PHPUnit\Framework\TestCase::class, false)) {
$app->onHook(\atk4\ui\App::HOOK_BEFORE_EXIT, function () {
\CoverageUtil::saveData();
});
Expand Down
90 changes: 39 additions & 51 deletions demos/layout/layouts_admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,67 +7,55 @@
/** @var \atk4\ui\App $app */
require_once __DIR__ . '/../init-app.php';

try {
$app = new \atk4\ui\App('Agile Toolkit Demo App');
$layout = \atk4\ui\Layout\Admin::addTo($app);

$app->initLayout(\atk4\ui\Layout\Admin::class);
$m_comp = $layout->menu->addMenu(['Layouts', 'icon' => 'puzzle']);
$m_comp->addItem(\atk4\ui\Layout\Centered::class);
$m_comp->addItem(\atk4\ui\Layout\Admin::class);

$m_comp = $app->layout->menu->addMenu(['Layouts', 'icon' => 'puzzle']);
$m_comp->addItem(\atk4\ui\Layout\Centered::class);
$m_comp->addItem(\atk4\ui\Layout\Admin::class);
$m_right = $layout->menuRight;
$m_right->addItem(['Warning', 'red', 'icon' => 'red warning']);
$m_user = $m_right->addMenu('John Smith');
$m_user->addItem('Profile');
$m_user->addDivider();
$m_user->addItem('Logout');

$m_right = $app->layout->menuRight;
$m_right->addItem(['Warning', 'red', 'icon' => 'red warning']);
$m_user = $m_right->addMenu('John Smith');
$m_user->addItem('Profile');
$m_user->addDivider();
$m_user->addItem('Logout');
$m_comp = $layout->menu->addMenu(['Component Demo', 'icon' => 'puzzle']);
$m_form = $m_comp->addMenu('Forms');
$m_form->addItem('Form Elements');
$m_form->addItem('Form Layouts');
$m_comp->addItem('CRUD');

$m_comp = $app->layout->menu->addMenu(['Component Demo', 'icon' => 'puzzle']);
$m_form = $m_comp->addMenu('Forms');
$m_form->addItem('Form Elements');
$m_form->addItem('Form Layouts');
$m_comp->addItem('CRUD');
$layout->menuLeft->addItem(['Home', 'icon' => 'home']);
$layout->menuLeft->addItem(['Topics', 'icon' => 'block layout']);
$layout->menuLeft->addItem(['Friends', 'icon' => 'smile']);
$layout->menuLeft->addItem(['History', 'icon' => 'calendar']);
$layout->menuLeft->addItem(['Settings', 'icon' => 'cogs']);

$app->layout->menuLeft->addItem(['Home', 'icon' => 'home']);
$app->layout->menuLeft->addItem(['Topics', 'icon' => 'block layout']);
$app->layout->menuLeft->addItem(['Friends', 'icon' => 'smile']);
$app->layout->menuLeft->addItem(['History', 'icon' => 'calendar']);
$app->layout->menuLeft->addItem(['Settings', 'icon' => 'cogs']);
$layout->template['Footer'] = 'ATK is awesome';

$app->layout->template['Footer'] = 'ATK is awesome';
\atk4\ui\Header::addTo($layout, ['Basic Form Example']);

\atk4\ui\Header::addTo($app, ['Basic Form Example']);
$f = \atk4\ui\Form::addTo($layout, ['segment']);
$f->setModel(new \atk4\data\Model());

$f = \atk4\ui\Form::addTo($app, ['segment']);
$f->setModel(new \atk4\data\Model());
$f_group = $f->addGroup('Name');
$f_group->addField('first_name', ['width' => 'eight']);
$f_group->addField('middle_name', ['width' => 'three']);
$f_group->addField('last_name', ['width' => 'five']);

$f_group = $f->addGroup('Name');
$f_group->addField('first_name', ['width' => 'eight']);
$f_group->addField('middle_name', ['width' => 'three']);
$f_group->addField('last_name', ['width' => 'five']);
$f_group = $f->addGroup('Address');
$f_group->addField('address', ['width' => 'twelve']);
$f_group->addField('zip', ['width' => 'four']);

$f_group = $f->addGroup('Address');
$f_group->addField('address', ['width' => 'twelve']);
$f_group->addField('zip', ['width' => 'four']);
$f->onSubmit(function (\atk4\ui\Form $form) {
$errors = [];

$f->onSubmit(function (\atk4\ui\Form $form) {
$errors = [];

foreach (['first_name', 'last_name', 'address'] as $field) {
if (!$form->model->get($field)) {
$errors[] = $form->error($field, 'Field ' . $field . ' is mandatory');
}
foreach (['first_name', 'last_name', 'address'] as $field) {
if (!$form->model->get($field)) {
$errors[] = $form->error($field, 'Field ' . $field . ' is mandatory');
}
}

return $errors ?: $form->success('No more errors', 'so we have saved everything into the database');
});

$app->run();
} catch (\atk4\core\Exception $e) {
var_dump($e->getMessage());

var_dump($e->getParams());

throw $e;
}
return $errors ?: $form->success('No more errors', 'so we have saved everything into the database');
});
7 changes: 5 additions & 2 deletions demos/layout/layouts_manual.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@
/** @var \atk4\ui\App $app */
require_once __DIR__ . '/../init-app.php';

$layout = new \atk4\ui\Layout\Generic(['defaultTemplate' => __DIR__ . '/../templates/layout1.html']);
$layout = new \atk4\ui\Layout\Generic(['defaultTemplate' => __DIR__ . '/templates/layout1.html']);

\atk4\ui\Lister::addTo($layout, [], ['Report'])
->setModel(new SomeData());

echo $layout->render();
$app->html = null;
$app->initLayout(\atk4\ui\Layout\Generic::class);

\atk4\ui\Text::addTo($app->layout)->addHTML($layout->render());
6 changes: 5 additions & 1 deletion demos/layout/layouts_nolayout.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,9 @@

// nothing to do with Agile UI - will not use any Layout
$a = new \atk4\ui\LoremIpsum();
$text = $a->generateLorem(150);

echo htmlspecialchars($a->generateLorem(150));
$app->html = null;
$app->initLayout(\atk4\ui\Layout\Generic::class);

\atk4\ui\Text::addTo($app->layout)->addParagraph($text);
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 0 additions & 1 deletion demos/templates/index1.html

This file was deleted.

11 changes: 11 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,19 @@
<testsuites>
<testsuite name="tests">
<directory>tests</directory>
<file>tests/DemosTest.php</file>
<file>tests/DemosHttpTest.php</file>
<file>tests/DemosHttpNoExitTest.php</file>
<exclude>tests/DemosTest.php</exclude>
<exclude>tests/DemosHttpTest.php</exclude>
<exclude>tests/DemosHttpNoExitTest.php</exclude>
</testsuite>
</testsuites>
<groups>
<exclude>
<group>demos_http</group>
</exclude>
</groups>
<logging>
<log type="coverage-php" target="build/logs/clover.cov"/>
</logging>
Expand Down
40 changes: 22 additions & 18 deletions src/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ static function ($severity, $msg, $file, $line) {
/**
* @param bool $for_shutdown if true will not pass in caughtException method
*/
public function callExit($for_shutdown = false)
public function callExit($for_shutdown = false): void
{
if (!$this->exit_called) {
$this->exit_called = true;
Expand Down Expand Up @@ -1000,11 +1000,11 @@ public function encodeJson($data, bool $forceObject = false): string
* Return exception message using HTML block and Semantic UI formatting. It's your job
* to put it inside boilerplate HTML and output, e.g:.
*
* $l = new \atk4\ui\App();
* $l->initLayout(\atk4\ui\Layout\Centered::class);
* $l->layout->template->setHTML('Content', $e->getHTML());
* $l->run();
* exit;
* $app = new \atk4\ui\App();
* $app->initLayout(\atk4\ui\Layout\Centered::class);
* $app->layout->template->setHTML('Content', $e->getHTML());
* $app->run();
* $app->callExit(true);
*/
public function renderExceptionHTML(\Throwable $exception): string
{
Expand Down Expand Up @@ -1054,33 +1054,37 @@ protected function outputResponse(string $data, array $headers): void
$headersAll = array_merge($this->response_headers, $this->normalizeHeaders($headers));
$headersNew = array_diff_assoc($headersAll, self::$_sentHeaders);

$isCli = \PHP_SAPI === 'cli'; // for phpunit

$lateErrorStr = null;
foreach (ob_get_status(true) as $status) {
if ($status['buffer_used'] !== 0) {
if ($status['buffer_used'] !== 0 && !$isCli) {
$lateErrorStr = $this->buildLateErrorStr('Unexpected output detected.');

break;
}
}

if ($lateErrorStr === null && count($headersNew) > 0 && headers_sent()) {
if ($lateErrorStr === null && count($headersNew) > 0 && headers_sent() && !$isCli) {
$lateErrorStr = $this->buildLateErrorStr('Headers already sent, more headers can not be set at this stage.');
}

if (!headers_sent()) {
if (!headers_sent() || $isCli) {
if ($lateErrorStr !== null) {
$headersNew = ['content-type' => 'text/plain', self::HEADER_STATUS_CODE => '500'];
}

foreach ($headersNew as $k => $v) {
if ($k === self::HEADER_STATUS_CODE) {
http_response_code($v === (string) (int) $v ? (int) $v : 500);
} else {
$kCamelCase = preg_replace_callback('~(?<![a-zA-Z])[a-z]~', function ($matches) {
return strtoupper($matches[0]);
}, $k);

header($kCamelCase . ': ' . $v);
if (!$isCli) {
if ($k === self::HEADER_STATUS_CODE) {
http_response_code($v === (string) (int) $v ? (int) $v : 500);
} else {
$kCamelCase = preg_replace_callback('~(?<![a-zA-Z])[a-z]~', function ($matches) {
return strtoupper($matches[0]);
}, $k);

header($kCamelCase . ': ' . $v);
}
}

self::$_sentHeaders[$k] = $v;
Expand All @@ -1089,7 +1093,7 @@ protected function outputResponse(string $data, array $headers): void

if ($lateErrorStr !== null) {
echo $lateErrorStr;
exit;
exit(1);
}

echo $data;
Expand Down
Loading

0 comments on commit 1da7b58

Please sign in to comment.