如何让Behat查找并统计特定文本的出现次数?
解决Behat统计页面特定文本出现次数的问题
你遇到的核心问题是:div:contains("%s")选择器找的是包含目标文本的div元素数量,而非文本本身在页面中出现的次数,而且这个选择器还把范围限制在了div标签内,漏掉了其他标签里的文本,这就是为什么你得到19个结果而非预期的2次。
下面给你两种针对性的解决方案,根据你的实际需求选择:
方案1:统计文本在页面纯内容中的出现次数(推荐,完全匹配你的需求)
这个方法不需要关心文本所在的标签类型,直接统计整个页面可见文本中目标字符串的出现次数,逻辑简单且准确:
public function iShouldSeeTimes($text, $count) { // 获取整个页面的纯文本内容(自动过滤HTML标签) $pageText = $this->getSession()->getPage()->getText(); // 统计目标文本的出现次数(默认大小写敏感) $actualCount = substr_count($pageText, $text); // 如果需要忽略大小写匹配,可以替换成下面这行: // $actualCount = substr_count(strtolower($pageText), strtolower($text)); if ($actualCount == (int)$count) { return; } throw new ExpectationException( sprintf('"%s" was supposed to appear %d times, got %d instead', $text, $count, $actualCount), $this->getSession() ); }
这个方案的优势:
- 不受元素类型限制:不管文本在div、p、span还是其他标签里,甚至直接在body中,都能被正确统计
- 真正统计文本出现的次数:比如一个元素里多次出现目标文本,也会被逐一计数(而不是只算一个元素)
方案2:统计包含目标文本的所有可见元素数量(如果你的需求是元素个数)
如果你其实是想统计有多少个独立元素包含该文本(不管元素内出现几次),可以把选择器改成通用匹配,但要排除script、style这类不显示的元素:
public function iShouldSeeTimes($text, $count) { // 匹配所有包含文本的可见元素,排除脚本和样式标签 $selector = sprintf('*:contains("%s"):not(script):not(style)', $text); $matchingElements = $this->getSession()->getPage()->findAll('css', $selector); $actualCount = count($matchingElements); if ($actualCount == (int)$count) { return; } throw new ExpectationException( sprintf('Elements containing "%s" were supposed to be %d, got %d instead', $text, $count, $actualCount), $this->getSession() ); }
补充:原代码的问题说明
你原代码里的strpos(reset($result)->getText(), $text)判断是多余的——因为:contains()选择器已经确保选中的元素包含目标文本了,这个判断完全没必要。另外,div:contains()的范围太窄,只能覆盖div标签内的文本,这也是结果不符合预期的关键原因之一。
内容的提问来源于stack exchange,提问作者Jaeger
相关产品推荐
相关产品推荐

