Laravel 测试页面上元素的顺序
Laravel test order of elements on page
我想用 Laravel TestCase 测试我的排序是否正常工作。我有简单的测试页:
<div id="values">
@foreach(['Value1', 'Value2'] as $value)
<div class="test-class">{{$value}}</div>
@endforeach
</div>
现在我想测试第一个 .test-class 元素是否包含 'Value1'。我尝试了不同的方法,但没有成功。这是第一个:
public function testSorting()
{
$this->visit(route('dummy'));
$this->see('Value1');
$this->seeInElement('.test-class:first-of-type', 'Value2');
}
这一个导致异常:
Symfony\Component\CssSelector\Exception\ExpressionErrorException: "*:first-of-type" is not implemented.
然后我试了
$this->seeInElement('#values:first-child', 'Value2');
我的测试是绿色的。但它应该是红色的,因为第一个child是'Value1'。它完全忽略了 ':first-child' 部分。
然后我试了
$this->seeInElement('#values:nth-child(1)', 'Value2');
也变绿了。所以这个方法也不行。
我错过了什么吗?或者无法使用 Laravel 测试来测试页面上元素的顺序?
不是针对您的特定问题的解决方案,而是针对您的问题的解决方法:
您可以使用 $loop->iteration
辅助变量枚举 test-class
divs,其中包含当前循环迭代的次数。
<div id="values">
@foreach(['Value1', 'Value2'] as $value)
<div class="test-class" id="value_{{$loop->iteration}}">{{$value}}</div>
@endforeach
</div>
现在您的 div 类 有一个以 1 开头的枚举 ID,您可以在测试中使用 select 或 #value_1
select首先 div:
$this->seeInElement('#value_1', 'Value2');
所以,我已经解决了。关键是查看 \Symfony\Component\DomCrawler\Crawler class。它有很多有用的方法,例如 first()、last() 或 eq($number).我在 TestCase class:
中创建了这个方法
public function seeInFirstElement($selector, $text)
{
$this->assertContains($text, trim($this->crawler->filter($selector)->first()->text()));
return $this;
}
您可以删除 trim() 函数,但如果测试失败,输出看起来会更好。
所以,在我的测试中,我使用这样的结构来测试排序:
$this->seeInFirstElement('.test-class', 'Value1');
我来晚了,但我一直在使用下面的方法来检查页面上项目的顺序。到目前为止似乎效果很好。
在您的 TestCase
基础 class 上实施以下方法。
/**
* Given a CSS selector string, check if the elements matching the query
* contain the values provided, in the order they are provided.
*
* @param string $selector
* @param array $contents
* @return $this
*/
public function seeInOrder($selector, Array $contents)
{
$matches = $this->crawler->filter($selector);
try {
foreach ($matches as $index => $domElement) {
$needle = $contents[$index];
$this->assertContains($needle, trim($domElement->textContent));
}
} catch (PHPUnit_Framework_ExpectationFailedException $e) {
$this->fail('Failed asserting that the element at index ' . $index . ' contains the string "' . $contents[$index] . '"');
}
return $this;
}
用法:
/**
* Test that the /books route returns a list of books in explicit order.
*
* @test
* @return void
*/
public function books_index_page_lists_books_in_explicit_order()
{
$book_1 = factory(App\Book::class)->create([
'order' => 0
]);
$book_2 = factory(App\Book::class)->create([
'order' => 1
]);
$this->visit('/books')
->see($book_1->title)
->see($book_2->title)
->seeInOrder('.books .book', [
$book_1->title,
$book_2->title
]);
}
我在 HTTP 测试中偶然发现了这个问题,如果您正在使用它,则无需像下面的答案那样构建自己的函数。 Laravel 附带了一堆断言,包括 assertSeeInOrder
:
https://laravel.com/docs/7.x/http-tests#assert-see-in-order
我想用 Laravel TestCase 测试我的排序是否正常工作。我有简单的测试页:
<div id="values">
@foreach(['Value1', 'Value2'] as $value)
<div class="test-class">{{$value}}</div>
@endforeach
</div>
现在我想测试第一个 .test-class 元素是否包含 'Value1'。我尝试了不同的方法,但没有成功。这是第一个:
public function testSorting()
{
$this->visit(route('dummy'));
$this->see('Value1');
$this->seeInElement('.test-class:first-of-type', 'Value2');
}
这一个导致异常:
Symfony\Component\CssSelector\Exception\ExpressionErrorException: "*:first-of-type" is not implemented.
然后我试了
$this->seeInElement('#values:first-child', 'Value2');
我的测试是绿色的。但它应该是红色的,因为第一个child是'Value1'。它完全忽略了 ':first-child' 部分。
然后我试了
$this->seeInElement('#values:nth-child(1)', 'Value2');
也变绿了。所以这个方法也不行。
我错过了什么吗?或者无法使用 Laravel 测试来测试页面上元素的顺序?
不是针对您的特定问题的解决方案,而是针对您的问题的解决方法:
您可以使用 $loop->iteration
辅助变量枚举 test-class
divs,其中包含当前循环迭代的次数。
<div id="values">
@foreach(['Value1', 'Value2'] as $value)
<div class="test-class" id="value_{{$loop->iteration}}">{{$value}}</div>
@endforeach
</div>
现在您的 div 类 有一个以 1 开头的枚举 ID,您可以在测试中使用 select 或 #value_1
select首先 div:
$this->seeInElement('#value_1', 'Value2');
所以,我已经解决了。关键是查看 \Symfony\Component\DomCrawler\Crawler class。它有很多有用的方法,例如 first()、last() 或 eq($number).我在 TestCase class:
中创建了这个方法public function seeInFirstElement($selector, $text)
{
$this->assertContains($text, trim($this->crawler->filter($selector)->first()->text()));
return $this;
}
您可以删除 trim() 函数,但如果测试失败,输出看起来会更好。 所以,在我的测试中,我使用这样的结构来测试排序:
$this->seeInFirstElement('.test-class', 'Value1');
我来晚了,但我一直在使用下面的方法来检查页面上项目的顺序。到目前为止似乎效果很好。
在您的 TestCase
基础 class 上实施以下方法。
/**
* Given a CSS selector string, check if the elements matching the query
* contain the values provided, in the order they are provided.
*
* @param string $selector
* @param array $contents
* @return $this
*/
public function seeInOrder($selector, Array $contents)
{
$matches = $this->crawler->filter($selector);
try {
foreach ($matches as $index => $domElement) {
$needle = $contents[$index];
$this->assertContains($needle, trim($domElement->textContent));
}
} catch (PHPUnit_Framework_ExpectationFailedException $e) {
$this->fail('Failed asserting that the element at index ' . $index . ' contains the string "' . $contents[$index] . '"');
}
return $this;
}
用法:
/**
* Test that the /books route returns a list of books in explicit order.
*
* @test
* @return void
*/
public function books_index_page_lists_books_in_explicit_order()
{
$book_1 = factory(App\Book::class)->create([
'order' => 0
]);
$book_2 = factory(App\Book::class)->create([
'order' => 1
]);
$this->visit('/books')
->see($book_1->title)
->see($book_2->title)
->seeInOrder('.books .book', [
$book_1->title,
$book_2->title
]);
}
我在 HTTP 测试中偶然发现了这个问题,如果您正在使用它,则无需像下面的答案那样构建自己的函数。 Laravel 附带了一堆断言,包括 assertSeeInOrder
:
https://laravel.com/docs/7.x/http-tests#assert-see-in-order