From 904939aa6dd9236ac9e13f4a9454065f649b460f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Sat, 16 Oct 2021 03:35:27 +0200 Subject: [PATCH] Fix Behat for CI (#1682) --- .github/workflows/test-unit.yml | 25 ++++++++++--------------- behat.yml.dist | 11 +++++++---- composer.json | 6 +++--- demos/_unit-test/callback.php | 2 +- demos/data-action/jsactions.php | 4 ++-- demos/interactive/card.php | 4 ++-- demos/tutorial/actions.php | 18 +++++++++--------- docs/form.rst | 2 +- phpstan.neon.dist | 30 +++--------------------------- src/Behat/Context.php | 2 +- src/Card.php | 8 +++++--- src/CardDeck.php | 6 +++--- src/Form.php | 2 +- src/View.php | 2 +- src/VirtualPage.php | 2 +- 15 files changed, 50 insertions(+), 74 deletions(-) diff --git a/.github/workflows/test-unit.yml b/.github/workflows/test-unit.yml index 72cb5f58df..26af46972a 100644 --- a/.github/workflows/test-unit.yml +++ b/.github/workflows/test-unit.yml @@ -60,7 +60,7 @@ jobs: - name: Check Coding Style (only for CodingStyle) if: matrix.type == 'CodingStyle' run: | - if [ "$(find demos/ -name '*.php' -print0 | xargs -0 grep -L "namespace Atk4\\\\Ui\\\\Demos;" | tee /dev/fd/2)" ]; then echo 'All demos/ files must have namespace declared' && (exit 1); fi + if [ "$(find demos/ -name '*.php' -print0 | xargs -0 grep -L "namespace Atk4\\\\Ui\\\\Demos[;\\\\]" | tee /dev/fd/2)" ]; then echo 'All demos/ files must have namespace declared' && (exit 1); fi vendor/bin/php-cs-fixer fix --dry-run --using-cache=no --diff --verbose - name: Run Static Analysis (only for StaticAnalysis) @@ -219,7 +219,7 @@ jobs: name: Behat runs-on: ubuntu-latest container: - image: ghcr.io/mvorisek/image-php:${{ matrix.php }}-node + image: ghcr.io/mvorisek/image-php:${{ matrix.php }}-selenium strategy: fail-fast: false matrix: @@ -255,12 +255,6 @@ jobs: image: ghcr.io/mvorisek/docker-oracle-xe-11g env: ORACLE_ALLOW_REMOTE: true - selenium-chrome: - image: selenium/standalone-chrome:latest - options: --health-cmd "/opt/bin/check-grid.sh" - selenium-firefox: - image: selenium/standalone-firefox:latest - options: --health-cmd "/opt/bin/check-grid.sh" steps: - name: Checkout uses: actions/checkout@v2 @@ -339,16 +333,17 @@ jobs: if [ -n "$LOG_COVERAGE" ]; then mkdir coverage && cp tools/CoverageUtil.php demos; fi sed -E "s/\(('sqlite:.+)\);/(\$_ENV['DB_DSN'] ?? \\1, \$_ENV['DB_USER'] ?? null, \$_ENV['DB_PASSWORD'] ?? null);/g" -i demos/db.default.php sed -i "s~'https://raw.githack.com/atk4/ui/develop/public.*~'/public',~" src/App.php - php -S 172.18.0.2:8888 > /dev/null 2>&1 & - sleep 0.2 + ci_wait_until () { timeout 30 sh -c "until { $1 2> /dev/null; }; do sleep 0.02; done" || timeout 15 sh -c "$1" || { echo "health timeout: $1"; exit 1; }; } + php -S 127.0.0.1:8888 > /dev/null 2>&1 & + ci_wait_until 'nc -w 1 127.0.0.1 8888' + if [ -f /etc/alpine-release ]; then addgroup browser && adduser browser -G browser -D -s /bin/sh; else adduser browser --gecos "" --disabled-login -shell /bin/sh > /dev/null; fi + { Xvfb -ac :99 -screen 0 1920x1200x24 2> /dev/null & } && export DISPLAY=:99 + ci_wait_until '[ -e /tmp/.X11-unix/X99 ]' + su browser -c 'java -Dwebdriver.chrome.whitelistedIps=127.0.0.1 -jar /opt/selenium-server-standalone.jar -role standalone -host 127.0.0.1 -port 4444 -sessionTimeout 15 -browserTimeout 12 > /dev/null 2>&1 &' + ci_wait_until 'nc -w 1 127.0.0.1 4444' if [ "${{ matrix.type }}" == "Firefox" ]; then sed -i "s~chrome~firefox~" behat.yml.dist; fi if [ "${{ matrix.type }}" == "Chrome Slow" ]; then echo 'sleep(1);' >> demos/init-app.php; fi - # remove once https://github.com/minkphp/Mink/pull/801 - # and https://github.com/minkphp/MinkSelenium2Driver/pull/322 are released - sed -i 's/usleep(100000)/usleep(5000)/' vendor/behat/mink/src/Element/Element.php - sed -i 's/usleep(100000)/usleep(5000)/' vendor/behat/mink-selenium2-driver/src/Selenium2Driver.php - - name: "Run tests: SQLite" run: | php demos/_demo-data/create-db.php diff --git a/behat.yml.dist b/behat.yml.dist index 4d149d5332..10c40d4d33 100644 --- a/behat.yml.dist +++ b/behat.yml.dist @@ -1,6 +1,6 @@ default: suites: - atk4_ui: + main: paths: features: '%paths.base%/tests-behat' contexts: @@ -8,15 +8,18 @@ default: - Atk4\Ui\Behat\Context extensions: Behat\MinkExtension: - base_url: 'http://172.18.0.2:8888/demos' + base_url: 'http://127.0.0.1:8888/demos' sessions: default: selenium2: browser: chrome - wd_host: 'http://selenium-chrome:4444/wd/hub' + wd_host: 'http://127.0.0.1:4444/wd/hub' capabilities: extra_capabilities: chrome: args: + - '--no-sandbox' - '--headless' - - '--window-size=1930,1200' + - '--disable-dev-shm-usage' + - '--disable-gpu' + - '--window-size=1920,1200' diff --git a/composer.json b/composer.json index bc33ce4b99..e80092cedf 100644 --- a/composer.json +++ b/composer.json @@ -62,10 +62,10 @@ }, "require-dev": { "behat/behat": "^3.8.2 || dev-master#6f38d11", - "behat/gherkin": "^4.8.1 || dev-master#5fbf806", - "behat/mink": "^1.8.2 || dev-master#1ab79d6", + "behat/gherkin": "^4.9", + "behat/mink": "^1.9", "behat/mink-extension": "^2.3.1", - "behat/mink-selenium2-driver": "^1.4", + "behat/mink-selenium2-driver": "^1.5", "ergebnis/composer-normalize": "^2.13", "friendsofphp/php-cs-fixer": "^3.0", "fzaninotto/faker": "^1.6", diff --git a/demos/_unit-test/callback.php b/demos/_unit-test/callback.php index 626bf1ae06..3fe3f9b3fb 100644 --- a/demos/_unit-test/callback.php +++ b/demos/_unit-test/callback.php @@ -25,7 +25,7 @@ $form->setModel($m->tryLoadAny(), [$m->fieldName()->name]); $form->getControl($m->fieldName()->name)->caption = 'TestName'; -$table = $app->add(new \Atk4\Ui\Table()); +$table = \Atk4\Ui\Table::addTo($app); $table->setModel($m); $button = Button::addTo($app, ['First', ['ui' => 'atk-test']]); diff --git a/demos/data-action/jsactions.php b/demos/data-action/jsactions.php index 1a1578fd58..8075b5415d 100644 --- a/demos/data-action/jsactions.php +++ b/demos/data-action/jsactions.php @@ -66,9 +66,9 @@ // Card component. $card = \Atk4\Ui\Card::addTo($app); $content = new \Atk4\Ui\View(['class' => ['content']]); -$content->add($img = new \Atk4\Ui\Image(['../images/kristy.png'])); +$img = \Atk4\Ui\Image::addTo($content, ['../images/kristy.png']); $img->addClass('right floated mini ui image'); -$content->add(new \Atk4\Ui\Header(['Kristy'])); +\Atk4\Ui\Header::addTo($content, ['Kristy']); $card->addContent($content); $card->addDescription('Kristy is a friend of Mully.'); diff --git a/demos/interactive/card.php b/demos/interactive/card.php index 8eb8d5fbd2..fb8b05fd71 100644 --- a/demos/interactive/card.php +++ b/demos/interactive/card.php @@ -33,9 +33,9 @@ $card = \Atk4\Ui\Card::addTo($app); $content = new \Atk4\Ui\View(['class' => ['content']]); -$content->add($img = new \Atk4\Ui\Image(['../images/kristy.png'])); +$img = \Atk4\Ui\Image::addTo($content, ['../images/kristy.png']); $img->addClass('right floated mini ui image'); -$content->add($header = new \Atk4\Ui\Header(['Kristy'])); +$header = \Atk4\Ui\Header::addTo($content, ['Kristy']); $card->addContent($content); $card->addDescription('Friend of Bob'); diff --git a/demos/tutorial/actions.php b/demos/tutorial/actions.php index 92dbb4ade9..f1c0ccc4c1 100644 --- a/demos/tutorial/actions.php +++ b/demos/tutorial/actions.php @@ -36,7 +36,7 @@ EOF ); - $page->add(new Demo())->setCodeAndCall(function (View $owner) { + Demo::addTo($page)->setCodeAndCall(function (View $owner) { $country = new \Atk4\Ui\Demos\CountryLock($owner->getApp()->db); $country->addUserAction('send_message'); @@ -59,7 +59,7 @@ EOF ); - $page->add(new Demo())->setCodeAndCall(function (View $owner) { + Demo::addTo($page)->setCodeAndCall(function (View $owner) { $country = new \Atk4\Ui\Demos\CountryLock($owner->getApp()->db); $country->addUserAction('send_message', function () { @@ -83,7 +83,7 @@ EOF ); - $page->add(new Demo())->setCodeAndCall(function (View $owner) { + Demo::addTo($page)->setCodeAndCall(function (View $owner) { $country = new \Atk4\Ui\Demos\CountryLock($owner->getApp()->db); $country = $country->loadAny(); @@ -99,7 +99,7 @@ EOF ); - $page->add(new Demo())->setCodeAndCall(function (View $owner) { + Demo::addTo($page)->setCodeAndCall(function (View $owner) { $country = new \Atk4\Ui\Demos\CountryLock($owner->getApp()->db); $country = $country->loadAny(); @@ -119,7 +119,7 @@ EOF ); - $page->add(new Demo())->setCodeAndCall(function (View $owner) { + Demo::addTo($page)->setCodeAndCall(function (View $owner) { $model = new \Atk4\Data\Model($owner->getApp()->db, ['table' => 'test']); $model->addUserAction('greet', [ @@ -147,9 +147,9 @@ }, ]); - $owner->add(new \Atk4\Ui\Form\Control\Line([ + \Atk4\Ui\Form\Control\Line::addTo($owner, [ 'action' => $model->getUserAction('greet'), - ])); + ]); \Atk4\Ui\View::addTo($owner, ['ui' => 'divider']); @@ -160,7 +160,7 @@ /* $wizard->addStep('More Ways', function ($page) { - $page->add(new Demo(['left_width' => 5, 'right_width' => 11]))->setCodeAndCall(function (View $owner) { + Demo::addTo($page, ['left_width' => 5, 'right_width' => 11])->setCodeAndCall(function (View $owner) { $model = new Stat($owner->getApp()->db); $model->addUserAction('mail', [ 'fields' => ['currency_field'], @@ -187,7 +187,7 @@ functionality and more. Next example shows how you can disable user action (add) EOF ); - $page->add(new Demo())->setCodeAndCall(function (View $owner) { + Demo::addTo($page)->setCodeAndCall(function (View $owner) { $country = new \Atk4\Ui\Demos\CountryLock($owner->getApp()->db); $country->getUserAction('add')->enabled = false; $country->getUserAction('delete')->enabled = function (Country $m) { return $m->id % 2 === 0; }; diff --git a/docs/form.rst b/docs/form.rst index 253dfc0001..c06b98b9dc 100644 --- a/docs/form.rst +++ b/docs/form.rst @@ -77,7 +77,7 @@ decorators defined at ``\Atk4\Ui\Form::Control``. See dedicated documentation fo To tweak the UI properties of an form control input use ``setInputAttr()`` (and not the surrounding
as ``setAttr()`` would do). Here is how to set the HTML "maxlength" attribute on the generated input field:: - $form = $this->add(new \Atk4\Ui\Form); + $form = \Atk4\Ui\Form::addTo($this); $form->setModel($model); $form->getControl('name')->setInputAttr('maxlength', 20); diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 176bff759f..3e03d09da6 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -42,12 +42,6 @@ parameters: - path: 'demos/_includes/Demo.php' message: '~^Call to an undefined method Atk4\\Ui\\JsChain::initHighlighting\(\)\.$~' - - - path: 'demos/_unit-test/callback.php' - message: '~^Call to an undefined method Atk4\\Ui\\AbstractView::setModel\(\)\.$~' - - - path: 'demos/_unit-test/callback.php' - message: '~^Call to an undefined method Atk4\\Ui\\AbstractView::jsReload\(\)\.$~' - path: 'demos/collection/tablefilter.php' message: '~^Call to an undefined method Atk4\\Ui\\Demos\\CountryLock::expr\(\)\.$~' @@ -144,6 +138,9 @@ parameters: - path: 'src/CallbackLater.php' message: '~^Method Atk4\\Ui\\CallbackLater::set\(\) should return mixed but return statement is missing\.$~' + - + path: 'src/Card.php' + message: '~^Call to an undefined method Atk4\\Ui\\AbstractView::setAction\(\)\.$~' - path: 'src/Card.php' message: '~^Call to an undefined method Atk4\\Ui\\View::addFields\(\)\.$~' @@ -321,9 +318,6 @@ parameters: - path: 'src/Card.php' message: '~^Method Atk4\\Ui\\Card::addButton\(\) should return Atk4\\Ui\\View\|null but returns Atk4\\Ui\\AbstractView\.$~' - - - path: 'src/CardDeck.php' - message: '~^Property Atk4\\Ui\\CardDeck::\$card \(Atk4\\Ui\\View\|string\) does not accept default value of type array\\.$~' - path: 'src/CardDeck.php' message: '~^Property Atk4\\Ui\\CardDeck::\$container \(Atk4\\Ui\\View\|null\) does not accept default value of type array\\.$~' @@ -366,9 +360,6 @@ parameters: - path: 'src/Crud.php' message: '~^Parameter \#2 \$fields \(array\|null\) of method Atk4\\Ui\\Crud::setModel\(\) should be contravariant with parameter \$columns \(array\|bool\) of method Atk4\\Ui\\Grid::setModel\(\)$~' - - - path: 'src/Form.php' - message: '~^Property Atk4\\Ui\\Form::\$cb \(Atk4\\Ui\\Callback\) does not accept Atk4\\Ui\\AbstractView\.$~' - path: 'src/Form.php' message: '~^Property Atk4\\Ui\\Form::\$layout \(Atk4\\Ui\\Form\\Layout\) does not accept array\\.$~' @@ -525,9 +516,6 @@ parameters: - path: 'src/View.php' message: '~^Method Atk4\\Ui\\View::getClosestOwner\(\) should return Atk4\\Ui\\View\|null but empty return statement found\.$~' - - - path: 'src/VirtualPage.php' - message: '~^Property Atk4\\Ui\\VirtualPage::\$cb \(Atk4\\Ui\\Callback\) does not accept Atk4\\Ui\\AbstractView\.$~' - path: 'src/VirtualPage.php' message: '~^Parameter \#1 \$fx \(Closure\) of method Atk4\\Ui\\VirtualPage::set\(\) should be contravariant with parameter \$arg1 \(mixed\) of method Atk4\\Ui\\View::set\(\)$~' @@ -840,9 +828,6 @@ parameters: - path: 'src/Card.php' message: '~^Parameter \#2 \$selector of method Atk4\\Ui\\View::on\(\) expects Atk4\\Ui\\JsExpressionable\|string\|null, Atk4\\Data\\Model\\UserAction given\.$~' - - - path: 'src/Form.php' - message: '~^Parameter \#1 \$object of method Atk4\\Ui\\View::add\(\) expects Atk4\\Ui\\View, Atk4\\Ui\\JsCallback given\.$~' - path: 'src/Form.php' message: '~^Parameter \#2 \$value of method Atk4\\Ui\\View::setAttr\(\) expects string\|null, int given\.$~' @@ -885,12 +870,6 @@ parameters: - path: 'src/UserAction/ModalExecutor.php' message: '~^Parameter \#2 \$selector of method Atk4\\Ui\\View::on\(\) expects Atk4\\Ui\\JsExpressionable\|string\|null, array\ given\.$~' - - - path: 'src/View.php' - message: '~^Parameter \#1 \$object of method Atk4\\Ui\\View::add\(\) expects Atk4\\Ui\\View, Atk4\\Ui\\JsCallback given\.$~' - - - path: 'src/VirtualPage.php' - message: '~^Parameter \#1 \$object of method Atk4\\Ui\\View::add\(\) expects Atk4\\Ui\\View, array\ given\.$~' - path: 'tests/JsTest.php' message: '~^Parameter \#1 \$args of class Atk4\\Ui\\JsFunction constructor expects array, null given\.$~' @@ -1146,9 +1125,6 @@ parameters: - path: 'src/Card.php' message: '~^Method Atk4\\Ui\\Card::addAction\(\) has parameter \$button with no typehint specified\.$~' - - - path: 'src/Card.php' - message: '~^Method Atk4\\Ui\\Card::addAction\(\) has parameter \$executor with no typehint specified\.$~' - path: 'src/Card.php' message: '~^Method Atk4\\Ui\\Card::addExtraFields\(\) has no return typehint specified\.$~' diff --git a/src/Behat/Context.php b/src/Behat/Context.php index 26f86b524d..51215c50d2 100644 --- a/src/Behat/Context.php +++ b/src/Behat/Context.php @@ -77,7 +77,7 @@ protected function jqueryWait(string $extraWaitCondition = 'true', int $maxWaitd } } - throw new Exception('jQuery did not finished within a time limit'); + throw new Exception('jQuery did not finish within a time limit'); } protected function disableAnimations(): void diff --git a/src/Card.php b/src/Card.php index 4c4aafbafe..6b3797181b 100644 --- a/src/Card.php +++ b/src/Card.php @@ -267,18 +267,20 @@ public function addSection(string $title = null, Model $model = null, array $fie /** * Add action executor to card. + * + * @param class-string $executorClass */ - public function addAction(Model\UserAction $action, $executor, $button = null) + public function addAction(Model\UserAction $action, $executorClass, $button = null) { if (!$button) { $button = new Button([$action->caption]); } $btn = $this->addButton($button); - $vp = VirtualPage::addTo($this)->set(function ($page) use ($executor, $action) { + $vp = VirtualPage::addTo($this)->set(function (View $page) use ($executorClass, $action) { $id = $this->stickyGet($this->name); - $page->add($executor = new $executor()); + $executor = $page->add(new $executorClass()); $action->setEntity($action->getModel()->load($id)); diff --git a/src/CardDeck.php b/src/CardDeck.php index ec7223ef0c..249a3ac533 100644 --- a/src/CardDeck.php +++ b/src/CardDeck.php @@ -16,8 +16,8 @@ class CardDeck extends View { public $ui = ''; - /** @var string|View Card type inside this deck. */ - public $card = [Card::class]; + /** @var string Card type inside this deck. */ + public $card = Card::class; /** @var string default template file. */ public $defaultTemplate = 'card-deck.html'; @@ -144,7 +144,7 @@ public function setModel(Model $model, array $fields = null, array $extra = null if ($count = $this->initPaginator()) { $this->model->each(function ($m) use ($fields, $extra) { - $c = $this->cardHolder->add(Factory::factory($this->card, ['useLabel' => $this->useLabel, 'useTable' => $this->useTable]))->addClass('segment'); + $c = $this->cardHolder->add(Factory::factory([$this->card], ['useLabel' => $this->useLabel, 'useTable' => $this->useTable]))->addClass('segment'); $c->setModel($m, $fields); if ($extra) { $c->addExtraFields($m, $extra, $this->extraGlue); diff --git a/src/Form.php b/src/Form.php index d755025a2d..7914261db7 100644 --- a/src/Form.php +++ b/src/Form.php @@ -184,7 +184,7 @@ protected function init(): void // set css loader for this form $this->setApiConfig(['stateContext' => '#' . $this->name]); - $this->cb = $this->add(new JsCallback(), ['desired_name' => 'submit']); + $this->cb = JsCallback::addTo($this, [], [['desired_name' => 'submit']]); } /** diff --git a/src/View.php b/src/View.php index f68c7bef32..a0c81ce93c 100644 --- a/src/View.php +++ b/src/View.php @@ -1104,7 +1104,7 @@ public function on($event, $selector = null, $action = null, $defaults = null) } // create callback, that will include event as part of the full name - $this->add($cb = new JsCallback(), ['desired_name' => $event]); + $cb = JsCallback::addTo($this, [], [['desired_name' => $event]]); if ($defaults['apiConfig'] ?? null) { $cb->apiConfig = $defaults['apiConfig']; } diff --git a/src/VirtualPage.php b/src/VirtualPage.php index 5ad5bd8cf5..e9a5a6a200 100644 --- a/src/VirtualPage.php +++ b/src/VirtualPage.php @@ -31,7 +31,7 @@ protected function init(): void { parent::init(); - $this->cb = $this->add([Callback::class, 'urlTrigger' => $this->urlTrigger ?: $this->name]); + $this->cb = Callback::addTo($this, ['urlTrigger' => $this->urlTrigger ?: $this->name]); unset($this->{'urlTrigger'}); }