From 7681bdb20ea57860d6b3fc4b912f23075f1333d8 Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Fri, 12 Jun 2020 12:11:21 +0800 Subject: [PATCH] MDL-66979: Switch to php-webdriver/webdriver This is currently using oleg-andreyev/MinkPhpWebDriver but I have raised https://github.com/oleg-andreyev/MinkPhpWebDriver/issues/4 to look at moving the project to php-wbdriver/MinkPhpWebDriver and trying to push it as the authoritative Mink driver. --- composer.json | 10 +- composer.lock | 2833 +++++++++++++++++ .../Driver/MoodleSelenium2Driver.php | 302 -- .../Driver/MoodleSelenium2Factory.php | 180 -- .../BehatExtension/Driver/Selenium2/README.md | 12 - .../Driver/Selenium2/moodle_syn-min.js | 8 - .../Driver/Selenium2/moodle_syn.js | 2658 ---------------- .../BehatExtension/Driver/WebDriver.php | 59 + .../Driver/WebDriverFactory.php | 50 + .../BehatExtension/Element/NodeElement.php | 94 - .../Output/Printer/MoodleProgressPrinter.php | 6 +- .../ServiceContainer/BehatExtension.php | 4 +- 12 files changed, 2954 insertions(+), 3262 deletions(-) create mode 100644 composer.lock delete mode 100755 src/Moodle/BehatExtension/Driver/MoodleSelenium2Driver.php delete mode 100644 src/Moodle/BehatExtension/Driver/MoodleSelenium2Factory.php delete mode 100644 src/Moodle/BehatExtension/Driver/Selenium2/README.md delete mode 100644 src/Moodle/BehatExtension/Driver/Selenium2/moodle_syn-min.js delete mode 100644 src/Moodle/BehatExtension/Driver/Selenium2/moodle_syn.js create mode 100644 src/Moodle/BehatExtension/Driver/WebDriver.php create mode 100644 src/Moodle/BehatExtension/Driver/WebDriverFactory.php delete mode 100644 src/Moodle/BehatExtension/Element/NodeElement.php diff --git a/composer.json b/composer.json index ab45fd5..d872f55 100644 --- a/composer.json +++ b/composer.json @@ -18,15 +18,21 @@ "role": "Developer" } ], + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/andrewnicols/MinkPhpWebDriver.git" + } + ], "require": { "php": ">=7.2.0", "behat/mink": "~1.8", "behat/mink-extension": "~2.3", "behat/mink-goutte-driver": "~1.2", - "behat/mink-selenium2-driver": "~1.4", + "oleg-andreyev/mink-facebook-web-driver": "dev-w3c", "symfony/process": "^4.0 || ^5.0", "behat/behat": "3.6.*" - }, + }, "autoload": { "psr-0": { "Moodle\\BehatExtension": "src/" diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..968e4aa --- /dev/null +++ b/composer.lock @@ -0,0 +1,2833 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "c5772825c6201687f60ca008da834692", + "packages": [ + { + "name": "behat/behat", + "version": "v3.6.1", + "source": { + "type": "git", + "url": "https://github.com/Behat/Behat.git", + "reference": "9bfe195b4745c32e068af03fa4df9558b4916d30" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Behat/Behat/zipball/9bfe195b4745c32e068af03fa4df9558b4916d30", + "reference": "9bfe195b4745c32e068af03fa4df9558b4916d30", + "shasum": "" + }, + "require": { + "behat/gherkin": "^4.6.0", + "behat/transliterator": "^1.2", + "container-interop/container-interop": "^1.2", + "ext-mbstring": "*", + "php": ">=5.3.3", + "psr/container": "^1.0", + "symfony/config": "^2.7.51 || ^3.0 || ^4.0 || ^5.0", + "symfony/console": "^2.7.51 || ^2.8.33 || ^3.3.15 || ^3.4.3 || ^4.0.3 || ^5.0", + "symfony/dependency-injection": "^2.7.51 || ^3.0 || ^4.0 || ^5.0", + "symfony/event-dispatcher": "^2.7.51 || ^3.0 || ^4.0 || ^5.0", + "symfony/translation": "^2.7.51 || ^3.0 || ^4.0 || ^5.0", + "symfony/yaml": "^2.7.51 || ^3.0 || ^4.0 || ^5.0" + }, + "require-dev": { + "herrera-io/box": "~1.6.1", + "phpunit/phpunit": "^4.8.36 || ^6.3", + "symfony/process": "~2.5 || ^3.0 || ^4.0 || ^5.0" + }, + "suggest": { + "ext-dom": "Needed to output test results in JUnit format." + }, + "bin": [ + "bin/behat" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.6.x-dev" + } + }, + "autoload": { + "psr-4": { + "Behat\\Behat\\": "src/Behat/Behat/", + "Behat\\Testwork\\": "src/Behat/Testwork/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + } + ], + "description": "Scenario-oriented BDD framework for PHP 5.3", + "homepage": "http://behat.org/", + "keywords": [ + "Agile", + "BDD", + "ScenarioBDD", + "Scrum", + "StoryBDD", + "User story", + "business", + "development", + "documentation", + "examples", + "symfony", + "testing" + ], + "time": "2020-02-06T09:54:48+00:00" + }, + { + "name": "behat/gherkin", + "version": "v4.6.2", + "source": { + "type": "git", + "url": "https://github.com/Behat/Gherkin.git", + "reference": "51ac4500c4dc30cbaaabcd2f25694299df666a31" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Behat/Gherkin/zipball/51ac4500c4dc30cbaaabcd2f25694299df666a31", + "reference": "51ac4500c4dc30cbaaabcd2f25694299df666a31", + "shasum": "" + }, + "require": { + "php": ">=5.3.1" + }, + "require-dev": { + "phpunit/phpunit": "~4.5|~5", + "symfony/phpunit-bridge": "~2.7|~3|~4", + "symfony/yaml": "~2.3|~3|~4" + }, + "suggest": { + "symfony/yaml": "If you want to parse features, represented in YAML files" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-0": { + "Behat\\Gherkin": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + } + ], + "description": "Gherkin DSL parser for PHP 5.3", + "homepage": "http://behat.org/", + "keywords": [ + "BDD", + "Behat", + "Cucumber", + "DSL", + "gherkin", + "parser" + ], + "time": "2020-03-17T14:03:26+00:00" + }, + { + "name": "behat/mink", + "version": "v1.8.1", + "source": { + "type": "git", + "url": "https://github.com/minkphp/Mink.git", + "reference": "07c6a9fe3fa98c2de074b25d9ed26c22904e3887" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/minkphp/Mink/zipball/07c6a9fe3fa98c2de074b25d9ed26c22904e3887", + "reference": "07c6a9fe3fa98c2de074b25d9ed26c22904e3887", + "shasum": "" + }, + "require": { + "php": ">=5.3.1", + "symfony/css-selector": "^2.7|^3.0|^4.0|^5.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20", + "symfony/debug": "^2.7|^3.0|^4.0", + "symfony/phpunit-bridge": "^3.4.38 || ^5.0.5" + }, + "suggest": { + "behat/mink-browserkit-driver": "extremely fast headless driver for Symfony\\Kernel-based apps (Sf2, Silex)", + "behat/mink-goutte-driver": "fast headless driver for any app without JS emulation", + "behat/mink-selenium2-driver": "slow, but JS-enabled driver for any app (requires Selenium2)", + "behat/mink-zombie-driver": "fast and JS-enabled headless driver for any app (requires node.js)", + "dmore/chrome-mink-driver": "fast and JS-enabled driver for any app (requires chromium or google chrome)" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8.x-dev" + } + }, + "autoload": { + "psr-4": { + "Behat\\Mink\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + } + ], + "description": "Browser controller/emulator abstraction for PHP", + "homepage": "http://mink.behat.org/", + "keywords": [ + "browser", + "testing", + "web" + ], + "time": "2020-03-11T15:45:53+00:00" + }, + { + "name": "behat/mink-browserkit-driver", + "version": "v1.3.4", + "source": { + "type": "git", + "url": "https://github.com/minkphp/MinkBrowserKitDriver.git", + "reference": "e3b90840022ebcd544c7b394a3c9597ae242cbee" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/minkphp/MinkBrowserKitDriver/zipball/e3b90840022ebcd544c7b394a3c9597ae242cbee", + "reference": "e3b90840022ebcd544c7b394a3c9597ae242cbee", + "shasum": "" + }, + "require": { + "behat/mink": "^1.7.1@dev", + "php": ">=5.3.6", + "symfony/browser-kit": "~2.3|~3.0|~4.0", + "symfony/dom-crawler": "~2.3|~3.0|~4.0" + }, + "require-dev": { + "mink/driver-testsuite": "dev-master", + "symfony/debug": "^2.7|^3.0|^4.0", + "symfony/http-kernel": "~2.3|~3.0|~4.0" + }, + "type": "mink-driver", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Behat\\Mink\\Driver\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + } + ], + "description": "Symfony2 BrowserKit driver for Mink framework", + "homepage": "http://mink.behat.org/", + "keywords": [ + "Mink", + "Symfony2", + "browser", + "testing" + ], + "time": "2020-03-11T09:49:45+00:00" + }, + { + "name": "behat/mink-extension", + "version": "2.3.1", + "source": { + "type": "git", + "url": "https://github.com/Behat/MinkExtension.git", + "reference": "80f7849ba53867181b7e412df9210e12fba50177" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Behat/MinkExtension/zipball/80f7849ba53867181b7e412df9210e12fba50177", + "reference": "80f7849ba53867181b7e412df9210e12fba50177", + "shasum": "" + }, + "require": { + "behat/behat": "^3.0.5", + "behat/mink": "^1.5", + "php": ">=5.3.2", + "symfony/config": "^2.7|^3.0|^4.0" + }, + "require-dev": { + "behat/mink-goutte-driver": "^1.1", + "phpspec/phpspec": "^2.0" + }, + "type": "behat-extension", + "extra": { + "branch-alias": { + "dev-master": "2.1.x-dev" + } + }, + "autoload": { + "psr-0": { + "Behat\\MinkExtension": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christophe Coevoet", + "email": "stof@notk.org" + }, + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com" + } + ], + "description": "Mink extension for Behat", + "homepage": "http://extensions.behat.org/mink", + "keywords": [ + "browser", + "gui", + "test", + "web" + ], + "time": "2018-02-06T15:36:30+00:00" + }, + { + "name": "behat/mink-goutte-driver", + "version": "v1.2.1", + "source": { + "type": "git", + "url": "https://github.com/minkphp/MinkGoutteDriver.git", + "reference": "8b9ad6d2d95bc70b840d15323365f52fcdaea6ca" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/minkphp/MinkGoutteDriver/zipball/8b9ad6d2d95bc70b840d15323365f52fcdaea6ca", + "reference": "8b9ad6d2d95bc70b840d15323365f52fcdaea6ca", + "shasum": "" + }, + "require": { + "behat/mink": "~1.6@dev", + "behat/mink-browserkit-driver": "~1.2@dev", + "fabpot/goutte": "~1.0.4|~2.0|~3.1", + "php": ">=5.3.1" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7|~3.0" + }, + "type": "mink-driver", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Behat\\Mink\\Driver\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + } + ], + "description": "Goutte driver for Mink framework", + "homepage": "http://mink.behat.org/", + "keywords": [ + "browser", + "goutte", + "headless", + "testing" + ], + "time": "2016-03-05T09:04:22+00:00" + }, + { + "name": "behat/transliterator", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/Behat/Transliterator.git", + "reference": "3c4ec1d77c3d05caa1f0bf8fb3aae4845005c7fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Behat/Transliterator/zipball/3c4ec1d77c3d05caa1f0bf8fb3aae4845005c7fc", + "reference": "3c4ec1d77c3d05caa1f0bf8fb3aae4845005c7fc", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "chuyskywalker/rolling-curl": "^3.1", + "php-yaoi/php-yaoi": "^1.0", + "phpunit/phpunit": "^4.8.36|^6.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "Behat\\Transliterator\\": "src/Behat/Transliterator" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Artistic-1.0" + ], + "description": "String transliterator", + "keywords": [ + "i18n", + "slug", + "transliterator" + ], + "time": "2020-01-14T16:39:13+00:00" + }, + { + "name": "container-interop/container-interop", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/container-interop/container-interop.git", + "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/container-interop/container-interop/zipball/79cbf1341c22ec75643d841642dd5d6acd83bdb8", + "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8", + "shasum": "" + }, + "require": { + "psr/container": "^1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Interop\\Container\\": "src/Interop/Container/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", + "homepage": "https://github.com/container-interop/container-interop", + "abandoned": "psr/container", + "time": "2017-02-14T19:40:03+00:00" + }, + { + "name": "fabpot/goutte", + "version": "v3.3.1", + "source": { + "type": "git", + "url": "https://github.com/FriendsOfPHP/Goutte.git", + "reference": "80a23b64f44d54dd571d114c473d9d7e9ed84ca5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FriendsOfPHP/Goutte/zipball/80a23b64f44d54dd571d114c473d9d7e9ed84ca5", + "reference": "80a23b64f44d54dd571d114c473d9d7e9ed84ca5", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "^6.0", + "php": ">=7.1.3", + "symfony/browser-kit": "^4.4|^5.0", + "symfony/css-selector": "^4.4|^5.0", + "symfony/dom-crawler": "^4.4|^5.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "^5.0" + }, + "type": "application", + "extra": { + "branch-alias": { + "dev-master": "3.3-dev" + } + }, + "autoload": { + "psr-4": { + "Goutte\\": "Goutte" + }, + "exclude-from-classmap": [ + "Goutte/Tests" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "A simple PHP Web Scraper", + "homepage": "https://github.com/FriendsOfPHP/Goutte", + "keywords": [ + "scraper" + ], + "time": "2020-11-01T09:30:18+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "6.5.5", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/9d4290de1cfd701f38099ef7e183b64b4b7b0c5e", + "reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.6.1", + "php": ">=5.5", + "symfony/polyfill-intl-idn": "^1.17.0" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", + "psr/log": "^1.1" + }, + "suggest": { + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.5-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "time": "2020-06-16T21:01:06+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "60d379c243457e073cff02bc323a2a86cb355631" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/60d379c243457e073cff02bc323a2a86cb355631", + "reference": "60d379c243457e073cff02bc323a2a86cb355631", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.4 || ^5.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "time": "2020-09-30T07:37:28+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.7.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/53330f47520498c0ae1f61f7e2c90f55690c06a3", + "reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "ext-zlib": "*", + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.7-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Schultze", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "time": "2020-09-30T07:37:11+00:00" + }, + { + "name": "oleg-andreyev/mink-facebook-web-driver", + "version": "dev-w3c", + "source": { + "type": "git", + "url": "https://github.com/andrewnicols/MinkPhpWebDriver.git", + "reference": "cc659c35e91241271b498d0bb1e1de97472f0e38" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/andrewnicols/MinkPhpWebDriver/zipball/cc659c35e91241271b498d0bb1e1de97472f0e38", + "reference": "cc659c35e91241271b498d0bb1e1de97472f0e38", + "shasum": "" + }, + "require": { + "behat/mink": "^1.8", + "php": ">=7.0", + "php-webdriver/webdriver": "^1.8" + }, + "require-dev": { + "behat/mink-extension": "^2.3", + "ext-json": "*", + "mink/driver-testsuite": "dev-integration-branch" + }, + "type": "mink-driver", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "OAndreyev\\Mink\\Driver\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "OAndreyev\\Mink\\Tests\\Driver\\": "tests" + } + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Oleg Andreyev", + "email": "oleg@andreyev.lv" + } + ], + "description": "MinkFacebookWebDriver driver for Mink framework", + "keywords": [ + "ajax", + "browser", + "javascript", + "jsonwire", + "testing", + "w3c", + "webdriver" + ], + "support": { + "source": "https://github.com/andrewnicols/MinkPhpWebDriver/tree/w3c" + }, + "time": "2020-12-07T11:57:57+00:00" + }, + { + "name": "php-webdriver/webdriver", + "version": "1.9.0", + "source": { + "type": "git", + "url": "https://github.com/php-webdriver/php-webdriver.git", + "reference": "e3633154554605274cc9d59837f55a7427d72003" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/e3633154554605274cc9d59837f55a7427d72003", + "reference": "e3633154554605274cc9d59837f55a7427d72003", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "ext-zip": "*", + "php": "^5.6 || ~7.0 || ^8.0", + "symfony/polyfill-mbstring": "^1.12", + "symfony/process": "^2.8 || ^3.1 || ^4.0 || ^5.0" + }, + "replace": { + "facebook/webdriver": "*" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.0", + "ondram/ci-detector": "^2.1 || ^3.5", + "php-coveralls/php-coveralls": "^2.4", + "php-mock/php-mock-phpunit": "^1.1 || ^2.0", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpunit/phpunit": "^5.7 || ^7 || ^8 || ^9", + "squizlabs/php_codesniffer": "^3.5", + "symfony/var-dumper": "^3.3 || ^4.0 || ^5.0" + }, + "suggest": { + "ext-SimpleXML": "For Firefox profile creation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.8.x-dev" + } + }, + "autoload": { + "psr-4": { + "Facebook\\WebDriver\\": "lib/" + }, + "files": [ + "lib/Exception/TimeoutException.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A PHP client for Selenium WebDriver. Previously facebook/webdriver.", + "homepage": "https://github.com/php-webdriver/php-webdriver", + "keywords": [ + "Chromedriver", + "geckodriver", + "php", + "selenium", + "webdriver" + ], + "time": "2020-11-19T15:21:05+00:00" + }, + { + "name": "psr/container", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "time": "2017-02-14T16:28:37+00:00" + }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "time": "2019-01-08T18:20:26+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "symfony/browser-kit", + "version": "v4.4.18", + "source": { + "type": "git", + "url": "https://github.com/symfony/browser-kit.git", + "reference": "85efcc33545ed472653eb2d00a4ab36e6258a5b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/85efcc33545ed472653eb2d00a4ab36e6258a5b6", + "reference": "85efcc33545ed472653eb2d00a4ab36e6258a5b6", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/dom-crawler": "^3.4|^4.0|^5.0" + }, + "require-dev": { + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/http-client": "^4.3|^5.0", + "symfony/mime": "^4.3|^5.0", + "symfony/process": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/process": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\BrowserKit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony BrowserKit Component", + "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-12-18T07:41:31+00:00" + }, + { + "name": "symfony/config", + "version": "v4.4.18", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "e501c56d2fa70798075b9811d0eb4c27de491459" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/e501c56d2fa70798075b9811d0eb4c27de491459", + "reference": "e501c56d2fa70798075b9811d0eb4c27de491459", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/filesystem": "^3.4|^4.0|^5.0", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/finder": "<3.4" + }, + "require-dev": { + "symfony/event-dispatcher": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/messenger": "^4.1|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/yaml": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/yaml": "To use the yaml reference dumper" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Config Component", + "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-12-09T08:58:17+00:00" + }, + { + "name": "symfony/console", + "version": "v5.2.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "47c02526c532fb381374dab26df05e7313978976" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/47c02526c532fb381374dab26df05e7313978976", + "reference": "47c02526c532fb381374dab26df05e7313978976", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.8", + "symfony/polyfill-php80": "^1.15", + "symfony/service-contracts": "^1.1|^2", + "symfony/string": "^5.1" + }, + "conflict": { + "symfony/dependency-injection": "<4.4", + "symfony/dotenv": "<5.1", + "symfony/event-dispatcher": "<4.4", + "symfony/lock": "<4.4", + "symfony/process": "<4.4" + }, + "provide": { + "psr/log-implementation": "1.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/event-dispatcher": "^4.4|^5.0", + "symfony/lock": "^4.4|^5.0", + "symfony/process": "^4.4|^5.0", + "symfony/var-dumper": "^4.4|^5.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Console Component", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command line", + "console", + "terminal" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-12-18T08:03:05+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v5.2.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "f789e7ead4c79e04ca9a6d6162fc629c89bd8054" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/f789e7ead4c79e04ca9a6d6162fc629c89bd8054", + "reference": "f789e7ead4c79e04ca9a6d6162fc629c89bd8054", + "shasum": "" + }, + "require": { + "php": ">=7.2.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony CssSelector Component", + "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-12-08T17:02:38+00:00" + }, + { + "name": "symfony/dependency-injection", + "version": "v4.4.18", + "source": { + "type": "git", + "url": "https://github.com/symfony/dependency-injection.git", + "reference": "3860f64c6deb2cb48b1ada27460c58ae479bdc0f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/3860f64c6deb2cb48b1ada27460c58ae479bdc0f", + "reference": "3860f64c6deb2cb48b1ada27460c58ae479bdc0f", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/container": "^1.0", + "symfony/service-contracts": "^1.1.6|^2" + }, + "conflict": { + "symfony/config": "<4.3|>=5.0", + "symfony/finder": "<3.4", + "symfony/proxy-manager-bridge": "<3.4", + "symfony/yaml": "<3.4" + }, + "provide": { + "psr/container-implementation": "1.0", + "symfony/service-implementation": "1.0" + }, + "require-dev": { + "symfony/config": "^4.3", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/config": "", + "symfony/expression-language": "For using expressions in service container configuration", + "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required", + "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", + "symfony/yaml": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DependencyInjection\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony DependencyInjection Component", + "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-12-18T07:41:31+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v2.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "5fa56b4074d1ae755beb55617ddafe6f5d78f665" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5fa56b4074d1ae755beb55617ddafe6f5d78f665", + "reference": "5fa56b4074d1ae755beb55617ddafe6f5d78f665", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-09-07T11:33:47+00:00" + }, + { + "name": "symfony/dom-crawler", + "version": "v4.4.18", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "d44fbb02b458fe18d00fea18f24c97cefb87577e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/d44fbb02b458fe18d00fea18f24c97cefb87577e", + "reference": "d44fbb02b458fe18d00fea18f24c97cefb87577e", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "masterminds/html5": "<2.6" + }, + "require-dev": { + "masterminds/html5": "^2.6", + "symfony/css-selector": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/css-selector": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DomCrawler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony DomCrawler Component", + "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-12-18T07:41:31+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v5.2.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "1c93f7a1dff592c252574c79a8635a8a80856042" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/1c93f7a1dff592c252574c79a8635a8a80856042", + "reference": "1c93f7a1dff592c252574c79a8635a8a80856042", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/event-dispatcher-contracts": "^2", + "symfony/polyfill-php80": "^1.15" + }, + "conflict": { + "symfony/dependency-injection": "<4.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/error-handler": "^4.4|^5.0", + "symfony/expression-language": "^4.4|^5.0", + "symfony/http-foundation": "^4.4|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/stopwatch": "^4.4|^5.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-12-18T08:03:05+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v2.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "0ba7d54483095a198fa51781bc608d17e84dffa2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/0ba7d54483095a198fa51781bc608d17e84dffa2", + "reference": "0ba7d54483095a198fa51781bc608d17e84dffa2", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/event-dispatcher": "^1" + }, + "suggest": { + "symfony/event-dispatcher-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-09-07T11:33:47+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v5.2.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "fa8f8cab6b65e2d99a118e082935344c5ba8c60d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/fa8f8cab6b65e2d99a118e082935344c5ba8c60d", + "reference": "fa8f8cab6b65e2d99a118e082935344c5ba8c60d", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Filesystem Component", + "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-11-30T17:05:38+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.20.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "f4ba089a5b6366e453971d3aad5fe8e897b37f41" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f4ba089a5b6366e453971d3aad5fe8e897b37f41", + "reference": "f4ba089a5b6366e453971d3aad5fe8e897b37f41", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.20-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-23T14:02:19+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.20.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "c7cf3f858ec7d70b89559d6e6eb1f7c2517d479c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/c7cf3f858ec7d70b89559d6e6eb1f7c2517d479c", + "reference": "c7cf3f858ec7d70b89559d6e6eb1f7c2517d479c", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.20-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-23T14:02:19+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.20.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "3b75acd829741c768bc8b1f84eb33265e7cc5117" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/3b75acd829741c768bc8b1f84eb33265e7cc5117", + "reference": "3b75acd829741c768bc8b1f84eb33265e7cc5117", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "symfony/polyfill-intl-normalizer": "^1.10", + "symfony/polyfill-php72": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.20-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-23T14:02:19+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.20.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "727d1096295d807c309fb01a851577302394c897" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/727d1096295d807c309fb01a851577302394c897", + "reference": "727d1096295d807c309fb01a851577302394c897", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.20-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-23T14:02:19+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.20.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "39d483bdf39be819deabf04ec872eb0b2410b531" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/39d483bdf39be819deabf04ec872eb0b2410b531", + "reference": "39d483bdf39be819deabf04ec872eb0b2410b531", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.20-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-23T14:02:19+00:00" + }, + { + "name": "symfony/polyfill-php72", + "version": "v1.20.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "cede45fcdfabdd6043b3592e83678e42ec69e930" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cede45fcdfabdd6043b3592e83678e42ec69e930", + "reference": "cede45fcdfabdd6043b3592e83678e42ec69e930", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.20-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-23T14:02:19+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.20.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "8ff431c517be11c78c48a39a66d37431e26a6bed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/8ff431c517be11c78c48a39a66d37431e26a6bed", + "reference": "8ff431c517be11c78c48a39a66d37431e26a6bed", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.20-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-23T14:02:19+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.20.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "e70aa8b064c5b72d3df2abd5ab1e90464ad009de" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/e70aa8b064c5b72d3df2abd5ab1e90464ad009de", + "reference": "e70aa8b064c5b72d3df2abd5ab1e90464ad009de", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.20-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-23T14:02:19+00:00" + }, + { + "name": "symfony/process", + "version": "v5.2.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "bd8815b8b6705298beaa384f04fabd459c10bedd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/bd8815b8b6705298beaa384f04fabd459c10bedd", + "reference": "bd8815b8b6705298beaa384f04fabd459c10bedd", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.15" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Process Component", + "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-12-08T17:03:37+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d15da7ba4957ffb8f1747218be9e1a121fd298a1", + "reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.0" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-09-07T11:33:47+00:00" + }, + { + "name": "symfony/string", + "version": "v5.2.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "5bd67751d2e3f7d6f770c9154b8fbcb2aa05f7ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/5bd67751d2e3f7d6f770c9154b8fbcb2aa05f7ed", + "reference": "5bd67751d2e3f7d6f770c9154b8fbcb2aa05f7ed", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "~1.15" + }, + "require-dev": { + "symfony/error-handler": "^4.4|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/translation-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.4|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "files": [ + "Resources/functions.php" + ], + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony String component", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-12-05T07:33:16+00:00" + }, + { + "name": "symfony/translation", + "version": "v4.4.18", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "c1001b7d75b3136648f94b245588209d881c6939" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/c1001b7d75b3136648f94b245588209d881c6939", + "reference": "c1001b7d75b3136648f94b245588209d881c6939", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/translation-contracts": "^1.1.6|^2" + }, + "conflict": { + "symfony/config": "<3.4", + "symfony/dependency-injection": "<3.4", + "symfony/http-kernel": "<4.4", + "symfony/yaml": "<3.4" + }, + "provide": { + "symfony/translation-implementation": "1.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/finder": "~2.8|~3.0|~4.0|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/intl": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1.2|^2", + "symfony/yaml": "^3.4|^4.0|^5.0" + }, + "suggest": { + "psr/log-implementation": "To use logging capability in translator", + "symfony/config": "", + "symfony/yaml": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Translation Component", + "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-12-08T16:59:59+00:00" + }, + { + "name": "symfony/translation-contracts", + "version": "v2.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "e2eaa60b558f26a4b0354e1bbb25636efaaad105" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/e2eaa60b558f26a4b0354e1bbb25636efaaad105", + "reference": "e2eaa60b558f26a4b0354e1bbb25636efaaad105", + "shasum": "" + }, + "require": { + "php": ">=7.2.5" + }, + "suggest": { + "symfony/translation-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Translation\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to translation", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-09-28T13:05:58+00:00" + }, + { + "name": "symfony/yaml", + "version": "v5.2.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "290ea5e03b8cf9b42c783163123f54441fb06939" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/290ea5e03b8cf9b42c783163123f54441fb06939", + "reference": "290ea5e03b8cf9b42c783163123f54441fb06939", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/console": "<4.4" + }, + "require-dev": { + "symfony/console": "^4.4|^5.0" + }, + "suggest": { + "symfony/console": "For validating YAML files using the lint command" + }, + "bin": [ + "Resources/bin/yaml-lint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-12-08T17:02:38+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": { + "oleg-andreyev/mink-facebook-web-driver": 20 + }, + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=7.2.0" + }, + "platform-dev": [], + "plugin-api-version": "1.1.0" +} diff --git a/src/Moodle/BehatExtension/Driver/MoodleSelenium2Driver.php b/src/Moodle/BehatExtension/Driver/MoodleSelenium2Driver.php deleted file mode 100755 index 98dc459..0000000 --- a/src/Moodle/BehatExtension/Driver/MoodleSelenium2Driver.php +++ /dev/null @@ -1,302 +0,0 @@ -session = $session; - - // The parent also stores the session. - parent::setSession($session); - } - - /** - * Instantiates the driver. - * - * @param string $browser Browser name - * @param array $desiredCapabilities The desired capabilities - * @param string $wdHost The WebDriver host - * @param array $moodleParameters Moodle parameters including our non-behat-friendly selenium capabilities - */ - public function __construct($browserName = 'firefox', $desiredCapabilities = null, $wdHost = 'http://localhost:4444/wd/hub', $moodleParameters = array()) { - // If they are set add them overridding if it's the case (not likely). - if (!empty($moodleParameters) && !empty($moodleParameters['capabilities'])) { - foreach ($moodleParameters['capabilities'] as $key => $capability) { - $desiredCapabilities[$key] = $capability; - } - } - - parent::__construct($browserName, $desiredCapabilities, $wdHost); - - // This class is instantiated by the dependencies injection system so - // prior to all of beforeSuite subscribers which will call getBrowser*() - self::$browser = $browserName; - } - - /** - * Forwards to getBrowser() so we keep compatibility with both static and non-static accesses. - * - * @deprecated - * @param string $name - * @param array $arguments - * @return mixed - */ - public static function __callStatic($name, $arguments) { - if ($name == 'getBrowserName') { - return self::getBrowser(); - } - - // Fallbacks calling the requested static method, we don't - // even know if it exists or not. - return call_user_func(array(self, $name), $arguments); - } - - /** - * Forwards to getBrowser() so we keep compatibility with both static and non-static accesses. - * - * @deprecated - * @param string $name - * @param array $arguments - * @return mixed - */ - public function __call($name, $arguments) { - if ($name == 'getBrowserName') { - return self::getBrowser(); - } - - // Fallbacks calling the requested instance method, we don't - // even know if it exists or not. - return call_user_func(array($this, $name), $arguments); - } - - /** - * Returns the browser being used. - * - * We need to know it: - * - To show info about the run. - * - In case there are differences between browsers in the steps. - * - * @static - * @return string - */ - public static function getBrowser() { - return self::$browser; - } - - /** - * Drag one element onto another. - * - * Override the original one to give YUI drag & drop - * time to consider it a valid drag & drop. It will need - * more changes in future to properly adapt to how YUI dd - * component behaves. - * - * @param string $sourceXpath - * @param string $destinationXpath - */ - public function dragTo($sourceXpath, $destinationXpath) { - $source = $this->getWebDriverSession()->element('xpath', $sourceXpath); - $destination = $this->getWebDriverSession()->element('xpath', $destinationXpath); - - // TODO: MDL-39727 This method requires improvements according to the YUI drag and drop component. - - $this->getWebDriverSession()->moveto(array( - 'element' => $source->getID() - )); - - $script = <<withSyn()->executeJsOnXpath($sourceXpath, $script); - - $this->getWebDriverSession()->buttondown(); - $this->getWebDriverSession()->moveto(array( - 'element' => $destination->getID() - )); - - // We add a 2 seconds wait to make YUI dd happy. - $this->wait(2 * 1000, false); - - $this->getWebDriverSession()->buttonup(); - - $script = <<withSyn()->executeJsOnXpath($destinationXpath, $script); - } - - /** - * Overwriten method to use our custom Syn library. - * - * Makes sure that the Syn event library has been injected into the current page, - * and return $this for a fluid interface, - * - * $this->withSyn()->executeJsOnXpath($xpath, $script); - * - * @return Selenium2Driver - */ - protected function withSyn() - { - $hasSyn = $this->getWebDriverSession()->execute(array( - 'script' => 'return typeof window["Syn"]!=="undefined"', - 'args' => array() - )); - - if (!$hasSyn) { - $synJs = file_get_contents(__DIR__.'/Selenium2/moodle_syn-min.js'); - $this->getWebDriverSession()->execute(array( - 'script' => $synJs, - 'args' => array() - )); - } - - return $this; - } - - /** - * Public interface to run Syn scripts. - * - * @see self::executeJsOnXpath() - * - * @param string $xpath the xpath to search with - * @param string $script the script to execute - * @param Boolean $sync whether to run the script synchronously (default is TRUE) - * - * @return mixed - */ - public function triggerSynScript($xpath, $script, $sync = true) { - return $this->withSyn()->executeJsOnXpath($xpath, $script, $sync); - } - - /** - * Overriding this as key::TAB is causing page scroll and rubrics scenarios are failing. - * https://github.com/minkphp/MinkSelenium2Driver/issues/194 - * {@inheritdoc} - */ - public function setValue($xpath, $value) { - $value = strval($value); - $element = $this->getWebDriverSession()->element('xpath', $xpath); - $elementName = strtolower($element->name()); - - if ('select' === $elementName) { - if (is_array($value)) { - $this->deselectAllOptions($element); - - foreach ($value as $option) { - $this->selectOptionOnElement($element, $option, true); - } - - return; - } - - $this->selectOption($element, $value); - - return; - } - - if ('input' === $elementName) { - $elementType = strtolower($element->attribute('type')); - - if (in_array($elementType, array('submit', 'image', 'button', 'reset'))) { - throw new DriverException(sprintf('Impossible to set value an element with XPath "%s" as it is not a select, textarea or textbox', $xpath)); - } - - if ('checkbox' === $elementType) { - if ($element->selected() xor (bool) $value) { - $this->clickOnElement($element); - } - - return; - } - - if ('radio' === $elementType) { - $this->selectRadioValue($element, $value); - - return; - } - - if ('file' === $elementType) { - $element->postValue(array('value' => array(strval($value)))); - - return; - } - } - - $value = strval($value); - - if (in_array($elementName, array('input', 'textarea'))) { - $existingValueLength = strlen($element->attribute('value')); - // Add the TAB key to ensure we unfocus the field as browsers are triggering the change event only - // after leaving the field. - $value = str_repeat(Key::BACKSPACE . Key::DELETE, $existingValueLength) . $value; - } - - $element->postValue(array('value' => array($value))); - $script = "Syn.trigger('change', {}, {{ELEMENT}})"; - $this->withSyn()->executeJsOnXpath($xpath, $script); - } - - /** - * Post key on specified xpath. - * - * @param string $xpath - */ - public function post_key($key, $xpath) { - $element = $this->getWebDriverSession()->element('xpath', $xpath); - $element->postValue(array('value' => array($key))); - } - - /** - * Find any Element at the specified xpath. - * - * @param string $xpath The xpath to search for - * @return NodeElement[] - */ - public function find($xpath) { - $elements = array(); - - foreach ($this->findElementXpaths($xpath) as $xpath) { - $elements[] = new NodeElement($xpath, $this->session); - } - - return $elements; - } -} diff --git a/src/Moodle/BehatExtension/Driver/MoodleSelenium2Factory.php b/src/Moodle/BehatExtension/Driver/MoodleSelenium2Factory.php deleted file mode 100644 index 22aba35..0000000 --- a/src/Moodle/BehatExtension/Driver/MoodleSelenium2Factory.php +++ /dev/null @@ -1,180 +0,0 @@ -. - -/** - * Moodle behat context class resolver. - * - * @package behat - * @copyright 2016 Rajesh Taneja - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace Moodle\BehatExtension\Driver; - -use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; -use Symfony\Component\DependencyInjection\Definition; -use Behat\MinkExtension\ServiceContainer\Driver\DriverFactory; - -class MoodleSelenium2Factory implements DriverFactory { - /** - * {@inheritdoc} - */ - public function getDriverName() { - return 'selenium2'; - } - - /** - * {@inheritdoc} - */ - public function supportsJavascript() { - return true; - } - - /** - * {@inheritdoc} - */ - public function configure(ArrayNodeDefinition $builder) { - $builder - ->children() - ->scalarNode('browser') - ->defaultValue('%mink.browser_name%') - ->end() - ->append($this->getCapabilitiesNode()) - ->scalarNode('wd_host') - ->defaultValue('http://localhost:4444/wd/hub') - ->end() - ->arrayNode('moodle_parameter') - ->useAttributeAsKey('key') - ->prototype('variable') - ->defaultValue('%behat.moodle.parameter%') - ->end() - ->end() - ; - } - - /** - * {@inheritdoc} - */ - public function buildDriver(array $config) { - if (!class_exists('Moodle\BehatExtension\Driver\MoodleSelenium2Driver')) { - throw new \RuntimeException(sprintf( - 'Install MinkSelenium2Driver in order to use %s driver.', - $this->getDriverName() - )); - } - - $extraCapabilities = $config['capabilities']['extra_capabilities']; - unset($config['capabilities']['extra_capabilities']); - - if (getenv('TRAVIS_JOB_NUMBER')) { - $guessedCapabilities = array( - 'tunnel-identifier' => getenv('TRAVIS_JOB_NUMBER'), - 'build' => getenv('TRAVIS_BUILD_NUMBER'), - 'tags' => array('Travis-CI', 'PHP '.phpversion()), - ); - } elseif (getenv('JENKINS_HOME')) { - $guessedCapabilities = array( - 'tunnel-identifier' => getenv('JOB_NAME'), - 'build' => getenv('BUILD_NUMBER'), - 'tags' => array('Jenkins', 'PHP '.phpversion(), getenv('BUILD_TAG')), - ); - } else { - $guessedCapabilities = array( - 'tags' => array(php_uname('n'), 'PHP '.phpversion()), - ); - } - - return new Definition('Moodle\BehatExtension\Driver\MoodleSelenium2Driver', array( - $config['browser'], - array_replace($extraCapabilities, $guessedCapabilities, $config['capabilities']), - $config['wd_host'], - $config['moodle_parameter'] - )); - } - - /** - * {@inheritdoc} - */ - protected function getCapabilitiesNode() { - $node = new ArrayNodeDefinition('capabilities'); - - $node - ->addDefaultsIfNotSet() - ->normalizeKeys(false) - ->children() - ->scalarNode('browserName')->defaultValue('firefox')->end() - ->scalarNode('platform')->defaultValue('ANY')->end() - ->scalarNode('browser')->defaultValue('firefox')->end() - ->scalarNode('ignoreZoomSetting')->defaultValue('false')->end() - ->scalarNode('name')->defaultValue('Behat feature suite')->end() - ->scalarNode('deviceOrientation')->defaultValue('portrait')->end() - ->scalarNode('deviceType')->defaultValue('tablet')->end() - ->booleanNode('javascriptEnabled')->end() - ->booleanNode('databaseEnabled')->end() - ->booleanNode('locationContextEnabled')->end() - ->booleanNode('applicationCacheEnabled')->end() - ->booleanNode('browserConnectionEnabled')->end() - ->booleanNode('webStorageEnabled')->end() - ->booleanNode('rotatable')->end() - ->booleanNode('acceptSslCerts')->end() - ->booleanNode('nativeEvents')->end() - ->arrayNode('proxy') - ->children() - ->scalarNode('proxyType')->end() - ->scalarNode('proxyAuthconfigUrl')->end() - ->scalarNode('ftpProxy')->end() - ->scalarNode('httpProxy')->end() - ->scalarNode('sslProxy')->end() - ->end() - ->validate() - ->ifTrue(function ($v) { - return empty($v); - }) - ->thenUnset() - ->end() - ->end() - ->arrayNode('firefox') - ->children() - ->scalarNode('profile') - ->validate() - ->ifTrue(function ($v) { - return !file_exists($v); - }) - ->thenInvalid('Cannot find profile zip file %s') - ->end() - ->end() - ->scalarNode('binary')->end() - ->end() - ->end() - ->arrayNode('chrome') - ->children() - ->arrayNode('switches')->prototype('scalar')->end()->end() - ->scalarNode('binary')->end() - ->arrayNode('extensions')->prototype('scalar')->end()->end() - ->end() - ->end() - ->arrayNode('extra_capabilities') - ->info('Custom capabilities merged with the known ones') - ->normalizeKeys(false) - ->useAttributeAsKey('name') - ->prototype('variable')->end() - ->end() - ->end(); - - return $node; - } -} diff --git a/src/Moodle/BehatExtension/Driver/Selenium2/README.md b/src/Moodle/BehatExtension/Driver/Selenium2/README.md deleted file mode 100644 index 19c10ec..0000000 --- a/src/Moodle/BehatExtension/Driver/Selenium2/README.md +++ /dev/null @@ -1,12 +0,0 @@ -Steps to generate the minified file in case we have local modifications and we can't used the minified -file generated by https://github.com/bitovi/syn. Hopefully a solution for https://github.com/bitovi/syn/issues/30 will -be merged upstream and we can get rid of these modifications and this README.md - -Steps to generate the minified version of syn.js -================================================ - -* Checkout the project with our local modifications -* cd to the directory -* npm install -* grunt build -* The resulting minified file will be stored in dist/syn.min.js diff --git a/src/Moodle/BehatExtension/Driver/Selenium2/moodle_syn-min.js b/src/Moodle/BehatExtension/Driver/Selenium2/moodle_syn-min.js deleted file mode 100644 index 304f2a3..0000000 --- a/src/Moodle/BehatExtension/Driver/Selenium2/moodle_syn-min.js +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Syn - 0.0.2 - * - * @copyright 2014 Bitovi - * Wed, 26 Feb 2014 08:30:25 GMT - * @license MIT - */ -!function(window){var __m2=function(){var a,b,c,d=window.Syn?window.Syn:{},e=function(a,b){var c;for(c in b)a[c]=b[c];return a},f={msie:!(!window.attachEvent||window.opera),opera:!!window.opera,webkit:navigator.userAgent.indexOf("AppleWebKit/")>-1,safari:navigator.userAgent.indexOf("AppleWebKit/")>-1&&-1===navigator.userAgent.indexOf("Chrome/"),gecko:navigator.userAgent.indexOf("Gecko")>-1,mobilesafari:!!navigator.userAgent.match(/Apple.*Mobile.*Safari/),rhino:navigator.userAgent.match(/Rhino/)&&!0},g=function(a,b,c){var d=c.ownerDocument.createEventObject();return e(d,b)},h={},i=1,j="_synthetic"+(new Date).getTime(),k=/keypress|keyup|keydown/,l=/load|unload|abort|error|select|change|submit|reset|focus|blur|resize|scroll/,m=function(a,b,c,d){return new m.init(a,b,c,d)};m.config=d,a=function(a,b,c){return a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent("on"+b,c)},b=function(a,b,c){return a.addEventListener?a.removeEventListener(b,c,!1):a.detachEvent("on"+b,c)},e(m,{init:function(a,b,c,d){var e=m.args(b,c,d),f=this;this.queue=[],this.element=e.element,"function"==typeof this[a]?this[a](e.options,e.element,function(){e.callback&&e.callback.apply(f,arguments),f.done.apply(f,arguments)}):(this.result=m.trigger(a,e.options,e.element),e.callback&&e.callback.call(this,e.element,this.result))},jquery:function(a){return window.FuncUnit&&window.FuncUnit.jQuery?window.FuncUnit.jQuery:a?m.helpers.getWindow(a).jQuery||window.jQuery:window.jQuery},args:function(){for(var a={},b=0;b0&&g.apply(this,[])},d.dispatchEvent(c),0>=h}try{window.event=c}catch(i){}return d.sourceIndex<=0||d.fireEvent&&d.fireEvent("on"+e,c)},create:{page:{event:function(a,b,c){var d,e=m.helpers.getWindow(c).document||document;if(e.createEvent)return d=e.createEvent("Events"),d.initEvent(a,!0,!0),d;try{d=g(a,b,c)}catch(f){}return d}},focus:{event:function(a,b,d){return m.onParents(d,function(a){if(m.isFocusable(a)){if("html"!==a.nodeName.toLowerCase())a.focus(),c=a;else if(c){var b=m.helpers.getWindow(d).document;if(b!==window.document)return!1;b.activeElement?(b.activeElement.blur(),c=null):(c.blur(),c=null)}return!1}}),!0}}},support:{clickChanges:!1,clickSubmits:!1,keypressSubmits:!1,mouseupSubmits:!1,radioClickChanges:!1,focusChanges:!1,linkHrefJS:!1,keyCharacters:!1,backspaceWorks:!1,mouseDownUpClicks:!1,tabKeyTabs:!1,keypressOnAnchorClicks:!1,optionClickBubbles:!1,ready:0},trigger:function(a,b,c){b||(b={});var d,e,f,g=m.create,h=g[a]&&g[a].setup,i=k.test(a)?"key":l.test(a)?"page":"mouse",j=g[a]||{},n=g[i],o=c;return 2===m.support.ready&&h&&h(a,b,c),f=b._autoPrevent,delete b._autoPrevent,j.event?e=j.event(a,b,c):(b=n.options?n.options(a,b,c):b,!m.support.changeBubbles&&/option/i.test(c.nodeName)&&(o=c.parentNode),d=n.event(a,b,o),e=m.dispatch(d,o,a,f)),e&&2===m.support.ready&&m.defaults[a]&&m.defaults[a].call(c,b,f),e},eventSupported:function(a){var b=document.createElement("div");a="on"+a;var c=a in b;return c||(b.setAttribute(a,"return;"),c="function"==typeof b[a]),b=null,c}}),e(m.init.prototype,{then:function(a,b,c,d){m.autoDelay&&this.delay();var e=m.args(b,c,d),f=this;return this.queue.unshift(function(b){return"function"!=typeof this[a]?(this.result=m.trigger(a,e.options,e.element),e.callback&&e.callback.call(this,e.element,this.result),this):(this.element=e.element||b,void this[a](e.options,this.element,function(){e.callback&&e.callback.apply(f,arguments),f.done.apply(f,arguments)}))}),this},delay:function(a,b){"function"==typeof a&&(b=a,a=null),a=a||600;var c=this;return this.queue.unshift(function(){setTimeout(function(){b&&b.apply(c,[]),c.done.apply(c,arguments)},a)}),this},done:function(a,b){b&&(this.element=b),this.queue.length&&this.queue.pop().call(this,this.element,a)},_click:function(a,b,c,d){m.helpers.addOffset(a,b),m.trigger("mousedown",a,b),setTimeout(function(){m.trigger("mouseup",a,b),!m.support.mouseDownUpClicks||d?(m.trigger("click",a,b),c(!0)):(m.create.click.setup("click",a,b),m.defaults.click.call(b),setTimeout(function(){c(!0)},1))},1)},_rightClick:function(a,b,c){m.helpers.addOffset(a,b);var d=e(e({},m.mouse.browser.right.mouseup),a);m.trigger("mousedown",d,b),setTimeout(function(){m.trigger("mouseup",d,b),m.mouse.browser.right.contextmenu&&m.trigger("contextmenu",e(e({},m.mouse.browser.right.contextmenu),a),b),c(!0)},1)},_dblclick:function(a,b,c){m.helpers.addOffset(a,b);var d=this;this._click(a,b,function(){setTimeout(function(){d._click(a,b,function(){m.trigger("dblclick",a,b),c(!0)},!0)},2)})}});for(var n=["click","dblclick","move","drag","key","type","rightClick"],o=function(a){m[a]=function(b,c,d){return m("_"+a,b,c,d)},m.init.prototype[a]=function(b,c,d){return this.then("_"+a,b,c,d)}},p=0;p",document.documentElement.appendChild(e),c=e.firstChild,a=c.childNodes[0],b=c.childNodes[2],d=c.getElementsByTagName("select")[0],Syn.trigger("click",{},c.childNodes[6]),a.checked=!1,a.onchange=function(){Syn.support.clickChanges=!0},Syn.trigger("click",{},a),Syn.support.clickChecks=a.checked,a.checked=!1,Syn.trigger("change",{},a),Syn.support.changeChecks=a.checked,c.onsubmit=function(a){return a.preventDefault&&a.preventDefault(),Syn.support.clickSubmits=!0,!1},Syn.trigger("click",{},b),c.childNodes[1].onchange=function(){Syn.support.radioClickChanges=!0},Syn.trigger("click",{},c.childNodes[1]),Syn.bind(e,"click",function(){Syn.support.optionClickBubbles=!0,Syn.unbind(e,"click",arguments.callee)}),Syn.trigger("click",{},d.firstChild),Syn.support.changeBubbles=Syn.eventSupported("change");e.onclick=function(){Syn.support.mouseDownUpClicks=!0},Syn.trigger("mousedown",{},e),Syn.trigger("mouseup",{},e),document.documentElement.removeChild(e),Syn.support.ready++}(),Syn}(__m2),__m4=function(a){return a.key.browsers={webkit:{prevent:{keyup:[],keydown:["char","keypress"],keypress:["char"]},character:{keydown:[0,"key"],keypress:["char","char"],keyup:[0,"key"]},specialChars:{keydown:[0,"char"],keyup:[0,"char"]},navigation:{keydown:[0,"key"],keyup:[0,"key"]},special:{keydown:[0,"key"],keyup:[0,"key"]},tab:{keydown:[0,"char"],keyup:[0,"char"]},"pause-break":{keydown:[0,"key"],keyup:[0,"key"]},caps:{keydown:[0,"key"],keyup:[0,"key"]},escape:{keydown:[0,"key"],keyup:[0,"key"]},"num-lock":{keydown:[0,"key"],keyup:[0,"key"]},"scroll-lock":{keydown:[0,"key"],keyup:[0,"key"]},print:{keyup:[0,"key"]},"function":{keydown:[0,"key"],keyup:[0,"key"]},"\r":{keydown:[0,"key"],keypress:["char","key"],keyup:[0,"key"]}},gecko:{prevent:{keyup:[],keydown:["char"],keypress:["char"]},character:{keydown:[0,"key"],keypress:["char",0],keyup:[0,"key"]},specialChars:{keydown:[0,"key"],keypress:[0,"key"],keyup:[0,"key"]},navigation:{keydown:[0,"key"],keypress:[0,"key"],keyup:[0,"key"]},special:{keydown:[0,"key"],keyup:[0,"key"]}," ":{keydown:[0,"key"],keypress:[0,"key"],keyup:[0,"key"]},"pause-break":{keydown:[0,"key"],keypress:[0,"key"],keyup:[0,"key"]},caps:{keydown:[0,"key"],keyup:[0,"key"]},escape:{keydown:[0,"key"],keypress:[0,"key"],keyup:[0,"key"]},"num-lock":{keydown:[0,"key"],keyup:[0,"key"]},"scroll-lock":{keydown:[0,"key"],keyup:[0,"key"]},print:{keyup:[0,"key"]},"function":{keydown:[0,"key"],keyup:[0,"key"]},"\r":{keydown:[0,"key"],keypress:[0,"key"],keyup:[0,"key"]}},msie:{prevent:{keyup:[],keydown:["char","keypress"],keypress:["char"]},character:{keydown:[null,"key"],keypress:[null,"char"],keyup:[null,"key"]},specialChars:{keydown:[null,"char"],keyup:[null,"char"]},navigation:{keydown:[null,"key"],keyup:[null,"key"]},special:{keydown:[null,"key"],keyup:[null,"key"]},tab:{keydown:[null,"char"],keyup:[null,"char"]},"pause-break":{keydown:[null,"key"],keyup:[null,"key"]},caps:{keydown:[null,"key"],keyup:[null,"key"]},escape:{keydown:[null,"key"],keypress:[null,"key"],keyup:[null,"key"]},"num-lock":{keydown:[null,"key"],keyup:[null,"key"]},"scroll-lock":{keydown:[null,"key"],keyup:[null,"key"]},print:{keyup:[null,"key"]},"function":{keydown:[null,"key"],keyup:[null,"key"]},"\r":{keydown:[null,"key"],keypress:[null,"key"],keyup:[null,"key"]}},opera:{prevent:{keyup:[],keydown:[],keypress:["char"]},character:{keydown:[null,"key"],keypress:[null,"char"],keyup:[null,"key"]},specialChars:{keydown:[null,"char"],keypress:[null,"char"],keyup:[null,"char"]},navigation:{keydown:[null,"key"],keypress:[null,"key"]},special:{keydown:[null,"key"],keypress:[null,"key"],keyup:[null,"key"]},tab:{keydown:[null,"char"],keypress:[null,"char"],keyup:[null,"char"]},"pause-break":{keydown:[null,"key"],keypress:[null,"key"],keyup:[null,"key"]},caps:{keydown:[null,"key"],keyup:[null,"key"]},escape:{keydown:[null,"key"],keypress:[null,"key"]},"num-lock":{keyup:[null,"key"],keydown:[null,"key"],keypress:[null,"key"]},"scroll-lock":{keydown:[null,"key"],keypress:[null,"key"],keyup:[null,"key"]},print:{},"function":{keydown:[null,"key"],keypress:[null,"key"],keyup:[null,"key"]},"\r":{keydown:[null,"key"],keypress:[null,"key"],keyup:[null,"key"]}}},a.mouse.browsers={webkit:{right:{mousedown:{button:2,which:3},mouseup:{button:2,which:3},contextmenu:{button:2,which:3}},left:{mousedown:{button:0,which:1},mouseup:{button:0,which:1},click:{button:0,which:1}}},opera:{right:{mousedown:{button:2,which:3},mouseup:{button:2,which:3}},left:{mousedown:{button:0,which:1},mouseup:{button:0,which:1},click:{button:0,which:1}}},msie:{right:{mousedown:{button:2},mouseup:{button:2},contextmenu:{button:0}},left:{mousedown:{button:1},mouseup:{button:1},click:{button:0}}},chrome:{right:{mousedown:{button:2,which:3},mouseup:{button:2,which:3},contextmenu:{button:2,which:3}},left:{mousedown:{button:0,which:1},mouseup:{button:0,which:1},click:{button:0,which:1}}},gecko:{left:{mousedown:{button:0,which:1},mouseup:{button:0,which:1},click:{button:0,which:1}},right:{mousedown:{button:2,which:3},mouseup:{button:2,which:3},contextmenu:{button:2,which:3}}}},a.key.browser=function(){if(a.key.browsers[window.navigator.userAgent])return a.key.browsers[window.navigator.userAgent];for(var b in a.browser)if(a.browser[b]&&a.key.browsers[b])return a.key.browsers[b];return a.key.browsers.gecko}(),a.mouse.browser=function(){if(a.mouse.browsers[window.navigator.userAgent])return a.mouse.browsers[window.navigator.userAgent];for(var b in a.browser)if(a.browser[b]&&a.mouse.browsers[b])return a.mouse.browsers[b];return a.mouse.browsers.gecko}(),a}(__m2,__m3),__m6=function(a){var b=[];a.typeable=function(a){-1==b.indexOf(a)&&b.push(a)},a.typeable.test=function(a){for(var c=0,d=b.length;d>c;c++)if(b[c](a))return!0;return!1};var c=a.typeable,d=/input|textarea/i;return c(function(a){return d.test(a.nodeName)}),c(function(a){return-1!=["","true"].indexOf(a.getAttribute("contenteditable"))}),a}(__m2),__m5=function(a){var b=a.helpers,c=function(a){if(void 0!==a.selectionStart)return document.activeElement&&document.activeElement!=a&&a.selectionStart==a.selectionEnd&&0==a.selectionStart?{start:a.value.length,end:a.value.length}:{start:a.selectionStart,end:a.selectionEnd};try{if("input"==a.nodeName.toLowerCase()){var c=b.getWindow(a).document.selection.createRange(),d=a.createTextRange();d.setEndPoint("EndToStart",c);var f=d.text.length;return{start:f,end:f+c.text.length}}var c=b.getWindow(a).document.selection.createRange(),d=c.duplicate(),g=c.duplicate(),h=c.duplicate();g.collapse(),h.collapse(!1),g.moveStart("character",-1),h.moveStart("character",-1),d.moveToElementText(a),d.setEndPoint("EndToEnd",c);var f=d.text.length-c.text.length,i=d.text.length;return 0!=f&&""==g.text&&(f+=2),0!=i&&""==h.text&&(i+=2),{start:f,end:i}}catch(j){var k=e.test(a.nodeName)?"value":"textContent";return{start:a[k].length,end:a[k].length}}},d=function(c){for(var d=b.getWindow(c).document,e=[],f=d.getElementsByTagName("*"),g=f.length,h=0;g>h;h++)a.isFocusable(f[h])&&f[h]!=d.documentElement&&e.push(f[h]);return e},e=/input|textarea/i,f=function(a){return e.test(a.nodeName)?a.value:a.textContent||a.innerText},g=function(a,b){e.test(a.nodeName)?a.value=b:a.textContent?a.textContent=b:a.innerText=b};b.extend(a,{keycodes:{"\b":8," ":9,"\r":13,shift:16,ctrl:17,alt:18,"pause-break":19,caps:20,escape:27,"num-lock":144,"scroll-lock":145,print:44,"page-up":33,"page-down":34,end:35,home:36,left:37,up:38,right:39,down:40,insert:45,"delete":46," ":32,0:48,1:49,2:50,3:51,4:52,5:53,6:54,7:55,8:56,9:57,a:65,b:66,c:67,d:68,e:69,f:70,g:71,h:72,i:73,j:74,k:75,l:76,m:77,n:78,o:79,p:80,q:81,r:82,s:83,t:84,u:85,v:86,w:87,x:88,y:89,z:90,num0:96,num1:97,num2:98,num3:99,num4:100,num5:101,num6:102,num7:103,num8:104,num9:105,"*":106,"+":107,subtract:109,decimal:110,divide:111,";":186,"=":187,",":188,dash:189,"-":189,period:190,".":190,"forward-slash":191,"/":191,"`":192,"[":219,"\\":220,"]":221,"'":222,"left window key":91,"right window key":92,"select key":93,f1:112,f2:113,f3:114,f4:115,f5:116,f6:117,f7:118,f8:119,f9:120,f10:121,f11:122,f12:123},selectText:function(a,b,c){if(a.setSelectionRange)c?(a.selectionStart=b,a.selectionEnd=c):(a.focus(),a.setSelectionRange(b,b));else if(a.createTextRange){var d=a.createTextRange();d.moveStart("character",b),c=c||b,d.moveEnd("character",c-a.value.length),d.select()}},getText:function(b){if(a.typeable.test(b)){var d=c(b);return b.value.substring(d.start,d.end)}var e=a.helpers.getWindow(b);return e.getSelection?e.getSelection().toString():e.document.getSelection?e.document.getSelection().toString():e.document.selection.createRange().text},getSelection:c}),b.extend(a.key,{data:function(c){if(a.key.browser[c])return a.key.browser[c];for(var d in a.key.kinds)if(b.inArray(c,a.key.kinds[d])>-1)return a.key.browser[d];return a.key.browser.character},isSpecial:function(b){for(var c=a.key.kinds.special,d=0;d-1&&a.key.defaults[d])return a.key.defaults[d];return a.key.defaults.character},defaults:{character:function(b,c,d,e,h){if(/num\d+/.test(d)&&(d=d.match(/\d+/)[0]),e||!a.support.keyCharacters&&a.typeable.test(this)){var i=f(this),j=i.substr(0,h.start),k=i.substr(h.end),l=d;g(this,j+l+k);var m="\n"==l&&a.support.textareaCarriage?2:l.length;a.selectText(this,j.length+m)}},c:function(){a.key.ctrlKey?a.key.clipboard=a.getText(this):a.key.defaults.character.apply(this,arguments)},v:function(b,c,d,e,f){a.key.ctrlKey?a.key.defaults.character.call(this,b,c,a.key.clipboard,!0,f):a.key.defaults.character.apply(this,arguments)},a:function(){a.key.ctrlKey?a.selectText(this,0,f(this).length):a.key.defaults.character.apply(this,arguments)},home:function(){a.onParents(this,function(a){return a.scrollHeight!=a.clientHeight?(a.scrollTop=0,!1):void 0})},end:function(){a.onParents(this,function(a){return a.scrollHeight!=a.clientHeight?(a.scrollTop=a.scrollHeight,!1):void 0})},"page-down":function(){a.onParents(this,function(a){if(a.scrollHeight!=a.clientHeight){var b=a.clientHeight;return a.scrollTop+=b,!1}})},"page-up":function(){a.onParents(this,function(a){if(a.scrollHeight!=a.clientHeight){var b=a.clientHeight;return a.scrollTop-=b,!1}})},"\b":function(b,c,d,e,h){if(!a.support.backspaceWorks&&a.typeable.test(this)){var i=f(this),j=i.substr(0,h.start),k=i.substr(h.end);h.start==h.end&&h.start>0?(g(this,j.substring(0,j.length-1)+k),a.selectText(this,h.start-1)):(g(this,j+k),a.selectText(this,h.start))}},"delete":function(b,c,d,e,h){if(!a.support.backspaceWorks&&a.typeable.test(this)){var i=f(this),j=i.substr(0,h.start),k=i.substr(h.end);h.start==h.end&&h.start<=f(this).length-1?g(this,j+k.substring(1)):g(this,j+k),a.selectText(this,h.start)}},"\r":function(b,c,d,e,f){var g=this.nodeName.toLowerCase();if("input"==g&&a.trigger("change",{},this),!a.support.keypressSubmits&&"input"==g){var h=a.closest(this,"form");h&&a.trigger("submit",{},h)}a.support.keyCharacters||"textarea"!=g||a.key.defaults.character.call(this,b,c,"\n",void 0,f),a.support.keypressOnAnchorClicks||"a"!=g||a.trigger("click",{},this)}," ":function(){var b,c,e=d(this),f=(a.tabIndex(this),null),g=0;for(orders=[];gf(this).length?f(this).length:g.end+1):a.selectText(this,g.end+1>f(this).length?f(this).length:g.end+1))},up:function(){/select/i.test(this.nodeName)&&(this.selectedIndex=this.selectedIndex?this.selectedIndex-1:0)},down:function(){/select/i.test(this.nodeName)&&(a.changeOnBlur(this,"selectedIndex",this.selectedIndex),this.selectedIndex=this.selectedIndex+1)},shift:function(){return null},ctrl:function(){return null}}}),b.extend(a.create,{keydown:{setup:function(c,d,e){-1!=b.inArray(d,a.key.kinds.special)&&(a.key[d+"Key"]=e)}},keypress:{setup:function(b,c,d){a.support.keyCharacters&&!a.support.keysOnNotFocused&&d.focus()}},keyup:{setup:function(c,d){-1!=b.inArray(d,a.key.kinds.special)&&(a.key[d+"Key"]=null)}},key:{options:function(c,d){return d="object"!=typeof d?{character:d}:d,d=b.extend({},d),d.character&&(b.extend(d,a.key.options(d.character,c)),delete d.character),d=b.extend({ctrlKey:!!a.key.ctrlKey,altKey:!!a.key.altKey,shiftKey:!!a.key.shiftKey,metaKey:!!a.key.metaKey},d)},event:function(a,c,d){var e=b.getWindow(d).document||document;if(e.createEvent){var f;try{f=e.createEvent("KeyEvents"),f.initKeyEvent(a,!0,!0,window,c.ctrlKey,c.altKey,c.shiftKey,c.metaKey,c.keyCode,c.charCode)}catch(g){f=b.createBasicStandardEvent(a,c,e)}return f.synthetic=!0,f}var f;try{f=b.createEventObject.apply(this,arguments),b.extend(f,c)}catch(g){}return f}}});var h={enter:"\r",backspace:"\b",tab:" ",space:" "};return b.extend(a.init.prototype,{_key:function(d,e,f){if(/-up$/.test(d)&&-1!=b.inArray(d.replace("-up",""),a.key.kinds.special))return a.trigger("keyup",d.replace("-up",""),e),void f(!0,e);var g,i=b.getWindow(e).document.activeElement,j=a.typeable.test(e)&&c(e),k=h[d]||d,l=a.trigger("keydown",k,e),m=a.key.getDefault,n=a.key.browser.prevent,o=a.key.options(k,"keypress");return l?o?(i!==b.getWindow(e).document.activeElement&&(e=b.getWindow(e).document.activeElement),l=a.trigger("keypress",o,e),l&&(g=m(k).call(e,o,b.getWindow(e),k,void 0,j))):g=m(k).call(e,o,b.getWindow(e),k,void 0,j):o&&-1==b.inArray("keypress",n.keydown)&&(i!==b.getWindow(e).document.activeElement&&(e=b.getWindow(e).document.activeElement),a.trigger("keypress",o,e)),g&&g.nodeName&&(e=g),null!==g?setTimeout(function(){a.support.oninput&&a.trigger("input",a.key.options(k,"input"),e),a.trigger("keyup",a.key.options(k,"keyup"),e),f(l,e)},1):f(l,e),e},_type:function(a,b,c){var d=(a+"").match(/(\[[^\]]+\])|([^\[])/g),e=this,f=function(a,g){var h=d.shift();return h?(g=g||b,h.length>1&&(h=h.substr(1,h.length-2)),void e._key(h,g,f)):void c(a,g)};f()}}),a.config.support?a.helpers.extend(a.support,a.config.support):!function(){if(!document.body)return void setTimeout(arguments.callee,1);var b,c,d,e,f,g,h,i=[window.scrollX,window.scrollY],j=window.document.activeElement,k=document.createElement("div");k.innerHTML="
",document.documentElement.appendChild(k),d=k.firstChild,b=d.childNodes[0],c=d.childNodes[2],e=d.getElementsByTagName("a")[0],f=d.getElementsByTagName("textarea")[0],g=d.childNodes[3],h=d.childNodes[4],d.onsubmit=function(b){return b.preventDefault&&b.preventDefault(),a.support.keypressSubmits=!0,b.returnValue=!1,!1},g.focus(),a.trigger("keypress","\r",g),a.trigger("keypress","a",g),a.support.keyCharacters="a"==g.value,g.value="a",a.trigger("keypress","\b",g),a.support.backspaceWorks=""==g.value,g.onchange=function(){a.support.focusChanges=!0},g.focus(),a.trigger("keypress","a",g),d.childNodes[5].focus(),a.trigger("keypress","b",g),a.support.keysOnNotFocused="ab"==g.value,a.bind(e,"click",function(b){return b.preventDefault&&b.preventDefault(),a.support.keypressOnAnchorClicks=!0,b.returnValue=!1,!1}),a.trigger("keypress","\r",e),a.support.textareaCarriage=4==f.value.length,a.support.oninput="oninput"in h,document.documentElement.removeChild(k),j&&j.focus(),window.scrollTo(i[0],i[1]),a.support.ready++}(),a}(__m2,__m6,__m4),__m7=function(a){!function(){if(!document.body)return void setTimeout(arguments.callee,1);var b=document.createElement("div");if(document.body.appendChild(b),a.helpers.extend(b.style,{width:"100px",height:"10000px",backgroundColor:"blue",position:"absolute",top:"10px",left:"0px",zIndex:19999}),document.body.scrollTop=11,document.elementFromPoint){var c=document.elementFromPoint(3,1);c==b?a.support.elementFromClient=!0:a.support.elementFromPage=!0,document.body.removeChild(b),document.body.scrollTop=0}}();var b=function(b,c){var d,e=b.clientX,f=b.clientY,g=a.helpers.getWindow(c);if(a.support.elementFromPage){var h=a.helpers.scrollOffset(g);e+=h.left,f+=h.top}return d=g.document.elementFromPoint?g.document.elementFromPoint(e,f):c,d===g.document.documentElement&&(b.clientY<0||b.clientX<0)?c:d},c=function(c,d,e){var f=b(d,e);return a.trigger(c,d,f||e),f},d=function(c,d,e){var f=b(c,d);if(e!=f&&f&&e){var g=a.helpers.extend({},c);g.relatedTarget=f,a.trigger("mouseout",g,e),g.relatedTarget=e,a.trigger("mouseover",g,f)}return a.trigger("mousemove",c,f||d),f},e=function(c,e,f,g,h){var i=new Date,j=e.clientX-c.clientX,k=e.clientY-c.clientY,l=a.helpers.getWindow(g),m=b(c,g),n=l.document.createElement("div"),o=0;move=function(){var b=new Date,p=a.helpers.scrollOffset(l),q=(0==o?0:b-i)/f,r={clientX:j*q+c.clientX,clientY:k*q+c.clientY};o++,1>q?(a.helpers.extend(n.style,{left:r.clientX+p.left+2+"px",top:r.clientY+p.top+2+"px"}),m=d(r,g,m),setTimeout(arguments.callee,15)):(m=d(e,g,m),l.document.body.removeChild(n),h())},a.helpers.extend(n.style,{height:"5px",width:"5px",backgroundColor:"red",position:"absolute",zIndex:19999,fontSize:"1px"}),l.document.body.appendChild(n),move()},f=function(a,b,d,f,g){c("mousedown",a,f),e(a,b,d,f,function(){c("mouseup",b,f),g()})},g=function(b){var c=a.jquery()(b),d=c.offset();return{pageX:d.left+c.outerWidth()/2,pageY:d.top+c.outerHeight()/2}},h=function(b,c,d){var e=/(\d+)[x ](\d+)/,f=/(\d+)X(\d+)/,h=/([+-]\d+)[xX ]([+-]\d+)/;if("string"==typeof b&&h.test(b)&&d){var i=g(d),j=b.match(h);b={pageX:i.pageX+parseInt(j[1]),pageY:i.pageY+parseInt(j[2])}}if("string"==typeof b&&e.test(b)){var j=b.match(e);b={pageX:parseInt(j[1]),pageY:parseInt(j[2])}}if("string"==typeof b&&f.test(b)){var j=b.match(f);b={clientX:parseInt(j[1]),clientY:parseInt(j[2])}}if("string"==typeof b&&(b=a.jquery()(b,c.document)[0]),b.nodeName&&(b=g(b)),b.pageX){var k=a.helpers.scrollOffset(c);b={clientX:b.pageX-k.left,clientY:b.pageY-k.top}}return b},i=function(b,c,d){if(b.clientY<0){var e=a.helpers.scrollOffset(d),f=(a.helpers.scrollDimensions(d),e.top+b.clientY-100),g=f-e.top;f>0||(f=0,g=-e.top),b.clientY=b.clientY-g,c.clientY=c.clientY-g,a.helpers.scrollOffset(d,{top:f,left:e.left})}};return a.helpers.extend(a.init.prototype,{_move:function(b,c,d){var f=a.helpers.getWindow(c),g=h(b.from||c,f,c),j=h(b.to||b,f,c);b.adjust!==!1&&i(g,j,f),e(g,j,b.duration||500,c,d)},_drag:function(b,c,d){var e=a.helpers.getWindow(c),g=h(b.from||c,e,c),j=h(b.to||b,e,c);b.adjust!==!1&&i(g,j,e),f(g,j,b.duration||500,c,d)}}),a}(__m2),__m1=function(a){return window.Syn=a,a}(__m2,__m3,__m4,__m5,__m7)}(window); \ No newline at end of file diff --git a/src/Moodle/BehatExtension/Driver/Selenium2/moodle_syn.js b/src/Moodle/BehatExtension/Driver/Selenium2/moodle_syn.js deleted file mode 100644 index 1a98446..0000000 --- a/src/Moodle/BehatExtension/Driver/Selenium2/moodle_syn.js +++ /dev/null @@ -1,2658 +0,0 @@ -/** - * Syn - 0.0.2 - * - * @copyright 2014 Bitovi - * Wed, 26 Feb 2014 08:30:25 GMT - * @license MIT - */ - -!function(window) { - -// ## src/synthetic.js -var __m2 = (function(){ - //allow for configuration of Syn - var opts = window.Syn ? window.Syn : {}; - - var extend = function( d, s ) { - var p; - for (p in s) { - d[p] = s[p]; - } - return d; - }, - // only uses browser detection for key events - browser = { - msie: !! (window.attachEvent && !window.opera), - opera: !! window.opera, - webkit: navigator.userAgent.indexOf('AppleWebKit/') > -1, - safari: navigator.userAgent.indexOf('AppleWebKit/') > -1 && navigator.userAgent.indexOf('Chrome/') === -1, - gecko: navigator.userAgent.indexOf('Gecko') > -1, - mobilesafari: !! navigator.userAgent.match(/Apple.*Mobile.*Safari/), - rhino: navigator.userAgent.match(/Rhino/) && true - }, - createEventObject = function( type, options, element ) { - var event = element.ownerDocument.createEventObject(); - return extend(event, options); - }, - data = {}, - id = 1, - expando = "_synthetic" + new Date().getTime(), - bind, unbind, key = /keypress|keyup|keydown/, - page = /load|unload|abort|error|select|change|submit|reset|focus|blur|resize|scroll/, - //this is maintained so we can click on html and blur the active element - activeElement, - - /** - * @class Syn - * @download funcunit/dist/syn.js - * @test funcunit/synthetic/qunit.html - * Syn is used to simulate user actions. It creates synthetic events and - * performs their default behaviors. - * - *

