Вход Регистрация
Файл: src/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/InteractsWithPages.php
Строк: 1027
<?php

namespace IlluminateFoundationTestingConcerns;

use 
Closure;
use 
Exception;
use 
IlluminateSupportStr;
use 
InvalidArgumentException;
use 
IlluminateHttpUploadedFile;
use 
SymfonyComponentDomCrawlerForm;
use 
SymfonyComponentDomCrawlerCrawler;
use 
IlluminateFoundationTestingHttpException;
use 
PHPUnit_Framework_ExpectationFailedException as PHPUnitException;

trait 
InteractsWithPages
{
    
/**
     * The DomCrawler instance.
     *
     * @var SymfonyComponentDomCrawlerCrawler
     */
    
protected $crawler;

    
/**
     * Nested crawler instances used by the "within" method.
     *
     * @var array
     */
    
protected $subCrawlers = [];

    
/**
     * All of the stored inputs for the current page.
     *
     * @var array
     */
    
protected $inputs = [];

    
/**
     * All of the stored uploads for the current page.
     *
     * @var array
     */
    
protected $uploads = [];

    
/**
     * Visit the given URI with a GET request.
     *
     * @param  string  $uri
     * @return $this
     */
    
public function visit($uri)
    {
        return 
$this->makeRequest('GET'$uri);
    }

    
/**
     * Make a request to the application and create a Crawler instance.
     *
     * @param  string  $method
     * @param  string  $uri
     * @param  array  $parameters
     * @param  array  $cookies
     * @param  array  $files
     * @return $this
     */
    
protected function makeRequest($method$uri$parameters = [], $cookies = [], $files = [])
    {
        
$uri $this->prepareUrlForRequest($uri);

        
$this->call($method$uri$parameters$cookies$files);

        
$this->clearInputs()->followRedirects()->assertPageLoaded($uri);

        
$this->currentUri $this->app->make('request')->fullUrl();

        
$this->crawler = new Crawler($this->response->getContent(), $this->currentUri);

        
$this->subCrawlers = [];

        return 
$this;
    }

    
/**
     * Make a request to the application using the given form.
     *
     * @param  SymfonyComponentDomCrawlerForm  $form
     * @param  array  $uploads
     * @return $this
     */
    
protected function makeRequestUsingForm(Form $form, array $uploads = [])
    {
        
$files $this->convertUploadsForTesting($form$uploads);

        return 
$this->makeRequest(
            
$form->getMethod(), $form->getUri(), $this->extractParametersFromForm($form), [], $files
        
);
    }

    
/**
     * Extract the parameters from the given form.
     *
     * @param  SymfonyComponentDomCrawlerForm  $form
     * @return array
     */
    
protected function extractParametersFromForm(Form $form)
    {
        
parse_str(http_build_query($form->getValues()), $parameters);

        return 
$parameters;
    }

    
/**
     * Follow redirects from the last response.
     *
     * @return $this
     */
    
protected function followRedirects()
    {
        while (
$this->response->isRedirect()) {
            
$this->makeRequest('GET'$this->response->getTargetUrl());
        }

        return 
$this;
    }

    
/**
     * Clear the inputs for the current page.
     *
     * @return $this
     */
    
protected function clearInputs()
    {
        
$this->inputs = [];

        
$this->uploads = [];

        return 
$this;
    }

    
/**
     * Assert that the current page matches a given URI.
     *
     * @param  string  $uri
     * @return $this
     */
    
protected function seePageIs($uri)
    {
        
$this->assertPageLoaded($uri $this->prepareUrlForRequest($uri));

        
$this->assertEquals(
            
$uri$this->currentUri"Did not land on expected page [{$uri}].n"
        
);

        return 
$this;
    }

    
/**
     * Assert that a given page successfully loaded.
     *
     * @param  string  $uri
     * @param  string|null  $message
     * @return void
     *
     * @throws IlluminateFoundationTestingHttpException
     */
    
protected function assertPageLoaded($uri$message null)
    {
        
$status $this->response->getStatusCode();

        try {
            
$this->assertEquals(200$status);
        } catch (
PHPUnitException $e) {
            
$message $message ?: "A request to [{$uri}] failed. Received status code [{$status}].";

            
$responseException = isset($this->response->exception)
                    ? 
$this->response->exception null;

            throw new 
HttpException($messagenull$responseException);
        }
    }

    
/**
     * Narrow the test content to a specific area of the page.
     *
     * @param  string  $element
     * @param  Closure  $callback
     * @return $this
     */
    
public function within($elementClosure $callback)
    {
        
$this->subCrawlers[] = $this->crawler()->filter($element);

        
$callback();

        
array_pop($this->subCrawlers);
    }

    
/**
     * Get the current crawler according to the test context.
     *
     * @return SymfonyComponentDomCrawlerCrawler
     */
    
protected function crawler()
    {
        return ! empty(
$this->subCrawlers)
                        ? 
end($this->subCrawlers)
                        : 
$this->crawler;
    }

    
/**
     * Get the HTML from the current context or the full response.
     *
     * @return string
     */
    
protected function html()
    {
        return 
$this->crawler()
            ? 
$this->crawler()->html()
            : 
$this->response->getContent();
    }

    
/**
     * Get the plain text from the current context or the full response.
     *
     * @return string
     */
    
protected function text()
    {
        return 
$this->crawler()
            ? 
$this->crawler()->text()
            : 
strip_tags($this->response->getContent());
    }

    
/**
     * Get the escaped text pattern.
     *
     * @param  string  $text
     * @return string
     */
    
protected function getEscapedPattern($text)
    {
        
$rawPattern preg_quote($text'/');

        
$escapedPattern preg_quote(e($text), '/');

        return 
$rawPattern == $escapedPattern
            
$rawPattern "({$rawPattern}|{$escapedPattern})";
    }

    
/**
     * Assert that a given string is seen on the current HTML.
     *
     * @param  string  $text
     * @param  bool  $negate
     * @return $this
     */
    
public function see($text$negate false)
    {
        if (
$negate) {
            return 
$this->dontSee($text);
        }

        if (! 
$this->hasSource($text)) {
            
$this->failPageInspection("Couldn't find [$text] on the page");
        }

        return 
$this;
    }

    
/**
     * Assert that a given string is not seen on the current HTML.
     *
     * @param  string  $text
     * @return $this
     */
    
public function dontSee($text)
    {
        if (
$this->hasSource($text)) {
            
$this->failPageInspection("The page should not contain [$text]");
        }

        return 
$this;
    }

    
/**
     * Check if the page contains the given text as part of the source.
     *
     * @param  string  $text
     * @return int|bool
     */
    
protected function hasSource($text)
    {
        
$pattern $this->getEscapedPattern($text);

        return 
preg_match("/$pattern/i"$this->html());
    }

    
/**
     * Assert that an element is present on the page.
     *
     * @param  string  $selector
     * @param  array  $attributes
     * @return void
     */
    
public function seeElement($selector, array $attributes = [])
    {
        if (! 
$this->hasElement($selector$attributes)) {
            
$element "[$selector]".(empty($attributes) ? '' ' with attributes '.json_encode($attributes));

            
$this->failPageInspection("Couldn't find $element on the page");
        }
    }

    
/**
     * Assert that an element is not present on the page.
     *
     * @param  string  $selector
     * @param  array  $attributes
     * @return void
     */
    
public function dontSeeElement($selector, array $attributes = [])
    {
        if (
$this->hasElement($selector$attributes)) {
            
$element "[$selector]".(empty($attributes) ? '' ' with attributes '.json_encode($attributes));

            
$this->failPageInspection("$element was found on the page");
        }
    }

    
/**
     * Determine if the given selector is present on the page.
     *
     * @param  string  $selector
     * @param  array  $attributes
     * @return bool
     */
    
protected function hasElement($selector, array $attributes = [])
    {
        
$elements $this->crawler()->filter($selector);

        if (
$elements->count() == 0) {
            return 
false;
        }

        if (empty(
$attributes)) {
            return 
true;
        }

        
$elements $elements->reduce(function ($element) use ($attributes) {
            return 
$this->hasAttributes($element$attributes);
        });

        return 
$elements->count() > 0;
    }

    
/**
     * Determines if the given element has the given attributes.
     *
     * @param  Crawler  $element
     * @param  array  $attributes
     * @return bool
     */
    
protected function hasAttributes(Crawler $element, array $attributes = [])
    {
        foreach (
$attributes as $name => $value) {
            if (
is_numeric($name)) {
                if (
$element->attr($value) === null) {
                    return 
false;
                }
            } else {
                if (
$element->attr($name) != $value) {
                    return 
false;
                }
            }
        }

        return 
true;
    }

    
/**
     * Assert that a given string is seen on the current text.
     *
     * @param  string  $text
     * @param  bool  $negate
     * @return $this
     */
    
public function seeText($text$negate false)
    {
        if (
$negate) {
            return 
$this->dontSeeText($text);
        }

        if (! 
$this->hasText($text)) {
            
$this->failPageInspection("Couldn't find the text [$text] on the page");
        }

        return 
$this;
    }

    
/**
     * Assert that a given string is not seen on the current text.
     *
     * @param  string  $text
     * @return $this
     */
    
public function dontSeeText($text)
    {
        if (
$this->hasText($text)) {
            
$this->failPageInspection("The page should not contain the text [$text]");
        }

        return 
$this;
    }

    
/**
     * Check if the page contains the given plain text.
     *
     * @param  string  $text
     * @return int|bool
     */
    
protected function hasText($text)
    {
        
$pattern $this->getEscapedPattern($text);

        return 
preg_match("/$pattern/i"$this->text());
    }

    
/**
     * Assert that a given string is seen inside an element.
     *
     * @param  string  $element
     * @param  string  $text
     * @param  bool  $negate
     * @return $this
     */
    
public function seeInElement($element$text$negate false)
    {
        if (
$negate) {
            return 
$this->dontSeeInElement($element$text);
        }

        
$this->assertTrue(
            
$this->hasInElement($element$text),
            
"Element [$element] should contain the expected text [{$text}]"
        
);

        return 
$this;
    }

    
/**
     * Assert that a given string is not seen inside an element.
     *
     * @param  string  $element
     * @param  string  $text
     * @return $this
     */
    
public function dontSeeInElement($element$text)
    {
        
$this->assertFalse(
            
$this->hasInElement($element$text),
            
"Element [$element] should not contain the expected text [{$text}]"
        
);

        return 
$this;
    }

    
/**
     * Check if the page contains text within the given element.
     *
     * @param  string  $element
     * @param  string  $text
     * @return bool
     */
    
protected function hasInElement($element$text)
    {
        
$elements $this->crawler()->filter($element);

        
$pattern $this->getEscapedPattern($text);

        foreach (
$elements as $element) {
            
$element = new Crawler($element);

            if (
preg_match("/$pattern/i"$element->html())) {
                return 
true;
            }
        }

        return 
false;
    }

    
/**
     * Assert that a given link is seen on the page.
     *
     * @param  string  $text
     * @param  string|null  $url
     * @return $this
     */
    
public function seeLink($text$url null)
    {
        
$message "No links were found with expected text [{$text}]";

        if (
$url) {
            
$message .= " and URL [{$url}]";
        }

        
$this->assertTrue($this->hasLink($text$url), "{$message}.");

        return 
$this;
    }

    
/**
     * Assert that a given link is not seen on the page.
     *
     * @param  string  $text
     * @param  string|null  $url
     * @return $this
     */
    
public function dontSeeLink($text$url null)
    {
        
$message "A link was found with expected text [{$text}]";

        if (
$url) {
            
$message .= " and URL [{$url}]";
        }

        
$this->assertFalse($this->hasLink($text$url), "{$message}.");

        return 
$this;
    }

    
/**
     * Check if the page has a link with the given $text and optional $url.
     *
     * @param  string  $text
     * @param  string|null  $url
     * @return bool
     */
    
protected function hasLink($text$url null)
    {
        
$links $this->crawler()->selectLink($text);

        if (
$links->count() == 0) {
            return 
false;
        }

        
// If the URL is null, we assume the developer only wants to find a link
        // with the given text regardless of the URL. So, if we find the link
        // we will return true now. Otherwise, we look for the given URL.
        
if ($url == null) {
            return 
true;
        }

        
$absoluteUrl $this->addRootToRelativeUrl($url);

        foreach (
$links as $link) {
            
$linkHref $link->getAttribute('href');

            if (
$linkHref == $url || $linkHref == $absoluteUrl) {
                return 
true;
            }
        }

        return 
false;
    }

    
/**
     * Add a root if the URL is relative (helper method of the hasLink function).
     *
     * @param  string  $url
     * @return string
     */
    
protected function addRootToRelativeUrl($url)
    {
        if (! 
Str::startsWith($url, ['http''https'])) {
            return 
$this->app->make('url')->to($url);
        }

        return 
$url;
    }

    
/**
     * Assert that an input field contains the given value.
     *
     * @param  string  $selector
     * @param  string  $expected
     * @return $this
     */
    
public function seeInField($selector$expected)
    {
        
$this->assertSame(
            
$expected$this->getInputOrTextAreaValue($selector),
            
"The field [{$selector}] does not contain the expected value [{$expected}]."
        
);

        return 
$this;
    }

    
/**
     * Assert that an input field does not contain the given value.
     *
     * @param  string  $selector
     * @param  string  $value
     * @return $this
     */
    
public function dontSeeInField($selector$value)
    {
        
$this->assertNotSame(
            
$this->getInputOrTextAreaValue($selector), $value,
            
"The input [{$selector}] should not contain the value [{$value}]."
        
);

        return 
$this;
    }

    
/**
     * Assert that the given checkbox is selected.
     *
     * @param  string  $selector
     * @return $this
     */
    
public function seeIsChecked($selector)
    {
        
$this->assertTrue(
            
$this->isChecked($selector),
            
"The checkbox [{$selector}] is not checked."
        
);

        return 
$this;
    }

    
/**
     * Assert that the given checkbox is not selected.
     *
     * @param  string  $selector
     * @return $this
     */
    
public function dontSeeIsChecked($selector)
    {
        
$this->assertFalse(
            
$this->isChecked($selector),
            
"The checkbox [{$selector}] is checked."
        
);

        return 
$this;
    }

    
/**
     * Assert that the expected value is selected.
     *
     * @param  string  $selector
     * @param  string  $expected
     * @return $this
     */
    
public function seeIsSelected($selector$expected)
    {
        
$this->assertContains(
            
$expected$this->getSelectedValue($selector),
            
"The field [{$selector}] does not contain the selected value [{$expected}]."
        
);

        return 
$this;
    }

    
/**
     * Assert that the given value is not selected.
     *
     * @param  string  $selector
     * @param  string  $value
     * @return $this
     */
    
public function dontSeeIsSelected($selector$value)
    {
        
$this->assertNotContains(
            
$value$this->getSelectedValue($selector),
            
"The field [{$selector}] contains the selected value [{$value}]."
        
);

        return 
$this;
    }

    
/**
     * Get the value of an input or textarea.
     *
     * @param  string  $selector
     * @return string
     *
     * @throws Exception
     */
    
protected function getInputOrTextAreaValue($selector)
    {
        
$field $this->filterByNameOrId($selector, ['input''textarea']);

        if (
$field->count() == 0) {
            throw new 
Exception("There are no elements with the name or ID [$selector].");
        }

        
$element $field->nodeName();

        if (
$element == 'input') {
            return 
$field->attr('value');
        }

        if (
$element == 'textarea') {
            return 
$field->text();
        }

        throw new 
Exception("Given selector [$selector] is not an input or textarea.");
    }

    
/**
     * Get the selected value of a select field or radio group.
     *
     * @param  string  $selector
     * @return string|null
     *
     * @throws Exception
     */
    
protected function getSelectedValue($selector)
    {
        
$field $this->filterByNameOrId($selector);

        if (
$field->count() == 0) {
            throw new 
Exception("There are no elements with the name or ID [$selector].");
        }

        
$element $field->nodeName();

        if (
$element == 'select') {
            return 
$this->getSelectedValueFromSelect($field);
        }

        if (
$element == 'input') {
            
$value $this->getCheckedValueFromRadioGroup($field);

            return 
$value ? [$value] : [];
        }

        throw new 
Exception("Given selector [$selector] is not a select or radio group.");
    }

    
/**
     * Get the selected value from a select field.
     *
     * @param  SymfonyComponentDomCrawlerCrawler  $field
     * @return array
     *
     * @throws Exception
     */
    
protected function getSelectedValueFromSelect(Crawler $field)
    {
        if (
$field->nodeName() !== 'select') {
            throw new 
Exception('Given element is not a select element.');
        }

        
$selected = [];

        foreach (
$field->children() as $option) {
            if (
$option->nodeName === 'optgroup') {
                foreach (
$option->childNodes as $child) {
                    if (
$child->hasAttribute('selected')) {
                        
$selected[] = $child->getAttribute('value');
                    }
                }
            } elseif (
$option->hasAttribute('selected')) {
                
$selected[] = $option->getAttribute('value');
            }
        }

        return 
$selected;
    }

    
/**
     * Get the checked value from a radio group.
     *
     * @param  SymfonyComponentDomCrawlerCrawler  $radioGroup
     * @return string|null
     *
     * @throws Exception
     */
    
protected function getCheckedValueFromRadioGroup(Crawler $radioGroup)
    {
        if (
$radioGroup->nodeName() !== 'input' || $radioGroup->attr('type') !== 'radio') {
            throw new 
Exception('Given element is not a radio button.');
        }

        foreach (
$radioGroup as $radio) {
            if (
$radio->hasAttribute('checked')) {
                return 
$radio->getAttribute('value');
            }
        }
    }

    
/**
     * Return true if the given checkbox is checked, false otherwise.
     *
     * @param  string  $selector
     * @return bool
     *
     * @throws Exception
     */
    
protected function isChecked($selector)
    {
        
$checkbox $this->filterByNameOrId($selector"input[type='checkbox']");

        if (
$checkbox->count() == 0) {
            throw new 
Exception("There are no checkbox elements with the name or ID [$selector].");
        }

        return 
$checkbox->attr('checked') !== null;
    }

    
/**
     * Click a link with the given body, name, or ID attribute.
     *
     * @param  string  $name
     * @return $this
     *
     * @throws InvalidArgumentException
     */
    
protected function click($name)
    {
        
$link $this->crawler()->selectLink($name);

        if (! 
count($link)) {
            
$link $this->filterByNameOrId($name'a');

            if (! 
count($link)) {
                throw new 
InvalidArgumentException(
                    
"Could not find a link with a body, name, or ID attribute of [{$name}]."
                
);
            }
        }

        
$this->visit($link->link()->getUri());

        return 
$this;
    }

    
/**
     * Fill an input field with the given text.
     *
     * @param  string  $text
     * @param  string  $element
     * @return $this
     */
    
protected function type($text$element)
    {
        return 
$this->storeInput($element$text);
    }

    
/**
     * Check a checkbox on the page.
     *
     * @param  string  $element
     * @return $this
     */
    
protected function check($element)
    {
        return 
$this->storeInput($elementtrue);
    }

    
/**
     * Uncheck a checkbox on the page.
     *
     * @param  string  $element
     * @return $this
     */
    
protected function uncheck($element)
    {
        return 
$this->storeInput($elementfalse);
    }

    
/**
     * Select an option from a drop-down.
     *
     * @param  string  $option
     * @param  string  $element
     * @return $this
     */
    
protected function select($option$element)
    {
        return 
$this->storeInput($element$option);
    }

    
/**
     * Attach a file to a form field on the page.
     *
     * @param  string  $absolutePath
     * @param  string  $element
     * @return $this
     */
    
protected function attach($absolutePath$element)
    {
        
$this->uploads[$element] = $absolutePath;

        return 
$this->storeInput($element$absolutePath);
    }

    
/**
     * Submit a form using the button with the given text value.
     *
     * @param  string  $buttonText
     * @return $this
     */
    
protected function press($buttonText)
    {
        return 
$this->submitForm($buttonText$this->inputs$this->uploads);
    }

    
/**
     * Submit a form on the page with the given input.
     *
     * @param  string  $buttonText
     * @param  array  $inputs
     * @param  array  $uploads
     * @return $this
     */
    
protected function submitForm($buttonText$inputs = [], $uploads = [])
    {
        
$this->makeRequestUsingForm($this->fillForm($buttonText$inputs), $uploads);

        return 
$this;
    }

    
/**
     * Fill the form with the given data.
     *
     * @param  string  $buttonText
     * @param  array  $inputs
     * @return SymfonyComponentDomCrawlerForm
     */
    
protected function fillForm($buttonText$inputs = [])
    {
        if (! 
is_string($buttonText)) {
            
$inputs $buttonText;

            
$buttonText null;
        }

        return 
$this->getForm($buttonText)->setValues($inputs);
    }

    
/**
     * Get the form from the page with the given submit button text.
     *
     * @param  string|null  $buttonText
     * @return SymfonyComponentDomCrawlerForm
     *
     * @throws InvalidArgumentException
     */
    
protected function getForm($buttonText null)
    {
        try {
            if (
$buttonText) {
                return 
$this->crawler()->selectButton($buttonText)->form();
            }

            return 
$this->crawler()->filter('form')->form();
        } catch (
InvalidArgumentException $e) {
            throw new 
InvalidArgumentException(
                
"Could not find a form that has submit button [{$buttonText}]."
            
);
        }
    }

    
/**
     * Store a form input in the local array.
     *
     * @param  string  $element
     * @param  string  $text
     * @return $this
     */
    
protected function storeInput($element$text)
    {
        
$this->assertFilterProducesResults($element);

        
$element str_replace('#'''$element);

        
$this->inputs[$element] = $text;

        return 
$this;
    }

    
/**
     * Assert that a filtered Crawler returns nodes.
     *
     * @param  string  $filter
     * @return void
     *
     * @throws InvalidArgumentException
     */
    
protected function assertFilterProducesResults($filter)
    {
        
$crawler $this->filterByNameOrId($filter);

        if (! 
count($crawler)) {
            throw new 
InvalidArgumentException(
                
"Nothing matched the filter [{$filter}] CSS query provided for [{$this->currentUri}]."
            
);
        }
    }

    
/**
     * Filter elements according to the given name or ID attribute.
     *
     * @param  string  $name
     * @param  array|string  $elements
     * @return SymfonyComponentDomCrawlerCrawler
     */
    
protected function filterByNameOrId($name$elements '*')
    {
        
$name str_replace('#'''$name);

        
$id str_replace(['['']'], ['\[''\]'], $name);

        
$elements is_array($elements) ? $elements : [$elements];

        
array_walk($elements, function (&$element) use ($name$id) {
            
$element "{$element}#{$id}{$element}[name='{$name}']";
        });

        return 
$this->crawler()->filter(implode(', '$elements));
    }

    
/**
     * Convert the given uploads to UploadedFile instances.
     *
     * @param  SymfonyComponentDomCrawlerForm  $form
     * @param  array  $uploads
     * @return array
     */
    
protected function convertUploadsForTesting(Form $form, array $uploads)
    {
        
$files $form->getFiles();

        
$names array_keys($files);

        
$files array_map(function (array $file$name) use ($uploads) {
            return isset(
$uploads[$name])
                        ? 
$this->getUploadedFileForTesting($file$uploads$name)
                        : 
$file;
        }, 
$files$names);

        return 
array_combine($names$files);
    }

    
/**
     * Create an UploadedFile instance for testing.
     *
     * @param  array  $file
     * @param  array  $uploads
     * @param  string  $name
     * @return IlluminateHttpUploadedFile
     */
    
protected function getUploadedFileForTesting($file$uploads$name)
    {
        return new 
UploadedFile(
            
$file['tmp_name'], basename($uploads[$name]), $file['type'], $file['size'], $file['error'], true
        
);
    }

    
/**
     * Fail the test with the given error message.
     *
     * @param  string  $message
     * @return void
     */
    
protected function failPageInspection($message)
    {
        
$this->fail($this->html().str_repeat("n"4).$message.'. Check content above.');
    }
}
Онлайн: 3
Реклама