Laravel HTTP 测试与Symfony的DomCrawler
Laravel  /  管理员 发布于 1年前   399
你是否曾经需要在 Laravel 的 HTTP 测试中断言 HTML 响应的一部分?
最近,我需要验证响应的部分内容,以验证是否渲染了重要内容。
比如说,你有一个重要的 JavaScript 文件,你想确保它包含在 DOM 中吗?
下面是我们要构建的测试 API:
$node = $response->get('/')
->crawl()
->filter('a')
->reduce(function (Crawler $node): bool {
return $node->attr('href') === 'https://www.zongscan.com';
});
$this->assertCount(1, $node);
在 PHP 中,有几种解析和遍历 DOM 的方法,如 PHP 的 DOMDocument、PHPUnit 的 DOM 断言(已废弃)、Symfony 的 DOMCrawler 组件等。
我更喜欢 Symfony 的 DOMCrawler 组件,它具有非常强大的过滤、遍历等功能。
让我们看看如何在 Laravel HTTP 测试中快速使用 DOMCrawler 组件!
代码示例
使用 DOMCrawler 的要点是创建一个新的 Crawler 实例,并将 HTML 内容传递给构造函数:
use Symfony\Component\DomCrawler\Crawler;
$crawler = new Crawler($response->getContent());
foreach ($crawler as $domElement) {
var_dump($domElement->nodeName);
}
直接使用 Crawler 实例是可行的,但会造成重复。
鉴于 Laravel 强大的宏功能,我们可以快速定义一个宏来抓取 TestResponse。
下面是我的宏用法:
$response = $this->get('/');
$crawler = $response->crawl();
// DOM traversal
// Assertions
如果您想试试,请在服务提供者的 boot() 方法中定义以下宏:
use Illuminate\Support\ServiceProvider;
use Illuminate\Testing\TestResponse;
use Symfony\Component\DomCrawler\Crawler;
use PHPUnit\Framework\Assert as PHPUnit;
// ...
public function boot(): void
{
TestResponse::macro('crawl', function(?callable $callback = null): Crawler {
if (empty($content = $this->getContent())) {
PHPUnit::fail('The HTTP response is empty.');
}
$callback ??= fn ($c): Crawler => $c;
return call_user_func($callback, new Crawler($content));
});
}
我们的宏执行以下操作
1.获取响应内容,如果内容为空,则测试立即失败
2.如果用户没有提供回调函数,则使用空凝聚赋值操作符创建一个直通回调函数
3.通过回调传递一个新的爬虫实例,最后返回一个爬虫实例
通过使用空凝聚赋值操作符,如果用户没有提供回调,我们就会提供一个默认的直通回调,从而避免了任何 if 检查。
可调用函数的设计理念是,用户可以遍历 DOM、执行一些断言,并在只需要 DOM 的一部分时,通过 crawl() 最终返回 DOM 的一个子集:
// Return the full content
$crawler = $response->crawl();
// Filter and return the filtered crawler instance
$card = $response->crawl(function (Crawler $c) {
return $c->filter('a')
->reduce(function (Crawler $node) {
return $node->attr('href') === 'https://www.zongscan.com';
});
});
也许这个例子有点矫枉过正,但让我们在默认的 Laravel 安装中验证 welcome.blade.php 中包含的 Laravel News HTML:
use Symfony\Component\DomCrawler\Crawler;
// ...
/**
* A basic test example.
*/
public function test_the_application_returns_a_successful_response(): void
{
$response = $this->get('/');
$response->assertStatus(200);
// Find the Laravel News node
$card = $response->crawl()
->filter('a')
->reduce(function (Crawler $node) {
return $node->attr('href') === 'https://www.zongscan.com';
});
$this->assertNotEmpty($card, 'The Laravel News homepage card was not found!');
// Validate that the $card node has an H2 with `Laravel News`
$this->assertEquals(
'Laravel News',
$card->filter('h2')->first()->text()
);
// Validate that the page shows the blurb
$blurb = $card
->filter('p')
->reduce(function (Crawler $n) {
return str($n->text())->startsWith('Laravel News is a community driven portal');
});
$this->assertCount(1, $blurb);
}
便捷助手函数
您可能想编写更多方便的助手来验证测试中的 DOM 元素。
例如,这里有一个验证节点是否存在的简单断言:
$response
->assertStatus(200)
->assertNodeExists('a[href="https://laravel-news.com"]');
下面是我定义的宏,它也允许与 TestResponse 实例连锁:
TestResponse::macro('assertNodeExists', function(string $selector): static {
$node = $this->crawl()->filter($selector);
$message = "Failed asserting the node exists with selector \"{$selector}\".";
PHPUnit::assertGreaterThan(0, $node->count(), $message);
return $this;
});
如果节点不存在,下面是我们的宏在测试输出中的示例:
1) Tests\Feature\ExampleTest::test_the_application_returns_a_successful_response
Failed asserting the node exists with selector "a[href="https://www.zongscan.com"]".
Failed asserting that 0 is greater than 0.
我建议你看看 Symphony DomCrawler 组件的功能。
https://symfony.com/doc/current/components/dom_crawler.html
它包括强大的 XPath 和 CSS 选择器、节点遍历等功能!
122 在
学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..123 在
Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..原梓番博客 在
在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..博主 在
佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..1111 在
佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
Copyright·© 2019 侯体宗版权所有·
粤ICP备20027696号