Basic Use

- * The following clicks an input element with id='description' - * and then types 'Hello World'. - * - @codestart - Syn.click({},'description') - .type("Hello World") - @codeend - *

User Actions and Events

- *

Syn is typically used to simulate user actions as opposed to triggering events. Typing characters - * is an example of a user action. The keypress that represents an 'a' - * character being typed is an example of an event. - *

- *

- * While triggering events is supported, it's much more useful to simulate actual user behavior. The - * following actions are supported by Syn: - *

- *
    - *
  • [Syn.prototype.click click] - a mousedown, focus, mouseup, and click.
  • - *
  • [Syn.prototype.dblclick dblclick] - two click! events followed by a dblclick.
  • - *
  • [Syn.prototype.key key] - types a single character (keydown, keypress, keyup).
  • - *
  • [Syn.prototype.type type] - types multiple characters into an element.
  • - *
  • [Syn.prototype.move move] - moves the mouse from one position to another (triggering mouseover / mouseouts).
  • - *
  • [Syn.prototype.drag drag] - a mousedown, followed by mousemoves, and a mouseup.
  • - *
- * All actions run asynchronously. - * Click on the links above for more - * information on how to use the specific action. - *

Asynchronous Callbacks

- * Actions don't complete immediately. This is almost - * entirely because focus() - * doesn't run immediately in IE. - * If you provide a callback function to Syn, it will - * be called after the action is completed. - *
The following checks that "Hello World" was entered correctly: - @codestart - Syn.click({},'description') - .type("Hello World", function(){ - - ok("Hello World" == document.getElementById('description').value) - }) - @codeend -

