Laravel version update
Laravel version update
This commit is contained in:
43
vendor/laravel/dusk/CHANGELOG.md
vendored
Normal file
43
vendor/laravel/dusk/CHANGELOG.md
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
# Release Notes for 1.0.x
|
||||
|
||||
## v1.0.13 (2017-04-20)
|
||||
|
||||
### Added
|
||||
- Added `illuminate/console` as dependency ([#232](https://github.com/laravel/dusk/pull/232))
|
||||
- Added security measurement against registering Dusk on production ([#229](https://github.com/laravel/dusk/pull/229))
|
||||
- Added `PHP_BINARY` constant to the list of PHP's executable binaries ([#240](https://github.com/laravel/dusk/pull/240))
|
||||
|
||||
### Changed
|
||||
- Changed `propagateScaffoldingToBrowser()` to `setUp()` for compatibility with PHPUnit ~6.0 ([#227](https://github.com/laravel/dusk/pull/227))
|
||||
- Changed `selected()` comparison to always cast the value to string ([#239](https://github.com/laravel/dusk/pull/239))
|
||||
|
||||
### Fixed
|
||||
- No longer throws exception when Tty is not available ([#226](https://github.com/laravel/dusk/pull/226))
|
||||
- Use `getAttribute('value')` instead of `getText()` for `textarea` elements ([#237](https://github.com/laravel/dusk/pull/237))
|
||||
- Fixed bug when giving strings with apostrophe to `clickLink()` ([#228](https://github.com/laravel/dusk/pull/228))
|
||||
|
||||
## v1.0.12 (2017-04-07)
|
||||
|
||||
### Added
|
||||
- Added automated tests for HTML elements identified by strings with a colon ([#214](https://github.com/laravel/dusk/pull/214))
|
||||
|
||||
### Fixed
|
||||
- Support for colon on HTML id tag ([#214](https://github.com/laravel/dusk/pull/214))
|
||||
|
||||
|
||||
## v1.0.11 (2017-03-20)
|
||||
|
||||
### Added
|
||||
- Added `assertSelectHasOptions()`, `assertSelectMissingOptions()`, `assertSelectHasOption()` and `and assertSelectMissingOption()` ([#195](https://github.com/laravel/dusk/pull/195))
|
||||
- Added purge console logs before starting tests ([#193](https://github.com/laravel/dusk/pull/193))
|
||||
- Added `assertPathIsNot()` ([#183](https://github.com/laravel/dusk/pull/183))
|
||||
- Added support for back button ([#187](https://github.com/laravel/dusk/pull/187))
|
||||
- Added `waitForLocation()` to allow waiting on `window.location` to be changed ([#176](https://github.com/laravel/dusk/pull/176))
|
||||
|
||||
### Changed
|
||||
- Updated ChromeDriver to v2.28 so that it works with Chrome 57 ([#199](https://github.com/laravel/dusk/pull/199))
|
||||
- Comparison to `option` inside `select` will no longer be strict ([#178](https://github.com/laravel/dusk/pull/178))
|
||||
- Type-hint Browser for auto-complete support ([#174](https://github.com/laravel/dusk/pull/174))
|
||||
|
||||
|
||||
## v1.0.10 (2017-03-03)
|
21
vendor/laravel/dusk/LICENSE.md
vendored
Normal file
21
vendor/laravel/dusk/LICENSE.md
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Taylor Otwell
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
BIN
vendor/laravel/dusk/bin/chromedriver-linux
vendored
Normal file
BIN
vendor/laravel/dusk/bin/chromedriver-linux
vendored
Normal file
Binary file not shown.
BIN
vendor/laravel/dusk/bin/chromedriver-mac
vendored
Normal file
BIN
vendor/laravel/dusk/bin/chromedriver-mac
vendored
Normal file
Binary file not shown.
BIN
vendor/laravel/dusk/bin/chromedriver-win.exe
vendored
Normal file
BIN
vendor/laravel/dusk/bin/chromedriver-win.exe
vendored
Normal file
Binary file not shown.
4
vendor/laravel/dusk/bin/jquery.js
vendored
Normal file
4
vendor/laravel/dusk/bin/jquery.js
vendored
Normal file
File diff suppressed because one or more lines are too long
41
vendor/laravel/dusk/composer.json
vendored
Normal file
41
vendor/laravel/dusk/composer.json
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "laravel/dusk",
|
||||
"description": "Laravel Dusk provides simple end-to-end testing and browser automation.",
|
||||
"keywords": ["laravel", "testing", "webdriver"],
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Taylor Otwell",
|
||||
"email": "taylor@laravel.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.6.4",
|
||||
"facebook/webdriver": "~1.0",
|
||||
"nesbot/carbon": "~1.20",
|
||||
"illuminate/console": "~5.5",
|
||||
"illuminate/support": "~5.5",
|
||||
"symfony/console": "~3.2",
|
||||
"symfony/process": "~3.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^5.7",
|
||||
"mockery/mockery": "^0.9.6"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Laravel\\Dusk\\": "src/"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0-dev"
|
||||
},
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Laravel\\Dusk\\DuskServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"minimum-stability": "dev"
|
||||
}
|
26
vendor/laravel/dusk/phpunit.xml.dist
vendored
Normal file
26
vendor/laravel/dusk/phpunit.xml.dist
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
bootstrap="vendor/autoload.php"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
failOnRisky="true"
|
||||
failOnWarning="true"
|
||||
processIsolation="false"
|
||||
stopOnError="false"
|
||||
stopOnFailure="false"
|
||||
verbose="true"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="Laravel Dusk Test Suite">
|
||||
<directory suffix="Test.php">./tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<filter>
|
||||
<whitelist processUncoveredFilesFromWhitelist="true">
|
||||
<directory suffix=".php">./src</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</phpunit>
|
20
vendor/laravel/dusk/readme.md
vendored
Normal file
20
vendor/laravel/dusk/readme.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
<p align="center"><img src="https://laravel.com/assets/img/components/logo-dusk.svg"></p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://travis-ci.org/laravel/dusk"><img src="https://travis-ci.org/laravel/dusk.svg" alt="Build Status"></a>
|
||||
<a href="https://packagist.org/packages/laravel/dusk"><img src="https://poser.pugx.org/laravel/dusk/d/total.svg" alt="Total Downloads"></a>
|
||||
<a href="https://packagist.org/packages/laravel/dusk"><img src="https://poser.pugx.org/laravel/dusk/v/stable.svg" alt="Latest Stable Version"></a>
|
||||
<a href="https://packagist.org/packages/laravel/dusk"><img src="https://poser.pugx.org/laravel/dusk/license.svg" alt="License"></a>
|
||||
</p>
|
||||
|
||||
## Introduction
|
||||
|
||||
Laravel Dusk provides an expressive, easy-to-use browser automation and testing API. By default, Dusk does not require you to install JDK or Selenium on your machine. Instead, Dusk uses a standalone Chromedriver. However, you are free to utilize any other Selenium driver you wish.
|
||||
|
||||
## Official Documentation
|
||||
|
||||
Documentation for Dusk can be found on the [Laravel website](https://laravel.com/docs/master/dusk).
|
||||
|
||||
## License
|
||||
|
||||
Laravel Dusk is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT)
|
386
vendor/laravel/dusk/src/Browser.php
vendored
Normal file
386
vendor/laravel/dusk/src/Browser.php
vendored
Normal file
@@ -0,0 +1,386 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Dusk;
|
||||
|
||||
use Closure;
|
||||
use BadMethodCallException;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Traits\Macroable;
|
||||
use Facebook\WebDriver\WebDriverDimension;
|
||||
|
||||
class Browser
|
||||
{
|
||||
use Concerns\InteractsWithAuthentication,
|
||||
Concerns\InteractsWithCookies,
|
||||
Concerns\InteractsWithElements,
|
||||
Concerns\InteractsWithJavascript,
|
||||
Concerns\InteractsWithMouse,
|
||||
Concerns\MakesAssertions,
|
||||
Concerns\WaitsForElements,
|
||||
Macroable {
|
||||
__call as macroCall;
|
||||
}
|
||||
|
||||
/**
|
||||
* The base URL for all URLs.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $baseUrl;
|
||||
|
||||
/**
|
||||
* The directory that will contain any screenshots.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $storeScreenshotsAt;
|
||||
|
||||
/**
|
||||
* The directory that will contain any console logs.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $storeConsoleLogAt;
|
||||
|
||||
/**
|
||||
* Get the callback which resolves the default user to authenticate.
|
||||
*
|
||||
* @var \Closure
|
||||
*/
|
||||
public static $userResolver;
|
||||
|
||||
/**
|
||||
* The RemoteWebDriver instance.
|
||||
*
|
||||
* @var \Facebook\WebDriver\Remote\RemoteWebDriver
|
||||
*/
|
||||
public $driver;
|
||||
|
||||
/**
|
||||
* The element resolver instance.
|
||||
*
|
||||
* @var ElementResolver
|
||||
*/
|
||||
public $resolver;
|
||||
|
||||
/**
|
||||
* The page object currently being viewed.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $page;
|
||||
|
||||
/**
|
||||
* Create a browser instance.
|
||||
*
|
||||
* @param \Facebook\WebDriver\Remote\RemoteWebDriver $driver
|
||||
* @param ElementResolver $resolver
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($driver, $resolver = null)
|
||||
{
|
||||
$this->driver = $driver;
|
||||
|
||||
$this->resolver = $resolver ?: new ElementResolver($driver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Browse to the given URL.
|
||||
*
|
||||
* @param string $url
|
||||
* @return $this
|
||||
*/
|
||||
public function visit($url)
|
||||
{
|
||||
// First, if the URL is an object it means we are actually dealing with a page
|
||||
// and we need to create this page then get the URL from the page object as
|
||||
// it contains the URL. Once that is done, we will be ready to format it.
|
||||
if (is_object($url)) {
|
||||
$page = $url;
|
||||
|
||||
$url = $page->url();
|
||||
}
|
||||
|
||||
// If the URL does not start with http or https, then we will prepend the base
|
||||
// URL onto the URL and navigate to the URL. This will actually navigate to
|
||||
// the URL in the browser. Then we will be ready to make assertions, etc.
|
||||
if (! Str::startsWith($url, ['http://', 'https://'])) {
|
||||
$url = static::$baseUrl.'/'.ltrim($url, '/');
|
||||
}
|
||||
|
||||
$this->driver->navigate()->to($url);
|
||||
|
||||
// If the page variable was set, we will call the "on" method which will set a
|
||||
// page instance variable and call an assert method on the page so that the
|
||||
// page can have the chance to verify that we are within the right pages.
|
||||
if (isset($page)) {
|
||||
$this->on($page);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Browse to the given route.
|
||||
*
|
||||
* @param string $route
|
||||
* @param array $parameters
|
||||
* @return $this
|
||||
*/
|
||||
public function visitRoute($route, $parameters = [])
|
||||
{
|
||||
return $this->visit(route($route, $parameters));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current page object.
|
||||
*
|
||||
* @param mixed $page
|
||||
* @return $this
|
||||
*/
|
||||
public function on($page)
|
||||
{
|
||||
$this->page = $page;
|
||||
|
||||
// Here we will set the page elements on the resolver instance, which will allow
|
||||
// the developer to access short-cuts for CSS selectors on the page which can
|
||||
// allow for more expressive navigation and interaction with all the pages.
|
||||
$this->resolver->pageElements(array_merge(
|
||||
$page::siteElements(), $page->elements()
|
||||
));
|
||||
|
||||
$page->assert($this);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the page.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function refresh()
|
||||
{
|
||||
$this->driver->navigate()->refresh();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate to the previous page.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function back()
|
||||
{
|
||||
$this->driver->navigate()->back();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximize the browser window.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function maximize()
|
||||
{
|
||||
$this->driver->manage()->window()->maximize();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resize the browser window.
|
||||
*
|
||||
* @param int $width
|
||||
* @param int $height
|
||||
* @return $this
|
||||
*/
|
||||
public function resize($width, $height)
|
||||
{
|
||||
$this->driver->manage()->window()->setSize(
|
||||
new WebDriverDimension($width, $height)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take a screenshot and store it with the given name.
|
||||
*
|
||||
* @param string $name
|
||||
* @return $this
|
||||
*/
|
||||
public function screenshot($name)
|
||||
{
|
||||
$this->driver->takeScreenshot(
|
||||
sprintf('%s/%s.png', rtrim(static::$storeScreenshotsAt, '/'), $name)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the console output with the given name.
|
||||
*
|
||||
* @param string $name
|
||||
* @return $this
|
||||
*/
|
||||
public function storeConsoleLog($name)
|
||||
{
|
||||
$console = $this->driver->manage()->getLog('browser');
|
||||
|
||||
if (! empty($console)) {
|
||||
file_put_contents(
|
||||
sprintf('%s/%s.log', rtrim(static::$storeConsoleLogAt, '/'), $name)
|
||||
, json_encode($console, JSON_PRETTY_PRINT)
|
||||
);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a Closure with a scoped browser instance.
|
||||
*
|
||||
* @param string $selector
|
||||
* @param \Closure $callback
|
||||
* @return $this
|
||||
*/
|
||||
public function within($selector, Closure $callback)
|
||||
{
|
||||
return $this->with($selector, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a Closure with a scoped browser instance.
|
||||
*
|
||||
* @param string $selector
|
||||
* @param \Closure $callback
|
||||
* @return $this
|
||||
*/
|
||||
public function with($selector, Closure $callback)
|
||||
{
|
||||
$browser = new static(
|
||||
$this->driver, new ElementResolver($this->driver, $this->resolver->format($selector))
|
||||
);
|
||||
|
||||
if ($this->page) {
|
||||
$browser->on($this->page);
|
||||
}
|
||||
|
||||
call_user_func($callback, $browser);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that jQuery is available on the page.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function ensurejQueryIsAvailable()
|
||||
{
|
||||
if ($this->driver->executeScript("return window.jQuery == null")) {
|
||||
$this->driver->executeScript(file_get_contents(__DIR__.'/../bin/jquery.js'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause for the given amount of milliseconds.
|
||||
*
|
||||
* @param int $milliseconds
|
||||
* @return $this
|
||||
*/
|
||||
public function pause($milliseconds)
|
||||
{
|
||||
usleep($milliseconds * 1000);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the browser.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function quit()
|
||||
{
|
||||
$this->driver->quit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tap the browser into a callback.
|
||||
*
|
||||
* @param \Closure $callback
|
||||
* @return $this
|
||||
*/
|
||||
public function tap($callback)
|
||||
{
|
||||
$callback($this);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump the content from the last response.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dump()
|
||||
{
|
||||
dd($this->driver->getPageSource());
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause execution of test and open Laravel Tinker (PsySH) REPL.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function tinker()
|
||||
{
|
||||
\Psy\Shell::debug([
|
||||
'browser' => $this,
|
||||
'driver' => $this->driver,
|
||||
'resolver' => $this->resolver,
|
||||
'page' => $this->page,
|
||||
], $this);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop running tests but leave the browser open.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function stop()
|
||||
{
|
||||
exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically call a method on the browser.
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($method, $parameters)
|
||||
{
|
||||
if (static::hasMacro($method)) {
|
||||
return $this->macroCall($method, $parameters);
|
||||
}
|
||||
|
||||
if ($this->page && method_exists($this->page, $method)) {
|
||||
array_unshift($parameters, $this);
|
||||
|
||||
$this->page->{$method}(...$parameters);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
throw new BadMethodCallException("Call to undefined method [{$method}].");
|
||||
}
|
||||
}
|
107
vendor/laravel/dusk/src/Concerns/InteractsWithAuthentication.php
vendored
Normal file
107
vendor/laravel/dusk/src/Concerns/InteractsWithAuthentication.php
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Dusk\Concerns;
|
||||
|
||||
use Laravel\Dusk\Browser;
|
||||
use PHPUnit\Framework\Assert as PHPUnit;
|
||||
|
||||
trait InteractsWithAuthentication
|
||||
{
|
||||
/**
|
||||
* Log into the application as the default user.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function login()
|
||||
{
|
||||
return $this->loginAs(call_user_func(Browser::$userResolver));
|
||||
}
|
||||
|
||||
/**
|
||||
* Log into the application using a given user ID or email.
|
||||
*
|
||||
* @param object|string $userId
|
||||
* @param string $guard
|
||||
* @return $this
|
||||
*/
|
||||
public function loginAs($userId, $guard = null)
|
||||
{
|
||||
$userId = method_exists($userId, 'getKey') ? $userId->getKey() : $userId;
|
||||
|
||||
return $this->visit(rtrim('/_dusk/login/'.$userId.'/'.$guard, '/'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Log out of the application.
|
||||
*
|
||||
* @param string $guard
|
||||
* @return $this
|
||||
*/
|
||||
public function logout($guard = null)
|
||||
{
|
||||
return $this->visit(rtrim('/_dusk/logout/'.$guard, '/'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ID and the class name of the authenticated user.
|
||||
*
|
||||
* @param string|null $guard
|
||||
* @return array
|
||||
*/
|
||||
protected function currentUserInfo($guard = null)
|
||||
{
|
||||
$response = $this->visit("/_dusk/user/{$guard}");
|
||||
|
||||
return json_decode(strip_tags($response->driver->getPageSource()), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the user is authenticated.
|
||||
*
|
||||
* @param string|null $guard
|
||||
* @return $this
|
||||
*/
|
||||
public function assertAuthenticated($guard = null)
|
||||
{
|
||||
PHPUnit::assertNotEmpty($this->currentUserInfo($guard), 'The user is not authenticated.');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the user is not authenticated.
|
||||
*
|
||||
* @param string|null $guard
|
||||
* @return $this
|
||||
*/
|
||||
public function assertGuest($guard = null)
|
||||
{
|
||||
PHPUnit::assertEmpty(
|
||||
$this->currentUserInfo($guard), 'The user is unexpectedly authenticated.'
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the user is authenticated as the given user.
|
||||
*
|
||||
* @param $user
|
||||
* @param string|null $guard
|
||||
* @return $this
|
||||
*/
|
||||
public function assertAuthenticatedAs($user, $guard = null)
|
||||
{
|
||||
$expected = [
|
||||
'id' => $user->getAuthIdentifier(),
|
||||
'className' => get_class($user),
|
||||
];
|
||||
|
||||
PHPUnit::assertSame(
|
||||
$expected, $this->currentUserInfo($guard),
|
||||
'The currently authenticated user is not who was expected.'
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
88
vendor/laravel/dusk/src/Concerns/InteractsWithCookies.php
vendored
Normal file
88
vendor/laravel/dusk/src/Concerns/InteractsWithCookies.php
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Dusk\Concerns;
|
||||
|
||||
use DateTimeInterface;
|
||||
|
||||
trait InteractsWithCookies
|
||||
{
|
||||
/**
|
||||
* Get or set an encrypted cookie's value.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string|null $value
|
||||
* @param int|DateTimeInterface|null $expiry
|
||||
* @param array $options
|
||||
* @return string
|
||||
*/
|
||||
public function cookie($name, $value = null, $expiry = null, array $options = [])
|
||||
{
|
||||
if ($value) {
|
||||
return $this->addCookie($name, $value, $expiry, $options);
|
||||
}
|
||||
|
||||
if ($cookie = $this->driver->manage()->getCookieNamed($name)) {
|
||||
return decrypt(rawurldecode($cookie['value']));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set a plain cookie's value.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string|null $value
|
||||
* @param int|DateTimeInterface|null $expiry
|
||||
* @param array $options
|
||||
* @return string
|
||||
*/
|
||||
public function plainCookie($name, $value = null, $expiry = null, array $options = [])
|
||||
{
|
||||
if ($value) {
|
||||
return $this->addCookie($name, $value, $expiry, $options, false);
|
||||
}
|
||||
|
||||
if ($cookie = $this->driver->manage()->getCookieNamed($name)) {
|
||||
return rawurldecode($cookie['value']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given cookie.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $value
|
||||
* @param int|DateTimeInterface|null $expiry
|
||||
* @param array $options
|
||||
* @param bool $encrypt
|
||||
* @return $this
|
||||
*/
|
||||
public function addCookie($name, $value, $expiry = null, array $options = [], $encrypt = true)
|
||||
{
|
||||
if ($encrypt) {
|
||||
$value = encrypt($value);
|
||||
}
|
||||
|
||||
if ($expiry instanceof DateTimeInterface) {
|
||||
$expiry = $expiry->getTimestamp();
|
||||
}
|
||||
|
||||
$this->driver->manage()->addCookie(
|
||||
array_merge($options, compact('expiry', 'name', 'value'))
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the given cookie.
|
||||
*
|
||||
* @param string $name
|
||||
* @return $this
|
||||
*/
|
||||
public function deleteCookie($name)
|
||||
{
|
||||
$this->driver->manage()->deleteCookieNamed($name);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
432
vendor/laravel/dusk/src/Concerns/InteractsWithElements.php
vendored
Normal file
432
vendor/laravel/dusk/src/Concerns/InteractsWithElements.php
vendored
Normal file
@@ -0,0 +1,432 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Dusk\Concerns;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Facebook\WebDriver\WebDriverBy;
|
||||
use Facebook\WebDriver\WebDriverKeys;
|
||||
use Facebook\WebDriver\Remote\LocalFileDetector;
|
||||
use Facebook\WebDriver\Interactions\WebDriverActions;
|
||||
|
||||
trait InteractsWithElements
|
||||
{
|
||||
/**
|
||||
* Get all of the elements matching the given selector.
|
||||
*
|
||||
* @param string $selector
|
||||
* @return array
|
||||
*/
|
||||
public function elements($selector)
|
||||
{
|
||||
return $this->resolver->all($selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the element matching the given selector.
|
||||
*
|
||||
* @param string $selector
|
||||
* @return \Facebook\WebDriver\Remote\RemoteWebElement|null
|
||||
*/
|
||||
public function element($selector)
|
||||
{
|
||||
return $this->resolver->find($selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Click the element at the given selector.
|
||||
*
|
||||
* @param string $selector
|
||||
* @return $this
|
||||
*/
|
||||
public function click($selector)
|
||||
{
|
||||
$this->resolver->findOrFail($selector)->click();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Right click the element at the given selector.
|
||||
*
|
||||
* @param string $selector
|
||||
* @return $this
|
||||
*/
|
||||
public function rightClick($selector)
|
||||
{
|
||||
(new WebDriverActions($this->driver))->contextClick(
|
||||
$this->resolver->findOrFail($selector)
|
||||
)->perform();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Click the link with the given text.
|
||||
*
|
||||
* @param string $link
|
||||
* @return $this
|
||||
*/
|
||||
public function clickLink($link)
|
||||
{
|
||||
$this->ensurejQueryIsAvailable();
|
||||
|
||||
$selector = addslashes(trim($this->resolver->format("a:contains({$link})")));
|
||||
|
||||
$this->driver->executeScript("jQuery.find(\"{$selector}\")[0].click();");
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Directly get or set the value attribute of an input field.
|
||||
*
|
||||
* @param string $selector
|
||||
* @param string|null $value
|
||||
* @return $this
|
||||
*/
|
||||
public function value($selector, $value = null)
|
||||
{
|
||||
if (is_null($value)) {
|
||||
return $this->resolver->findOrFail($selector)->getAttribute('value');
|
||||
}
|
||||
|
||||
$selector = $this->resolver->format($selector);
|
||||
|
||||
$this->driver->executeScript(
|
||||
"document.querySelector('{$selector}').value = '{$value}';"
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text of the element matching the given selector.
|
||||
*
|
||||
* @param string $selector
|
||||
* @return string
|
||||
*/
|
||||
public function text($selector)
|
||||
{
|
||||
return $this->resolver->findOrFail($selector)->getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the given attribute from the element matching the given selector.
|
||||
*
|
||||
* @param string $selector
|
||||
* @param string $attribute
|
||||
* @return string
|
||||
*/
|
||||
public function attribute($selector, $attribute)
|
||||
{
|
||||
return $this->resolver->findOrFail($selector)->getAttribute($attribute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the given keys to the element matching the given selector.
|
||||
*
|
||||
* @param string $selector
|
||||
* @param dynamic $keys
|
||||
* @return $this
|
||||
*/
|
||||
public function keys($selector, ...$keys)
|
||||
{
|
||||
$this->resolver->findOrFail($selector)->sendKeys($this->parseKeys($keys));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the keys before sending to the keyboard.
|
||||
*
|
||||
* @param array $keys
|
||||
* @return array
|
||||
*/
|
||||
protected function parseKeys($keys)
|
||||
{
|
||||
return collect($keys)->map(function ($key) {
|
||||
if (is_string($key) && Str::startsWith($key, '{') && Str::endsWith($key, '}')) {
|
||||
$key = constant(WebDriverKeys::class.'::'.strtoupper(trim($key, '{}')));
|
||||
}
|
||||
|
||||
if (is_array($key) && Str::startsWith($key[0], '{')) {
|
||||
$key[0] = constant(WebDriverKeys::class.'::'.strtoupper(trim($key[0], '{}')));
|
||||
}
|
||||
|
||||
return $key;
|
||||
})->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Type the given value in the given field.
|
||||
*
|
||||
* @param string $field
|
||||
* @param string $value
|
||||
* @return $this
|
||||
*/
|
||||
public function type($field, $value)
|
||||
{
|
||||
$this->resolver->resolveForTyping($field)->clear()->sendKeys($value);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type the given value in the given field without clearing it.
|
||||
*
|
||||
* @param string $field
|
||||
* @param string $value
|
||||
* @return $this
|
||||
*/
|
||||
public function append($field, $value)
|
||||
{
|
||||
$this->resolver->resolveForTyping($field)->sendKeys($value);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the given field.
|
||||
*
|
||||
* @param string $field
|
||||
* @return $this
|
||||
*/
|
||||
public function clear($field)
|
||||
{
|
||||
$this->resolver->resolveForTyping($field)->clear();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the given value or random value of a drop-down field.
|
||||
*
|
||||
* @param string $field
|
||||
* @param string $value
|
||||
* @return $this
|
||||
*/
|
||||
public function select($field, $value = null)
|
||||
{
|
||||
$element = $this->resolver->resolveForSelection($field);
|
||||
|
||||
$options = $element->findElements(WebDriverBy::tagName('option'));
|
||||
|
||||
if (is_null($value)) {
|
||||
$options[array_rand($options)]->click();
|
||||
}
|
||||
|
||||
else {
|
||||
foreach ($options as $option) {
|
||||
if ((string) $option->getAttribute('value') === (string) $value) {
|
||||
$option->click();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the given value of a radio button field.
|
||||
*
|
||||
* @param string $field
|
||||
* @param string $value
|
||||
* @return $this
|
||||
*/
|
||||
public function radio($field, $value)
|
||||
{
|
||||
$this->resolver->resolveForRadioSelection($field, $value)->click();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the given checkbox.
|
||||
*
|
||||
* @param string $field
|
||||
* @param string $value
|
||||
* @return $this
|
||||
*/
|
||||
public function check($field, $value = null)
|
||||
{
|
||||
$element = $this->resolver->resolveForChecking($field, $value);
|
||||
|
||||
if (! $element->isSelected()) {
|
||||
$element->click();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uncheck the given checkbox.
|
||||
*
|
||||
* @param string $field
|
||||
* @param string $value
|
||||
* @return $this
|
||||
*/
|
||||
public function uncheck($field, $value = null)
|
||||
{
|
||||
$element = $this->resolver->resolveForChecking($field, $value);
|
||||
|
||||
if ($element->isSelected()) {
|
||||
$element->click();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach the given file to the field.
|
||||
*
|
||||
* @param string $field
|
||||
* @param string $path
|
||||
* @return $this
|
||||
*/
|
||||
public function attach($field, $path)
|
||||
{
|
||||
$element = $this->resolver->resolveForAttachment($field);
|
||||
|
||||
$element->setFileDetector(new LocalFileDetector)->sendKeys($path);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Press the button with the given text or name.
|
||||
*
|
||||
* @param string $button
|
||||
* @return $this
|
||||
*/
|
||||
public function press($button)
|
||||
{
|
||||
$this->resolver->resolveForButtonPress($button)->click();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Press the button with the given text or name.
|
||||
*
|
||||
* @param string $button
|
||||
* @param int $seconds
|
||||
* @return $this
|
||||
*/
|
||||
public function pressAndWaitFor($button, $seconds = 5)
|
||||
{
|
||||
$element = $this->resolver->resolveForButtonPress($button);
|
||||
|
||||
$element->click();
|
||||
|
||||
return $this->waitUsing($seconds, 100, function () use ($element) {
|
||||
return $element->isEnabled();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Drag an element to another element using selectors.
|
||||
*
|
||||
* @param string $from
|
||||
* @param string $to
|
||||
* @return $this
|
||||
*/
|
||||
public function drag($from, $to)
|
||||
{
|
||||
(new WebDriverActions($this->driver))->dragAndDrop(
|
||||
$this->resolver->findOrFail($from), $this->resolver->findOrFail($to)
|
||||
)->perform();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Drag an element up.
|
||||
*
|
||||
* @param string $selector
|
||||
* @param int $offset
|
||||
* @return $this
|
||||
*/
|
||||
public function dragUp($selector, $offset)
|
||||
{
|
||||
return $this->dragOffset($selector, 0, -$offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drag an element down.
|
||||
*
|
||||
* @param string $selector
|
||||
* @param int $offset
|
||||
* @return $this
|
||||
*/
|
||||
public function dragDown($selector, $offset)
|
||||
{
|
||||
return $this->dragOffset($selector, 0, $offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drag an element to the left.
|
||||
*
|
||||
* @param string $selector
|
||||
* @param int $offset
|
||||
* @return $this
|
||||
*/
|
||||
public function dragLeft($selector, $offset)
|
||||
{
|
||||
return $this->dragOffset($selector, -$offset, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drag an element to the right.
|
||||
*
|
||||
* @param string $selector
|
||||
* @param int $offset
|
||||
* @return $this
|
||||
*/
|
||||
public function dragRight($selector, $offset)
|
||||
{
|
||||
return $this->dragOffset($selector, $offset, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drag an element by the given offset.
|
||||
*
|
||||
* @param string $selector
|
||||
* @param int $x
|
||||
* @param int $y
|
||||
* @return $this
|
||||
*/
|
||||
public function dragOffset($selector, $x = 0, $y = 0)
|
||||
{
|
||||
(new WebDriverActions($this->driver))->dragAndDropBy(
|
||||
$this->resolver->findOrFail($selector), $x, $y
|
||||
)->perform();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept a JavaScript dialog.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function acceptDialog()
|
||||
{
|
||||
$this->driver->switchTo()->alert()->accept();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismiss a JavaScript dialog.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function dismissDialog()
|
||||
{
|
||||
$this->driver->switchTo()->alert()->dismiss();
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
19
vendor/laravel/dusk/src/Concerns/InteractsWithJavascript.php
vendored
Normal file
19
vendor/laravel/dusk/src/Concerns/InteractsWithJavascript.php
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Dusk\Concerns;
|
||||
|
||||
trait InteractsWithJavascript
|
||||
{
|
||||
/**
|
||||
* Execute JavaScript within the browser.
|
||||
*
|
||||
* @param string|array $scripts
|
||||
* @return array
|
||||
*/
|
||||
public function script($scripts)
|
||||
{
|
||||
return collect((array) $scripts)->map(function ($script) {
|
||||
return $this->driver->executeScript($script);
|
||||
})->all();
|
||||
}
|
||||
}
|
21
vendor/laravel/dusk/src/Concerns/InteractsWithMouse.php
vendored
Normal file
21
vendor/laravel/dusk/src/Concerns/InteractsWithMouse.php
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Dusk\Concerns;
|
||||
|
||||
trait InteractsWithMouse
|
||||
{
|
||||
/**
|
||||
* Move the mouse over the given selector.
|
||||
*
|
||||
* @param string $selector
|
||||
* @return $this
|
||||
*/
|
||||
public function mouseover($selector)
|
||||
{
|
||||
$element = $this->resolver->findOrFail($selector);
|
||||
|
||||
$this->driver->getMouse()->mouseMove($element->getCoordinates());
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
676
vendor/laravel/dusk/src/Concerns/MakesAssertions.php
vendored
Normal file
676
vendor/laravel/dusk/src/Concerns/MakesAssertions.php
vendored
Normal file
@@ -0,0 +1,676 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Dusk\Concerns;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use PHPUnit\Framework\Assert as PHPUnit;
|
||||
use Facebook\WebDriver\Exception\NoSuchElementException;
|
||||
|
||||
trait MakesAssertions
|
||||
{
|
||||
/**
|
||||
* Assert that the page title is the given value.
|
||||
*
|
||||
* @param string $title
|
||||
* @return $this
|
||||
*/
|
||||
public function assertTitle($title)
|
||||
{
|
||||
PHPUnit::assertEquals($title, $this->driver->getTitle());
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the page title contains the given value.
|
||||
*
|
||||
* @param string $title
|
||||
* @return $this
|
||||
*/
|
||||
public function assertTitleContains($title)
|
||||
{
|
||||
PHPUnit::assertTrue(
|
||||
Str::contains($this->driver->getTitle(), $title)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the current URL path matches the given pattern.
|
||||
*
|
||||
* @param string $path
|
||||
* @return $this
|
||||
*/
|
||||
public function assertPathIs($path)
|
||||
{
|
||||
$pattern = preg_quote($path, '/');
|
||||
|
||||
$pattern = str_replace('\*', '.*', $pattern);
|
||||
|
||||
PHPUnit::assertRegExp('/^'.$pattern.'/u', parse_url(
|
||||
$this->driver->getCurrentURL()
|
||||
)['path']);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the current URL path begins with given path.
|
||||
*
|
||||
* @param string $path
|
||||
* @return $this
|
||||
*/
|
||||
public function assertPathBeginsWith($path)
|
||||
{
|
||||
PHPUnit::assertStringStartsWith($path, parse_url(
|
||||
$this->driver->getCurrentURL()
|
||||
)['path']);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the current URL path does not match the given path.
|
||||
*
|
||||
* @param string $path
|
||||
* @return $this
|
||||
*/
|
||||
public function assertPathIsNot($path)
|
||||
{
|
||||
PHPUnit::assertNotEquals($path, parse_url(
|
||||
$this->driver->getCurrentURL()
|
||||
)['path']);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the current URL path matches the given route.
|
||||
*
|
||||
* @param string $route
|
||||
* @param array $parameters
|
||||
* @return $this
|
||||
*/
|
||||
public function assertRouteIs($route, $parameters = [])
|
||||
{
|
||||
return $this->assertPathIs(route($route, $parameters, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that a query string parameter is present and has a given value.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $value
|
||||
* @return $this
|
||||
*/
|
||||
public function assertQueryStringHas($name, $value = null)
|
||||
{
|
||||
$output = $this->assertHasQueryStringParameter($name);
|
||||
|
||||
if (is_null($value)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
PHPUnit::assertEquals(
|
||||
$value, $output[$name],
|
||||
"Query string parameter [{$name}] had value [{$output[$name]}], but expected [{$value}]."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given query string parameter is missing.
|
||||
*
|
||||
* @param string $name
|
||||
* @return $this
|
||||
*/
|
||||
public function assertQueryStringMissing($name)
|
||||
{
|
||||
$parsedUrl = parse_url($this->driver->getCurrentURL());
|
||||
|
||||
if (! array_key_exists('query', $parsedUrl)) {
|
||||
PHPUnit::assertTrue(true);
|
||||
return $this;
|
||||
}
|
||||
|
||||
parse_str($parsedUrl['query'], $output);
|
||||
|
||||
PHPUnit::assertArrayNotHasKey(
|
||||
$name, $output,
|
||||
"Found unexpected query string parameter [{$name}] in [".$this->driver->getCurrentURL()."]."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given query string parameter is present.
|
||||
*
|
||||
* @param string $name
|
||||
* @return $this
|
||||
*/
|
||||
protected function assertHasQueryStringParameter($name)
|
||||
{
|
||||
$parsedUrl = parse_url($this->driver->getCurrentURL());
|
||||
|
||||
PHPUnit::assertArrayHasKey(
|
||||
'query', $parsedUrl,
|
||||
"Did not see expected query string in [".$this->driver->getCurrentURL()."]."
|
||||
);
|
||||
|
||||
parse_str($parsedUrl['query'], $output);
|
||||
|
||||
PHPUnit::assertArrayHasKey(
|
||||
$name, $output,
|
||||
"Did not see expected query string parameter [{$name}] in [".$this->driver->getCurrentURL()."]."
|
||||
);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given cookie is present.
|
||||
*
|
||||
* @param string $name
|
||||
* @return $this
|
||||
*/
|
||||
public function assertHasCookie($name)
|
||||
{
|
||||
PHPUnit::assertTrue(
|
||||
! is_null($this->cookie($name)),
|
||||
"Did not find expected cookie [{$name}]."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that an encrypted cookie has a given value.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $value
|
||||
* @param bool $decrypt
|
||||
* @return $this
|
||||
*/
|
||||
public function assertCookieValue($name, $value, $decrypt = true)
|
||||
{
|
||||
$actual = $decrypt ? $this->cookie($name) : $this->plainCookie($name);
|
||||
|
||||
PHPUnit::assertEquals(
|
||||
$value, $actual,
|
||||
"Cookie [{$name}] had value [{$actual}], but expected [{$value}]."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that a cookie has a given value.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $value
|
||||
* @return $this
|
||||
*/
|
||||
public function assertPlainCookieValue($name, $value)
|
||||
{
|
||||
return $this->assertCookieValue($name, $value, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given text appears on the page.
|
||||
*
|
||||
* @param string $text
|
||||
* @return $this
|
||||
*/
|
||||
public function assertSee($text)
|
||||
{
|
||||
return $this->assertSeeIn('', $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given text does not appear on the page.
|
||||
*
|
||||
* @param string $text
|
||||
* @return $this
|
||||
*/
|
||||
public function assertDontSee($text)
|
||||
{
|
||||
return $this->assertDontSeeIn('', $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given text appears within the given selector.
|
||||
*
|
||||
* @param string $selector
|
||||
* @param string $text
|
||||
* @return $this
|
||||
*/
|
||||
public function assertSeeIn($selector, $text)
|
||||
{
|
||||
$fullSelector = $this->resolver->format($selector);
|
||||
|
||||
$element = $this->resolver->findOrFail($selector);
|
||||
|
||||
PHPUnit::assertTrue(
|
||||
Str::contains($element->getText(), $text),
|
||||
"Did not see expected text [{$text}] within element [{$fullSelector}]."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given text does not appear within the given selector.
|
||||
*
|
||||
* @param string $selector
|
||||
* @param string $text
|
||||
* @return $this
|
||||
*/
|
||||
public function assertDontSeeIn($selector, $text)
|
||||
{
|
||||
$fullSelector = $this->resolver->format($selector);
|
||||
|
||||
$element = $this->resolver->findOrFail($selector);
|
||||
|
||||
PHPUnit::assertFalse(
|
||||
Str::contains($element->getText(), $text),
|
||||
"Saw unexpected text [{$text}] within element [{$fullSelector}]."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given source code is present on the page.
|
||||
*
|
||||
* @param string $code
|
||||
* @return $this
|
||||
*/
|
||||
public function assertSourceHas($code)
|
||||
{
|
||||
PHPUnit::assertContains(
|
||||
$code, $this->driver->getPageSource(),
|
||||
"Did not find expected source code [{$code}]"
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given source code is not present on the page.
|
||||
*
|
||||
* @param string $code
|
||||
* @return $this
|
||||
*/
|
||||
public function assertSourceMissing($code)
|
||||
{
|
||||
PHPUnit::assertNotContains(
|
||||
$code, $this->driver->getPageSource(),
|
||||
"Found unexpected source code [{$code}]"
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given link is visible.
|
||||
*
|
||||
* @param string $link
|
||||
* @return $this
|
||||
*/
|
||||
public function assertSeeLink($link)
|
||||
{
|
||||
if ($this->resolver->prefix) {
|
||||
$message = "Did not see expected link [{$link}] within [{$this->resolver->prefix}].";
|
||||
} else {
|
||||
$message = "Did not see expected link [{$link}].";
|
||||
}
|
||||
|
||||
PHPUnit::assertTrue(
|
||||
$this->seeLink($link),
|
||||
$message
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given link is not visible.
|
||||
*
|
||||
* @param string $link
|
||||
* @return $this
|
||||
*/
|
||||
public function assertDontSeeLink($link)
|
||||
{
|
||||
if ($this->resolver->prefix) {
|
||||
$message = "Saw unexpected link [{$link}] within [{$this->resolver->prefix}].";
|
||||
} else {
|
||||
$message = "Saw unexpected expected link [{$link}].";
|
||||
}
|
||||
|
||||
PHPUnit::assertFalse(
|
||||
$this->seeLink($link),
|
||||
$message
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given link is visible.
|
||||
*
|
||||
* @param string $link
|
||||
* @return bool
|
||||
*/
|
||||
public function seeLink($link)
|
||||
{
|
||||
$this->ensurejQueryIsAvailable();
|
||||
|
||||
$selector = addslashes(trim($this->resolver->format("a:contains('{$link}')")));
|
||||
|
||||
$script = <<<JS
|
||||
var link = jQuery.find("{$selector}");
|
||||
return link.length > 0 && jQuery(link).is(':visible');
|
||||
JS;
|
||||
|
||||
return $this->driver->executeScript($script);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given input or text area contains the given value.
|
||||
*
|
||||
* @param string $field
|
||||
* @param string $value
|
||||
* @return $this
|
||||
*/
|
||||
public function assertInputValue($field, $value)
|
||||
{
|
||||
PHPUnit::assertEquals($value, $this->inputValue($field));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given input or text area does not contain the given value.
|
||||
*
|
||||
* @param string $field
|
||||
* @param string $value
|
||||
* @return $this
|
||||
*/
|
||||
public function assertInputValueIsNot($field, $value)
|
||||
{
|
||||
PHPUnit::assertNotEquals($value, $this->inputValue($field));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the given input or text area field.
|
||||
*
|
||||
* @param string $field
|
||||
* @return string
|
||||
*/
|
||||
public function inputValue($field)
|
||||
{
|
||||
$element = $this->resolver->resolveForTyping($field);
|
||||
|
||||
return in_array($element->getTagName(), ['input', 'textarea'])
|
||||
? $element->getAttribute('value')
|
||||
: $element->getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given checkbox field is checked.
|
||||
*
|
||||
* @param string $field
|
||||
* @param string $value
|
||||
* @return $this
|
||||
*/
|
||||
public function assertChecked($field, $value = null)
|
||||
{
|
||||
$element = $this->resolver->resolveForChecking($field, $value);
|
||||
|
||||
PHPUnit::assertTrue(
|
||||
$element->isSelected(),
|
||||
"Expected checkbox [{$field}] to be checked, but it wasn't."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given checkbox field is not checked.
|
||||
*
|
||||
* @param string $field
|
||||
* @param string $value
|
||||
* @return $this
|
||||
*/
|
||||
public function assertNotChecked($field, $value = null)
|
||||
{
|
||||
$element = $this->resolver->resolveForChecking($field, $value);
|
||||
|
||||
PHPUnit::assertFalse(
|
||||
$element->isSelected(),
|
||||
"Checkbox [{$field}] was unexpectedly checked."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given radio field is selected.
|
||||
*
|
||||
* @param string $field
|
||||
* @param string $value
|
||||
* @return $this
|
||||
*/
|
||||
function assertRadioSelected($field, $value)
|
||||
{
|
||||
$element = $this->resolver->resolveForRadioSelection($field, $value);
|
||||
|
||||
PHPUnit::assertTrue(
|
||||
$element->isSelected(),
|
||||
"Expected radio [{$field}] to be selected, but it wasn't."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given radio field is not selected.
|
||||
*
|
||||
* @param string $field
|
||||
* @param string $value
|
||||
* @return $this
|
||||
*/
|
||||
public function assertRadioNotSelected($field, $value = null)
|
||||
{
|
||||
$element = $this->resolver->resolveForRadioSelection($field, $value);
|
||||
|
||||
PHPUnit::assertFalse(
|
||||
$element->isSelected(),
|
||||
"Radio [{$field}] was unexpectedly selected."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given select field has the given value selected.
|
||||
*
|
||||
* @param string $field
|
||||
* @param string $value
|
||||
* @return $this
|
||||
*/
|
||||
public function assertSelected($field, $value)
|
||||
{
|
||||
PHPUnit::assertTrue(
|
||||
$this->selected($field, $value),
|
||||
"Expected value [{$value}] to be selected for [{$field}], but it wasn't."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given select field does not have the given value selected.
|
||||
*
|
||||
* @param string $field
|
||||
* @param string $value
|
||||
* @return $this
|
||||
*/
|
||||
public function assertNotSelected($field, $value)
|
||||
{
|
||||
PHPUnit::assertFalse(
|
||||
$this->selected($field, $value),
|
||||
"Unexpected value [{$value}] selected for [{$field}]."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given array of values are available to be selected.
|
||||
*
|
||||
* @param string $field
|
||||
* @param array $values
|
||||
* @return $this
|
||||
*/
|
||||
public function assertSelectHasOptions($field, array $values)
|
||||
{
|
||||
PHPUnit::assertCount(
|
||||
count($values),
|
||||
$this->resolver->resolveSelectOptions($field, $values),
|
||||
"Expected options [".implode(',', $values)."] for selection field [{$field}] to be available."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given array of values are not available to be selected.
|
||||
*
|
||||
* @param string $field
|
||||
* @param array $values
|
||||
* @return $this
|
||||
*/
|
||||
public function assertSelectMissingOptions($field, array $values)
|
||||
{
|
||||
PHPUnit::assertCount(
|
||||
0, $this->resolver->resolveSelectOptions($field, $values),
|
||||
"Unexpected options [".implode(',', $values)."] for selection field [{$field}]."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given value is available to be selected on the given field.
|
||||
*
|
||||
* @param string $field
|
||||
* @param string $value
|
||||
* @return $this
|
||||
*/
|
||||
public function assertSelectHasOption($field, $value)
|
||||
{
|
||||
return $this->assertSelectHasOptions($field, [$value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given value is not available to be selected on the given field.
|
||||
*
|
||||
* @param string $field
|
||||
* @param string $value
|
||||
* @return $this
|
||||
*/
|
||||
public function assertSelectMissingOption($field, $value)
|
||||
{
|
||||
return $this->assertSelectMissingOptions($field, [$value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given value is selected for the given select field.
|
||||
*
|
||||
* @param string $field
|
||||
* @param string $value
|
||||
* @return bool
|
||||
*/
|
||||
public function selected($field, $value)
|
||||
{
|
||||
$element = $this->resolver->resolveForSelection($field);
|
||||
|
||||
return (string) $element->getAttribute('value') === (string) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the element at the given selector has the given value.
|
||||
*
|
||||
* @param string $selector
|
||||
* @param string $value
|
||||
* @return $this
|
||||
*/
|
||||
public function assertValue($selector, $value)
|
||||
{
|
||||
$actual = $this->resolver->findOrFail($selector)->getAttribute('value');
|
||||
|
||||
PHPUnit::assertEquals($value, $actual);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the element with the given selector is visible.
|
||||
*
|
||||
* @param string $selector
|
||||
* @return $this
|
||||
*/
|
||||
public function assertVisible($selector)
|
||||
{
|
||||
$fullSelector = $this->resolver->format($selector);
|
||||
|
||||
PHPUnit::assertTrue(
|
||||
$this->resolver->findOrFail($selector)->isDisplayed(),
|
||||
"Element [{$fullSelector}] is not visible."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the element with the given selector is not on the page.
|
||||
*
|
||||
* @param string $selector
|
||||
* @return $this
|
||||
*/
|
||||
public function assertMissing($selector)
|
||||
{
|
||||
$fullSelector = $this->resolver->format($selector);
|
||||
|
||||
try {
|
||||
$missing = ! $this->resolver->findOrFail($selector)->isDisplayed();
|
||||
} catch (NoSuchElementException $e) {
|
||||
$missing = true;
|
||||
}
|
||||
|
||||
PHPUnit::assertTrue($missing, "Saw unexpected element [{$fullSelector}].");
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that a JavaScript dialog with given message has been opened.
|
||||
*
|
||||
* @param string $message
|
||||
* @return $this
|
||||
*/
|
||||
public function assertDialogOpened($message)
|
||||
{
|
||||
PHPUnit::assertEquals(
|
||||
$message, $this->driver->switchTo()->alert()->getText()
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
179
vendor/laravel/dusk/src/Concerns/WaitsForElements.php
vendored
Normal file
179
vendor/laravel/dusk/src/Concerns/WaitsForElements.php
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Dusk\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Exception;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Str;
|
||||
use Facebook\WebDriver\Exception\TimeOutException;
|
||||
use Facebook\WebDriver\Exception\NoSuchElementException;
|
||||
|
||||
trait WaitsForElements
|
||||
{
|
||||
/**
|
||||
* Execute the given callback in a scoped browser once the selector is available.
|
||||
*
|
||||
* @param string $selector
|
||||
* @param Closure $callback
|
||||
* @param int $seconds
|
||||
* @return $this
|
||||
*/
|
||||
public function whenAvailable($selector, Closure $callback, $seconds = 5)
|
||||
{
|
||||
return $this->waitFor($selector, $seconds)->with($selector, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the given selector to be visible.
|
||||
*
|
||||
* @param string $selector
|
||||
* @param int $seconds
|
||||
* @return $this
|
||||
*/
|
||||
public function waitFor($selector, $seconds = 5)
|
||||
{
|
||||
return $this->waitUsing($seconds, 100, function () use ($selector) {
|
||||
return $this->resolver->findOrFail($selector)->isDisplayed();
|
||||
}, "Waited {$seconds} seconds for selector [{$selector}].");
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the given selector to be removed.
|
||||
*
|
||||
* @param string $selector
|
||||
* @param int $seconds
|
||||
* @return $this
|
||||
*/
|
||||
public function waitUntilMissing($selector, $seconds = 5)
|
||||
{
|
||||
return $this->waitUsing($seconds, 100, function () use ($selector) {
|
||||
try {
|
||||
$missing = ! $this->resolver->findOrFail($selector)->isDisplayed();
|
||||
} catch (NoSuchElementException $e) {
|
||||
$missing = true;
|
||||
}
|
||||
|
||||
return $missing;
|
||||
}, "Waited {$seconds} seconds for removal of selector [{$selector}].");
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the given text to be visible.
|
||||
*
|
||||
* @param string $text
|
||||
* @param int $seconds
|
||||
* @return $this
|
||||
*/
|
||||
public function waitForText($text, $seconds = 5)
|
||||
{
|
||||
return $this->waitUsing($seconds, 100, function () use ($text) {
|
||||
return Str::contains($this->resolver->findOrFail('')->getText(), $text);
|
||||
}, "Waited {$seconds} seconds for text [{$text}].");
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the given link to be visible.
|
||||
*
|
||||
* @param string $link
|
||||
* @param int $seconds
|
||||
* @return $this
|
||||
*/
|
||||
public function waitForLink($link, $seconds = 5)
|
||||
{
|
||||
return $this->waitUsing($seconds, 100, function () use ($link) {
|
||||
return $this->seeLink($link);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the given location.
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $seconds
|
||||
* @return $this
|
||||
*/
|
||||
public function waitForLocation($path, $seconds = 5)
|
||||
{
|
||||
return $this->waitUntil("window.location.pathname == '{$path}'", $seconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until the given script returns true.
|
||||
*
|
||||
* @param string $script
|
||||
* @param int $seconds
|
||||
* @return $this
|
||||
*/
|
||||
public function waitUntil($script, $seconds = 5)
|
||||
{
|
||||
if (! Str::startsWith($script, 'return ')) {
|
||||
$script = 'return '.$script;
|
||||
}
|
||||
|
||||
if (! Str::endsWith($script, ';')) {
|
||||
$script = $script.';';
|
||||
}
|
||||
|
||||
return $this->waitUsing($seconds, 100, function () use ($script) {
|
||||
return $this->driver->executeScript($script);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the current page to reload.
|
||||
*
|
||||
* @param Closure $callback
|
||||
* @param int $seconds
|
||||
* @return $this
|
||||
*/
|
||||
public function waitForReload($callback = null, $seconds = 5)
|
||||
{
|
||||
$token = str_random();
|
||||
|
||||
$this->driver->executeScript("window['{$token}'] = {};");
|
||||
|
||||
if ($callback) {
|
||||
$callback($this);
|
||||
}
|
||||
|
||||
return $this->waitUsing($seconds, 100, function () use ($token) {
|
||||
return $this->driver->executeScript("return typeof window['{$token}'] === 'undefined';");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the given callback to be true.
|
||||
*
|
||||
* @param int $seconds
|
||||
* @param int $interval
|
||||
* @param Closure $callback
|
||||
* @param string|null $message
|
||||
* @return $this
|
||||
* @throws TimeOutException
|
||||
*/
|
||||
public function waitUsing($seconds, $interval, Closure $callback, $message = null)
|
||||
{
|
||||
$this->pause($interval);
|
||||
|
||||
$started = Carbon::now();
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
if ($callback()) {
|
||||
break;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
//
|
||||
}
|
||||
|
||||
if ($started->lt(Carbon::now()->subSeconds($seconds))) {
|
||||
throw new TimeOutException($message ?: "Waited {$seconds} seconds for callback.");
|
||||
}
|
||||
|
||||
$this->pause($interval);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
230
vendor/laravel/dusk/src/Console/DuskCommand.php
vendored
Normal file
230
vendor/laravel/dusk/src/Console/DuskCommand.php
vendored
Normal file
@@ -0,0 +1,230 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Dusk\Console;
|
||||
|
||||
use Dotenv\Dotenv;
|
||||
use Illuminate\Console\Command;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\Process\ProcessBuilder;
|
||||
use Symfony\Component\Process\Exception\RuntimeException;
|
||||
|
||||
class DuskCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'dusk';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Run the Dusk tests for the application';
|
||||
|
||||
/**
|
||||
* Indicates if the project has its own PHPUnit configuration.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasPhpUnitConfiguration = false;
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->ignoreValidationErrors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->purgeScreenshots();
|
||||
|
||||
$this->purgeConsoleLogs();
|
||||
|
||||
$options = array_slice($_SERVER['argv'], 2);
|
||||
|
||||
return $this->withDuskEnvironment(function () use ($options) {
|
||||
$process = (new ProcessBuilder())
|
||||
->setTimeout(null)
|
||||
->setPrefix($this->binary())
|
||||
->setArguments($this->phpunitArguments($options))
|
||||
->getProcess();
|
||||
|
||||
try {
|
||||
$process->setTty(true);
|
||||
} catch (RuntimeException $e) {
|
||||
$this->output->writeln('Warning: '.$e->getMessage());
|
||||
}
|
||||
|
||||
return $process->run(function ($type, $line) {
|
||||
$this->output->write($line);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the PHP binary to execute.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function binary()
|
||||
{
|
||||
return [PHP_BINARY, 'vendor/phpunit/phpunit/phpunit'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array of arguments for running PHPUnit.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function phpunitArguments($options)
|
||||
{
|
||||
return array_merge(['-c', base_path('phpunit.dusk.xml')], $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Purge the failure screenshots
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function purgeScreenshots()
|
||||
{
|
||||
$files = Finder::create()->files()
|
||||
->in(base_path('tests/Browser/screenshots'))
|
||||
->name('failure-*');
|
||||
|
||||
foreach ($files as $file) {
|
||||
@unlink($file->getRealPath());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Purge the console logs.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function purgeConsoleLogs()
|
||||
{
|
||||
$files = Finder::create()->files()
|
||||
->in(base_path('tests/Browser/console'))
|
||||
->name('*.log');
|
||||
|
||||
foreach ($files as $file) {
|
||||
@unlink($file->getRealPath());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the given callback with the Dusk configuration files.
|
||||
*
|
||||
* @param \Closure $callback
|
||||
* @return mixed
|
||||
*/
|
||||
protected function withDuskEnvironment($callback)
|
||||
{
|
||||
if (file_exists(base_path($this->duskFile()))) {
|
||||
if (file_get_contents(base_path('.env')) !== file_get_contents(base_path($this->duskFile()))) {
|
||||
$this->backupEnvironment();
|
||||
}
|
||||
|
||||
$this->refreshEnvironment();
|
||||
}
|
||||
|
||||
$this->writeConfiguration();
|
||||
|
||||
return tap($callback(), function () {
|
||||
$this->removeConfiguration();
|
||||
|
||||
if (file_exists(base_path($this->duskFile())) && file_exists(base_path('.env.backup'))) {
|
||||
$this->restoreEnvironment();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Backup the current environment file.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function backupEnvironment()
|
||||
{
|
||||
copy(base_path('.env'), base_path('.env.backup'));
|
||||
|
||||
copy(base_path($this->duskFile()), base_path('.env'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the backed-up environment file.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function restoreEnvironment()
|
||||
{
|
||||
copy(base_path('.env.backup'), base_path('.env'));
|
||||
|
||||
unlink(base_path('.env.backup'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the current environment variables.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function refreshEnvironment()
|
||||
{
|
||||
(new Dotenv(base_path()))->overload();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the Dusk PHPUnit configuration.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function writeConfiguration()
|
||||
{
|
||||
if (! file_exists($file = base_path('phpunit.dusk.xml'))) {
|
||||
copy(realpath(__DIR__.'/../../stubs/phpunit.xml'), $file);
|
||||
} else {
|
||||
$this->hasPhpUnitConfiguration = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the Dusk PHPUnit configuration.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function removeConfiguration()
|
||||
{
|
||||
if (! $this->hasPhpUnitConfiguration) {
|
||||
unlink(base_path('phpunit.dusk.xml'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the Dusk file for the environment.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function duskFile()
|
||||
{
|
||||
if (file_exists(base_path($file = '.env.dusk.'.$this->laravel->environment()))) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
return '.env.dusk';
|
||||
}
|
||||
}
|
95
vendor/laravel/dusk/src/Console/InstallCommand.php
vendored
Normal file
95
vendor/laravel/dusk/src/Console/InstallCommand.php
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Dusk\Console;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class InstallCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'dusk:install';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Install Dusk into the application';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
if (! is_dir(base_path('tests/Browser/Pages'))) {
|
||||
mkdir(base_path('tests/Browser/Pages'), 0755, true);
|
||||
}
|
||||
|
||||
if (! is_dir(base_path('tests/Browser/screenshots'))) {
|
||||
$this->createScreenshotsDirectory();
|
||||
}
|
||||
|
||||
if (! is_dir(base_path('tests/Browser/console'))) {
|
||||
$this->createConsoleDirectory();
|
||||
}
|
||||
|
||||
$subs = [
|
||||
'ExampleTest.stub' => base_path('tests/Browser/ExampleTest.php'),
|
||||
'HomePage.stub' => base_path('tests/Browser/Pages/HomePage.php'),
|
||||
'DuskTestCase.stub' => base_path('tests/DuskTestCase.php'),
|
||||
'Page.stub' => base_path('tests/Browser/Pages/Page.php'),
|
||||
];
|
||||
|
||||
foreach ($subs as $stub => $file) {
|
||||
if (! is_file($file)) {
|
||||
copy(__DIR__.'/../../stubs/'.$stub, $file);
|
||||
}
|
||||
}
|
||||
|
||||
$this->info('Dusk scaffolding installed successfully.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the screenshots directory.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function createScreenshotsDirectory()
|
||||
{
|
||||
mkdir(base_path('tests/Browser/screenshots'), 0755, true);
|
||||
|
||||
file_put_contents(base_path('tests/Browser/screenshots/.gitignore'), '*
|
||||
!.gitignore
|
||||
');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the console directory.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function createConsoleDirectory()
|
||||
{
|
||||
mkdir(base_path('tests/Browser/console'), 0755, true);
|
||||
|
||||
file_put_contents(base_path('tests/Browser/console/.gitignore'), '*
|
||||
!.gitignore
|
||||
');
|
||||
}
|
||||
}
|
73
vendor/laravel/dusk/src/Console/MakeCommand.php
vendored
Normal file
73
vendor/laravel/dusk/src/Console/MakeCommand.php
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Dusk\Console;
|
||||
|
||||
use Illuminate\Console\GeneratorCommand;
|
||||
|
||||
class MakeCommand extends GeneratorCommand
|
||||
{
|
||||
/**
|
||||
* The console command name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'dusk:make {name : The name of the class}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Create a new Dusk test class';
|
||||
|
||||
/**
|
||||
* The type of class being generated.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $type = 'Test';
|
||||
|
||||
/**
|
||||
* Get the stub file for the generator.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getStub()
|
||||
{
|
||||
return __DIR__.'/stubs/test.stub';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
protected function getPath($name)
|
||||
{
|
||||
$name = str_replace_first($this->rootNamespace(), '', $name);
|
||||
|
||||
return $this->laravel->basePath().'/tests'.str_replace('\\', '/', $name).'.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default namespace for the class.
|
||||
*
|
||||
* @param string $rootNamespace
|
||||
* @return string
|
||||
*/
|
||||
protected function getDefaultNamespace($rootNamespace)
|
||||
{
|
||||
return $rootNamespace.'\Browser';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return 'Tests';
|
||||
}
|
||||
}
|
73
vendor/laravel/dusk/src/Console/PageCommand.php
vendored
Normal file
73
vendor/laravel/dusk/src/Console/PageCommand.php
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Dusk\Console;
|
||||
|
||||
use Illuminate\Console\GeneratorCommand;
|
||||
|
||||
class PageCommand extends GeneratorCommand
|
||||
{
|
||||
/**
|
||||
* The console command name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'dusk:page {name : The name of the class}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Create a new Dusk page class';
|
||||
|
||||
/**
|
||||
* The type of class being generated.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $type = 'Page';
|
||||
|
||||
/**
|
||||
* Get the stub file for the generator.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getStub()
|
||||
{
|
||||
return __DIR__.'/stubs/page.stub';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the destination class path.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
protected function getPath($name)
|
||||
{
|
||||
$name = str_replace_first($this->rootNamespace(), '', $name);
|
||||
|
||||
return $this->laravel->basePath().'/tests'.str_replace('\\', '/', $name).'.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default namespace for the class.
|
||||
*
|
||||
* @param string $rootNamespace
|
||||
* @return string
|
||||
*/
|
||||
protected function getDefaultNamespace($rootNamespace)
|
||||
{
|
||||
return $rootNamespace.'\Browser\Pages';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return 'Tests';
|
||||
}
|
||||
}
|
42
vendor/laravel/dusk/src/Console/stubs/page.stub
vendored
Normal file
42
vendor/laravel/dusk/src/Console/stubs/page.stub
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace DummyNamespace;
|
||||
|
||||
use Laravel\Dusk\Browser;
|
||||
use Laravel\Dusk\Page as BasePage;
|
||||
|
||||
class DummyClass extends BasePage
|
||||
{
|
||||
/**
|
||||
* Get the URL for the page.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function url()
|
||||
{
|
||||
return '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the browser is on the page.
|
||||
*
|
||||
* @param Browser $browser
|
||||
* @return void
|
||||
*/
|
||||
public function assert(Browser $browser)
|
||||
{
|
||||
$browser->assertPathIs($this->url());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the element shortcuts for the page.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function elements()
|
||||
{
|
||||
return [
|
||||
'@element' => '#selector',
|
||||
];
|
||||
}
|
||||
}
|
23
vendor/laravel/dusk/src/Console/stubs/test.stub
vendored
Normal file
23
vendor/laravel/dusk/src/Console/stubs/test.stub
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace DummyNamespace;
|
||||
|
||||
use Tests\DuskTestCase;
|
||||
use Laravel\Dusk\Browser;
|
||||
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||
|
||||
class DummyClass extends DuskTestCase
|
||||
{
|
||||
/**
|
||||
* A Dusk test example.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testExample()
|
||||
{
|
||||
$this->browse(function (Browser $browser) {
|
||||
$browser->visit('/')
|
||||
->assertSee('Laravel');
|
||||
});
|
||||
}
|
||||
}
|
44
vendor/laravel/dusk/src/Dusk.php
vendored
Normal file
44
vendor/laravel/dusk/src/Dusk.php
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Dusk;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
class Dusk
|
||||
{
|
||||
/**
|
||||
* Register the Dusk service provider.
|
||||
*
|
||||
* @param array $options
|
||||
* @return void
|
||||
*/
|
||||
public static function register(array $options = [])
|
||||
{
|
||||
if (static::duskEnvironment($options)) {
|
||||
app()->register(DuskServiceProvider::class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if Dusk may run in this environment.
|
||||
*
|
||||
* @param array $options
|
||||
* @return bool
|
||||
*/
|
||||
protected static function duskEnvironment($options)
|
||||
{
|
||||
if (! isset($options['environments'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_string($options['environments'])) {
|
||||
$options['environments'] = [$options['environments']];
|
||||
}
|
||||
|
||||
if (! is_array($options['environments'])) {
|
||||
throw new InvalidArgumentException("Dusk environments must be listed as an array.");
|
||||
}
|
||||
|
||||
return app()->environment(...$options['environments']);
|
||||
}
|
||||
}
|
55
vendor/laravel/dusk/src/DuskServiceProvider.php
vendored
Normal file
55
vendor/laravel/dusk/src/DuskServiceProvider.php
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Dusk;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class DuskServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap any package services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
Route::get('/_dusk/login/{userId}/{guard?}', [
|
||||
'middleware' => 'web',
|
||||
'uses' => 'Laravel\Dusk\Http\Controllers\UserController@login',
|
||||
]);
|
||||
|
||||
Route::get('/_dusk/logout/{guard?}', [
|
||||
'middleware' => 'web',
|
||||
'uses' => 'Laravel\Dusk\Http\Controllers\UserController@logout',
|
||||
]);
|
||||
|
||||
Route::get('/_dusk/user/{guard?}', [
|
||||
'middleware' => 'web',
|
||||
'uses' => 'Laravel\Dusk\Http\Controllers\UserController@user',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register any package services.
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
if ($this->app->environment('production')) {
|
||||
throw new Exception('It is unsafe to run Dusk in production.');
|
||||
}
|
||||
|
||||
if ($this->app->runningInConsole()) {
|
||||
$this->commands([
|
||||
Console\InstallCommand::class,
|
||||
Console\DuskCommand::class,
|
||||
Console\MakeCommand::class,
|
||||
Console\PageCommand::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
377
vendor/laravel/dusk/src/ElementResolver.php
vendored
Normal file
377
vendor/laravel/dusk/src/ElementResolver.php
vendored
Normal file
@@ -0,0 +1,377 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Dusk;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Support\Str;
|
||||
use InvalidArgumentException;
|
||||
use Facebook\WebDriver\WebDriverBy;
|
||||
use Illuminate\Support\Traits\Macroable;
|
||||
|
||||
class ElementResolver
|
||||
{
|
||||
use Macroable;
|
||||
|
||||
/**
|
||||
* The remote web driver instance.
|
||||
*
|
||||
* @var \Facebook\WebDriver\Remote\RemoteWebDriver
|
||||
*/
|
||||
public $driver;
|
||||
|
||||
/**
|
||||
* The selector prefix for the resolver.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $prefix;
|
||||
|
||||
/**
|
||||
* Set the elements the resolver should use as shortcuts.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $elements = [];
|
||||
|
||||
/**
|
||||
* The button finding methods.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $buttonFinders = [
|
||||
'findById',
|
||||
'findButtonBySelector',
|
||||
'findButtonByName',
|
||||
'findButtonByValue',
|
||||
'findButtonByText'
|
||||
];
|
||||
|
||||
/**
|
||||
* Create a new element resolver instance.
|
||||
*
|
||||
* @param \Facebook\WebDriver\Remote\RemoteWebDriver $driver
|
||||
* @param string $prefix
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($driver, $prefix = 'body')
|
||||
{
|
||||
$this->driver = $driver;
|
||||
$this->prefix = trim($prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the page elements the resolver should use as shortcuts.
|
||||
*
|
||||
* @param array $elements
|
||||
* @return $this
|
||||
*/
|
||||
public function pageElements(array $elements)
|
||||
{
|
||||
$this->elements = $elements;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the element for a given input "field".
|
||||
*
|
||||
* @param string $field
|
||||
* @return \Facebook\WebDriver\Remote\RemoteWebElement
|
||||
*/
|
||||
public function resolveForTyping($field)
|
||||
{
|
||||
if (! is_null($element = $this->findById($field))) {
|
||||
return $element;
|
||||
}
|
||||
|
||||
return $this->firstOrFail([
|
||||
$field, "input[name='{$field}']", "textarea[name='{$field}']"
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the element for a given select "field".
|
||||
*
|
||||
* @param string $field
|
||||
* @return \Facebook\WebDriver\Remote\RemoteWebElement
|
||||
*/
|
||||
public function resolveForSelection($field)
|
||||
{
|
||||
if (! is_null($element = $this->findById($field))) {
|
||||
return $element;
|
||||
}
|
||||
|
||||
return $this->firstOrFail([
|
||||
$field, "select[name='{$field}']"
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve all the options with the given value on the select field.
|
||||
*
|
||||
* @param string $field
|
||||
* @param array $values
|
||||
* @return array
|
||||
*/
|
||||
public function resolveSelectOptions($field, array $values)
|
||||
{
|
||||
$options = $this->resolveForSelection($field)
|
||||
->findElements(WebDriverBy::tagName('option'));
|
||||
|
||||
if (empty($options)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return array_filter($options, function($option) use ($values) {
|
||||
return in_array($option->getAttribute('value'), $values);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the element for a given radio "field" / value.
|
||||
*
|
||||
* @param string $field
|
||||
* @param string $value
|
||||
* @return \Facebook\WebDriver\Remote\RemoteWebElement
|
||||
*/
|
||||
public function resolveForRadioSelection($field, $value = null)
|
||||
{
|
||||
if (! is_null($element = $this->findById($field))) {
|
||||
return $element;
|
||||
}
|
||||
|
||||
if (is_null($value)) {
|
||||
throw new InvalidArgumentException(
|
||||
"No value was provided for radio button [{$field}]."
|
||||
);
|
||||
}
|
||||
|
||||
return $this->firstOrFail([
|
||||
$field, "input[type=radio][name='{$field}'][value='{$value}']"
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the element for a given checkbox "field".
|
||||
*
|
||||
* @param string $field
|
||||
* @param string $value
|
||||
* @return \Facebook\WebDriver\Remote\RemoteWebElement
|
||||
*/
|
||||
public function resolveForChecking($field, $value = null)
|
||||
{
|
||||
if (! is_null($element = $this->findById($field))) {
|
||||
return $element;
|
||||
}
|
||||
|
||||
$selector = "input[type=checkbox][name='{$field}']";
|
||||
|
||||
if (! is_null($value)) {
|
||||
$selector .= "[value='{$value}']";
|
||||
}
|
||||
|
||||
return $this->firstOrFail([
|
||||
$field, $selector
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the element for a given file "field".
|
||||
*
|
||||
* @param string $field
|
||||
* @return \Facebook\WebDriver\Remote\RemoteWebElement
|
||||
*/
|
||||
public function resolveForAttachment($field)
|
||||
{
|
||||
if (! is_null($element = $this->findById($field))) {
|
||||
return $element;
|
||||
}
|
||||
|
||||
return $this->firstOrFail([
|
||||
$field, "input[type=file][name='{$field}']"
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the element for a given button.
|
||||
*
|
||||
* @param string $button
|
||||
* @return \Facebook\WebDriver\Remote\RemoteWebElement
|
||||
*/
|
||||
public function resolveForButtonPress($button)
|
||||
{
|
||||
foreach ($this->buttonFinders as $method) {
|
||||
if (! is_null($element = $this->{$method}($button))) {
|
||||
return $element;
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException(
|
||||
"Unable to locate button [{$button}]."
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the element for a given button by selector.
|
||||
*
|
||||
* @param string $button
|
||||
* @return \Facebook\WebDriver\Remote\RemoteWebElement|null
|
||||
*/
|
||||
protected function findButtonBySelector($button)
|
||||
{
|
||||
if (! is_null($element = $this->find($button))) {
|
||||
return $element;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the element for a given button by name.
|
||||
*
|
||||
* @param string $button
|
||||
* @return \Facebook\WebDriver\Remote\RemoteWebElement|null
|
||||
*/
|
||||
protected function findButtonByName($button)
|
||||
{
|
||||
if (! is_null($element = $this->find("input[type=submit][name='{$button}']")) ||
|
||||
! is_null($element = $this->find("input[type=button][value='{$button}']")) ||
|
||||
! is_null($element = $this->find("button[name='{$button}']"))) {
|
||||
return $element;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the element for a given button by value.
|
||||
*
|
||||
* @param string $button
|
||||
* @return \Facebook\WebDriver\Remote\RemoteWebElement|null
|
||||
*/
|
||||
protected function findButtonByValue($button)
|
||||
{
|
||||
foreach ($this->all("input[type=submit]") as $element) {
|
||||
if ($element->getAttribute('value') === $button) {
|
||||
return $element;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the element for a given button by text.
|
||||
*
|
||||
* @param string $button
|
||||
* @return \Facebook\WebDriver\Remote\RemoteWebElement|null
|
||||
*/
|
||||
protected function findButtonByText($button)
|
||||
{
|
||||
foreach ($this->all('button') as $element) {
|
||||
if (Str::contains($element->getText(), $button)) {
|
||||
return $element;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to find the selector by ID.
|
||||
*
|
||||
* @param string $selector
|
||||
* @return \Facebook\WebDriver\Remote\RemoteWebElement|null
|
||||
*/
|
||||
protected function findById($selector)
|
||||
{
|
||||
if (preg_match('/^#[\w\-:]+$/', $selector)) {
|
||||
return $this->driver->findElement(WebDriverBy::id(substr($selector, 1)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an element by the given selector or return null.
|
||||
*
|
||||
* @param string $selector
|
||||
* @return \Facebook\WebDriver\Remote\RemoteWebElement|null
|
||||
*/
|
||||
public function find($selector)
|
||||
{
|
||||
try {
|
||||
return $this->findOrFail($selector);
|
||||
} catch (Exception $e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first element matching the given selectors.
|
||||
*
|
||||
* @param array $selectors
|
||||
* @return \Facebook\WebDriver\Remote\RemoteWebElement
|
||||
*/
|
||||
public function firstOrFail($selectors)
|
||||
{
|
||||
foreach ((array) $selectors as $selector) {
|
||||
try {
|
||||
return $this->findOrFail($selector);
|
||||
} catch (Exception $e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an element by the given selector or throw an exception.
|
||||
*
|
||||
* @param string $selector
|
||||
* @return \Facebook\WebDriver\Remote\RemoteWebElement
|
||||
*/
|
||||
public function findOrFail($selector)
|
||||
{
|
||||
if (! is_null($element = $this->findById($selector))) {
|
||||
return $element;
|
||||
}
|
||||
|
||||
return $this->driver->findElement(
|
||||
WebDriverBy::cssSelector($this->format($selector))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the elements by the given selector or return an empty array.
|
||||
*
|
||||
* @param string $selector
|
||||
* @return array
|
||||
*/
|
||||
public function all($selector)
|
||||
{
|
||||
try {
|
||||
return $this->driver->findElements(
|
||||
WebDriverBy::cssSelector($this->format($selector))
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
//
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the given selector with the current prefix.
|
||||
*
|
||||
* @param string $selector
|
||||
* @return string
|
||||
*/
|
||||
public function format($selector)
|
||||
{
|
||||
$sortedElements = collect($this->elements)->sortByDesc(function($element, $key){
|
||||
return strlen($key);
|
||||
})->toArray();
|
||||
|
||||
$selector = str_replace(
|
||||
array_keys($sortedElements), array_values($sortedElements), $originalSelector = $selector
|
||||
);
|
||||
|
||||
if (starts_with($selector, '@') && $selector === $originalSelector) {
|
||||
$selector = '[dusk="'.explode('@', $selector)[1].'"]';
|
||||
}
|
||||
|
||||
return trim($this->prefix.' '.$selector);
|
||||
}
|
||||
}
|
74
vendor/laravel/dusk/src/Http/Controllers/UserController.php
vendored
Normal file
74
vendor/laravel/dusk/src/Http/Controllers/UserController.php
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Dusk\Http\Controllers;
|
||||
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class UserController
|
||||
{
|
||||
/**
|
||||
* Retrieve the authenticated user identifier and class name.
|
||||
*
|
||||
* @param string|null $guard
|
||||
* @return array
|
||||
*/
|
||||
public function user($guard = null)
|
||||
{
|
||||
$user = Auth::guard($guard)->user();
|
||||
|
||||
if (! $user) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => $user->getAuthIdentifier(),
|
||||
'className' => get_class($user),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Login using the given user ID / email.
|
||||
*
|
||||
* @param string $userId
|
||||
* @param string $guard
|
||||
* @return Response
|
||||
*/
|
||||
public function login($userId, $guard = null)
|
||||
{
|
||||
$model = $this->modelForGuard(
|
||||
$guard = $guard ?: config('auth.defaults.guard')
|
||||
);
|
||||
|
||||
if (str_contains($userId, '@')) {
|
||||
$user = (new $model)->where('email', $userId)->first();
|
||||
} else {
|
||||
$user = (new $model)->find($userId);
|
||||
}
|
||||
|
||||
Auth::guard($guard)->login($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the user out of the application.
|
||||
*
|
||||
* @param string $guard
|
||||
* @return Response
|
||||
*/
|
||||
public function logout($guard = null)
|
||||
{
|
||||
Auth::guard($guard ?: config('auth.defaults.guard'))->logout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the model for the given guard.
|
||||
*
|
||||
* @param string $guard
|
||||
* @return string
|
||||
*/
|
||||
protected function modelForGuard($guard)
|
||||
{
|
||||
$provider = config("auth.guards.{$guard}.provider");
|
||||
|
||||
return config("auth.providers.{$provider}.model");
|
||||
}
|
||||
}
|
44
vendor/laravel/dusk/src/Page.php
vendored
Normal file
44
vendor/laravel/dusk/src/Page.php
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Dusk;
|
||||
|
||||
abstract class Page
|
||||
{
|
||||
/**
|
||||
* Get the URL for the page.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function url();
|
||||
|
||||
/**
|
||||
* Assert that the browser is on the page.
|
||||
*
|
||||
* @param \Laravel\Dusk\Browser $browser
|
||||
* @return void
|
||||
*/
|
||||
public function assert(Browser $browser)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the element shortcuts for the page.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function elements()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the global element shortcuts for the site.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function siteElements()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
118
vendor/laravel/dusk/src/SupportsChrome.php
vendored
Normal file
118
vendor/laravel/dusk/src/SupportsChrome.php
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Dusk;
|
||||
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Process\Process;
|
||||
use Symfony\Component\Process\ProcessBuilder;
|
||||
|
||||
trait SupportsChrome
|
||||
{
|
||||
/**
|
||||
* The path to the custom Chromedriver binary.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected static $chromeDriver;
|
||||
|
||||
/**
|
||||
* The Chromedriver process instance.
|
||||
*
|
||||
* @var \Symfony\Component\Process\Process
|
||||
*/
|
||||
protected static $chromeProcess;
|
||||
|
||||
/**
|
||||
* Start the Chromedriver process.
|
||||
*
|
||||
* @throws \RuntimeException if the driver file path doesn't exist.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function startChromeDriver()
|
||||
{
|
||||
static::$chromeProcess = static::buildChromeProcess();
|
||||
|
||||
static::$chromeProcess->start();
|
||||
|
||||
static::afterClass(function () {
|
||||
static::stopChromeDriver();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the Chromedriver process.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function stopChromeDriver()
|
||||
{
|
||||
if (static::$chromeProcess) {
|
||||
static::$chromeProcess->stop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the process to run the Chromedriver.
|
||||
*
|
||||
* @throws \RuntimeException if the driver file path doesn't exist.
|
||||
*
|
||||
* @return \Symfony\Component\Process\Process
|
||||
*/
|
||||
protected static function buildChromeProcess()
|
||||
{
|
||||
$driver = static::$chromeDriver
|
||||
?: realpath(__DIR__.'/../bin/chromedriver-'.static::driverSuffix());
|
||||
|
||||
if (realpath($driver) === false) {
|
||||
throw new RuntimeException("Invalid path to Chromedriver [{$driver}].");
|
||||
}
|
||||
|
||||
return (new ProcessBuilder())
|
||||
->setPrefix(realpath($driver))
|
||||
->getProcess()
|
||||
->setEnv(static::chromeEnvironment());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the path to the custom Chromedriver.
|
||||
*
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
public static function useChromedriver($path)
|
||||
{
|
||||
static::$chromeDriver = $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Chromedriver environment variables.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function chromeEnvironment()
|
||||
{
|
||||
if (PHP_OS === 'Darwin' || PHP_OS === 'WINNT') {
|
||||
return [];
|
||||
}
|
||||
|
||||
return ['DISPLAY' => ':0'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the suffix for the Chromedriver binary.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function driverSuffix()
|
||||
{
|
||||
switch (PHP_OS) {
|
||||
case 'Darwin':
|
||||
return 'mac';
|
||||
case 'WINNT':
|
||||
return 'win.exe';
|
||||
default:
|
||||
return 'linux';
|
||||
}
|
||||
}
|
||||
}
|
245
vendor/laravel/dusk/src/TestCase.php
vendored
Normal file
245
vendor/laravel/dusk/src/TestCase.php
vendored
Normal file
@@ -0,0 +1,245 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Dusk;
|
||||
|
||||
use Closure;
|
||||
use Exception;
|
||||
use Throwable;
|
||||
use ReflectionFunction;
|
||||
use Illuminate\Support\Collection;
|
||||
use Facebook\WebDriver\Remote\RemoteWebDriver;
|
||||
use Facebook\WebDriver\Remote\DesiredCapabilities;
|
||||
use Illuminate\Foundation\Testing\TestCase as FoundationTestCase;
|
||||
|
||||
abstract class TestCase extends FoundationTestCase
|
||||
{
|
||||
use SupportsChrome;
|
||||
|
||||
/**
|
||||
* All of the active browser instances.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $browsers = [];
|
||||
|
||||
/**
|
||||
* The callbacks that should be run on class tear down.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $afterClassCallbacks = [];
|
||||
|
||||
/**
|
||||
* Register the base URL with Dusk.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
Browser::$baseUrl = $this->baseUrl();
|
||||
|
||||
Browser::$storeScreenshotsAt = base_path('tests/Browser/screenshots');
|
||||
|
||||
Browser::$storeConsoleLogAt = base_path('tests/Browser/console');
|
||||
|
||||
Browser::$userResolver = function () {
|
||||
return $this->user();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Tear down the Dusk test case class.
|
||||
*
|
||||
* @afterClass
|
||||
* @return void
|
||||
*/
|
||||
public static function tearDownDuskClass()
|
||||
{
|
||||
static::closeAll();
|
||||
|
||||
foreach (static::$afterClassCallbacks as $callback) {
|
||||
$callback();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an "after class" tear down callback.
|
||||
*
|
||||
* @param \Closure $callback
|
||||
* @return void
|
||||
*/
|
||||
public static function afterClass(Closure $callback)
|
||||
{
|
||||
static::$afterClassCallbacks[] = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new browser instance.
|
||||
*
|
||||
* @param \Closure $callback
|
||||
* @return \Laravel\Dusk\Browser|void
|
||||
* @throws \Exception
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function browse(Closure $callback)
|
||||
{
|
||||
$browsers = $this->createBrowsersFor($callback);
|
||||
|
||||
try {
|
||||
$callback(...$browsers->all());
|
||||
} catch (Exception $e) {
|
||||
$this->captureFailuresFor($browsers);
|
||||
|
||||
throw $e;
|
||||
} catch (Throwable $e) {
|
||||
$this->captureFailuresFor($browsers);
|
||||
|
||||
throw $e;
|
||||
} finally {
|
||||
$this->storeConsoleLogsFor($browsers);
|
||||
|
||||
static::$browsers = $this->closeAllButPrimary($browsers);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the browser instances needed for the given callback.
|
||||
*
|
||||
* @param \Closure $callback
|
||||
* @return array
|
||||
*/
|
||||
protected function createBrowsersFor(Closure $callback)
|
||||
{
|
||||
if (count(static::$browsers) === 0) {
|
||||
static::$browsers = collect([$this->newBrowser($this->createWebDriver())]);
|
||||
}
|
||||
|
||||
$additional = $this->browsersNeededFor($callback) - 1;
|
||||
|
||||
for ($i = 0; $i < $additional; $i++) {
|
||||
static::$browsers->push($this->newBrowser($this->createWebDriver()));
|
||||
}
|
||||
|
||||
return static::$browsers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Browser instance.
|
||||
*
|
||||
* @param \Facebook\WebDriver\Remote\RemoteWebDriver $driver
|
||||
* @return \Laravel\Dusk\Browser
|
||||
*/
|
||||
protected function newBrowser($driver)
|
||||
{
|
||||
return new Browser($driver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of browsers needed for a given callback.
|
||||
*
|
||||
* @param \Closure $callback
|
||||
* @return int
|
||||
*/
|
||||
protected function browsersNeededFor(Closure $callback)
|
||||
{
|
||||
return (new ReflectionFunction($callback))->getNumberOfParameters();
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture failure screenshots for each browser.
|
||||
*
|
||||
* @param \Illuminate\Support\Collection $browsers
|
||||
* @return void
|
||||
*/
|
||||
protected function captureFailuresFor($browsers)
|
||||
{
|
||||
$browsers->each(function ($browser, $key) {
|
||||
$browser->screenshot('failure-'.$this->getName().'-'.$key);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the console output for the given browsers.
|
||||
*
|
||||
* @param \Illuminate\Support\Collection $browsers
|
||||
* @return void
|
||||
*/
|
||||
protected function storeConsoleLogsFor($browsers)
|
||||
{
|
||||
$browsers->each(function ($browser, $key) {
|
||||
$browser->storeConsoleLog($this->getName().'-'.$key);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Close all of the browsers except the primary (first) one.
|
||||
*
|
||||
* @param \Illuminate\Support\Collection $browsers
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
protected function closeAllButPrimary($browsers)
|
||||
{
|
||||
$browsers->slice(1)->each->quit();
|
||||
|
||||
return $browsers->take(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close all of the active browsers.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function closeAll()
|
||||
{
|
||||
Collection::make(static::$browsers)->each->quit();
|
||||
|
||||
static::$browsers = collect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the remote web driver instance.
|
||||
*
|
||||
* @return \Facebook\WebDriver\Remote\RemoteWebDriver
|
||||
*/
|
||||
protected function createWebDriver()
|
||||
{
|
||||
return retry(5, function () {
|
||||
return $this->driver();
|
||||
}, 50);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the RemoteWebDriver instance.
|
||||
*
|
||||
* @return \Facebook\WebDriver\Remote\RemoteWebDriver
|
||||
*/
|
||||
protected function driver()
|
||||
{
|
||||
return RemoteWebDriver::create(
|
||||
'http://localhost:9515', DesiredCapabilities::chrome()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the application's base URL.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected function baseUrl()
|
||||
{
|
||||
return config('app.url');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a callback that returns the default user to authenticate.
|
||||
*
|
||||
* @return \Closure
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function user()
|
||||
{
|
||||
throw new Exception("User resolver has not been set.");
|
||||
}
|
||||
}
|
43
vendor/laravel/dusk/stubs/DuskTestCase.stub
vendored
Normal file
43
vendor/laravel/dusk/stubs/DuskTestCase.stub
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use Laravel\Dusk\TestCase as BaseTestCase;
|
||||
use Facebook\WebDriver\Chrome\ChromeOptions;
|
||||
use Facebook\WebDriver\Remote\RemoteWebDriver;
|
||||
use Facebook\WebDriver\Remote\DesiredCapabilities;
|
||||
|
||||
abstract class DuskTestCase extends BaseTestCase
|
||||
{
|
||||
use CreatesApplication;
|
||||
|
||||
/**
|
||||
* Prepare for Dusk test execution.
|
||||
*
|
||||
* @beforeClass
|
||||
* @return void
|
||||
*/
|
||||
public static function prepare()
|
||||
{
|
||||
static::startChromeDriver();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the RemoteWebDriver instance.
|
||||
*
|
||||
* @return \Facebook\WebDriver\Remote\RemoteWebDriver
|
||||
*/
|
||||
protected function driver()
|
||||
{
|
||||
$options = (new ChromeOptions)->addArguments([
|
||||
'--disable-gpu',
|
||||
'--headless'
|
||||
]);
|
||||
|
||||
return RemoteWebDriver::create(
|
||||
'http://localhost:9515', DesiredCapabilities::chrome()->setCapability(
|
||||
ChromeOptions::CAPABILITY, $options
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
23
vendor/laravel/dusk/stubs/ExampleTest.stub
vendored
Normal file
23
vendor/laravel/dusk/stubs/ExampleTest.stub
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser;
|
||||
|
||||
use Tests\DuskTestCase;
|
||||
use Laravel\Dusk\Browser;
|
||||
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||
|
||||
class ExampleTest extends DuskTestCase
|
||||
{
|
||||
/**
|
||||
* A basic browser test example.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testBasicExample()
|
||||
{
|
||||
$this->browse(function (Browser $browser) {
|
||||
$browser->visit('/')
|
||||
->assertSee('Laravel');
|
||||
});
|
||||
}
|
||||
}
|
41
vendor/laravel/dusk/stubs/HomePage.stub
vendored
Normal file
41
vendor/laravel/dusk/stubs/HomePage.stub
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser\Pages;
|
||||
|
||||
use Laravel\Dusk\Browser;
|
||||
|
||||
class HomePage extends Page
|
||||
{
|
||||
/**
|
||||
* Get the URL for the page.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function url()
|
||||
{
|
||||
return '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the browser is on the page.
|
||||
*
|
||||
* @param Browser $browser
|
||||
* @return void
|
||||
*/
|
||||
public function assert(Browser $browser)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the element shortcuts for the page.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function elements()
|
||||
{
|
||||
return [
|
||||
'@element' => '#selector',
|
||||
];
|
||||
}
|
||||
}
|
20
vendor/laravel/dusk/stubs/Page.stub
vendored
Normal file
20
vendor/laravel/dusk/stubs/Page.stub
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser\Pages;
|
||||
|
||||
use Laravel\Dusk\Page as BasePage;
|
||||
|
||||
abstract class Page extends BasePage
|
||||
{
|
||||
/**
|
||||
* Get the global element shortcuts for the site.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function siteElements()
|
||||
{
|
||||
return [
|
||||
'@element' => '#selector',
|
||||
];
|
||||
}
|
||||
}
|
21
vendor/laravel/dusk/stubs/phpunit.xml
vendored
Normal file
21
vendor/laravel/dusk/stubs/phpunit.xml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
bootstrap="vendor/autoload.php"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false">
|
||||
<testsuites>
|
||||
<testsuite name="Browser Test Suite">
|
||||
<directory suffix="Test.php">./tests/Browser</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<filter>
|
||||
<whitelist processUncoveredFilesFromWhitelist="true">
|
||||
<directory suffix=".php">./app</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</phpunit>
|
Reference in New Issue
Block a user