sinnebeck/laravel-dom-assertions

v1.5.4 2024-08-28 06:25 UTC

README

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads

此包提供了一些额外的断言助手,用于在HTTP测试中使用。如果您曾经需要比 assertSeeassertSeeInOrderassertSeeTextassertSeeTextInOrderassertDontSeeassertDontSeeText 更多的视图断言控制,那么这个包就是为您准备的。

安装

您可以通过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)。请参阅 许可证文件 了解更多信息。