Laravel 5.6 updates
Travis config update Removed HHVM script as Laravel no longer support HHVM after releasing 5.3
This commit is contained in:
BIN
vendor/laravel/dusk/bin/chromedriver-linux
vendored
BIN
vendor/laravel/dusk/bin/chromedriver-linux
vendored
Binary file not shown.
BIN
vendor/laravel/dusk/bin/chromedriver-mac
vendored
BIN
vendor/laravel/dusk/bin/chromedriver-mac
vendored
Binary file not shown.
BIN
vendor/laravel/dusk/bin/chromedriver-win.exe
vendored
BIN
vendor/laravel/dusk/bin/chromedriver-win.exe
vendored
Binary file not shown.
18
vendor/laravel/dusk/composer.json
vendored
18
vendor/laravel/dusk/composer.json
vendored
@@ -10,17 +10,17 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.6.4",
|
||||
"facebook/webdriver": "~1.0",
|
||||
"php": ">=7.1.0",
|
||||
"facebook/webdriver": "~1.3",
|
||||
"nesbot/carbon": "~1.20",
|
||||
"illuminate/console": "~5.5",
|
||||
"illuminate/support": "~5.5",
|
||||
"symfony/console": "~3.2",
|
||||
"symfony/process": "~3.2"
|
||||
"illuminate/console": "~5.6",
|
||||
"illuminate/support": "~5.6",
|
||||
"symfony/console": "~4.0",
|
||||
"symfony/process": "~4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^5.7",
|
||||
"mockery/mockery": "^0.9.6"
|
||||
"mockery/mockery": "~1.0",
|
||||
"phpunit/phpunit": "~7.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
@@ -29,7 +29,7 @@
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0-dev"
|
||||
"dev-master": "4.0-dev"
|
||||
},
|
||||
"laravel": {
|
||||
"providers": [
|
||||
|
1
vendor/laravel/dusk/phpunit.xml.dist
vendored
1
vendor/laravel/dusk/phpunit.xml.dist
vendored
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
beStrictAboutTestsThatDoNotTestAnything="false"
|
||||
bootstrap="vendor/autoload.php"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
|
71
vendor/laravel/dusk/src/Browser.php
vendored
71
vendor/laravel/dusk/src/Browser.php
vendored
@@ -7,6 +7,7 @@ use BadMethodCallException;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Traits\Macroable;
|
||||
use Facebook\WebDriver\WebDriverDimension;
|
||||
use Facebook\WebDriver\Remote\WebDriverBrowserType;
|
||||
|
||||
class Browser
|
||||
{
|
||||
@@ -42,6 +43,16 @@ class Browser
|
||||
*/
|
||||
public static $storeConsoleLogAt;
|
||||
|
||||
/**
|
||||
* The browsers that support retrieving logs.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $supportsRemoteLogs = [
|
||||
WebDriverBrowserType::CHROME,
|
||||
WebDriverBrowserType::PHANTOMJS,
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the callback which resolves the default user to authenticate.
|
||||
*
|
||||
@@ -49,6 +60,13 @@ class Browser
|
||||
*/
|
||||
public static $userResolver;
|
||||
|
||||
/**
|
||||
* The default wait time in seconds.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public static $waitSeconds = 5;
|
||||
|
||||
/**
|
||||
* The RemoteWebDriver instance.
|
||||
*
|
||||
@@ -70,6 +88,13 @@ class Browser
|
||||
*/
|
||||
public $page;
|
||||
|
||||
/**
|
||||
* The component object currently being viewed.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $component;
|
||||
|
||||
/**
|
||||
* Create a browser instance.
|
||||
*
|
||||
@@ -87,7 +112,7 @@ class Browser
|
||||
/**
|
||||
* Browse to the given URL.
|
||||
*
|
||||
* @param string $url
|
||||
* @param string|Page $url
|
||||
* @return $this
|
||||
*/
|
||||
public function visit($url)
|
||||
@@ -229,13 +254,15 @@ class Browser
|
||||
*/
|
||||
public function storeConsoleLog($name)
|
||||
{
|
||||
$console = $this->driver->manage()->getLog('browser');
|
||||
if (in_array($this->driver->getCapabilities()->getBrowserName(), static::$supportsRemoteLogs)) {
|
||||
$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)
|
||||
);
|
||||
if (!empty($console)) {
|
||||
file_put_contents(
|
||||
sprintf('%s/%s.log', rtrim(static::$storeConsoleLogAt, '/'), $name)
|
||||
, json_encode($console, JSON_PRETTY_PRINT)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -270,11 +297,33 @@ class Browser
|
||||
$browser->on($this->page);
|
||||
}
|
||||
|
||||
if ($selector instanceof Component) {
|
||||
$browser->onComponent($selector, $this->resolver);
|
||||
}
|
||||
|
||||
call_user_func($callback, $browser);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function onComponent($component, $parentResolver)
|
||||
{
|
||||
$this->component = $component;
|
||||
|
||||
// Here we will set the component elements on the resolver instance, which will allow
|
||||
// the developer to access short-cuts for CSS selectors on the component which can
|
||||
// allow for more expressive navigation and interaction with all the components.
|
||||
$this->resolver->pageElements(
|
||||
$component->elements() + $parentResolver->elements
|
||||
);
|
||||
|
||||
$component->assert($this);
|
||||
|
||||
$this->resolver->prefix = $this->resolver->format(
|
||||
$component->selector()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that jQuery is available on the page.
|
||||
*
|
||||
@@ -373,6 +422,14 @@ class Browser
|
||||
return $this->macroCall($method, $parameters);
|
||||
}
|
||||
|
||||
if ($this->component && method_exists($this->component, $method)) {
|
||||
array_unshift($parameters, $this);
|
||||
|
||||
$this->component->{$method}(...$parameters);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
if ($this->page && method_exists($this->page, $method)) {
|
||||
array_unshift($parameters, $this);
|
||||
|
||||
|
102
vendor/laravel/dusk/src/Chrome/ChromeProcess.php
vendored
Normal file
102
vendor/laravel/dusk/src/Chrome/ChromeProcess.php
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Dusk\Chrome;
|
||||
|
||||
use RuntimeException;
|
||||
use Illuminate\Support\Str;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
class ChromeProcess
|
||||
{
|
||||
/**
|
||||
* The path to the Chromedriver.
|
||||
*
|
||||
* @var String
|
||||
*/
|
||||
protected $driver;
|
||||
|
||||
/**
|
||||
* Create a new ChromeProcess instance.
|
||||
*
|
||||
* @param string $driver
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($driver = null)
|
||||
{
|
||||
$this->driver = $driver;
|
||||
|
||||
if (! is_null($driver) && realpath($driver) === false) {
|
||||
throw new RuntimeException("Invalid path to Chromedriver [{$driver}].");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the process to run Chromedriver.
|
||||
*
|
||||
* @return \Symfony\Component\Process\Process
|
||||
*/
|
||||
public function toProcess()
|
||||
{
|
||||
if ($this->driver) {
|
||||
return $this->process();
|
||||
}
|
||||
|
||||
if ($this->onWindows()) {
|
||||
$this->driver = realpath(__DIR__.'/../../bin/chromedriver-win.exe');
|
||||
|
||||
return $this->process();
|
||||
}
|
||||
|
||||
$this->driver = $this->onMac()
|
||||
? realpath(__DIR__.'/../../bin/chromedriver-mac')
|
||||
: realpath(__DIR__.'/../../bin/chromedriver-linux');
|
||||
|
||||
return $this->process();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the Chromedriver with Symfony Process.
|
||||
*
|
||||
* @return \Symfony\Component\Process\Process
|
||||
*/
|
||||
protected function process()
|
||||
{
|
||||
return (new Process(
|
||||
[realpath($this->driver)], null, $this->chromeEnvironment()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Chromedriver environment variables.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function chromeEnvironment()
|
||||
{
|
||||
if ($this->onMac() || $this->onWindows()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return ['DISPLAY' => ':0'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if Dusk is running on Windows or Windows Subsystem for Linux.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function onWindows()
|
||||
{
|
||||
return PHP_OS === 'WINNT' || Str::contains(php_uname(), 'Microsoft');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if Dusk is running on Mac.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function onMac()
|
||||
{
|
||||
return PHP_OS === 'Darwin';
|
||||
}
|
||||
}
|
@@ -1,10 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Dusk;
|
||||
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Process\Process;
|
||||
use Symfony\Component\Process\ProcessBuilder;
|
||||
namespace Laravel\Dusk\Chrome;
|
||||
|
||||
trait SupportsChrome
|
||||
{
|
||||
@@ -55,23 +51,13 @@ trait SupportsChrome
|
||||
/**
|
||||
* Build the process to run the Chromedriver.
|
||||
*
|
||||
* @throws \RuntimeException if the driver file path doesn't exist.
|
||||
*
|
||||
* @return \Symfony\Component\Process\Process
|
||||
* @throws \RuntimeException if the driver file path doesn't exist.
|
||||
*/
|
||||
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());
|
||||
return (new ChromeProcess(static::$chromeDriver))->toProcess();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,35 +70,4 @@ trait SupportsChrome
|
||||
{
|
||||
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';
|
||||
}
|
||||
}
|
||||
}
|
44
vendor/laravel/dusk/src/Component.php
vendored
Normal file
44
vendor/laravel/dusk/src/Component.php
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Dusk;
|
||||
|
||||
abstract class Component
|
||||
{
|
||||
/**
|
||||
* Get the root selector associated with this component.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function selector();
|
||||
|
||||
/**
|
||||
* Assert that the current page contains this component.
|
||||
*
|
||||
* @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 [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow this class to be used in place of a selector string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
@@ -86,7 +86,7 @@ trait InteractsWithAuthentication
|
||||
/**
|
||||
* Assert that the user is authenticated as the given user.
|
||||
*
|
||||
* @param $user
|
||||
* @param mixed $user
|
||||
* @param string|null $guard
|
||||
* @return $this
|
||||
*/
|
||||
|
@@ -14,7 +14,7 @@ trait InteractsWithElements
|
||||
* Get all of the elements matching the given selector.
|
||||
*
|
||||
* @param string $selector
|
||||
* @return array
|
||||
* @return \Facebook\WebDriver\Remote\RemoteWebElement[]
|
||||
*/
|
||||
public function elements($selector)
|
||||
{
|
||||
@@ -32,45 +32,18 @@ trait InteractsWithElements
|
||||
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
|
||||
* @param string $element
|
||||
* @return $this
|
||||
*/
|
||||
public function clickLink($link)
|
||||
public function clickLink($link, $element = "a")
|
||||
{
|
||||
$this->ensurejQueryIsAvailable();
|
||||
|
||||
$selector = addslashes(trim($this->resolver->format("a:contains({$link})")));
|
||||
$selector = addslashes(trim($this->resolver->format("{$element}:contains({$link})")));
|
||||
|
||||
$this->driver->executeScript("jQuery.find(\"{$selector}\")[0].click();");
|
||||
|
||||
@@ -213,9 +186,7 @@ trait InteractsWithElements
|
||||
|
||||
if (is_null($value)) {
|
||||
$options[array_rand($options)]->click();
|
||||
}
|
||||
|
||||
else {
|
||||
} else {
|
||||
foreach ($options as $option) {
|
||||
if ((string) $option->getAttribute('value') === (string) $value) {
|
||||
$option->click();
|
||||
@@ -418,6 +389,19 @@ trait InteractsWithElements
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type the given value in an open JavaScript prompt dialog.
|
||||
*
|
||||
* @param string $value
|
||||
* @return $this
|
||||
*/
|
||||
public function typeInDialog($value)
|
||||
{
|
||||
$this->driver->switchTo()->alert()->sendKeys($value);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismiss a JavaScript dialog.
|
||||
*
|
||||
|
@@ -2,8 +2,26 @@
|
||||
|
||||
namespace Laravel\Dusk\Concerns;
|
||||
|
||||
use Facebook\WebDriver\Interactions\WebDriverActions;
|
||||
|
||||
trait InteractsWithMouse
|
||||
{
|
||||
/**
|
||||
* Move the mouse by offset X and Y.
|
||||
*
|
||||
* @param int $xOffset
|
||||
* @param int $yOffset
|
||||
* @return $this
|
||||
*/
|
||||
public function moveMouse($xOffset, $yOffset)
|
||||
{
|
||||
(new WebDriverActions($this->driver))->moveByOffset(
|
||||
$xOffset, $yOffset
|
||||
)->perform();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the mouse over the given selector.
|
||||
*
|
||||
@@ -18,4 +36,76 @@ trait InteractsWithMouse
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Click the element at the given selector.
|
||||
*
|
||||
* @param string|null $selector
|
||||
* @return $this
|
||||
*/
|
||||
public function click($selector = null)
|
||||
{
|
||||
if (is_null($selector)) {
|
||||
(new WebDriverActions($this->driver))->click()->perform();
|
||||
} else {
|
||||
$this->resolver->findOrFail($selector)->click();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a mouse click and hold the mouse button down.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function clickAndHold()
|
||||
{
|
||||
(new WebDriverActions($this->driver))->clickAndHold()->perform();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a double click at the current mouse position.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function doubleClick()
|
||||
{
|
||||
(new WebDriverActions($this->driver))->doubleClick()->perform();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Right click the element at the given selector.
|
||||
*
|
||||
* @param string|null $selector
|
||||
* @return $this
|
||||
*/
|
||||
public function rightClick($selector = null)
|
||||
{
|
||||
if (is_null($selector)) {
|
||||
(new WebDriverActions($this->driver))->contextClick()->perform();
|
||||
} else {
|
||||
(new WebDriverActions($this->driver))->contextClick(
|
||||
$this->resolver->findOrFail($selector)
|
||||
)->perform();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the currenctly clicked mouse button.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function releaseMouse()
|
||||
{
|
||||
(new WebDriverActions($this->driver))->release()->perform();
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
331
vendor/laravel/dusk/src/Concerns/MakesAssertions.php
vendored
331
vendor/laravel/dusk/src/Concerns/MakesAssertions.php
vendored
@@ -4,6 +4,7 @@ namespace Laravel\Dusk\Concerns;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use PHPUnit\Framework\Assert as PHPUnit;
|
||||
use Facebook\WebDriver\Remote\RemoteWebElement;
|
||||
use Facebook\WebDriver\Exception\NoSuchElementException;
|
||||
|
||||
trait MakesAssertions
|
||||
@@ -16,7 +17,10 @@ trait MakesAssertions
|
||||
*/
|
||||
public function assertTitle($title)
|
||||
{
|
||||
PHPUnit::assertEquals($title, $this->driver->getTitle());
|
||||
PHPUnit::assertEquals(
|
||||
$title, $this->driver->getTitle(),
|
||||
"Expected title [{$title}] does not equal actual title [{$this->driver->getTitle()}]."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -30,7 +34,36 @@ trait MakesAssertions
|
||||
public function assertTitleContains($title)
|
||||
{
|
||||
PHPUnit::assertTrue(
|
||||
Str::contains($this->driver->getTitle(), $title)
|
||||
Str::contains($this->driver->getTitle(), $title),
|
||||
"Did not see expected value [{$title}] within title [{$this->driver->getTitle()}]."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the current URL matches the given URL.
|
||||
*
|
||||
* @param string $url
|
||||
* @return $this
|
||||
*/
|
||||
public function assertUrlIs($url)
|
||||
{
|
||||
$pattern = str_replace('\*', '.*', preg_quote($url, '/'));
|
||||
|
||||
$segments = parse_url($this->driver->getCurrentURL());
|
||||
|
||||
$currentUrl = sprintf(
|
||||
'%s://%s%s%s',
|
||||
$segments['scheme'],
|
||||
$segments['host'],
|
||||
array_get($segments, 'port', '') ? ':'.$segments['port'] : '',
|
||||
array_get($segments, 'path', '')
|
||||
);
|
||||
|
||||
PHPUnit::assertRegExp(
|
||||
'/^'.$pattern.'$/u', $currentUrl,
|
||||
"Actual URL [{$this->driver->getCurrentURL()}] does not equal expected URL [{$url}]."
|
||||
);
|
||||
|
||||
return $this;
|
||||
@@ -48,9 +81,12 @@ trait MakesAssertions
|
||||
|
||||
$pattern = str_replace('\*', '.*', $pattern);
|
||||
|
||||
PHPUnit::assertRegExp('/^'.$pattern.'/u', parse_url(
|
||||
$this->driver->getCurrentURL()
|
||||
)['path']);
|
||||
$actualPath = parse_url($this->driver->getCurrentURL())['path'];
|
||||
|
||||
PHPUnit::assertRegExp(
|
||||
'/^'.$pattern.'$/u', $actualPath,
|
||||
"Actual path [{$actualPath}] does not equal expected path [{$path}]."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -63,9 +99,12 @@ trait MakesAssertions
|
||||
*/
|
||||
public function assertPathBeginsWith($path)
|
||||
{
|
||||
PHPUnit::assertStringStartsWith($path, parse_url(
|
||||
$this->driver->getCurrentURL()
|
||||
)['path']);
|
||||
$actualPath = parse_url($this->driver->getCurrentURL())['path'];
|
||||
|
||||
PHPUnit::assertStringStartsWith(
|
||||
$path, $actualPath,
|
||||
"Actual path [{$actualPath}] does not begin with expected path [{$path}]."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -78,9 +117,68 @@ trait MakesAssertions
|
||||
*/
|
||||
public function assertPathIsNot($path)
|
||||
{
|
||||
PHPUnit::assertNotEquals($path, parse_url(
|
||||
$this->driver->getCurrentURL()
|
||||
)['path']);
|
||||
$actualPath = parse_url($this->driver->getCurrentURL())['path'];
|
||||
|
||||
PHPUnit::assertNotEquals(
|
||||
$path, $actualPath,
|
||||
"Path [{$path}] should not equal the actual value."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the current URL fragment matches the given pattern.
|
||||
*
|
||||
* @param string $fragment
|
||||
* @return $this
|
||||
*/
|
||||
public function assertFragmentIs($fragment)
|
||||
{
|
||||
$pattern = preg_quote($fragment, '/');
|
||||
|
||||
$actualFragment = (string) parse_url($this->driver->executeScript('return window.location.href;'), PHP_URL_FRAGMENT);
|
||||
|
||||
PHPUnit::assertRegExp(
|
||||
'/^'.str_replace('\*', '.*', $pattern).'$/u', $actualFragment,
|
||||
"Actual fragment [{$actualFragment}] does not equal expected fragment [{$fragment}]."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the current URL fragment begins with given fragment.
|
||||
*
|
||||
* @param string $fragment
|
||||
* @return $this
|
||||
*/
|
||||
public function assertFragmentBeginsWith($fragment)
|
||||
{
|
||||
$actualFragment = (string) parse_url($this->driver->executeScript('return window.location.href;'), PHP_URL_FRAGMENT);
|
||||
|
||||
PHPUnit::assertStringStartsWith(
|
||||
$fragment, $actualFragment,
|
||||
"Actual fragment [$actualFragment] does not begin with expected fragment [$fragment]."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the current URL fragment does not match the given fragment.
|
||||
*
|
||||
* @param string $fragment
|
||||
* @return $this
|
||||
*/
|
||||
public function assertFragmentIsNot($fragment)
|
||||
{
|
||||
$actualFragment = (string) parse_url($this->driver->executeScript('return window.location.href;'), PHP_URL_FRAGMENT);
|
||||
|
||||
PHPUnit::assertNotEquals(
|
||||
$fragment, $actualFragment,
|
||||
"Fragment [{$fragment}] should not equal the actual value."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -149,7 +247,7 @@ trait MakesAssertions
|
||||
* Assert that the given query string parameter is present.
|
||||
*
|
||||
* @param string $name
|
||||
* @return $this
|
||||
* @return array
|
||||
*/
|
||||
protected function assertHasQueryStringParameter($name)
|
||||
{
|
||||
@@ -186,6 +284,22 @@ trait MakesAssertions
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given cookie is not present.
|
||||
*
|
||||
* @param string $name
|
||||
* @return $this
|
||||
*/
|
||||
public function assertCookieMissing($name)
|
||||
{
|
||||
PHPUnit::assertTrue(
|
||||
is_null($this->cookie($name)),
|
||||
"Found unexpected cookie [{$name}]."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that an encrypted cookie has a given value.
|
||||
*
|
||||
@@ -347,7 +461,7 @@ trait MakesAssertions
|
||||
if ($this->resolver->prefix) {
|
||||
$message = "Saw unexpected link [{$link}] within [{$this->resolver->prefix}].";
|
||||
} else {
|
||||
$message = "Saw unexpected expected link [{$link}].";
|
||||
$message = "Saw unexpected link [{$link}].";
|
||||
}
|
||||
|
||||
PHPUnit::assertFalse(
|
||||
@@ -387,7 +501,10 @@ JS;
|
||||
*/
|
||||
public function assertInputValue($field, $value)
|
||||
{
|
||||
PHPUnit::assertEquals($value, $this->inputValue($field));
|
||||
PHPUnit::assertEquals(
|
||||
$value, $this->inputValue($field),
|
||||
"Expected value [{$value}] for the [{$field}] input does not equal the actual value [{$this->inputValue($field)}]."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -401,7 +518,10 @@ JS;
|
||||
*/
|
||||
public function assertInputValueIsNot($field, $value)
|
||||
{
|
||||
PHPUnit::assertNotEquals($value, $this->inputValue($field));
|
||||
PHPUnit::assertNotEquals(
|
||||
$value, $this->inputValue($field),
|
||||
"Value [{$value}] for the [{$field}] input should not equal the actual value."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -466,7 +586,7 @@ JS;
|
||||
* @param string $value
|
||||
* @return $this
|
||||
*/
|
||||
function assertRadioSelected($field, $value)
|
||||
public function assertRadioSelected($field, $value)
|
||||
{
|
||||
$element = $this->resolver->resolveForRadioSelection($field, $value);
|
||||
|
||||
@@ -540,9 +660,14 @@ JS;
|
||||
*/
|
||||
public function assertSelectHasOptions($field, array $values)
|
||||
{
|
||||
$options = $this->resolver->resolveSelectOptions($field, $values);
|
||||
|
||||
$options = collect($options)->unique(function (RemoteWebElement $option) {
|
||||
return $option->getAttribute('value');
|
||||
})->all();
|
||||
|
||||
PHPUnit::assertCount(
|
||||
count($values),
|
||||
$this->resolver->resolveSelectOptions($field, $values),
|
||||
count($values), $options,
|
||||
"Expected options [".implode(',', $values)."] for selection field [{$field}] to be available."
|
||||
);
|
||||
|
||||
@@ -638,6 +763,24 @@ JS;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the element with the given selector is present in the DOM.
|
||||
*
|
||||
* @param string $selector
|
||||
* @return $this
|
||||
*/
|
||||
public function assertPresent($selector)
|
||||
{
|
||||
$fullSelector = $this->resolver->format($selector);
|
||||
|
||||
PHPUnit::assertTrue(
|
||||
! is_null($this->resolver->find($selector)),
|
||||
"Element [{$fullSelector}] is not present."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the element with the given selector is not on the page.
|
||||
*
|
||||
@@ -667,10 +810,160 @@ JS;
|
||||
*/
|
||||
public function assertDialogOpened($message)
|
||||
{
|
||||
$actualMessage = $this->driver->switchTo()->alert()->getText();
|
||||
|
||||
PHPUnit::assertEquals(
|
||||
$message, $this->driver->switchTo()->alert()->getText()
|
||||
$message, $actualMessage,
|
||||
"Expected dialog message [{$message}] does not equal actual message [{$actualMessage}]."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given field is enabled.
|
||||
*
|
||||
* @param string $field
|
||||
* @return $this
|
||||
*/
|
||||
public function assertEnabled($field) {
|
||||
$element = $this->resolver->resolveForField($field);
|
||||
|
||||
PHPUnit::assertTrue(
|
||||
$element->isEnabled(),
|
||||
"Expected element [{$field}] to be enabled, but it wasn't."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given field is disabled.
|
||||
*
|
||||
* @param string $field
|
||||
* @return $this
|
||||
*/
|
||||
public function assertDisabled($field) {
|
||||
$element = $this->resolver->resolveForField($field);
|
||||
|
||||
PHPUnit::assertFalse(
|
||||
$element->isEnabled(),
|
||||
"Expected element [{$field}] to be disabled, but it wasn't."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given field is focused.
|
||||
*
|
||||
* @param string $field
|
||||
* @return $this
|
||||
*/
|
||||
public function assertFocused($field) {
|
||||
$element = $this->resolver->resolveForField($field);
|
||||
|
||||
PHPUnit::assertTrue(
|
||||
$this->driver->switchTo()->activeElement()->equals($element),
|
||||
"Expected element [{$field}] to be focused, but it wasn't."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given field is not focused.
|
||||
*
|
||||
* @param string $field
|
||||
* @return $this
|
||||
*/
|
||||
public function assertNotFocused($field) {
|
||||
$element = $this->resolver->resolveForField($field);
|
||||
|
||||
PHPUnit::assertFalse(
|
||||
$this->driver->switchTo()->activeElement()->equals($element),
|
||||
"Expected element [{$field}] not to be focused, but it was."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the Vue component's attribute at the given key has the given value.
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
* @param string|null $componentSelector
|
||||
* @return $this
|
||||
*/
|
||||
public function assertVue($key, $value, $componentSelector = null)
|
||||
{
|
||||
PHPUnit::assertEquals($value, $this->vueAttribute($componentSelector, $key));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the Vue component's attribute at the given key
|
||||
* does not have the given value.
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
* @param string|null $componentSelector
|
||||
* @return $this
|
||||
*/
|
||||
public function assertVueIsNot($key, $value, $componentSelector = null)
|
||||
{
|
||||
PHPUnit::assertNotEquals($value, $this->vueAttribute($componentSelector, $key));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the Vue component's attribute at the given key
|
||||
* is an array that contains the given value.
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
* @param string|null $componentSelector
|
||||
* @return $this
|
||||
*/
|
||||
public function assertVueContains($key, $value, $componentSelector = null)
|
||||
{
|
||||
PHPUnit::assertContains($value, $this->vueAttribute($componentSelector, $key));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the Vue component's attribute at the given key
|
||||
* is an array that does not contain the given value.
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
* @param string|null $componentSelector
|
||||
* @return $this
|
||||
*/
|
||||
public function assertVueDoesNotContain($key, $value, $componentSelector = null)
|
||||
{
|
||||
PHPUnit::assertNotContains($value, $this->vueAttribute($componentSelector, $key));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the value of the Vue component's attribute at the given key.
|
||||
*
|
||||
* @param string $componentSelector
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function vueAttribute($componentSelector, $key)
|
||||
{
|
||||
$fullSelector = $this->resolver->format($componentSelector);
|
||||
|
||||
return $this->driver->executeScript(
|
||||
"return document.querySelector('" . $fullSelector . "').__vue__." . $key
|
||||
);
|
||||
}
|
||||
}
|
||||
|
199
vendor/laravel/dusk/src/Concerns/ProvidesBrowser.php
vendored
Normal file
199
vendor/laravel/dusk/src/Concerns/ProvidesBrowser.php
vendored
Normal file
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Dusk\Concerns;
|
||||
|
||||
use Closure;
|
||||
use Exception;
|
||||
use Throwable;
|
||||
use ReflectionFunction;
|
||||
use Laravel\Dusk\Browser;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
trait ProvidesBrowser
|
||||
{
|
||||
/**
|
||||
* 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 = [];
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
$name = str_replace('\\', '_', get_class($this)).'_'.$this->getName(false);
|
||||
|
||||
$browser->screenshot('failure-'.$name.'-'.$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) {
|
||||
$name = str_replace('\\', '_', get_class($this)).'_'.$this->getName(false);
|
||||
|
||||
$browser->storeConsoleLog($name.'-'.$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
|
||||
*/
|
||||
abstract protected function driver();
|
||||
}
|
@@ -8,6 +8,7 @@ use Carbon\Carbon;
|
||||
use Illuminate\Support\Str;
|
||||
use Facebook\WebDriver\Exception\TimeOutException;
|
||||
use Facebook\WebDriver\Exception\NoSuchElementException;
|
||||
use Facebook\WebDriver\WebDriverExpectedCondition;
|
||||
|
||||
trait WaitsForElements
|
||||
{
|
||||
@@ -19,7 +20,7 @@ trait WaitsForElements
|
||||
* @param int $seconds
|
||||
* @return $this
|
||||
*/
|
||||
public function whenAvailable($selector, Closure $callback, $seconds = 5)
|
||||
public function whenAvailable($selector, Closure $callback, $seconds = null)
|
||||
{
|
||||
return $this->waitFor($selector, $seconds)->with($selector, $callback);
|
||||
}
|
||||
@@ -31,11 +32,11 @@ trait WaitsForElements
|
||||
* @param int $seconds
|
||||
* @return $this
|
||||
*/
|
||||
public function waitFor($selector, $seconds = 5)
|
||||
public function waitFor($selector, $seconds = null)
|
||||
{
|
||||
return $this->waitUsing($seconds, 100, function () use ($selector) {
|
||||
return $this->resolver->findOrFail($selector)->isDisplayed();
|
||||
}, "Waited {$seconds} seconds for selector [{$selector}].");
|
||||
}, "Waited %s seconds for selector [{$selector}].");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -45,7 +46,7 @@ trait WaitsForElements
|
||||
* @param int $seconds
|
||||
* @return $this
|
||||
*/
|
||||
public function waitUntilMissing($selector, $seconds = 5)
|
||||
public function waitUntilMissing($selector, $seconds = null)
|
||||
{
|
||||
return $this->waitUsing($seconds, 100, function () use ($selector) {
|
||||
try {
|
||||
@@ -55,7 +56,7 @@ trait WaitsForElements
|
||||
}
|
||||
|
||||
return $missing;
|
||||
}, "Waited {$seconds} seconds for removal of selector [{$selector}].");
|
||||
}, "Waited %s seconds for removal of selector [{$selector}].");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,11 +66,11 @@ trait WaitsForElements
|
||||
* @param int $seconds
|
||||
* @return $this
|
||||
*/
|
||||
public function waitForText($text, $seconds = 5)
|
||||
public function waitForText($text, $seconds = null)
|
||||
{
|
||||
return $this->waitUsing($seconds, 100, function () use ($text) {
|
||||
return Str::contains($this->resolver->findOrFail('')->getText(), $text);
|
||||
}, "Waited {$seconds} seconds for text [{$text}].");
|
||||
}, "Waited %s seconds for text [{$text}].");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,7 +80,7 @@ trait WaitsForElements
|
||||
* @param int $seconds
|
||||
* @return $this
|
||||
*/
|
||||
public function waitForLink($link, $seconds = 5)
|
||||
public function waitForLink($link, $seconds = null)
|
||||
{
|
||||
return $this->waitUsing($seconds, 100, function () use ($link) {
|
||||
return $this->seeLink($link);
|
||||
@@ -93,11 +94,24 @@ trait WaitsForElements
|
||||
* @param int $seconds
|
||||
* @return $this
|
||||
*/
|
||||
public function waitForLocation($path, $seconds = 5)
|
||||
public function waitForLocation($path, $seconds = null)
|
||||
{
|
||||
return $this->waitUntil("window.location.pathname == '{$path}'", $seconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the given location using a named route.
|
||||
*
|
||||
* @param string $route
|
||||
* @param array $parameters
|
||||
* @param int $seconds
|
||||
* @return $this
|
||||
*/
|
||||
public function waitForRoute($route, $parameters = [], $seconds = null)
|
||||
{
|
||||
return $this->waitForLocation(route($route, $parameters), $seconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until the given script returns true.
|
||||
*
|
||||
@@ -105,7 +119,7 @@ trait WaitsForElements
|
||||
* @param int $seconds
|
||||
* @return $this
|
||||
*/
|
||||
public function waitUntil($script, $seconds = 5)
|
||||
public function waitUntil($script, $seconds = null)
|
||||
{
|
||||
if (! Str::startsWith($script, 'return ')) {
|
||||
$script = 'return '.$script;
|
||||
@@ -120,6 +134,23 @@ trait WaitsForElements
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for a JavaScript dialog to open.
|
||||
*
|
||||
* @param int $seconds
|
||||
* @return $this
|
||||
*/
|
||||
public function waitForDialog($seconds = null)
|
||||
{
|
||||
$seconds = is_null($seconds) ? static::$waitSeconds : $seconds;
|
||||
|
||||
$this->driver->wait($seconds, 100)->until(
|
||||
WebDriverExpectedCondition::alertIsPresent(), "Waited {$seconds} seconds for dialog."
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the current page to reload.
|
||||
*
|
||||
@@ -127,7 +158,7 @@ trait WaitsForElements
|
||||
* @param int $seconds
|
||||
* @return $this
|
||||
*/
|
||||
public function waitForReload($callback = null, $seconds = 5)
|
||||
public function waitForReload($callback = null, $seconds = null)
|
||||
{
|
||||
$token = str_random();
|
||||
|
||||
@@ -139,7 +170,7 @@ trait WaitsForElements
|
||||
|
||||
return $this->waitUsing($seconds, 100, function () use ($token) {
|
||||
return $this->driver->executeScript("return typeof window['{$token}'] === 'undefined';");
|
||||
});
|
||||
}, 'Waited %s seconds for page reload.');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,6 +185,8 @@ trait WaitsForElements
|
||||
*/
|
||||
public function waitUsing($seconds, $interval, Closure $callback, $message = null)
|
||||
{
|
||||
$seconds = is_null($seconds) ? static::$waitSeconds : $seconds;
|
||||
|
||||
$this->pause($interval);
|
||||
|
||||
$started = Carbon::now();
|
||||
@@ -168,7 +201,10 @@ trait WaitsForElements
|
||||
}
|
||||
|
||||
if ($started->lt(Carbon::now()->subSeconds($seconds))) {
|
||||
throw new TimeOutException($message ?: "Waited {$seconds} seconds for callback.");
|
||||
throw new TimeOutException($message
|
||||
? sprintf($message, $seconds)
|
||||
: "Waited {$seconds} seconds for callback."
|
||||
);
|
||||
}
|
||||
|
||||
$this->pause($interval);
|
||||
|
73
vendor/laravel/dusk/src/Console/ComponentCommand.php
vendored
Normal file
73
vendor/laravel/dusk/src/Console/ComponentCommand.php
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Dusk\Console;
|
||||
|
||||
use Illuminate\Console\GeneratorCommand;
|
||||
|
||||
class ComponentCommand extends GeneratorCommand
|
||||
{
|
||||
/**
|
||||
* The console command name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'dusk:component {name : The name of the class}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Create a new Dusk component class';
|
||||
|
||||
/**
|
||||
* The type of class being generated.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $type = 'Component';
|
||||
|
||||
/**
|
||||
* Get the stub file for the generator.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getStub()
|
||||
{
|
||||
return __DIR__.'/stubs/component.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\Components';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function rootNamespace()
|
||||
{
|
||||
return 'Tests';
|
||||
}
|
||||
}
|
22
vendor/laravel/dusk/src/Console/DuskCommand.php
vendored
22
vendor/laravel/dusk/src/Console/DuskCommand.php
vendored
@@ -3,9 +3,10 @@
|
||||
namespace Laravel\Dusk\Console;
|
||||
|
||||
use Dotenv\Dotenv;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Console\Command;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\Process\ProcessBuilder;
|
||||
use Symfony\Component\Process\Process;
|
||||
use Symfony\Component\Process\Exception\RuntimeException;
|
||||
|
||||
class DuskCommand extends Command
|
||||
@@ -15,7 +16,7 @@ class DuskCommand extends Command
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'dusk';
|
||||
protected $signature = 'dusk {--without-tty : Disable output to TTY}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
@@ -54,17 +55,15 @@ class DuskCommand extends Command
|
||||
|
||||
$this->purgeConsoleLogs();
|
||||
|
||||
$options = array_slice($_SERVER['argv'], 2);
|
||||
$options = array_slice($_SERVER['argv'], $this->option('without-tty') ? 3 : 2);
|
||||
|
||||
return $this->withDuskEnvironment(function () use ($options) {
|
||||
$process = (new ProcessBuilder())
|
||||
->setTimeout(null)
|
||||
->setPrefix($this->binary())
|
||||
->setArguments($this->phpunitArguments($options))
|
||||
->getProcess();
|
||||
$process = (new Process(array_merge(
|
||||
$this->binary(), $this->phpunitArguments($options)
|
||||
)))->setTimeout(null);
|
||||
|
||||
try {
|
||||
$process->setTty(true);
|
||||
$process->setTty(! $this->option('without-tty'));
|
||||
} catch (RuntimeException $e) {
|
||||
$this->output->writeln('Warning: '.$e->getMessage());
|
||||
}
|
||||
@@ -88,10 +87,15 @@ class DuskCommand extends Command
|
||||
/**
|
||||
* Get the array of arguments for running PHPUnit.
|
||||
*
|
||||
* @param array $options
|
||||
* @return array
|
||||
*/
|
||||
protected function phpunitArguments($options)
|
||||
{
|
||||
$options = array_values(array_filter($options, function ($option) {
|
||||
return ! Str::startsWith($option, '--env=');
|
||||
}));
|
||||
|
||||
return array_merge(['-c', base_path('phpunit.dusk.xml')], $options);
|
||||
}
|
||||
|
||||
|
@@ -41,6 +41,10 @@ class InstallCommand extends Command
|
||||
mkdir(base_path('tests/Browser/Pages'), 0755, true);
|
||||
}
|
||||
|
||||
if (! is_dir(base_path('tests/Browser/Components'))) {
|
||||
mkdir(base_path('tests/Browser/Components'), 0755, true);
|
||||
}
|
||||
|
||||
if (! is_dir(base_path('tests/Browser/screenshots'))) {
|
||||
$this->createScreenshotsDirectory();
|
||||
}
|
||||
@@ -49,14 +53,14 @@ class InstallCommand extends Command
|
||||
$this->createConsoleDirectory();
|
||||
}
|
||||
|
||||
$subs = [
|
||||
$stubs = [
|
||||
'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) {
|
||||
foreach ($stubs as $stub => $file) {
|
||||
if (! is_file($file)) {
|
||||
copy(__DIR__.'/../../stubs/'.$stub, $file);
|
||||
}
|
||||
|
42
vendor/laravel/dusk/src/Console/stubs/component.stub
vendored
Normal file
42
vendor/laravel/dusk/src/Console/stubs/component.stub
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace DummyNamespace;
|
||||
|
||||
use Laravel\Dusk\Browser;
|
||||
use Laravel\Dusk\Component as BaseComponent;
|
||||
|
||||
class DummyClass extends BaseComponent
|
||||
{
|
||||
/**
|
||||
* Get the root selector for the component.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function selector()
|
||||
{
|
||||
return '#selector';
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the browser page contains the component.
|
||||
*
|
||||
* @param Browser $browser
|
||||
* @return void
|
||||
*/
|
||||
public function assert(Browser $browser)
|
||||
{
|
||||
$browser->assertVisible($this->selector());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the element shortcuts for the component.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function elements()
|
||||
{
|
||||
return [
|
||||
'@element' => '#selector',
|
||||
];
|
||||
}
|
||||
}
|
@@ -3,9 +3,8 @@
|
||||
namespace DummyNamespace;
|
||||
|
||||
use Laravel\Dusk\Browser;
|
||||
use Laravel\Dusk\Page as BasePage;
|
||||
|
||||
class DummyClass extends BasePage
|
||||
class DummyClass extends Page
|
||||
{
|
||||
/**
|
||||
* Get the URL for the page.
|
||||
|
@@ -49,6 +49,7 @@ class DuskServiceProvider extends ServiceProvider
|
||||
Console\DuskCommand::class,
|
||||
Console\MakeCommand::class,
|
||||
Console\PageCommand::class,
|
||||
Console\ComponentCommand::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
26
vendor/laravel/dusk/src/ElementResolver.php
vendored
26
vendor/laravel/dusk/src/ElementResolver.php
vendored
@@ -111,7 +111,7 @@ class ElementResolver
|
||||
*
|
||||
* @param string $field
|
||||
* @param array $values
|
||||
* @return array
|
||||
* @return \Facebook\WebDriver\Remote\RemoteWebElement[]
|
||||
*/
|
||||
public function resolveSelectOptions($field, array $values)
|
||||
{
|
||||
@@ -122,7 +122,7 @@ class ElementResolver
|
||||
return [];
|
||||
}
|
||||
|
||||
return array_filter($options, function($option) use ($values) {
|
||||
return array_filter($options, function ($option) use ($values) {
|
||||
return in_array($option->getAttribute('value'), $values);
|
||||
});
|
||||
}
|
||||
@@ -192,6 +192,24 @@ class ElementResolver
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the element for a given "field".
|
||||
*
|
||||
* @param string $field
|
||||
* @return \Facebook\WebDriver\Remote\RemoteWebElement
|
||||
*/
|
||||
public function resolveForField($field)
|
||||
{
|
||||
if (! is_null($element = $this->findById($field))) {
|
||||
return $element;
|
||||
}
|
||||
|
||||
return $this->firstOrFail([
|
||||
$field, "input[name='{$field}']", "textarea[name='{$field}']",
|
||||
"select[name='{$field}']", "button[name='{$field}']"
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the element for a given button.
|
||||
*
|
||||
@@ -337,7 +355,7 @@ class ElementResolver
|
||||
* Find the elements by the given selector or return an empty array.
|
||||
*
|
||||
* @param string $selector
|
||||
* @return array
|
||||
* @return \Facebook\WebDriver\Remote\RemoteWebElement[]
|
||||
*/
|
||||
public function all($selector)
|
||||
{
|
||||
@@ -360,7 +378,7 @@ class ElementResolver
|
||||
*/
|
||||
public function format($selector)
|
||||
{
|
||||
$sortedElements = collect($this->elements)->sortByDesc(function($element, $key){
|
||||
$sortedElements = collect($this->elements)->sortByDesc(function ($element, $key) {
|
||||
return strlen($key);
|
||||
})->toArray();
|
||||
|
||||
|
@@ -31,19 +31,16 @@ class UserController
|
||||
*
|
||||
* @param string $userId
|
||||
* @param string $guard
|
||||
* @return Response
|
||||
*/
|
||||
public function login($userId, $guard = null)
|
||||
{
|
||||
$model = $this->modelForGuard(
|
||||
$guard = $guard ?: config('auth.defaults.guard')
|
||||
);
|
||||
$guard = $guard ?: config('auth.defaults.guard');
|
||||
|
||||
if (str_contains($userId, '@')) {
|
||||
$user = (new $model)->where('email', $userId)->first();
|
||||
} else {
|
||||
$user = (new $model)->find($userId);
|
||||
}
|
||||
$provider = Auth::guard($guard)->getProvider();
|
||||
|
||||
$user = str_contains($userId, '@')
|
||||
? $provider->retrieveByCredentials(['email' => $userId])
|
||||
: $provider->retrieveById($userId);
|
||||
|
||||
Auth::guard($guard)->login($user);
|
||||
}
|
||||
@@ -52,7 +49,6 @@ class UserController
|
||||
* Log the user out of the application.
|
||||
*
|
||||
* @param string $guard
|
||||
* @return Response
|
||||
*/
|
||||
public function logout($guard = null)
|
||||
{
|
||||
|
189
vendor/laravel/dusk/src/TestCase.php
vendored
189
vendor/laravel/dusk/src/TestCase.php
vendored
@@ -2,32 +2,16 @@
|
||||
|
||||
namespace Laravel\Dusk;
|
||||
|
||||
use Closure;
|
||||
use Exception;
|
||||
use Throwable;
|
||||
use ReflectionFunction;
|
||||
use Illuminate\Support\Collection;
|
||||
use Laravel\Dusk\Chrome\SupportsChrome;
|
||||
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 = [];
|
||||
use Concerns\ProvidesBrowser,
|
||||
SupportsChrome;
|
||||
|
||||
/**
|
||||
* Register the base URL with Dusk.
|
||||
@@ -49,167 +33,6 @@ abstract class TestCase extends FoundationTestCase
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@@ -225,7 +48,7 @@ abstract class TestCase extends FoundationTestCase
|
||||
/**
|
||||
* Determine the application's base URL.
|
||||
*
|
||||
* @var string
|
||||
* @return string
|
||||
*/
|
||||
protected function baseUrl()
|
||||
{
|
||||
@@ -233,9 +56,9 @@ abstract class TestCase extends FoundationTestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a callback that returns the default user to authenticate.
|
||||
* Return the default user to authenticate.
|
||||
*
|
||||
* @return \Closure
|
||||
* @return \App\User|int|null
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function user()
|
||||
|
Reference in New Issue
Block a user