Asynchronous Chaining

-

You might have noticed the [Syn.prototype.then then] method. It provides chaining - so you can do a sequence of events with a single (final) callback. -

- If an element isn't provided to then, it uses the previous Syn's element. -

- The following does a lot of stuff before checking the result: - @codestart - Syn.type('ice water','title') - .type('ice and water','description') - .click({},'create') - .drag({to: 'favorites'},'newRecipe', - function(){ - ok($('#newRecipe').parents('#favorites').length); - }) - @codeend - -

jQuery Helper

- If jQuery is present, Syn adds a triggerSyn helper you can use like: - @codestart - $("#description").triggerSyn("type","Hello World"); - @codeend - *

Key Event Recording

- *

Every browser has very different rules for dispatching key events. - * As there is no way to feature detect how a browser handles key events, - * synthetic uses a description of how the browser behaves generated - * by a recording application.

- *

- * If you want to support a browser not currently supported, you can - * record that browser's key event description and add it to - * Syn.key.browsers by it's navigator agent. - *

- @codestart - Syn.key.browsers["Envjs\ Resig/20070309 PilotFish/1.2.0.10\1.6"] = { - 'prevent': - {"keyup":[],"keydown":["char","keypress"],"keypress":["char"]}, - 'character': - { ... } - } - @codeend - *

