sinnebeck / laravel-dom-assertions
Requires
- php: ^8.0
- ext-dom: *
- ext-libxml: *
- illuminate/testing: ^9.0|^10.0|^11.0
- symfony/css-selector: ^6.0|^7.0
Requires (Dev)
- laravel/pint: ^1.2
- nunomaduro/larastan: ^2.2
- orchestra/testbench: ^7.0|^8.0|^9.0
- pestphp/pest: ^1.0|^2.34
- phpstan/extension-installer: ^1.2
- phpstan/phpstan-deprecation-rules: ^1.0
- phpstan/phpstan-phpunit: ^1.1
- vimeo/psalm: ^4.29|^5.22
README
此包提供了一些额外的断言助手,用于在HTTP测试中使用。如果您曾经需要比 assertSee
、assertSeeInOrder
、assertSeeText
、assertSeeTextInOrder
、assertDontSee
和 assertDontSeeText
更多的视图断言控制,那么这个包就是为您准备的。
安装
您可以通过composer安装此包
composer require sinnbeck/laravel-dom-assertions --dev
示例
假设我们有一个包含以下html的视图
<nav> <ul> @foreach ($menuItems as $menuItem) <li @class([ "p-3 text-white", "text-blue-500 active" => Route::is($menuItem->route) ])> <a href="{{route($menuItem->route)}}">{{$menuItem->name}}</a> </li> @endforeach </ul> </nav>
现在我们想确保在访问此路由时选择了正确的菜单项。我们可以尝试使用一些正则表达式来匹配它,但它可能会很容易出错。
$response = $this->get(route('about')) ->assertOk(); $this->assertMatchesRegularExpression( '/<li(.)*class="(.)*active(.)*">(.|\n)*About(.|\n)*?<\/li>/', $response->getContent() );
但这可能会非常脆弱,一个简单的换行符就可能导致它失败。
使用此包,您现在可以使用如下表达式语法。
$this->get(route('about')) ->assertOk() ->assertElementExists('nav > ul', function(\Sinnbeck\DomAssertions\Asserts\AssertElement $ul) { $ul->contains('li', [ 'class' => 'active', 'text' => 'About' ]); $ul->doesntContain('li', [ 'class' => 'active', 'text' => 'Home' ]); });
使用方法
测试DOM
在测试中调用路由时,您可能想确保视图包含某些元素。为了测试这一点,您可以在测试响应上使用 ->assertElementExists()
方法。以下将确保解析的响应中有一个body标签。请注意,此包假设具有合适的HTML结构,如果它们缺失,则会在您的HTML中添加html、head和body标签!
$this->get('/some-route') ->assertElementExists();
如果您想获取页面上的特定元素,您可以提供css选择器作为第一个参数以获取一个特定的元素。
$this->get('/some-route') ->assertElementExists('#nav');
->assertElementExists()
的第二个参数是一个闭包,它接收一个 \Sinnbeck\DomAssertions\Asserts\AssertElement
的实例。这允许您对元素本身进行断言。这里我们正在断言该元素是 div
。
$this->get('/some-route') ->assertElementExists('#overview', function (AssertElement $assert) { $assert->is('div'); });
就像表单一样,您也可以断言某些属性是否存在
$this->get('/some-route') ->assertElementExists('#overview', function (AssertElement $assert) { $assert->has('x-data', '{foo: 1}'); });
或不存在
$this->get('/some-route') ->assertElementExists('#overview', function (AssertElement $assert) { $assert->doesntHave('x-data', '{foo: 2}'); });
您还可以确保存在某些子元素。
$this->get('/some-route') ->assertElementExists('#overview', function (AssertElement $assert) { $assert->contains('div'); });
如果您需要更具体,可以使用css选择器。
$this->get('/some-route') ->assertElementExists('#overview', function (AssertElement $assert) { $assert->contains('div:nth-of-type(3)'); });
您还可以检查子元素是否有某些属性。
$this->get('/some-route') ->assertElementExists('#overview', function (AssertElement $assert) { $assert->contains('li.list-item', [ 'x-data' => 'foobar' ]); });
或确保某些子元素不存在
$this->get('/some-route') ->assertElementExists('#overview', function (AssertElement $assert) { $assert->doesntContain('li.list-item', [ 'x-data' => 'foobar' ]); });
Contains还可以接受一个第三参数来指定元素应匹配多少次。
$this->get('/some-route') ->assertElementExists('#overview', function (AssertElement $assert) { $assert->contains('li.list-item', [ 'x-data' => 'foobar' ], 3); });
如果您只想检查元素类型,则可以省略第二个参数。
$this->get('/some-route') ->assertElementExists('#overview', function (AssertElement $assert) { $assert->contains('li.list-item', 3); });
您还可以找到某个特定元素并对它进行断言。请注意,它只会检查第一个匹配的元素。
$this->get('/some-route') ->assertElementExists('#overview', function (AssertElement $assert) { $assert->find('li.list-item'); });
您还可以作为第二个参数添加一个闭包,该闭包接收一个 \Sinnbeck\DomAssertions\Asserts\AssertElement
的实例。
$this->get('/some-route') ->assertElementExists('#overview', function (AssertElement $assert) { $assert->find('li.nth-of-type(3)', function (AssertElement $element) { $element->is('li'); }); });
如果您想对所有匹配选择的元素进行断言,可以使用 'each'。
$this->get('/some-route') ->assertElementExists('#overview', function (AssertElement $assert) { $assert->each('li', function (AssertElement $element) { $element->has('class', 'list-item'); }); });
您还可以无限地断言DOM结构。
$this->get('/some-route') ->assertElementExists(function (AssertElement $element) { $element->find('div', function (AssertElement $element) { $element->is('div'); $element->find('p', function (AssertElement $element) { $element->is('p'); $element->find('#label', function (AssertElement $element) { $element->is('span'); }); }); $element->find('p:nth-of-type(2)', function (AssertElement $element) { $element->is('p'); $element->find('.sub-header', function (AssertElement $element) { $element->is('h4'); }); }); }); });
测试表单
测试表单允许使用上述所有DOM断言,但有一些特殊的助手来帮助测试表单。我们不会使用 ->assertElementExists()
,而是在测试响应上使用 ->assertFormExists()
方法。
$this->get('/some-route') ->assertFormExists();
->assertFormExists()
方法将检查它找到的第一个表单。如果您有多个表单,并想使用第一个以外的表单,您可以将css选择器作为第一个参数提供以获取特定的一个。
$this->get('/some-route') ->assertFormExists('#users-form');
如果有多个匹配项,它将返回第一个匹配的表单。
$this->get('/some-route') ->assertFormExists(null, 'nav .logout-form');
->assertFormExists()
方法的第二个参数是一个闭包,该闭包接收一个 \Sinnbeck\DomAssertions\Asserts\AssertForm
实例。这允许您对表单本身进行断言。在这里,我们断言它具有特定的 action 和 method
$this->get('/some-route') ->assertFormExists('#form1', function (AssertForm $form) { $form->hasAction('/logout') ->hasMethod('post'); });
如果您省略了 CSS 选择器,它将自动默认查找页面上的第一个表单
$this->get('/some-route') ->assertFormExists(function (AssertForm $form) { $form->hasAction('/logout') ->hasMethod('post'); });
您还可以检查 csrf 和方法欺骗
$this->get('/some-route') ->assertFormExists(function (AssertForm $form) { $form->hasAction('/update-user') ->hasMethod('post') ->hasCSRF() ->hasSpoofMethod('PUT'); });
检查除 GET 和 POST 以外的其他方法将自动将调用转发到 ->hasSpoofMethod()
$this->get('/some-route') ->assertFormExists(function (AssertForm $form) { $form->hasMethod('PUT'); });
甚至可以检查任意属性
$this->get('/some-route') ->assertFormExists(function (AssertForm $form) { $form->has('x-data', 'foo') $form->hasEnctype('multipart/form-data'); //it also works with magic methods });
您还可以轻松测试输入或文本区域
$this->get('/some-route') ->assertFormExists(function (AssertForm $form) { $form->containsInput([ 'name' => 'first_name', 'value' => 'Gunnar', ]) ->containsTextarea([ 'name' => 'comment', 'value' => '...', ]); });
或任意子元素
$this->get('/some-route') ->assertFormExists(function (AssertForm $form) { $form->contains('label', [ 'for' => 'username', ]) ->containsButton([ //or use a magic method 'type' => 'submit', ]); });
您还可以确保某些子元素不存在。
$this->get('/some-route') ->assertFormExists(function (AssertForm $form) { $form->doesntContain('label', [ 'for' => 'username', ]); });
测试选择器的操作也很简单,它与 assertFormExists()
的工作方式类似。它将选择器作为第一个参数,将闭包作为第二个参数。第二个参数返回一个 \Sinnbeck\DomAssertions\Asserts\AssertSelect
实例。这可以用来断言选择器具有某些属性。
$this->get('/some-route') ->assertFormExists(function (AssertForm $form) { $form->findSelect('select:nth-of-type(2)', function (AssertSelect $select) { $select->has('name', 'country'); }); });
您还可以断言它具有某些选项。您可以检查一个特定的选项或一个选项数组
$this->get('/some-route') ->assertFormExists(function (AssertForm $form) { $form->findSelect('select:nth-of-type(2)', function (AssertSelect $select) { $select->containsOption([ [ 'x-data' => 'none', 'value' => 'none', 'text' => 'None', ] ]) ->containsOptions( [ 'value' => 'dk', 'text' => 'Denmark', ], [ 'value' => 'us', 'text' => 'USA', ], ); }); });
您还可以检查选择器是否有值。
$this->get('/some-route') ->assertFormExists('#form1', function (AssertForm $form) { $form->findSelect('select', function (AssertSelect $select) { $select->hasValue('da'); }); });
您还可以检查具有多个值的选择器
$this->get('/some-route') ->assertFormExists('#form1', function (AssertForm $form) { $form->findSelect('select', function (AssertSelect $select) { $select->hasValues(['da', 'en']); }); });
测试 datalists 的工作方式与选择器基本相同。唯一不同的是,选择器需要是 datalist
或 id(例如 #my-list
)。断言使用 \Sinnbeck\DomAssertions\Asserts\AssertDatalist
类。
$this->get('/some-route') ->assertFormExists('#form1', function (AssertForm $form) { $form->findDatalist('#skills', function (AssertDatalist $list) { $list->containsOptions( [ 'value' => 'PHP', ], [ 'value' => 'Javascript', ], ); }); });
Livewire 的使用
由于 Livewire 使用 Laravel 的 TestResponse
类,因此您可以在无需任何更改的情况下轻松使用此包与 Livewire
Livewire::test(UserForm::class) ->assertElementExists('form', function (AssertElement $form) { $form->find('#submit', function (AssertElement $assert) { $assert->is('button'); $assert->has('text', 'Submit'); })->contains('[wire\:model="name"]', 1); });
Blade 视图的使用
您还可以使用此包来测试 blade 视图。
$this->view('navigation') ->assertElementExists('nav > ul', function(AssertElement $ul) { $ul->contains('li', [ 'class' => 'active', ]); });
方法概述
测试此包
vendor/bin/pest
变更日志
请参阅 变更日志 了解最近更改的更多信息。
贡献
请参阅 贡献指南 了解详细信息。
鸣谢
许可证
MIT 许可证(MIT)。请参阅 许可证文件 了解更多信息。