1. Go to this page and download the library: Download zenstruck/browser library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
zenstruck / browser example snippets
public function testViewPostAndAddComment()
{
// assumes a "Post" is in the database with an id of 3
$this->browser()
->visit('/posts/3')
->assertSuccessful()
->assertSeeIn('title', 'My First Post')
->assertSeeIn('h1', 'My First Post')
->assertNotSeeElement('#comments')
->fillField('Comment', 'My First Comment')
->click('Submit')
->assertOn('/posts/3')
->assertSeeIn('#comments', 'My First Comment')
;
}
public function testViewPostAndAddComment()
{
$post = PostFactory::new()->create(['title' => 'My First Post']);
$this->browser()
->visit("/posts/{$post->getId()}")
->assertSuccessful()
->assertSeeIn('title', 'My First Post')
->assertSeeIn('h1', 'My First Post')
->assertNotSeeElement('#comments')
->fillField('Comment', 'My First Comment')
->click('Submit')
->assertOn("/posts/{$post->getId()}")
->assertSeeIn('#comments', 'My First Comment')
;
}
namespace App\Tests;
use PHPUnit\Framework\TestCase;
use Zenstruck\Browser\Test\HasBrowser;
class MyTest extends TestCase
{
use HasBrowser;
/**
* Requires this test extends Symfony\Bundle\FrameworkBundle\Test\KernelTestCase
* or Symfony\Bundle\FrameworkBundle\Test\WebTestCase.
*/
public function test_using_kernel_browser(): void
{
$this->browser()
->visit('/my/page')
->assertSeeIn('h1', 'Page Title')
;
}
/**
* Requires this test extends Symfony\Component\Panther\PantherTestCase.
*/
public function test_using_panther_browser(): void
{
$this->pantherBrowser()
->visit('/my/page')
->assertSeeIn('h1', 'Page Title')
;
}
}
/** @var \Zenstruck\Browser $browser **/
$browser
// ACTIONS
->visit('/my/page')
->click('A link')
->fillField('Name', 'Kevin')
->checkField('Accept Terms')
->uncheckField('Accept Terms')
->selectField('Canada') // "radio" select
->selectField('Type', 'Employee') // "select" single option
->selectField('Notification', ['Email', 'SMS']) // "select" multiple options
->selectField('Notification', []) // "un-select" all multiple options
->attachFile('Photo', '/path/to/photo.jpg')
->attachFile('Photo', ['/path/to/photo1.jpg', '/path/to/photo2.jpg']) // attach multiple files (if field supports this)
->click('Submit')
// ASSERTIONS
->assertOn('/my/page') // by default checks "path", "query" and "fragment"
->assertOn('/a/page', ['path']) // check just the "path"
// these look in the entire response body (useful for non-html pages)
->assertContains('some text')
->assertNotContains('some text')
// these look in the html only
->assertSee('some text')
->assertNotSee('some text')
->assertSeeIn('h1', 'some text')
->assertNotSeeIn('h1', 'some text')
->assertSeeElement('h1')
->assertNotSeeElement('h1')
->assertElementCount('ul li', 2)
->assertElementAttributeContains('head meta[name=description]', 'content', 'my description')
->assertElementAttributeNotContains('head meta[name=description]', 'content', 'my description')
// form field assertions
->assertFieldEquals('Username', 'kevin')
->assertFieldNotEquals('Username', 'john')
// form checkbox assertions
->assertChecked('Accept Terms')
->assertNotChecked('Accept Terms')
// form select assertions
->assertSelected('Type', 'Employee')
->assertNotSelected('Type', 'Admin')
// form multi-select assertions
->assertSelected('Roles', 'Content Editor')
->assertSelected('Roles', 'Human Resources')
->assertNotSelected('Roles', 'Owner')
// CONVENIENCE METHODS
->use(function() {
// do something without breaking
})
->use(function(\Zenstruck\Browser $browser) {
// access the current Browser instance
})
->use(function(\Symfony\Component\BrowserKit\AbstractBrowser $browser)) {
// access the "inner" browser
})
->use(function(\Symfony\Component\BrowserKit\CookieJar $cookieJar)) {
// access the cookie jar
$cookieJar->expire('MOCKSESSID');
})
->use(function(\Zenstruck\Browser $browser, \Symfony\Component\DomCrawler\Crawler $crawler) {
// access the current Browser instance and the current crawler
})
->crawler() // Symfony\Component\DomCrawler\Crawler instance for the current response
->content() // string - raw response body
// save the raw source of the current page
// by default, saves to "<project-root>/var/browser/source"
// configure with "BROWSER_SOURCE_DIR" env variable
->saveSource('source.txt')
// the following use symfony/var-dumper's dump() function and continue
->dump() // raw response body
->dump('h1') // html element
->dump('foo') // if json response, array key
->dump('foo.*.baz') // if json response, JMESPath notation can be used
// the following use symfony/var-dumper's dd() function ("dump & die")
->dd() // raw response body or array if json
->dd('h1') // html element
->dd('foo') // if json response, array key
->dd('foo.*.baz') // if json response, JMESPath notation can be used
;
/** @var \Zenstruck\Browser\KernelBrowser $browser **/
$browser
// response assertions
->assertStatus(200)
->assertSuccessful() // 2xx status code
->assertRedirected() // 3xx status code
->assertHeaderEquals('Content-Type', 'text/html; charset=UTF-8')
->assertHeaderContains('Content-Type', 'html')
->assertHeaderEquals('X-Not-Present-Header', null)
// helpers for quickly checking the content type
->assertJson()
->assertXml()
->assertHtml()
->assertContentType('zip')
// by default, exceptions are caught and converted to a response
// use the BROWSER_CATCH_EXCEPTIONS environment variable to change default
// this disables that behaviour allowing you to use TestCase::expectException()
->throwExceptions()
// enable catching exceptions
->catchExceptions()
// by default, the kernel is rebooted between requests
// this disables this behaviour
->disableReboot()
// re-enable rebooting between requests if previously disabled
->enableReboot()
// enable the profiler for the next request (if not globally enabled)
->withProfiling()
// by default, redirects are followed, this disables that behaviour
// use the BROWSER_FOLLOW_REDIRECTS environment variable to change default
->interceptRedirects()
// enable following redirects
// if currently on a redirect response, follows
->followRedirects()
// Follows a redirect if ->interceptRedirects() has been turned on
->followRedirect() // follows all redirects by default
->followRedirect(1) // just follow 1 redirect
// combination of assertRedirected(), followRedirect(), assertOn()
->assertRedirectedTo('/some/page') // follows all redirects by default
->assertRedirectedTo('/some/page', 1) // just follow 1 redirect
// combination of interceptRedirects(), withProfiling(), click()
// useful for submitting forms and making assertions on the "redirect response"
->clickAndIntercept('button')
// exception assertions for the "next request"
->expectException(MyException::class, 'the message')
->post('/url/that/throws/exception') // fails if above exception not thrown
->expectException(MyException::class, 'the message')
->click('link or button') // fails if above exception not thrown
;
// Access the Symfony Profiler for the last request
$queryCount = $browser
// If profiling is not globally enabled for tests, ->withProfiling()
// must be called before the request.
->profile()->getCollector('db')->getQueryCount()
;
// "use" a specific data collector
$browser->use(function(\Symfony\Component\HttpKernel\DataCollector\RequestDataCollector $collector) {
// ...
})
/** @var \Zenstruck\Browser\KernelBrowser $browser **/
$browser
// authenticate a user for subsequent actions
->actingAs($user) // \Symfony\Component\Security\Core\User\UserInterface
// fail if authenticated
->assertNotAuthenticated()
// fail if NOT authenticated
->assertAuthenticated()
// fails if NOT authenticated as "kbond"
->assertAuthenticated('kbond')
// \Symfony\Component\Security\Core\User\UserInterface
->assertAuthenticated($user)
;
use Zenstruck\Browser\HttpOptions;
/** @var \Zenstruck\Browser\KernelBrowser $browser **/
$browser
// http methods
->get('/api/endpoint')
->put('/api/endpoint')
->post('/api/endpoint')
->delete('/api/endpoint')
// second parameter can be an array of request options
->post('/api/endpoint', [
// request headers
'headers' => ['X-Token' => 'my-token'],
// request body
'body' => 'request body',
])
->post('/api/endpoint', [
// json_encode request body and set Content-Type/Accept headers to application/json
'json' => ['request' => 'body'],
// simulates an AJAX request (sets the X-Requested-With to XMLHttpRequest)
'ajax' => true,
])
// optionally use the provided Zenstruck\Browser\HttpOptions object
->post('/api/endpoint',
HttpOptions::create()->withHeader('X-Token', 'my-token')->withBody('request body')
)
// sets the Content-Type/Accept headers to application/json
->post('/api/endpoint', HttpOptions::json())
// json encodes value and sets as body
->post('/api/endpoint', HttpOptions::json(['request' => 'body']))
// simulates an AJAX request (sets the X-Requested-With to XMLHttpRequest)
->post('/api/endpoint', HttpOptions::ajax())
// simulates a JSON AJAX request
->post('/api/endpoint', HttpOptions::jsonAjax())
;
/** @var \Zenstruck\Browser\KernelBrowser $browser **/
$browser
->get('/api/endpoint')
->assertJson() // ensures the content-type is application/json
->assertJsonMatches('foo.bar.baz', 1) // automatically calls ->assertJson()
->assertJsonMatches('foo.*.baz', [1, 2, 3])
->assertJsonMatches('length(foo)', 3)
->assertJsonMatches('"@some:thing"', 6) // note: special characters like : and @ need to be wrapped in quotes
;
// access the json "crawler"
$json = $browser
->get('/api/endpoint')
->json()
;
$json->assertMatches('foo.bar.baz', 1);
$json->assertHas('foo.bar.baz');
$json->assertMissing('foo.bar.boo');
$json->search('foo.bar.baz'); // mixed (the found value at "JMESPath expression")
$json->decoded(); // the decoded json
(string) $json; // the json string pretty-printed
// "use" the json crawler
$json = $browser
->get('/api/endpoint')
->use(function(\Zenstruck\Browser\Json $json) {
// Json acts like a proxy of zenstruck/assert Expectation class
$json->hasCount(5);
$json->contains('foo');
// assert on children: the closure gets Json object contextualized on given selector
// {"foo": "bar"}
$json->assertThat('foo', fn(Json $json) => $json->equals('bar'))
// assert on each element of an array
// {"foo": [1, 2, 3]}
$json->assertThatEach('foo', fn(Json $json) => $json->isGreaterThan(0));
// assert json matches given json schema
$json->assertMatchesSchema(file_get_contents('/path/to/json-schema.json'));
})
;
/** @var \Zenstruck\Browser\PantherBrowser $browser **/
$browser
// pauses the tests and enters "interactive mode" which
// allows you to investigate the current state in the browser
// ( ->takeScreenshot('screenshot.png')
// save the browser's javascript console error log
// by default, saves to "<project-root>/var/browser/console-log"
// configure with "BROWSER_CONSOLE_LOG_DIR" env variable
->saveConsoleLog('console.log')
// check if element is visible in the browser
->assertVisible('.selector')
->assertNotVisible('.selector')
// wait x milliseconds
->wait(1000) // 1 second
->waitUntilVisible('.selector')
->waitUntilNotVisible('.selector')
->waitUntilSeeIn('.selector', 'some text')
->waitUntilNotSeeIn('.selector', 'some text')
->doubleClick('Link')
->rightClick('Link')
// dump() the browser's console error log
->dumpConsoleLog()
// dd() the browser's console error log
->ddConsoleLog()
// dd() and take screenshot (default filename is "screenshot.png")
->ddScreenshot()
;
namespace App\Tests;
use Symfony\Component\Panther\PantherTestCase;
use Zenstruck\Browser\Test\HasBrowser;
class MyTest extends PantherTestCase
{
use HasBrowser;
public function testDemo(): void
{
$browser1 = $this->pantherBrowser()
->visit('/my/page')
// ...
;
$browser2 = $this->pantherBrowser()
->visit('/my/page')
// ...
;
}
}
namespace App\Tests;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Zenstruck\Browser\KernelBrowser;
use Zenstruck\Browser\Test\HasBrowser;
class MyTest extends KernelTestCase
{
use HasBrowser {
browser as baseKernelBrowser;
}
public function testDemo(): void
{
$this->browser()
->assertOn('/') // browser always starts on the homepage (as defined below)
;
}
protected function browser(): KernelBrowser
{
return $this->baseKernelBrowser()
->interceptRedirects() // always intercept redirects
->throwExceptions() // always throw exceptions
->visit('/') // always start on the homepage
;
}
}
namespace App\Tests;
use Zenstruck\Browser\Component;
use Zenstruck\Browser\KernelBrowser;
/**
* If only using this component with a specific browser, this type hint can help your IDE.
*
* @method KernelBrowser browser()
*/
class CommentComponent extends Component
{
public function assertHasNoComments(): self
{
$this->browser()->assertElementCount('#comments li', 0);
return $this; // optionally make methods fluent
}
public function assertHasComment(string $body, string $author): self
{
$this->browser()
->assertSeeIn('#comments li span.body', $body)
->assertSeeIn('#comments li span.author', $author)
;
return $this;
}
public function addComment(string $body, string $author): self
{
$this->browser()
->fillField('Name', $author)
->fillField('Comment', $body)
->click('Add Comment')
;
return $this;
}
protected function preAssertions(): void
{
// this is called as soon as the component is loaded
$this->browser()->assertSeeElement('#comments');
}
protected function preActions(): void
{
// this is called when the component is loaded but before
// preAssertions(). Useful for page components where you
// need to navigate to the page:
// $this->browser()->visit('/contact');
}
}
/** @var \Zenstruck\Browser $browser **/
$browser
->visit('/post/1')
->use(function(CommentComponent $component) {
// the function typehint triggers the component to be loaded,
// preActions() run and preAssertions() run
$component
->assertHasNoComments()
->addComment('comment body', 'Kevin')
->assertHasComment('comment body')
;
})
;
// you can optionally inject multiple components into the ->use() callback
$browser->use(function(Component1 $component1, Component2 $component2) {
$component1->doSomething();
$component2->doSomethingElse();
});
/** @var \Zenstruck\Browser\KernelBrowser $browser **/
$browser
->setDefaultHttpOptions(['headers' => ['X-Token' => 'my-token']])
// now all http requests will have the X-Token header
->get('/endpoint')
// "per-request" options will be merged with the default
->get('/endpoint', ['headers' => ['Another' => 'Header']])
;
namespace App\Tests;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Zenstruck\Browser\KernelBrowser;
use Zenstruck\Browser\Test\HasBrowser;
class MyTest extends KernelTestCase
{
use HasBrowser {
browser as baseKernelBrowser;
}
public function testDemo(): void
{
$this->browser()
// all http requests in this test class will have the X-Token header
->get('/endpoint')
// "per-request" options will be merged with the default
->get('/endpoint', ['headers' => ['Another' => 'Header']])
;
}
protected function browser(): KernelBrowser
{
return $this->baseKernelBrowser()
->setDefaultHttpOptions(['headers' => ['X-Token' => 'my-token']])
;
}
}
namespace App\Tests;
use Zenstruck\Browser\HttpOptions;
class AppHttpOptions extends HttpOptions
{
public static function api(string $token, $json = null): self
{
return self::json($json)
->withHeader('X-Token', $token)
;
}
}
use Zenstruck\Browser\HttpOptions;
/** @var \Zenstruck\Browser\KernelBrowser $browser **/
$browser
// instead of
->post('/api/endpoint', HttpOptions::json()->withHeader('X-Token', 'my-token'))
// use your ApiHttpOptions object
->post('/api/endpoint', AppHttpOptions::api('my-token'))
;
namespace App\Tests;
use Zenstruck\Browser\KernelBrowser;
class AppBrowser extends KernelBrowser
{
public function assertHasToolbar(): self
{
return $this->assertSeeElement('#toolbar');
}
}
namespace App\Tests;
use App\Tests\AppBrowser;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Zenstruck\Browser\Test\HasBrowser;
/**
* @method AppBrowser browser()
*/
abstract class MyTest extends WebTestCase
{
use HasBrowser;
}
namespace App\Tests\Browser;
trait AuthenticationExtension
{
public function loginAs(string $username, string $password): self
{
return $this
->visit('/login')
->fillField('email', $username)
->fillField('password', $password)
->click('Login')
;
}
public function logout(): self
{
return $this->visit('/logout');
}
public function assertLoggedIn(): self
{
$this->assertSee('Logout');
return $this;
}
public function assertLoggedInAs(string $user): self
{
$this->assertSee($user);
return $this;
}
public function assertNotLoggedIn(): self
{
$this->assertSee('Login');
return $this;
}
}
namespace App\Tests;
use App\Tests\Browser\AuthenticationExtension;
use Zenstruck\Browser\KernelBrowser;
class AppBrowser extends KernelBrowser
{
use AuthenticationExtension;
}
public function testDemo(): void
{
$this->browser()
// goes to the /login page, fills email/password fields,
// and presses the Login button
->loginAs('[email protected]', 'password')
// asserts text "Logout" exists (assumes you have a logout link when users are logged in)
->assertLoggedIn()
// asserts email exists as text (assumes you display the user's email when they are logged in)
->assertLoggedInAs('[email protected]')
// goes to the /logout page
->logout()
// asserts text "Login" exists (assumes you have a login link when users not logged in)
->assertNotLoggedIn()
;
}
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.