Limitations

- * Syn fully supports IE 6+, FF 3+, Chrome, Safari, Opera 10+. - * With FF 1+, drag / move events are only partially supported. They will - * not trigger mouseover / mouseout events.
- * Safari crashes when a mousedown is triggered on a select. Syn will not - * create this event. - *

Contributing to Syn

- * Have we missed something? We happily accept patches. The following are - * important objects and properties of Syn: - *
    - *
  • Syn.create - contains methods to setup, convert options, and create an event of a specific type.
  • - *
  • Syn.defaults - default behavior by event type (except for keys).
  • - *
  • Syn.key.defaults - default behavior by key.
  • - *
  • Syn.keycodes - supported keys you can type.
  • - *
- *

Roll Your Own Functional Test Framework

- *

Syn is really the foundation of JavaScriptMVC's functional testing framework - [FuncUnit]. - * But, we've purposely made Syn work without any dependencies in the hopes that other frameworks or - * testing solutions can use it as well. - *

- * @constructor - * Creates a synthetic event on the element. - * @param {Object} type - * @param {Object} options - * @param {Object} element - * @param {Object} callback - * @return Syn - */ - Syn = function( type, options, element, callback ) { - return (new Syn.init(type, options, element, callback)); - }; - - Syn.config = opts; - - bind = function( el, ev, f ) { - return el.addEventListener ? el.addEventListener(ev, f, false) : el.attachEvent("on" + ev, f); - }; - unbind = function( el, ev, f ) { - return el.addEventListener ? el.removeEventListener(ev, f, false) : el.detachEvent("on" + ev, f); - }; - - /** - * @Static - */ - extend(Syn, { - /** - * Creates a new synthetic event instance - * @hide - * @param {Object} type - * @param {Object} options - * @param {Object} element - * @param {Object} callback - */ - init: function( type, options, element, callback ) { - var args = Syn.args(options, element, callback), - self = this; - this.queue = []; - this.element = args.element; - - //run event - if ( typeof this[type] === "function" ) { - this[type](args.options, args.element, function( defaults, el ) { - args.callback && args.callback.apply(self, arguments); - self.done.apply(self, arguments); - }); - } else { - this.result = Syn.trigger(type, args.options, args.element); - args.callback && args.callback.call(this, args.element, this.result); - } - }, - jquery: function( el, fast ) { - if ( window.FuncUnit && window.FuncUnit.jQuery ) { - return window.FuncUnit.jQuery; - } - if ( el ) { - return Syn.helpers.getWindow(el).jQuery || window.jQuery; - } - else { - return window.jQuery; - } - }, - /** - * Returns an object with the args for a Syn. - * @hide - * @return {Object} - */ - args: function() { - var res = {}, - i = 0; - for ( ; i < arguments.length; i++ ) { - if ( typeof arguments[i] === 'function' ) { - res.callback = arguments[i]; - } else if ( arguments[i] && arguments[i].jquery ) { - res.element = arguments[i][0]; - } else if ( arguments[i] && arguments[i].nodeName ) { - res.element = arguments[i]; - } else if ( res.options && typeof arguments[i] === 'string' ) { //we can get by id - res.element = document.getElementById(arguments[i]); - } - else if ( arguments[i] ) { - res.options = arguments[i]; - } - } - return res; - }, - click: function( options, element, callback ) { - Syn('click!', options, element, callback); - }, - /** - * @attribute defaults - * Default actions for events. Each default function is called with this as its - * element. It should return true if a timeout - * should happen after it. If it returns an element, a timeout will happen - * and the next event will happen on that element. - */ - defaults: { - focus: function() { - if (!Syn.support.focusChanges ) { - var element = this, - nodeName = element.nodeName.toLowerCase(); - Syn.data(element, "syntheticvalue", element.value); - - //TODO, this should be textarea too - //and this might be for only text style inputs ... hmmmmm .... - if ( nodeName === "input" || nodeName === "textarea" ) { - bind(element, "blur", function() { - if ( Syn.data(element, "syntheticvalue") != element.value ) { - - Syn.trigger("change", {}, element); - } - unbind(element, "blur", arguments.callee); - }); - - } - } - }, - submit: function() { - Syn.onParents(this, function( el ) { - if ( el.nodeName.toLowerCase() === 'form' ) { - el.submit(); - return false; - } - }); - } - }, - changeOnBlur: function( element, prop, value ) { - - bind(element, "blur", function() { - if ( value !== element[prop] ) { - Syn.trigger("change", {}, element); - } - unbind(element, "blur", arguments.callee); - }); - - }, - /** - * Returns the closest element of a particular type. - * @hide - * @param {Object} el - * @param {Object} type - */ - closest: function( el, type ) { - while ( el && el.nodeName.toLowerCase() !== type.toLowerCase() ) { - el = el.parentNode; - } - return el; - }, - /** - * adds jQuery like data (adds an expando) and data exists FOREVER :) - * @hide - * @param {Object} el - * @param {Object} key - * @param {Object} value - */ - data: function( el, key, value ) { - var d; - if (!el[expando] ) { - el[expando] = id++; - } - if (!data[el[expando]] ) { - data[el[expando]] = {}; - } - d = data[el[expando]]; - if ( value ) { - data[el[expando]][key] = value; - } else { - return data[el[expando]][key]; - } - }, - /** - * Calls a function on the element and all parents of the element until the function returns - * false. - * @hide - * @param {Object} el - * @param {Object} func - */ - onParents: function( el, func ) { - var res; - while ( el && res !== false ) { - res = func(el); - el = el.parentNode; - } - return el; - }, - //regex to match focusable elements - focusable: /^(a|area|frame|iframe|label|input|select|textarea|button|html|object)$/i, - /** - * Returns if an element is focusable - * @hide - * @param {Object} elem - */ - isFocusable: function( elem ) { - var attributeNode; - - // IE8 Standards doesn't like this on some elements - if(elem.getAttributeNode){ - attributeNode = elem.getAttributeNode("tabIndex") - } - - return this.focusable.test(elem.nodeName) || - (attributeNode && attributeNode.specified) && - Syn.isVisible(elem); - }, - /** - * Returns if an element is visible or not - * @hide - * @param {Object} elem - */ - isVisible: function( elem ) { - return (elem.offsetWidth && elem.offsetHeight) || (elem.clientWidth && elem.clientHeight); - }, - /** - * Gets the tabIndex as a number or null - * @hide - * @param {Object} elem - */ - tabIndex: function( elem ) { - var attributeNode = elem.getAttributeNode("tabIndex"); - return attributeNode && attributeNode.specified && (parseInt(elem.getAttribute('tabIndex')) || 0); - }, - bind: bind, - unbind: unbind, - browser: browser, - //some generic helpers - helpers: { - createEventObject: createEventObject, - createBasicStandardEvent: function( type, defaults, doc ) { - var event; - try { - event = doc.createEvent("Events"); - } catch (e2) { - event = doc.createEvent("UIEvents"); - } finally { - event.initEvent(type, true, true); - extend(event, defaults); - } - return event; - }, - inArray: function( item, array ) { - var i =0; - for ( ; i < array.length; i++ ) { - if ( array[i] === item ) { - return i; - } - } - return -1; - }, - getWindow: function( element ) { - if(element.ownerDocument){ - return element.ownerDocument.defaultView || element.ownerDocument.parentWindow; - } - }, - extend: extend, - scrollOffset: function( win , set) { - var doc = win.document.documentElement, - body = win.document.body; - if(set){ - window.scrollTo(set.left, set.top); - - } else { - return { - left: (doc && doc.scrollLeft || body && body.scrollLeft || 0) + (doc.clientLeft || 0), - top: (doc && doc.scrollTop || body && body.scrollTop || 0) + (doc.clientTop || 0) - }; - } - - }, - scrollDimensions: function(win){ - var doc = win.document.documentElement, - body = win.document.body, - docWidth = doc.clientWidth, - docHeight = doc.clientHeight, - compat = win.document.compatMode === "CSS1Compat"; - - return { - height: compat && docHeight || - body.clientHeight || docHeight, - width: compat && docWidth || - body.clientWidth || docWidth - }; - }, - addOffset: function( options, el ) { - var jq = Syn.jquery(el), - off; - if ( typeof options === 'object' && options.clientX === undefined && options.clientY === undefined && options.pageX === undefined && options.pageY === undefined && jq ) { - el = jq(el); - off = el.offset(); - options.pageX = off.left + el.width() / 2; - options.pageY = off.top + el.height() / 2; - } - } - }, - // place for key data - key: { - ctrlKey: null, - altKey: null, - shiftKey: null, - metaKey: null - }, - //triggers an event on an element, returns true if default events should be run - /** - * Dispatches an event and returns true if default events should be run. - * @hide - * @param {Object} event - * @param {Object} element - * @param {Object} type - * @param {Object} autoPrevent - */ - dispatch: function( event, element, type, autoPrevent ) { - - // dispatchEvent doesn't always work in IE (mostly in a popup) - if ( element.dispatchEvent && event ) { - var preventDefault = event.preventDefault, - prevents = autoPrevent ? -1 : 0; - - //automatically prevents the default behavior for this event - //this is to protect agianst nasty browser freezing bug in safari - if ( autoPrevent ) { - bind(element, type, function( ev ) { - ev.preventDefault(); - unbind(this, type, arguments.callee); - }); - } - - - event.preventDefault = function() { - prevents++; - if (++prevents > 0 ) { - preventDefault.apply(this, []); - } - }; - element.dispatchEvent(event); - return prevents <= 0; - } else { - try { - window.event = event; - } catch (e) {} - //source element makes sure element is still in the document - return element.sourceIndex <= 0 || (element.fireEvent && element.fireEvent('on' + type, event)); - } - }, - /** - * @attribute - * @hide - * An object of eventType -> function that create that event. - */ - create: { - //-------- PAGE EVENTS --------------------- - page: { - event: function( type, options, element ) { - var doc = Syn.helpers.getWindow(element).document || document, - event; - if ( doc.createEvent ) { - event = doc.createEvent("Events"); - - event.initEvent(type, true, true); - return event; - } - else { - try { - event = createEventObject(type, options, element); - } - catch (e) {} - return event; - } - } - }, - // unique events - focus: { - event: function( type, options, element ) { - Syn.onParents(element, function( el ) { - if ( Syn.isFocusable(el) ) { - if ( el.nodeName.toLowerCase() !== 'html' ) { - el.focus(); - activeElement = el; - } - else if ( activeElement ) { - // TODO: The HTML element isn't focasable in IE, but it is - // in FF. We should detect this and do a true focus instead - // of just a blur - var doc = Syn.helpers.getWindow(element).document; - if ( doc !== window.document ) { - return false; - } else if ( doc.activeElement ) { - doc.activeElement.blur(); - activeElement = null; - } else { - activeElement.blur(); - activeElement = null; - } - - - } - return false; - } - }); - return true; - } - } - }, - /** - * @attribute support - * - * Feature detected properties of a browser's event system. - * Support has the following properties: - * - * - `backspaceWorks` - typing a backspace removes a character - * - `clickChanges` - clicking on an option element creates a change event. - * - `clickSubmits` - clicking on a form button submits the form. - * - `focusChanges` - focus/blur creates a change event. - * - `keypressOnAnchorClicks` - Keying enter on an anchor triggers a click. - * - `keypressSubmits` - enter key submits - * - `keyCharacters` - typing a character shows up - * - `keysOnNotFocused` - enters keys when not focused. - * - `linkHrefJS` - An achor's href JavaScript is run. - * - `mouseDownUpClicks` - A mousedown followed by mouseup creates a click event. - * - `mouseupSubmits` - a mouseup on a form button submits the form. - * - `radioClickChanges` - clicking a radio button changes the radio. - * - `tabKeyTabs` - A tab key changes tabs. - * - `textareaCarriage` - a new line in a textarea creates a carriage return. - * - * - */ - support: { - clickChanges: false, - clickSubmits: false, - keypressSubmits: false, - mouseupSubmits: false, - radioClickChanges: false, - focusChanges: false, - linkHrefJS: false, - keyCharacters: false, - backspaceWorks: false, - mouseDownUpClicks: false, - tabKeyTabs: false, - keypressOnAnchorClicks: false, - optionClickBubbles: false, - ready: 0 - }, - /** - * Creates a synthetic event and dispatches it on the element. - * This will run any default actions for the element. - * Typically you want to use Syn, but if you want the return value, use this. - * @param {String} type - * @param {Object} options - * @param {HTMLElement} element - * @return {Boolean} true if default events were run, false if otherwise. - */ - trigger: function( type, options, element ) { - options || (options = {}); - - var create = Syn.create, - setup = create[type] && create[type].setup, - kind = key.test(type) ? 'key' : (page.test(type) ? "page" : "mouse"), - createType = create[type] || {}, - createKind = create[kind], - event, ret, autoPrevent, dispatchEl = element; - - //any setup code? - Syn.support.ready === 2 && setup && setup(type, options, element); - - autoPrevent = options._autoPrevent; - //get kind - delete options._autoPrevent; - - if ( createType.event ) { - ret = createType.event(type, options, element); - } else { - //convert options - options = createKind.options ? createKind.options(type, options, element) : options; - - if (!Syn.support.changeBubbles && /option/i.test(element.nodeName) ) { - dispatchEl = element.parentNode; //jQuery expects clicks on select - } - - //create the event - event = createKind.event(type, options, dispatchEl); - - //send the event - ret = Syn.dispatch(event, dispatchEl, type, autoPrevent); - } - - ret && Syn.support.ready === 2 && Syn.defaults[type] && Syn.defaults[type].call(element, options, autoPrevent); - return ret; - }, - eventSupported: function( eventName ) { - var el = document.createElement("div"); - eventName = "on" + eventName; - - var isSupported = (eventName in el); - if (!isSupported ) { - el.setAttribute(eventName, "return;"); - isSupported = typeof el[eventName] === "function"; - } - el = null; - - return isSupported; - } - - }); - /** - * @Prototype - */ - extend(Syn.init.prototype, { - /** - * @function then - *

- * Then is used to chain a sequence of actions to be run one after the other. - * This is useful when many asynchronous actions need to be performed before some - * final check needs to be made. - *

- *

The following clicks and types into the id='age' element and then checks that only numeric characters can be entered.

- *

Example

- * @codestart - * Syn('click',{},'age') - * .then('type','I am 12',function(){ - * equals($('#age').val(),"12") - * }) - * @codeend - * If the element argument is undefined, then the last element is used. - * - * @param {String} type The type of event or action to create: "_click", "_dblclick", "_drag", "_type". - * @param {Object} options Optiosn to pass to the event. - * @param {String|HTMLElement} [element] A element's id or an element. If undefined, defaults to the previous element. - * @param {Function} [callback] A function to callback after the action has run, but before any future chained actions are run. - */ - then: function( type, options, element, callback ) { - if ( Syn.autoDelay ) { - this.delay(); - } - var args = Syn.args(options, element, callback), - self = this; - - - //if stack is empty run right away - //otherwise ... unshift it - this.queue.unshift(function( el, prevented ) { - - if ( typeof this[type] === "function" ) { - this.element = args.element || el; - this[type](args.options, this.element, function( defaults, el ) { - args.callback && args.callback.apply(self, arguments); - self.done.apply(self, arguments); - }); - } else { - this.result = Syn.trigger(type, args.options, args.element); - args.callback && args.callback.call(this, args.element, this.result); - return this; - } - }) - return this; - }, - /** - * Delays the next command a set timeout. - * @param {Number} [timeout] - * @param {Function} [callback] - */ - delay: function( timeout, callback ) { - if ( typeof timeout === 'function' ) { - callback = timeout; - timeout = null; - } - timeout = timeout || 600; - var self = this; - this.queue.unshift(function() { - setTimeout(function() { - callback && callback.apply(self, []) - self.done.apply(self, arguments); - }, timeout); - }); - return this; - }, - done: function( defaults, el ) { - el && (this.element = el); - if ( this.queue.length ) { - this.queue.pop().call(this, this.element, defaults); - } - - }, - /** - * @function click - * Clicks an element by triggering a mousedown, - * mouseup, - * and a click event. - *

Example

- * @codestart - * Syn.click({},'create',function(){ - * //check something - * }) - * @codeend - * You can also provide the coordinates of the click. - * If jQuery is present, it will set clientX and clientY - * for you. Here's how to set it yourself: - * @codestart - * Syn.click( - * {clientX: 20, clientY: 100}, - * 'create', - * function(){ - * //check something - * }) - * @codeend - * You can also provide pageX and pageY and Syn will convert it for you. - * @param {Object} options - * @param {HTMLElement} element - * @param {Function} callback - */ - "_click": function( options, element, callback, force ) { - Syn.helpers.addOffset(options, element); - Syn.trigger("mousedown", options, element); - - //timeout is b/c IE is stupid and won't call focus handlers - setTimeout(function() { - Syn.trigger("mouseup", options, element); - if (!Syn.support.mouseDownUpClicks || force ) { - Syn.trigger("click", options, element); - callback(true); - } else { - //we still have to run the default (presumably) - Syn.create.click.setup('click', options, element); - Syn.defaults.click.call(element); - //must give time for callback - setTimeout(function() { - callback(true); - }, 1); - } - - }, 1); - }, - /** - * Right clicks in browsers that support it (everyone but opera). - * @param {Object} options - * @param {Object} element - * @param {Object} callback - */ - "_rightClick": function( options, element, callback ) { - Syn.helpers.addOffset(options, element); - var mouseopts = extend(extend({}, Syn.mouse.browser.right.mouseup), options); - - Syn.trigger("mousedown", mouseopts, element); - - //timeout is b/c IE is stupid and won't call focus handlers - setTimeout(function() { - Syn.trigger("mouseup", mouseopts, element); - if ( Syn.mouse.browser.right.contextmenu ) { - Syn.trigger("contextmenu", extend(extend({}, Syn.mouse.browser.right.contextmenu), options), element); - } - callback(true); - }, 1); - }, - /** - * @function dblclick - * Dblclicks an element. This runs two [Syn.prototype.click click] events followed by - * a dblclick on the element. - *

Example

- * @codestart - * Syn.dblclick({},'open') - * @codeend - * @param {Object} options - * @param {HTMLElement} element - * @param {Function} callback - */ - "_dblclick": function( options, element, callback ) { - Syn.helpers.addOffset(options, element); - var self = this; - this._click(options, element, function() { - setTimeout(function() { - self._click(options, element, function() { - Syn.trigger("dblclick", options, element); - callback(true); - }, true); - }, 2); - - }); - } - }); - - var actions = ["click", "dblclick", "move", "drag", "key", "type", 'rightClick'], - makeAction = function( name ) { - Syn[name] = function( options, element, callback ) { - return Syn("_" + name, options, element, callback); - }; - Syn.init.prototype[name] = function( options, element, callback ) { - return this.then("_" + name, options, element, callback); - }; - }, - i = 0; - - for ( ; i < actions.length; i++ ) { - makeAction(actions[i]); - } - - - - return Syn; -})(); - -// ## src/mouse.js -var __m3 = (function(Syn) { -//handles mosue events - - var h = Syn.helpers, - getWin = h.getWindow; - - Syn.mouse = {}; - h.extend(Syn.defaults, { - mousedown: function( options ) { - Syn.trigger("focus", {}, this) - }, - click: function() { - // prevents the access denied issue in IE if the click causes the element to be destroyed - var element = this, href, type, radioChanged, nodeName, scope; - try { - href = element.href; - type = element.type; - createChange = Syn.data(element, "createChange"); - radioChanged = Syn.data(element, "radioChanged"); - scope = getWin(element); - nodeName = element.nodeName.toLowerCase(); - } catch (e) { - return; - } - //get old values - - //this code was for restoring the href attribute to prevent popup opening - //if ((href = Syn.data(element, "href"))) { - // element.setAttribute('href', href) - //} - - //run href javascript - if (!Syn.support.linkHrefJS && /^\s*javascript:/.test(href) ) { - //eval js - var code = href.replace(/^\s*javascript:/, "") - - //try{ - if ( code != "//" && code.indexOf("void(0)") == -1 ) { - if ( window.selenium ) { - eval("with(selenium.browserbot.getCurrentWindow()){" + code + "}") - } else { - eval("with(scope){" + code + "}") - } - } - } - - //submit a form - if (!(Syn.support.clickSubmits) && (nodeName == "input" && type == "submit") || nodeName == 'button' ) { - - var form = Syn.closest(element, "form"); - if ( form ) { - Syn.trigger("submit", {}, form) - } - - } - //follow a link, probably needs to check if in an a. - if ( nodeName == "a" && element.href && !/^\s*javascript:/.test(href) ) { - scope.location.href = href; - - } - - //change a checkbox - if ( nodeName == "input" && type == "checkbox" ) { - - //if(!Syn.support.clickChecks && !Syn.support.changeChecks){ - // element.checked = !element.checked; - //} - if (!Syn.support.clickChanges ) { - Syn.trigger("change", {}, element); - } - } - - //change a radio button - if ( nodeName == "input" && type == "radio" ) { // need to uncheck others if not checked - if ( radioChanged && !Syn.support.radioClickChanges ) { - Syn.trigger("change", {}, element); - } - } - // change options - if ( nodeName == "option" && createChange ) { - Syn.trigger("change", {}, element.parentNode); //does not bubble - Syn.data(element, "createChange", false) - } - } - }) - - //add create and setup behavior for mosue events - h.extend(Syn.create, { - mouse: { - options: function( type, options, element ) { - var doc = document.documentElement, - body = document.body, - center = [options.pageX || 0, options.pageY || 0], - //browser might not be loaded yet (doing support code) - left = Syn.mouse.browser && Syn.mouse.browser.left[type], - right = Syn.mouse.browser && Syn.mouse.browser.right[type]; - return h.extend({ - bubbles: true, - cancelable: true, - view: window, - detail: 1, - screenX: 1, - screenY: 1, - clientX: options.clientX || center[0] - (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc.clientLeft || 0), - clientY: options.clientY || center[1] - (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc.clientTop || 0), - ctrlKey: !! Syn.key.ctrlKey, - altKey: !! Syn.key.altKey, - shiftKey: !! Syn.key.shiftKey, - metaKey: !! Syn.key.metaKey, - button: left && left.button != null ? left.button : right && right.button || (type == 'contextmenu' ? 2 : 0), - relatedTarget: document.documentElement - }, options); - }, - event: function( type, defaults, element ) { //Everyone Else - var doc = getWin(element).document || document - if ( doc.createEvent ) { - var event; - - try { - event = doc.createEvent('MouseEvents'); - event.initMouseEvent(type, defaults.bubbles, defaults.cancelable, defaults.view, defaults.detail, defaults.screenX, defaults.screenY, defaults.clientX, defaults.clientY, defaults.ctrlKey, defaults.altKey, defaults.shiftKey, defaults.metaKey, defaults.button, defaults.relatedTarget); - } catch (e) { - event = h.createBasicStandardEvent(type, defaults, doc) - } - event.synthetic = true; - return event; - } else { - var event; - try { - event = h.createEventObject(type, defaults, element) - } - catch (e) {} - - return event; - } - - } - }, - click: { - setup: function( type, options, element ) { - var nodeName = element.nodeName.toLowerCase(), - type; - - //we need to manually 'check' in browser that can't check - //so checked has the right value - if (!Syn.support.clickChecks && !Syn.support.changeChecks && nodeName === "input" ) { - type = element.type.toLowerCase(); //pretty sure lowercase isn't needed - if ( type === 'checkbox' ) { - element.checked = !element.checked; - } - if ( type === "radio" ) { - //do the checks manually - if (!element.checked ) { //do nothing, no change - try { - Syn.data(element, "radioChanged", true); - } catch (e) {} - element.checked = true; - } - } - } - - if ( nodeName == "a" && element.href && !/^\s*javascript:/.test(element.href) ) { - - //save href - Syn.data(element, "href", element.href) - - //remove b/c safari/opera will open a new tab instead of changing the page - // this has been removed because newer versions don't have this problem - //element.setAttribute('href', 'javascript://') - //however this breaks scripts using the href - //we need to listen to this and prevent the default behavior - //and run the default behavior ourselves. Boo! - } - //if select or option, save old value and mark to change - if (/option/i.test(element.nodeName) ) { - var child = element.parentNode.firstChild, - i = -1; - while ( child ) { - if ( child.nodeType == 1 ) { - i++; - if ( child == element ) break; - } - child = child.nextSibling; - } - if ( i !== element.parentNode.selectedIndex ) { - //shouldn't this wait on triggering - //change? - element.parentNode.selectedIndex = i; - Syn.data(element, "createChange", true) - } - } - - } - }, - mousedown: { - setup: function( type, options, element ) { - var nn = element.nodeName.toLowerCase(); - //we have to auto prevent default to prevent freezing error in safari - if ( Syn.browser.safari && (nn == "select" || nn == "option") ) { - options._autoPrevent = true; - } - } - } - }); - //do support code - (function() { - if (!document.body ) { - setTimeout(arguments.callee, 1) - return; - } - window.linkHrefJS = Syn.support.linkHrefJS; - window.synSupportLinkHrefJSTest = function() { - linkHrefJS = true; - }; - - var div = document.createElement("div"), - checkbox, submit, form, input, select; - - div.innerHTML = "
" + "" + "" + "" + "" + "" + "" + "" + "" + "
"; - document.documentElement.appendChild(div); - form = div.firstChild - checkbox = form.childNodes[0]; - submit = form.childNodes[2]; - select = form.getElementsByTagName('select')[0] - - //trigger click for linkHrefJS support, childNodes[6] === anchor - Syn.trigger('click', {}, form.childNodes[6]); - - checkbox.checked = false; - checkbox.onchange = function() { - Syn.support.clickChanges = true; - } - - Syn.trigger("click", {}, checkbox) - Syn.support.clickChecks = checkbox.checked; - - checkbox.checked = false; - - Syn.trigger("change", {}, checkbox); - - Syn.support.changeChecks = checkbox.checked; - - form.onsubmit = function( ev ) { - if ( ev.preventDefault ) ev.preventDefault(); - Syn.support.clickSubmits = true; - return false; - } - Syn.trigger("click", {}, submit) - - - - form.childNodes[1].onchange = function() { - Syn.support.radioClickChanges = true; - } - Syn.trigger("click", {}, form.childNodes[1]) - - - Syn.bind(div, 'click', function() { - Syn.support.optionClickBubbles = true; - Syn.unbind(div, 'click', arguments.callee) - }) - Syn.trigger("click", {}, select.firstChild) - - - Syn.support.changeBubbles = Syn.eventSupported('change'); - - //test if mousedown followed by mouseup causes click (opera), make sure there are no clicks after this - var clicksCount = 0 - div.onclick = function() { - Syn.support.mouseDownUpClicks = true; - //we should use this to check for opera potentially, but would - //be difficult to remove element correctly - //Syn.support.mouseDownUpRepeatClicks = (2 == (++clicksCount)) - } - Syn.trigger("mousedown", {}, div) - Syn.trigger("mouseup", {}, div) - - //setTimeout(function(){ - // Syn.trigger("mousedown",{},div) - // Syn.trigger("mouseup",{},div) - //},1) - - document.documentElement.removeChild(div); - - //check stuff - Syn.support.ready++; - })(); - return Syn; -})(__m2); - -// ## src/browsers.js -var __m4 = (function(Syn) { - Syn.key.browsers = { - webkit : { - 'prevent': - {"keyup":[],"keydown":["char","keypress"],"keypress":["char"]}, - 'character': - {"keydown":[0,"key"],"keypress":["char","char"],"keyup":[0,"key"]}, - 'specialChars': - {"keydown":[0,"char"],"keyup":[0,"char"]}, - 'navigation': - {"keydown":[0,"key"],"keyup":[0,"key"]}, - 'special': - {"keydown":[0,"key"],"keyup":[0,"key"]}, - 'tab': - {"keydown":[0,"char"],"keyup":[0,"char"]}, - 'pause-break': - {"keydown":[0,"key"],"keyup":[0,"key"]}, - 'caps': - {"keydown":[0,"key"],"keyup":[0,"key"]}, - 'escape': - {"keydown":[0,"key"],"keyup":[0,"key"]}, - 'num-lock': - {"keydown":[0,"key"],"keyup":[0,"key"]}, - 'scroll-lock': - {"keydown":[0,"key"],"keyup":[0,"key"]}, - 'print': - {"keyup":[0,"key"]}, - 'function': - {"keydown":[0,"key"],"keyup":[0,"key"]}, - '\r': - {"keydown":[0,"key"],"keypress":["char","key"],"keyup":[0,"key"]} - }, - gecko : { - 'prevent': - {"keyup":[],"keydown":["char"],"keypress":["char"]}, - 'character': - {"keydown":[0,"key"],"keypress":["char",0],"keyup":[0,"key"]}, - 'specialChars': - {"keydown":[0,"key"],"keypress":[0,"key"],"keyup":[0,"key"]}, - 'navigation': - {"keydown":[0,"key"],"keypress":[0,"key"],"keyup":[0,"key"]}, - 'special': - {"keydown":[0,"key"],"keyup":[0,"key"]}, - '\t': - {"keydown":[0,"key"],"keypress":[0,"key"],"keyup":[0,"key"]}, - 'pause-break': - {"keydown":[0,"key"],"keypress":[0,"key"],"keyup":[0,"key"]}, - 'caps': - {"keydown":[0,"key"],"keyup":[0,"key"]}, - 'escape': - {"keydown":[0,"key"],"keypress":[0,"key"],"keyup":[0,"key"]}, - 'num-lock': - {"keydown":[0,"key"],"keyup":[0,"key"]}, - 'scroll-lock': - {"keydown":[0,"key"],"keyup":[0,"key"]}, - 'print': - {"keyup":[0,"key"]}, - 'function': - {"keydown":[0,"key"],"keyup":[0,"key"]}, - '\r': - {"keydown":[0,"key"],"keypress":[0,"key"],"keyup":[0,"key"]} - }, - msie : { - 'prevent':{"keyup":[],"keydown":["char","keypress"],"keypress":["char"]}, - 'character':{"keydown":[null,"key"],"keypress":[null,"char"],"keyup":[null,"key"]}, - 'specialChars':{"keydown":[null,"char"],"keyup":[null,"char"]}, - 'navigation':{"keydown":[null,"key"],"keyup":[null,"key"]}, - 'special':{"keydown":[null,"key"],"keyup":[null,"key"]}, - 'tab':{"keydown":[null,"char"],"keyup":[null,"char"]}, - 'pause-break':{"keydown":[null,"key"],"keyup":[null,"key"]}, - 'caps':{"keydown":[null,"key"],"keyup":[null,"key"]}, - 'escape':{"keydown":[null,"key"],"keypress":[null,"key"],"keyup":[null,"key"]}, - 'num-lock':{"keydown":[null,"key"],"keyup":[null,"key"]}, - 'scroll-lock':{"keydown":[null,"key"],"keyup":[null,"key"]}, - 'print':{"keyup":[null,"key"]}, - 'function':{"keydown":[null,"key"],"keyup":[null,"key"]}, - '\r':{"keydown":[null,"key"],"keypress":[null,"key"],"keyup":[null,"key"]} - }, - opera : { - 'prevent': - {"keyup":[],"keydown":[],"keypress":["char"]}, - 'character': - {"keydown":[null,"key"],"keypress":[null,"char"],"keyup":[null,"key"]}, - 'specialChars': - {"keydown":[null,"char"],"keypress":[null,"char"],"keyup":[null,"char"]}, - 'navigation': - {"keydown":[null,"key"],"keypress":[null,"key"]}, - 'special': - {"keydown":[null,"key"],"keypress":[null,"key"],"keyup":[null,"key"]}, - 'tab': - {"keydown":[null,"char"],"keypress":[null,"char"],"keyup":[null,"char"]}, - 'pause-break': - {"keydown":[null,"key"],"keypress":[null,"key"],"keyup":[null,"key"]}, - 'caps': - {"keydown":[null,"key"],"keyup":[null,"key"]}, - 'escape': - {"keydown":[null,"key"],"keypress":[null,"key"]}, - 'num-lock': - {"keyup":[null,"key"],"keydown":[null,"key"],"keypress":[null,"key"]}, - 'scroll-lock': - {"keydown":[null,"key"],"keypress":[null,"key"],"keyup":[null,"key"]}, - 'print': - {}, - 'function': - {"keydown":[null,"key"],"keypress":[null,"key"],"keyup":[null,"key"]}, - '\r': - {"keydown":[null,"key"],"keypress":[null,"key"],"keyup":[null,"key"]} - } - }; - - Syn.mouse.browsers = { - webkit : {"right":{"mousedown":{"button":2,"which":3},"mouseup":{"button":2,"which":3},"contextmenu":{"button":2,"which":3}}, - "left":{"mousedown":{"button":0,"which":1},"mouseup":{"button":0,"which":1},"click":{"button":0,"which":1}}}, - opera: {"right":{"mousedown":{"button":2,"which":3},"mouseup":{"button":2,"which":3}}, - "left":{"mousedown":{"button":0,"which":1},"mouseup":{"button":0,"which":1},"click":{"button":0,"which":1}}}, - msie: { "right":{"mousedown":{"button":2},"mouseup":{"button":2},"contextmenu":{"button":0}}, - "left":{"mousedown":{"button":1},"mouseup":{"button":1},"click":{"button":0}}}, - chrome : {"right":{"mousedown":{"button":2,"which":3},"mouseup":{"button":2,"which":3},"contextmenu":{"button":2,"which":3}}, - "left":{"mousedown":{"button":0,"which":1},"mouseup":{"button":0,"which":1},"click":{"button":0,"which":1}}}, - gecko: {"left":{"mousedown":{"button":0,"which":1},"mouseup":{"button":0,"which":1},"click":{"button":0,"which":1}}, - "right":{"mousedown":{"button":2,"which":3},"mouseup":{"button":2,"which":3},"contextmenu":{"button":2,"which":3}}} - } - - //set browser - Syn.key.browser = - (function(){ - if(Syn.key.browsers[window.navigator.userAgent]){ - return Syn.key.browsers[window.navigator.userAgent]; - } - for(var browser in Syn.browser){ - if(Syn.browser[browser] && Syn.key.browsers[browser]){ - return Syn.key.browsers[browser] - } - } - return Syn.key.browsers.gecko; - })(); - - Syn.mouse.browser = - (function(){ - if(Syn.mouse.browsers[window.navigator.userAgent]){ - return Syn.mouse.browsers[window.navigator.userAgent]; - } - for(var browser in Syn.browser){ - if(Syn.browser[browser] && Syn.mouse.browsers[browser]){ - return Syn.mouse.browsers[browser] - } - } - return Syn.mouse.browsers.gecko; - })(); - return Syn; -})(__m2, __m3); - -// ## src/typeable.js -var __m6 = (function(Syn){ - // Holds functions that test for typeability - var typeables = []; - - /* - * @function typeable - * Registers a function that is used to determine if an - * element can be typed into. The user can define as many - * test functions as needed. By default there are 2 typeable - * functions, one for inputs and textareas, and another - * for contenteditable elements. - * - * @param {Function} fn Function to register. - */ - Syn.typeable = function(fn){ - if(typeables.indexOf(fn) == -1) { - typeables.push(fn); - } - }; - - /* - * @function test - * Tests whether an element can be typed into using the test - * functions registered by [Syn.typeable typeable]. If any of the - * test functions returns true, `test` will return true and allow - * the element to be typed into. - * - * @param {HTMLElement} el the element to test. - * @return {Boolean} true if the element can be typed into. - */ - Syn.typeable.test = function(el){ - for(var i = 0, len = typeables.length; i < len; i++) { - if(typeables[i](el)) { - return true; - } - } - return false; - }; - - var type = Syn.typeable; - - // Inputs and textareas - var typeableExp = /input|textarea/i; - type(function(el){ - return typeableExp.test(el.nodeName); - }); - - // Content editable - type(function(el){ - return ["", "true"].indexOf(el.getAttribute("contenteditable")) != -1; - }); - - return Syn; -})(__m2); - -// ## src/key.js -var __m5 = (function(Syn) { - var h = Syn.helpers, - - // gets the selection of an input or textarea - getSelection = function( el ) { - // use selectionStart if we can - if ( el.selectionStart !== undefined ) { - // this is for opera, so we don't have to focus to type how we think we would - if ( document.activeElement && document.activeElement != el && el.selectionStart == el.selectionEnd && el.selectionStart == 0 ) { - return { - start: el.value.length, - end: el.value.length - }; - } - return { - start: el.selectionStart, - end: el.selectionEnd - } - } else { - //check if we aren't focused - try { - //try 2 different methods that work differently (IE breaks depending on type) - if ( el.nodeName.toLowerCase() == 'input' ) { - var real = h.getWindow(el).document.selection.createRange(), - r = el.createTextRange(); - r.setEndPoint("EndToStart", real); - - var start = r.text.length - return { - start: start, - end: start + real.text.length - } - } - else { - var real = h.getWindow(el).document.selection.createRange(), - r = real.duplicate(), - r2 = real.duplicate(), - r3 = real.duplicate(); - r2.collapse(); - r3.collapse(false); - r2.moveStart('character', -1) - r3.moveStart('character', -1) - //select all of our element - r.moveToElementText(el) - //now move our endpoint to the end of our real range - r.setEndPoint('EndToEnd', real); - var start = r.text.length - real.text.length, - end = r.text.length; - if ( start != 0 && r2.text == "" ) { - start += 2; - } - if ( end != 0 && r3.text == "" ) { - end += 2; - } - //if we aren't at the start, but previous is empty, we are at start of newline - return { - start: start, - end: end - } - } - } catch (e) { - var prop = formElExp.test(el.nodeName) ? "value" : "textContent"; - - return { - start: el[prop].length, - end: el[prop].length - }; - } - } - }, - // gets all focusable elements - getFocusable = function( el ) { - var document = h.getWindow(el).document, - res = []; - - var els = document.getElementsByTagName('*'), - len = els.length; - - for ( var i = 0; i < len; i++ ) { - Syn.isFocusable(els[i]) && els[i] != document.documentElement && res.push(els[i]) - } - return res; - }, - formElExp = /input|textarea/i, - // Get the text from an element. - getText = function(el){ - if(formElExp.test(el.nodeName)) { - return el.value; - } - return el.textContent || el.innerText; - }, - // Set the text of an element. - setText = function(el, value){ - if(formElExp.test(el.nodeName)){ - el.value = value; - } else if(el.textContent) { - el.textContent = value; - } else { - el.innerText = value; - } - }; - - /** - * @add Syn static - */ - h.extend(Syn, { - /** - * @attribute - * A list of the keys and their keycodes codes you can type. - * You can add type keys with - * @codestart - * Syn('key','delete','title'); - * - * //or - * - * Syn('type','One Two Three[left][left][delete]','title') - * @codeend - * - * The following are a list of keys you can type: - * @codestart text - * \b - backspace - * \t - tab - * \r - enter - * ' ' - space - * a-Z 0-9 - normal characters - * /!@#$*,.? - All other typeable characters - * page-up - scrolls up - * page-down - scrolls down - * end - scrolls to bottom - * home - scrolls to top - * insert - changes how keys are entered - * delete - deletes the next character - * left - moves cursor left - * right - moves cursor right - * up - moves the cursor up - * down - moves the cursor down - * f1-12 - function buttons - * shift, ctrl, alt - special keys - * pause-break - the pause button - * scroll-lock - locks scrolling - * caps - makes caps - * escape - escape button - * num-lock - allows numbers on keypad - * print - screen capture - * subtract - subtract (keypad) - - * dash - dash - - * divide - divide (keypad) / - * forward-slash - forward slash / - * decimal - decimal (keypad) . - * period - period . - * @codeend - */ - keycodes: { - //backspace - '\b': 8, - - //tab - '\t': 9, - - //enter - '\r': 13, - - //special - 'shift': 16, - 'ctrl': 17, - 'alt': 18, - - //weird - 'pause-break': 19, - 'caps': 20, - 'escape': 27, - 'num-lock': 144, - 'scroll-lock': 145, - 'print': 44, - - //navigation - 'page-up': 33, - 'page-down': 34, - 'end': 35, - 'home': 36, - 'left': 37, - 'up': 38, - 'right': 39, - 'down': 40, - 'insert': 45, - 'delete': 46, - - //normal characters - ' ': 32, - '0': 48, - '1': 49, - '2': 50, - '3': 51, - '4': 52, - '5': 53, - '6': 54, - '7': 55, - '8': 56, - '9': 57, - 'a': 65, - 'b': 66, - 'c': 67, - 'd': 68, - 'e': 69, - 'f': 70, - 'g': 71, - 'h': 72, - 'i': 73, - 'j': 74, - 'k': 75, - 'l': 76, - 'm': 77, - 'n': 78, - 'o': 79, - 'p': 80, - 'q': 81, - 'r': 82, - 's': 83, - 't': 84, - 'u': 85, - 'v': 86, - 'w': 87, - 'x': 88, - 'y': 89, - 'z': 90, - //normal-characters, numpad - 'num0': 96, - 'num1': 97, - 'num2': 98, - 'num3': 99, - 'num4': 100, - 'num5': 101, - 'num6': 102, - 'num7': 103, - 'num8': 104, - 'num9': 105, - '*': 106, - '+': 107, - 'subtract': 109, - 'decimal': 110, - //normal-characters, others - 'divide': 111, - ';': 186, - '=': 187, - ',': 188, - 'dash': 189, - '-': 189, - 'period': 190, - '.': 190, - 'forward-slash': 191, - '/': 191, - '`': 192, - '[': 219, - '\\': 220, - ']': 221, - "'": 222, - - //ignore these, you shouldn't use them - 'left window key': 91, - 'right window key': 92, - 'select key': 93, - - - 'f1': 112, - 'f2': 113, - 'f3': 114, - 'f4': 115, - 'f5': 116, - 'f6': 117, - 'f7': 118, - 'f8': 119, - 'f9': 120, - 'f10': 121, - 'f11': 122, - 'f12': 123 - }, - - // selects text on an element - selectText: function( el, start, end ) { - if ( el.setSelectionRange ) { - if (!end ) { - el.focus(); - el.setSelectionRange(start, start); - } else { - el.selectionStart = start; - el.selectionEnd = end; - } - } else if ( el.createTextRange ) { - //el.focus(); - var r = el.createTextRange(); - r.moveStart('character', start); - end = end || start; - r.moveEnd('character', end - el.value.length); - - r.select(); - } - }, - getText: function( el ) { - //first check if the el has anything selected .. - if ( Syn.typeable.test(el) ) { - var sel = getSelection(el); - return el.value.substring(sel.start, sel.end) - } - //otherwise get from page - var win = Syn.helpers.getWindow(el); - if ( win.getSelection ) { - return win.getSelection().toString(); - } - else if ( win.document.getSelection ) { - return win.document.getSelection().toString() - } - else { - return win.document.selection.createRange().text; - } - }, - getSelection: getSelection - }); - - h.extend(Syn.key, { - // retrieves a description of what events for this character should look like - data: function( key ) { - //check if it is described directly - if ( Syn.key.browser[key] ) { - return Syn.key.browser[key]; - } - for ( var kind in Syn.key.kinds ) { - if ( h.inArray(key, Syn.key.kinds[kind]) > -1 ) { - return Syn.key.browser[kind] - } - } - return Syn.key.browser.character - }, - - //returns the special key if special - isSpecial: function( keyCode ) { - var specials = Syn.key.kinds.special; - for ( var i = 0; i < specials.length; i++ ) { - if ( Syn.keycodes[specials[i]] == keyCode ) { - return specials[i]; - } - } - }, - /** - * @hide - * gets the options for a key and event type ... - * @param {Object} key - * @param {Object} event - */ - options: function( key, event ) { - var keyData = Syn.key.data(key); - - if (!keyData[event] ) { - //we shouldn't be creating this event - return null; - } - - var charCode = keyData[event][0], - keyCode = keyData[event][1], - result = {}; - - if ( keyCode == 'key' ) { - result.keyCode = Syn.keycodes[key] - } else if ( keyCode == 'char' ) { - result.keyCode = key.charCodeAt(0) - } else { - result.keyCode = keyCode; - } - - if ( charCode == 'char' ) { - result.charCode = key.charCodeAt(0) - } else if ( charCode !== null ) { - result.charCode = charCode; - } - - // all current browsers have which property to normalize keyCode/charCode - if(result.keyCode){ - result.which = result.keyCode; - } else { - result.which = result.charCode; - } - - - return result - }, - //types of event keys - kinds: { - special: ["shift", 'ctrl', 'alt', 'caps'], - specialChars: ["\b"], - navigation: ["page-up", 'page-down', 'end', 'home', 'left', 'up', 'right', 'down', 'insert', 'delete'], - 'function': ['f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'f10', 'f11', 'f12'] - }, - //returns the default function - // some keys have default functions - // some 'kinds' of keys have default functions - getDefault: function( key ) { - //check if it is described directly - if ( Syn.key.defaults[key] ) { - return Syn.key.defaults[key]; - } - for ( var kind in Syn.key.kinds ) { - if ( h.inArray(key, Syn.key.kinds[kind]) > -1 && Syn.key.defaults[kind] ) { - return Syn.key.defaults[kind]; - } - } - return Syn.key.defaults.character - }, - // default behavior when typing - defaults: { - 'character': function( options, scope, key, force, sel ) { - if (/num\d+/.test(key) ) { - key = key.match(/\d+/)[0] - } - - if ( force || (!Syn.support.keyCharacters && Syn.typeable.test(this)) ) { - var current = getText(this), - before = current.substr(0, sel.start), - after = current.substr(sel.end), - character = key; - - setText(this, before + character + after); - //handle IE inserting \r\n - var charLength = character == "\n" && Syn.support.textareaCarriage ? 2 : character.length; - Syn.selectText(this, before.length + charLength) - } - }, - 'c': function( options, scope, key, force, sel ) { - if ( Syn.key.ctrlKey ) { - Syn.key.clipboard = Syn.getText(this) - } else { - Syn.key.defaults.character.apply(this, arguments); - } - }, - 'v': function( options, scope, key, force, sel ) { - if ( Syn.key.ctrlKey ) { - Syn.key.defaults.character.call(this, options, scope, Syn.key.clipboard, true, sel); - } else { - Syn.key.defaults.character.apply(this, arguments); - } - }, - 'a': function( options, scope, key, force, sel ) { - if ( Syn.key.ctrlKey ) { - Syn.selectText(this, 0, getText(this).length) - } else { - Syn.key.defaults.character.apply(this, arguments); - } - }, - 'home': function() { - Syn.onParents(this, function( el ) { - if ( el.scrollHeight != el.clientHeight ) { - el.scrollTop = 0; - return false; - } - }) - }, - 'end': function() { - Syn.onParents(this, function( el ) { - if ( el.scrollHeight != el.clientHeight ) { - el.scrollTop = el.scrollHeight; - return false; - } - }) - }, - 'page-down': function() { - //find the first parent we can scroll - Syn.onParents(this, function( el ) { - if ( el.scrollHeight != el.clientHeight ) { - var ch = el.clientHeight - el.scrollTop += ch; - return false; - } - }) - }, - 'page-up': function() { - Syn.onParents(this, function( el ) { - if ( el.scrollHeight != el.clientHeight ) { - var ch = el.clientHeight - el.scrollTop -= ch; - return false; - } - }) - }, - '\b': function( options, scope, key, force, sel ) { - //this assumes we are deleting from the end - if (!Syn.support.backspaceWorks && Syn.typeable.test(this) ) { - var current = getText(this), - before = current.substr(0, sel.start), - after = current.substr(sel.end); - - if ( sel.start == sel.end && sel.start > 0 ) { - //remove a character - setText(this, before.substring(0, before.length - 1) + after); - Syn.selectText(this, sel.start - 1); - } else { - setText(this, before + after); - Syn.selectText(this, sel.start); - } - - //set back the selection - } - }, - 'delete': function( options, scope, key, force, sel ) { - if (!Syn.support.backspaceWorks && Syn.typeable.test(this) ) { - var current = getText(this), - before = current.substr(0, sel.start), - after = current.substr(sel.end); - if ( sel.start == sel.end && sel.start <= getText(this).length - 1 ) { - setText(this, before + after.substring(1)); - } else { - setText(this, before + after); - } - Syn.selectText(this, sel.start); - } - }, - '\r': function( options, scope, key, force, sel ) { - - var nodeName = this.nodeName.toLowerCase() - // submit a form - if (nodeName == 'input' ) { - Syn.trigger("change", {}, this); - } - - if (!Syn.support.keypressSubmits && nodeName == 'input' ) { - var form = Syn.closest(this, "form"); - if ( form ) { - Syn.trigger("submit", {}, form); - } - - } - //newline in textarea - if (!Syn.support.keyCharacters && nodeName == 'textarea' ) { - Syn.key.defaults.character.call(this, options, scope, "\n", undefined, sel) - } - // 'click' hyperlinks - if (!Syn.support.keypressOnAnchorClicks && nodeName == 'a' ) { - Syn.trigger("click", {}, this); - } - }, - // - // Gets all focusable elements. If the element (this) - // doesn't have a tabindex, finds the next element after. - // If the element (this) has a tabindex finds the element - // with the next higher tabindex OR the element with the same - // tabindex after it in the document. - // @return the next element - // - '\t': function( options, scope ) { - // focusable elements - var focusEls = getFocusable(this), - // the current element's tabindex - tabIndex = Syn.tabIndex(this), - // will be set to our guess for the next element - current = null, - // the next index we care about - currentIndex = 1000000000, - // set to true once we found 'this' element - found = false, - i = 0, - el, - //the tabindex of the tabable element we are looking at - elIndex, firstNotIndexed, prev; - orders = []; - for (; i < focusEls.length; i++ ) { - orders.push([focusEls[i], i]); - } - var sort = function( order1, order2 ) { - var el1 = order1[0], - el2 = order2[0], - tab1 = Syn.tabIndex(el1) || 0, - tab2 = Syn.tabIndex(el2) || 0; - if ( tab1 == tab2 ) { - return order1[1] - order2[1] - } else { - if ( tab1 == 0 ) { - return 1; - } else if ( tab2 == 0 ) { - return -1; - } else { - return tab1 - tab2; - } - } - } - orders.sort(sort); - //now find current - for ( i = 0; i < orders.length; i++ ) { - el = orders[i][0]; - if ( this == el ) { - if (!Syn.key.shiftKey ) { - current = orders[i + 1][0]; - if (!current ) { - current = orders[0][0] - } - } else { - current = orders[i - 1][0]; - if (!current ) { - current = orders[focusEls.length - 1][0] - } - } - - } - } - - //restart if we didn't find anything - if (!current ) { - current = firstNotIndexed; - } - current && current.focus(); - return current; - }, - 'left': function( options, scope, key, force, sel ) { - if ( Syn.typeable.test(this) ) { - if ( Syn.key.shiftKey ) { - Syn.selectText(this, sel.start == 0 ? 0 : sel.start - 1, sel.end) - } else { - Syn.selectText(this, sel.start == 0 ? 0 : sel.start - 1) - } - } - }, - 'right': function( options, scope, key, force, sel ) { - if ( Syn.typeable.test(this) ) { - if ( Syn.key.shiftKey ) { - Syn.selectText(this, sel.start, sel.end + 1 > getText(this).length ? getText(this).length : sel.end + 1) - } else { - Syn.selectText(this, sel.end + 1 > getText(this).length ? getText(this).length : sel.end + 1) - } - } - }, - 'up': function() { - if (/select/i.test(this.nodeName) ) { - - this.selectedIndex = this.selectedIndex ? this.selectedIndex - 1 : 0; - //set this to change on blur? - } - }, - 'down': function() { - if (/select/i.test(this.nodeName) ) { - Syn.changeOnBlur(this, "selectedIndex", this.selectedIndex) - this.selectedIndex = this.selectedIndex + 1; - //set this to change on blur? - } - }, - 'shift': function() { - return null; - }, - 'ctrl': function() { - return null; - } - } - }); - - h.extend(Syn.create, { - keydown: { - setup: function( type, options, element ) { - if ( h.inArray(options, Syn.key.kinds.special) != -1 ) { - Syn.key[options + "Key"] = element; - } - } - }, - keypress: { - setup: function( type, options, element ) { - // if this browsers supports writing keys on events - // but doesn't write them if the element isn't focused - // focus on the element (ignored if already focused) - if ( Syn.support.keyCharacters && !Syn.support.keysOnNotFocused ) { - element.focus() - } - } - }, - keyup: { - setup: function( type, options, element ) { - if ( h.inArray(options, Syn.key.kinds.special) != -1 ) { - Syn.key[options + "Key"] = null; - } - } - }, - key: { - // return the options for a key event - options: function( type, options, element ) { - //check if options is character or has character - options = typeof options != "object" ? { - character: options - } : options; - - //don't change the orignial - options = h.extend({}, options) - if ( options.character ) { - h.extend(options, Syn.key.options(options.character, type)); - delete options.character; - } - - options = h.extend({ - ctrlKey: !! Syn.key.ctrlKey, - altKey: !! Syn.key.altKey, - shiftKey: !! Syn.key.shiftKey, - metaKey: !! Syn.key.metaKey - }, options) - - return options; - }, - // creates a key event - event: function( type, options, element ) { //Everyone Else - var doc = h.getWindow(element).document || document; - if ( doc.createEvent ) { - var event; - - try { - - event = doc.createEvent("KeyEvents"); - event.initKeyEvent(type, true, true, window, options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.keyCode, options.charCode); - } - catch (e) { - event = h.createBasicStandardEvent(type, options, doc); - } - event.synthetic = true; - return event; - } - else { - var event; - try { - event = h.createEventObject.apply(this, arguments); - h.extend(event, options) - } - catch (e) {} - - return event; - } - } - } - }); - - var convert = { - "enter": "\r", - "backspace": "\b", - "tab": "\t", - "space": " " - } - - /** - * @add Syn prototype - */ - h.extend(Syn.init.prototype, { - /** - * @function key - * Types a single key. The key should be - * a string that matches a - * [Syn.static.keycodes]. - * - * The following sends a carridge return - * to the 'name' element. - * @codestart - * Syn.key('\r','name') - * @codeend - * For each character, a keydown, keypress, and keyup is triggered if - * appropriate. - * @param {String|Number} options - * @param {HTMLElement} [element] - * @param {Function} [callback] - * @return {HTMLElement} the element currently focused. - */ - _key: function( options, element, callback ) { - //first check if it is a special up - if (/-up$/.test(options) && h.inArray(options.replace("-up", ""), Syn.key.kinds.special) != -1 ) { - Syn.trigger('keyup', options.replace("-up", ""), element) - callback(true, element); - return; - } - - // keep reference to current activeElement - var activeElement = h.getWindow(element).document.activeElement, - caret = Syn.typeable.test(element) && getSelection(element), - key = convert[options] || options, - // should we run default events - runDefaults = Syn.trigger('keydown', key, element), - - // a function that gets the default behavior for a key - getDefault = Syn.key.getDefault, - - // how this browser handles preventing default events - prevent = Syn.key.browser.prevent, - - // the result of the default event - defaultResult, - - keypressOptions = Syn.key.options(key, 'keypress'); - - - if ( runDefaults ) { - //if the browser doesn't create keypresses for this key, run default - if (!keypressOptions ) { - defaultResult = getDefault(key).call(element, keypressOptions, h.getWindow(element), key, undefined, caret) - } else { - //do keypress - // check if activeElement changed b/c someone called focus in keydown - if( activeElement !== h.getWindow(element).document.activeElement ) { - element = h.getWindow(element).document.activeElement; - } - - runDefaults = Syn.trigger('keypress', keypressOptions, element) - if ( runDefaults ) { - defaultResult = getDefault(key).call(element, keypressOptions, h.getWindow(element), key, undefined, caret) - } - } - } else { - //canceled ... possibly don't run keypress - if ( keypressOptions && h.inArray('keypress', prevent.keydown) == -1 ) { - // check if activeElement changed b/c someone called focus in keydown - if( activeElement !== h.getWindow(element).document.activeElement ) { - element = h.getWindow(element).document.activeElement; - } - - Syn.trigger('keypress', keypressOptions, element) - } - } - if ( defaultResult && defaultResult.nodeName ) { - element = defaultResult - } - - if ( defaultResult !== null ) { - setTimeout(function() { - if(Syn.support.oninput) { - Syn.trigger('input', Syn.key.options(key, 'input'), element); - } - Syn.trigger('keyup', Syn.key.options(key, 'keyup'), element) - callback(runDefaults, element) - }, 1) - } else { - callback(runDefaults, element) - } - - - //do mouseup - return element; - // is there a keypress? .. if not , run default - // yes -> did we prevent it?, if not run ... - }, - /** - * @function type - * Types sequence of [Syn.key key actions]. Each - * character is typed, one at a type. - * Multi-character keys like 'left' should be - * enclosed in square brackents. - * - * The following types 'JavaScript MVC' then deletes the space. - * @codestart - * Syn.type('JavaScript MVC[left][left][left]\b','name') - * @codeend - * - * Type is able to handle (and move with) tabs (\t). - * The following simulates tabing and entering values in a form and - * eventually submitting the form. - * @codestart - * Syn.type("Justin\tMeyer\t27\tjustinbmeyer@gmail.com\r") - * @codeend - * @param {String} options the text to type - * @param {HTMLElement} [element] an element or an id of an element - * @param {Function} [callback] a function to callback - */ - _type: function( options, element, callback ) { - //break it up into parts ... - //go through each type and run - var parts = (options+"").match(/(\[[^\]]+\])|([^\[])/g), - self = this, - runNextPart = function( runDefaults, el ) { - var part = parts.shift(); - if (!part ) { - callback(runDefaults, el); - return; - } - el = el || element; - if ( part.length > 1 ) { - part = part.substr(1, part.length - 2) - } - self._key(part, el, runNextPart) - } - - runNextPart(); - - } - }); - - if(!Syn.config.support) { - //do support code - !function() { - if (!document.body ) { - setTimeout(arguments.callee, 1) - return; - } - - // Store the current state before making any changes to focus. - var startPos = [ window.scrollX, window.scrollY ], - startNode = window.document.activeElement; - - var div = document.createElement("div"), - checkbox, submit, form, input, submitted = false, - anchor, textarea, inputter, one; - - div.innerHTML = "
" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "
"; - - document.documentElement.appendChild(div); - form = div.firstChild; - checkbox = form.childNodes[0]; - submit = form.childNodes[2]; - anchor = form.getElementsByTagName("a")[0]; - textarea = form.getElementsByTagName("textarea")[0]; - inputter = form.childNodes[3]; - one = form.childNodes[4]; - - form.onsubmit = function( ev ) { - if ( ev.preventDefault ) ev.preventDefault(); - Syn.support.keypressSubmits = true; - ev.returnValue = false; - return false; - }; - // Firefox 4 won't write key events if the element isn't focused - inputter.focus(); - Syn.trigger("keypress", "\r", inputter); - - - Syn.trigger("keypress", "a", inputter); - Syn.support.keyCharacters = inputter.value == "a"; - - - inputter.value = "a"; - Syn.trigger("keypress", "\b", inputter); - Syn.support.backspaceWorks = inputter.value == ""; - - - - inputter.onchange = function() { - Syn.support.focusChanges = true; - } - inputter.focus(); - Syn.trigger("keypress", "a", inputter); - form.childNodes[5].focus(); // this will throw a change event - Syn.trigger("keypress", "b", inputter); - Syn.support.keysOnNotFocused = inputter.value == "ab"; - - //test keypress \r on anchor submits - Syn.bind(anchor, "click", function( ev ) { - if ( ev.preventDefault ) ev.preventDefault(); - Syn.support.keypressOnAnchorClicks = true; - ev.returnValue = false; - return false; - }) - Syn.trigger("keypress", "\r", anchor); - - Syn.support.textareaCarriage = textarea.value.length == 4; - - // IE only, oninput event. - Syn.support.oninput = 'oninput' in one; - - document.documentElement.removeChild(div); - // Return element focus and scroll position to it's position at the start of the function. - if (startNode) { - startNode.focus(); - } - window.scrollTo(startPos[0], startPos[1]); - - Syn.support.ready++; - }(); - } - else { - Syn.helpers.extend(Syn.support, Syn.config.support); - } - - return Syn; -})(__m2, __m6, __m4); - -// ## src/drag/drag.js -var __m7 = (function(Syn) { - - // check if elementFromPageExists - (function() { - - // document body has to exists for this test - if (!document.body ) { - setTimeout(arguments.callee, 1) - return; - } - var div = document.createElement('div') - document.body.appendChild(div); - Syn.helpers.extend(div.style, { - width: "100px", - height: "10000px", - backgroundColor: "blue", - position: "absolute", - top: "10px", - left: "0px", - zIndex: 19999 - }); - document.body.scrollTop = 11; - if (!document.elementFromPoint ) { - return; - } - var el = document.elementFromPoint(3, 1) - if ( el == div ) { - Syn.support.elementFromClient = true; - } - else { - Syn.support.elementFromPage = true; - } - document.body.removeChild(div); - document.body.scrollTop = 0; - })(); - - - //gets an element from a point - var elementFromPoint = function( point, element ) { - var clientX = point.clientX, - clientY = point.clientY, - win = Syn.helpers.getWindow(element), - el; - - - - if ( Syn.support.elementFromPage ) { - var off = Syn.helpers.scrollOffset(win); - clientX = clientX + off.left; //convert to pageX - clientY = clientY + off.top; //convert to pageY - } - el = win.document.elementFromPoint ? win.document.elementFromPoint(clientX, clientY) : element; - if ( el === win.document.documentElement && (point.clientY < 0 || point.clientX < 0) ) { - return element; - } else { - return el; - } - }, - //creates an event at a certain point - createEventAtPoint = function( event, point, element ) { - var el = elementFromPoint(point, element) - Syn.trigger(event, point, el || element) - return el; - }, - // creates a mousemove event, but first triggering mouseout / mouseover if appropriate - mouseMove = function( point, element, last ) { - var el = elementFromPoint(point, element) - if ( last != el && el && last ) { - var options = Syn.helpers.extend({}, point); - options.relatedTarget = el; - Syn.trigger("mouseout", options, last); - options.relatedTarget = last; - Syn.trigger("mouseover", options, el); - } - - Syn.trigger("mousemove", point, el || element) - return el; - }, - // start and end are in clientX, clientY - startMove = function( start, end, duration, element, callback ) { - var startTime = new Date(), - distX = end.clientX - start.clientX, - distY = end.clientY - start.clientY, - win = Syn.helpers.getWindow(element), - current = elementFromPoint(start, element), - cursor = win.document.createElement('div'), - calls = 0; - move = function() { - //get what fraction we are at - var now = new Date(), - scrollOffset = Syn.helpers.scrollOffset(win), - fraction = (calls == 0 ? 0 : now - startTime) / duration, - options = { - clientX: distX * fraction + start.clientX, - clientY: distY * fraction + start.clientY - }; - calls++; - if ( fraction < 1 ) { - Syn.helpers.extend(cursor.style, { - left: (options.clientX + scrollOffset.left + 2) + "px", - top: (options.clientY + scrollOffset.top + 2) + "px" - }) - current = mouseMove(options, element, current) - setTimeout(arguments.callee, 15) - } - else { - current = mouseMove(end, element, current); - win.document.body.removeChild(cursor) - callback(); - } - } - Syn.helpers.extend(cursor.style, { - height: "5px", - width: "5px", - backgroundColor: "red", - position: "absolute", - zIndex: 19999, - fontSize: "1px" - }) - win.document.body.appendChild(cursor) - move(); - }, - startDrag = function( start, end, duration, element, callback ) { - createEventAtPoint("mousedown", start, element); - startMove(start, end, duration, element, function() { - createEventAtPoint("mouseup", end, element); - callback(); - }) - }, - center = function( el ) { - var j = Syn.jquery()(el), - o = j.offset(); - return { - pageX: o.left + (j.outerWidth() / 2), - pageY: o.top + (j.outerHeight() / 2) - } - }, - convertOption = function( option, win, from ) { - var page = /(\d+)[x ](\d+)/, - client = /(\d+)X(\d+)/, - relative = /([+-]\d+)[xX ]([+-]\d+)/ - //check relative "+22x-44" - if ( typeof option == 'string' && relative.test(option) && from ) { - var cent = center(from), - parts = option.match(relative); - option = { - pageX: cent.pageX + parseInt(parts[1]), - pageY: cent.pageY + parseInt(parts[2]) - } - } - if ( typeof option == 'string' && page.test(option) ) { - var parts = option.match(page) - option = { - pageX: parseInt(parts[1]), - pageY: parseInt(parts[2]) - } - } - if ( typeof option == 'string' && client.test(option) ) { - var parts = option.match(client) - option = { - clientX: parseInt(parts[1]), - clientY: parseInt(parts[2]) - } - } - if ( typeof option == 'string' ) { - option = Syn.jquery()(option, win.document)[0]; - } - if ( option.nodeName ) { - option = center(option) - } - if ( option.pageX ) { - var off = Syn.helpers.scrollOffset(win); - option = { - clientX: option.pageX - off.left, - clientY: option.pageY - off.top - } - } - return option; - }, - // if the client chords are not going to be visible ... scroll the page so they will be ... - adjust = function(from, to, win){ - if(from.clientY < 0){ - var off = Syn.helpers.scrollOffset(win); - var dimensions = Syn.helpers.scrollDimensions(win), - top = off.top + (from.clientY) - 100, - diff = top - off.top - - // first, lets see if we can scroll 100 px - if( top > 0){ - - } else { - top =0; - diff = -off.top; - } - from.clientY = from.clientY - diff; - to.clientY = to.clientY - diff; - Syn.helpers.scrollOffset(win,{top: top, left: off.left}); - - //throw "out of bounds!" - } - } - /** - * @add Syn prototype - */ - Syn.helpers.extend(Syn.init.prototype, { - /** - * @function move - * Moves the cursor from one point to another. - * - * ### Quick Example - * - * The following moves the cursor from (0,0) in - * the window to (100,100) in 1 second. - * - * Syn.move( - * { - * from: {clientX: 0, clientY: 0}, - * to: {clientX: 100, clientY: 100}, - * duration: 1000 - * }, - * document.document) - * - * ## Options - * - * There are many ways to configure the endpoints of the move. - * - * ### PageX and PageY - * - * If you pass pageX or pageY, these will get converted - * to client coordinates. - * - * Syn.move( - * { - * from: {pageX: 0, pageY: 0}, - * to: {pageX: 100, pageY: 100} - * }, - * document.document) - * - * ### String Coordinates - * - * You can set the pageX and pageY as strings like: - * - * Syn.move( - * { - * from: "0x0", - * to: "100x100" - * }, - * document.document) - * - * ### Element Coordinates - * - * If jQuery is present, you can pass an element as the from or to option - * and the coordinate will be set as the center of the element. - - * Syn.move( - * { - * from: $(".recipe")[0], - * to: $("#trash")[0] - * }, - * document.document) - * - * ### Query Strings - * - * If jQuery is present, you can pass a query string as the from or to option. - * - * Syn.move( - * { - * from: ".recipe", - * to: "#trash" - * }, - * document.document) - * - * ### No From - * - * If you don't provide a from, the element argument passed to Syn is used. - * - * Syn.move( - * { to: "#trash" }, - * 'myrecipe') - * - * ### Relative - * - * You can move the drag relative to the center of the from element. - * - * Syn.move("+20 +30", "myrecipe"); - * - * @param {Object} options options to configure the drag - * @param {HTMLElement} from the element to move - * @param {Function} callback a callback that happens after the drag motion has completed - */ - _move: function( options, from, callback ) { - //need to convert if elements - var win = Syn.helpers.getWindow(from), - fro = convertOption(options.from || from, win, from), - to = convertOption(options.to || options, win, from); - - options.adjust !== false && adjust(fro, to, win); - startMove(fro, to, options.duration || 500, from, callback); - - }, - /** - * @function drag - * Creates a mousedown and drags from one point to another. - * Check out [Syn.prototype.move move] for API details. - * - * @param {Object} options - * @param {Object} from - * @param {Object} callback - */ - _drag: function( options, from, callback ) { - //need to convert if elements - var win = Syn.helpers.getWindow(from), - fro = convertOption(options.from || from, win, from), - to = convertOption(options.to || options, win, from); - - options.adjust !== false && adjust(fro, to, win); - startDrag(fro, to, options.duration || 500, from, callback); - - } - }) - return Syn; -})(__m2); - -// ## src/syn.js -var __m1 = (function(Syn) { - window.Syn = Syn; - - return Syn; -})(__m2, __m3, __m4, __m5, __m7); - -}(window); \ No newline at end of file diff --git a/src/Moodle/BehatExtension/Driver/WebDriver.php b/src/Moodle/BehatExtension/Driver/WebDriver.php new file mode 100644 index 0000000..90a5784 --- /dev/null +++ b/src/Moodle/BehatExtension/Driver/WebDriver.php @@ -0,0 +1,59 @@ +. + +/** + * Driver factory for the Moodle WebDriver. + * + * @package behat + * @copyright 2020 Andrew Nicols + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace Moodle\BehatExtension\Driver; + +use Behat\MinkExtension\ServiceContainer\Driver\DriverFactory; +use OAndreyev\Mink\Driver\WebDriverFactory as UpstreamFactory; +use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; +use Symfony\Component\DependencyInjection\Definition; + +class WebDriverFactory extends UpstreamFactory implements DriverFactory { + /** + * {@inheritdoc} + */ + public function buildDriver(array $config) + { + // Merge capabilities + $extraCapabilities = $config['capabilities']['extra_capabilities']; + unset($config['capabilities']['extra_capabilities']); + $capabilities = array_replace($this->guessCapabilities(), $extraCapabilities, $config['capabilities']); + + // Build driver definition + return new Definition(WebDriver::class, [ + $config['browser'], + $capabilities, + $config['wd_host'], + ]); + } +} diff --git a/src/Moodle/BehatExtension/Element/NodeElement.php b/src/Moodle/BehatExtension/Element/NodeElement.php deleted file mode 100644 index 1c729d0..0000000 --- a/src/Moodle/BehatExtension/Element/NodeElement.php +++ /dev/null @@ -1,94 +0,0 @@ -. - -/** - * Node Element. - * - * @package moodlehq-behat-extension - * @copyright 2019 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace Moodle\BehatExtension\Element; - -use Behat\Mink\Element\NodeElement as MinkNodeElement; - -/** - * Node Element. - * - * @package moodlehq-behat-extension - * @copyright 2019 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class NodeElement extends MinkNodeElement { - /** - * Click the current node. - * - * This implementation includes a fix for Firefox on Ubuntu 1804 to ensure that the clicked node is visible before - * it is clicked. - */ - public function click() { - $browser = \Moodle\BehatExtension\Driver\MoodleSelenium2Driver::getBrowser(); - if (in_array(strtolower($browser), ['firefox'])) { - $this->ensure_node_is_in_viewport(); - } - - parent::click(); - } - - - /** - * Attempt to ensure that the node is in the viewport given a margin of error. - * - * This ensures that the top is below the top of the viewport, and the bottom is above the bottom of the viewport. - * It does not handle the following cases: - * - Where the node is bigger than the viewport - * - Where the node is covered by another element. - * - Where the node is to the left or right of the viewport - * - * @param int $margin A margin aroudn th - */ - public function ensure_node_is_in_viewport(int $margin = 20) { - $xpath = $this->getXPath(); - $xpathsubs = [ - "\r\n" => " ", - "\r" => " ", - "\n" => " ", - '"' => '\"', - ]; - $xpath = str_replace(array_keys($xpathsubs), array_values($xpathsubs), $this->getXpath()); - // Fetch the node by xpath, then check that the top is below the top of the document, and the bottom is below - // the bottom of the document. - // Note: This does not handle the case where the item being clicked is bigger than the window. Nor does it - // handle the case where the node is covered by another element. - $js = <<= 0 - margin)); - } - - if (node && !isVisible(node)) { - node.scrollIntoView(); - } -})(); -EOF; - $this->getSession()->executeScript($js); - } -} diff --git a/src/Moodle/BehatExtension/Output/Printer/MoodleProgressPrinter.php b/src/Moodle/BehatExtension/Output/Printer/MoodleProgressPrinter.php index 41ee4d8..5118307 100644 --- a/src/Moodle/BehatExtension/Output/Printer/MoodleProgressPrinter.php +++ b/src/Moodle/BehatExtension/Output/Printer/MoodleProgressPrinter.php @@ -33,6 +33,7 @@ use Behat\Testwork\Hook\Tester\Setup\HookedTeardown; use Behat\Testwork\Output\Printer\OutputPrinter; use Behat\Testwork\Tester\Result\TestResult; +use Moodle\BehatExtension\Driver\WebDriver; /** * Prints hooks in a pretty fashion. @@ -90,14 +91,11 @@ public function printTeardown(Formatter $formatter, Teardown $teardown) { public function printMoodleInfo($printer) { require_once($this->moodledirroot . '/lib/behat/classes/util.php'); - $browser = \Moodle\BehatExtension\Driver\MoodleSelenium2Driver::getBrowser(); + $browser = WebDriver::getBrowserName(); // Calling all directly from here as we avoid more behat framework extensions. $runinfo = \behat_util::get_site_info(); $runinfo .= 'Server OS "' . PHP_OS . '"' . ', Browser: "' . $browser . '"' . PHP_EOL; - if (in_array(strtolower($browser), ['chrome','firefox'])) { - $runinfo .= 'Browser specific fixes have been applied. See http://docs.moodle.org/dev/Acceptance_testing#Browser_specific_fixes' . PHP_EOL; - } $runinfo .= 'Started at ' . date('d-m-Y, H:i', time()); $printer->writeln($runinfo); diff --git a/src/Moodle/BehatExtension/ServiceContainer/BehatExtension.php b/src/Moodle/BehatExtension/ServiceContainer/BehatExtension.php index 63a629f..44009fc 100644 --- a/src/Moodle/BehatExtension/ServiceContainer/BehatExtension.php +++ b/src/Moodle/BehatExtension/ServiceContainer/BehatExtension.php @@ -14,7 +14,6 @@ use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; use Behat\Behat\EventDispatcher\ServiceContainer\EventDispatcherExtension; -use Moodle\BehatExtension\Driver\MoodleSelenium2Factory; use Behat\Testwork\Suite\ServiceContainer\SuiteExtension; use Behat\Behat\Definition\ServiceContainer\DefinitionExtension; use Behat\Testwork\Cli\ServiceContainer\CliExtension; @@ -22,6 +21,7 @@ use Behat\Behat\Gherkin\ServiceContainer\GherkinExtension; use Behat\Testwork\Output\ServiceContainer\OutputExtension; use Behat\Testwork\Specification\ServiceContainer\SpecificationExtension; +use Moodle\BehatExtension\Driver\WebDriverFactory; /** * Behat extension for moodle @@ -281,7 +281,7 @@ public function getConfigKey() { */ public function initialize(ExtensionManager $extensionManager) { if (null !== $minkExtension = $extensionManager->getExtension('mink')) { - $minkExtension->registerDriverFactory(new MoodleSelenium2Factory()); + $minkExtension->registerDriverFactory(new WebDriverFactory()); } }