silverstripe / behat-extension
SilverStripe 框架 Behat 扩展
Requires
- php: ^8.1
- behat/behat: ^3.11.0
- behat/mink: ^1.10.0
- friends-of-behat/mink-extension: ^2
- phpunit/phpunit: ^9.5
- silverstripe/framework: ^5
- silverstripe/mink-facebook-web-driver: ^2
- silverstripe/testsession: ^3
- squizlabs/php_codesniffer: ^3.7
- symfony/dom-crawler: ^6.1
- symfony/finder: ^6.1
- 6.x-dev
- 5.x-dev
- dev-master / 5.x-dev
- 5.4.x-dev
- 5.4.0
- 5.3.x-dev
- 5.3.2
- 5.3.1
- 5.3.0
- 5.2.x-dev
- 5.2.1
- 5.2.0
- 5.1.x-dev
- 5.1.1
- 5.1.0
- 5.0.x-dev
- 5.0.9
- 5.0.8
- 5.0.7
- 5.0.6
- 5.0.5
- 5.0.4
- 5.0.3
- 5.0.2
- 5.0.1
- 5.0.0
- 4.x-dev
- 4.12.x-dev
- 4.12.0
- 4.11.x-dev
- 4.11.5
- 4.11.4
- 4.11.3
- 4.11.2
- 4.11.1
- 4.11.0
- 4.10.x-dev
- 4.10.0
- 4.9.x-dev
- 4.9.1
- 4.9.0
- 4.8.x-dev
- 4.8.2
- 4.8.1
- 4.8.0
- 4.7.x-dev
- 4.7.0
- 4.6.x-dev
- 4.6.0
- 4.5.x-dev
- 4.5.0
- 4.4.x-dev
- 4.4.0
- 4.3.x-dev
- 4.3.0
- 4.2.2
- 4.2.1
- 4.2.0
- 4.1.0
- 4.0.x-dev
- 4.0.0
- 4.0.0-beta1
- 4.0.0-alpha2
- 3.x-dev / 3.1.x-dev
- 3.0.x-dev
- 3.0.0
- 3.0.0-rc1
- 3.0.0-beta3
- 3.0.0-beta2
- 3.0.0-beta1
- 3.0.0-alpha10
- 3.0.0-alpha9
- 3.0.0-alpha8
- 3.0.0-alpha7
- 3.0.0-alpha6
- 3.0.0-alpha5
- 3.0.0-alpha4
- 3.0.0-alpha3
- 3.0.0-alpha2
- 3.0.0-alpha1
- 2.x-dev
- 2.3.7
- 2.3.6
- 2.3.5
- 2.3.4
- 2.3.3
- 2.3.2
- 2.3.1
- 2.3.0
- 2.2.3
- 2.2.2
- 2.2.1
- 2.2.0
- 2.1.x-dev
- 2.1.1
- 2.1.0
- 2.0.0
- 1.0.x-dev
- 1.0.5
- 1.0.4
- 1.0.3
- 1.0.2
- 1.0.1
- 1.0.0
- 0.1.x-dev
- dev-feature/upgrade-mink
- dev-webservice-tutorial
- dev-experiments/behat-3-upgrade
This package is auto-updated.
Last update: 2024-09-18 03:30:08 UTC
README
概述
Behat 是一个行为驱动开发的测试框架。因为它主要通过浏览器与您的网站进行交互,所以您不需要任何特定的集成工具就可以与基本的 Silverstripe 网站一起使用,只需按照 标准的 Behat 使用说明 进行操作。
如果您想超越与现有网站和数据库的交互,例如更改数据库内容,这些内容稍后需要回滚到“干净的状态”,则此扩展非常有用。
它提供了以下帮助
- 在 Behat 上下文中提供对 Silverstripe 类的访问
- 自动设置临时数据库
- 在每个场景中重置数据库内容
- 为 SilverStripe 的登录表单和其他常见任务预建上下文
- 创建具有预定义权限的成员固定值
- 在 Behat 场景中创建 YML 固定值定义
- 等待 jQuery Ajax 响应(而不是固定的等待时间)
- 捕获 JavaScript 错误并通过 Selenium 记录日志
- 当检测到断言错误时,将截图保存到文件系统
为了实现这一点,该扩展做出了一个基本假设:您的 Behat 测试与测试的 Silverstripe 代码库相同的同一个应用程序运行,在一个本地托管网站上,来自相同的代码库。这很重要,因为我们需要访问底层的 SilverStripe PHP 类。当然,您可以使用远程浏览器进行实际测试。
注意:该扩展仅与 selenium2
Mink 驱动程序进行了测试。
安装
在 Silverstripe CMS 项目中(请参阅 入门文档),通过 Composer 添加 Silverstripe Behat 扩展。
composer require --dev silverstripe/behat-extension
下载独立的 Google Chrome WebDriver
除非您已设置 SS_BASE_URL
,否则您还需要指定您网站根目录的 URL。您可以将它添加到项目根目录中现有的 behat.yml
配置文件,或在终端会话中将它设置为环境变量。
export BEHAT_PARAMS="extensions[SilverStripe\BehatExtension\MinkExtension][base_url]=http://localhost/"
使用
启动 ChromeDriver
您可以在另一个终端会话中本地运行服务器
chromedriver
运行测试
现在您可以运行测试(例如,针对 framework
模块)
vendor/bin/behat @framework
或者通过名称运行单个场景(支持正则表达式)
vendor/bin/behat --name 'My scenario title' @framework
这将默认启动 Chrome 浏览器。其他浏览器和配置可以在 behat.yml
中进行配置。
使用独立命令运行(需要 Bash)
如果您使用 silverstripe/serve
和 chromedriver
运行,您还可以使用以下命令,这些命令将自动为单个测试启动和停止这些服务。
vendor/bin/behat-ss @framework
这将自动化
- 启动服务器
- 启动 chromedriver
- 运行 behat
- 关闭 chromedriver
- 关闭服务器
请确保在 .env
中将 SS_BASE_URL
设置为 http://localhost:8080
教程
配置
Silverstripe安装程序已经包含一个YML配置文件,该文件可以用于在位于项目根目录的独立ChromeDriver服务器上运行测试,文件名为behat.yml
。
请确保您已在.env
文件中配置了SS_BASE_URL
。
通用的Mink配置设置位于SilverStripe\BehatExtension\MinkExtension
,它是Behat\MinkExtension\Extension
的子类。
设置概述(所有都在extensions.SilverStripe\BehatExtension\Extension
路径下)
ajax_steps
:由于Silverstripe广泛使用AJAX请求,我们必须想出一个更有效、更简洁的方法来处理它们,而不是仅仅使用可选的ajax_steps
。在这里定义的步骤通过特殊的AJAX处理器进行匹配,以便它们可以被“捕获”,从而调整延迟。您可以使用管道分隔的字符串或匹配步骤定义的子字符串列表。ajax_timeout
:在多少毫秒后,Ajax请求被视为超时,并且脚本继续执行断言以避免死锁(默认值:5000)。screenshot_path
:用于存储失败步骤最后已知状态的截图的绝对路径。该目录中的截图名称由特征文件名和失败行号组成。
示例:behat.yml
default: suites: framework: paths: - '%paths.modules.framework%/tests/behat/features' contexts: - SilverStripe\Framework\Tests\Behaviour\FeatureContext - SilverStripe\Framework\Tests\Behaviour\CmsFormsContext - SilverStripe\Framework\Tests\Behaviour\CmsUiContext - SilverStripe\BehatExtension\Context\BasicContext - SilverStripe\BehatExtension\Context\EmailContext - SilverStripe\BehatExtension\Context\LoginContext - SilverStripe\BehatExtension\Context\FixtureContext: - '%paths.modules.framework%/tests/behat/features/files/' extensions: SilverStripe\BehatExtension\MinkExtension: default_session: facebook_web_driver javascript_session: facebook_web_driver facebook_web_driver: browser: chrome wd_host: "http://127.0.0.1:9515" #chromedriver port SilverStripe\BehatExtension\Extension: screenshot_path: '%paths.base%/artifacts/screenshots'
模块初始化
现在您可以开始编写功能了!只需在任何代码库中创建*.feature
文件,并像上面那样运行它们。我们建议使用tests/behat/features
的文件夹结构,因为它与SilverStripe的PHPUnit测试的常见位置保持一致。
Behat测试依赖于包含步骤定义的FeatureContext
类,并且可以由其他子上下文组成,例如用于SilverStripe特定CMS步骤(有关详细信息,请参阅behat.org)。由于步骤定义非常特定于领域,您可能需要自己的上下文。Silverstripe Behat扩展提供了一个初始化脚本,该脚本在推荐的文件夹结构中生成模板。
vendor/bin/behat --init @mymodule --namespace="MyVendor\MyModule"
注意:命名空间是必需的
现在您将有一个位于mymodule/tests/behat/src/FeatureContext.php
的类,默认情况下,它将由composer.json添加psr-4类映射。同时,还将创建一个包含功能的文件夹,路径为mymodule/tests/behat/features
。将构建一个mymodule/behat.yml
,其中包含以模块命名的默认套件。
可用的步骤定义
该扩展包含几个BehatContext
子类,并提供了一些额外的步骤定义。其中一些在一般网站测试中很有用,其他一些则特定于SilverStripe。要找出所有可用的步骤(以及它们定义的文件),请运行以下命令
vendor/bin/behat @mymodule --definitions=i
注意:在Silverstripe的framework
模块中还有更多特定的步骤定义,用于与CMS界面交互(请参阅framework/tests/behat/features/bootstrap
)。除了动态列表之外,在指南末尾还可以找到可用的步骤的速查表。
测试数据
由于每次测试运行都会创建一个新的数据库,除非您明确定义,否则您不能依赖于现有状态。
数据库默认值
获取默认数据的最简单方法是使用DataObject->requireDefaultRecords()
。许多模块已经定义了此方法,例如,blog
模块自动在页面树中创建默认的BlogHolder
条目。有时这些默认值可能适得其反,因此您需要通过在功能定义的顶部放置@database-defaults
标签来“启用”它们。默认值在每个场景之后自动重置。
内联定义
如果您需要更多关于正在创建哪些记录的灵活性和透明度,请使用行内定义语法。以下示例展示了某些语法变体
Feature: Do something with pages As an site owner I want to manage pages Background: # Creates a new page without data. Can be accessed later under this identifier Given a "page" "Page 1" # Uses a custom RegistrationPage type And an "error page" "Register" # Creates a page with inline properties And a "page" "Page 2" with "URLSegment"="page-1" and "Content"="my page 1" # Field names can be tabular, and based on DataObject::$field_labels And the "page" "Page 3" has the following data | Content | <blink> | | My Property | foo | | My Boolean | bar | # Pages are published by default, can be explicitly unpublished And the "page" "Page 1" is not published # Create a hierarchy, and reference a record created earlier And the "page" "Page 1.1" is a child of a "page" "Page 1" # Specific page type step And a "page" "My Redirect" which redirects to a "page" "Page 1" And a "member" "Website User" with "FavouritePage"="=>Page.Page 1" @javascript Scenario: View a page in the tree Given I am logged in with "ADMIN" permissions And I go to "/admin/pages" Then I should see "Page 1"
- 固定项(Fixtures)是在您定义的位置创建的。如果您希望在每次场景之前创建固定项,请将它们定义在背景(Background)中。如果您只想在特定场景运行时创建它们,请在那里定义。
- 固定项在场景之间会被清除。
- 基本语法适用于所有
DataObject
子类,但某些特定的表示法,如“未发布”(is not published),需要在类上应用如Hierarchy
等扩展。 - 记录类型、标识符、属性名称和属性值都需要引用。
- 记录类型(类名)可以使用更自然的表示法(例如,“注册页面”而不是“Registration Page”)。
- 记录类型支持
$singular_name
表示法,该表示法也用于在整个CMS中引用类型。记录属性名称也以相同的方式支持$field_labels
表示法。 - 属性值也可以使用
=>
符号来指示记录之间的关系。表示法为=><classname>.<identifier>
。对于has_many
或many_many
关系,可以使用逗号分隔多个关系。
编写Behat测试
目录结构
作为一个惯例,Silverstripe Behat测试位于您的模块的tests/behat
子文件夹中。您可以使用以下命令创建它
mkdir -p mymodule/tests/behat/features/ mkdir -p mymodule/tests/behat/src/
FeatureContext
通用的Behat使用说明也适用于这里。唯一的重大区别是扩展您的自己的FeatureContext
的基类:它应该是SilverStripeContext
而不是BehatContext
。
示例:mymodule/tests/behat/src/FeatureContext.php
namespace MyModule\Test\Behaviour; use SilverStripe\BehatExtension\Context\SilverStripeContext; class FeatureContext extends SilverStripeContext { }
屏幕尺寸
在某些Selenium驱动程序中,您可以通过capabilities
定义来定义期望的浏览器窗口大小。然而,Selenium默认情况下不支持此功能,因此我们通过环境变量添加了一个解决方案。
BEHAT_SCREEN_SIZE=320x600 vendor/bin/behat
检查PHP会话
Behat从CLI执行,这反过来会在浏览器中触发Web请求。此浏览器会话与PHP会话信息相关联,例如已登录的用户。在每个请求之后,会话信息作为TestSessionEnvironment
的一部分持久化到磁盘,以便与Behat CLI共享。
示例:检索当前登录的成员
use SilverStripe\TestSession\TestsessionEnvironment; $env = Injector::inst()->get(TestSessionEnvironment::class); $state = $env->getState(); if (isset($state->session['loggedInAs'])) { $member = \Member::get()->byID($state->session['loggedInAs']); } else { $member = null; }
常见问题解答
未找到FeatureContext
这很可能是Composer的自动加载生成器问题。请确保在vendor/composer/autoload_classmap.php
文件中提到了“SilverStripe”,如果没有,请调用composer dump-autoload
。
我如何在步骤中等待异步操作?
有时您需要在调用下一个步骤/断言之前等待AJAX请求或CSS动画完成。Mink提供了wait()方法用于此目的 - 只需让执行等待直到JavaScript表达式满足您的标准。将此表达式作为CSS选择器是非常常见的。Behat测试自带了对等待任何挂起的jQuery.ajax()
请求的支持,请检查BasicContext->handleAjaxBeforeStep()
和ajax_steps
配置选项。
为什么模块需要知道文件系统上的框架路径?
有时Silverstripe需要知道您网站的URL。当您在Web浏览器中访问您的网站时,这很容易处理,但如果您在命令行中执行脚本,它就没有办法知道了。
模块如何与SS数据库交互?
模块在初始化时创建临时数据库,并在每个场景之前通过使用/dev/tests/setdb
TestRunner端点切换到替代数据库会话。
如果需要,它还会用默认记录填充此临时数据库。
可以包含您自己的固定项,进一步解释。
为什么在新安装的情况下测试通过,但在我自己的项目中失败?
因为我们直接测试接口,对查看元素所做的任何更改都有可能干扰测试。通过从头开始构建测试数据库,我们试图最大限度地减少这种影响。尽管如此,以下是一些可能出现问题的例子:
- 第三方 Silverstripe 模块,会安装默认数据
- 默认界面语言的更改
- 移除管理区域或特定字段的配置
目前还没有方法可以排除测试运行中的违规模块。您必须调整测试以绕过这些更改,或者在没有这些模块的“沙箱”项目中运行测试。
当出现问题时,我该如何调试?
首先,阅读控制台输出。Behat 会告诉您哪些步骤失败了。
Silverstripe 行为测试框架也会通知您一些事件。它试图捕获一些 JavaScript 错误和 AJAX 错误,尽管它限于页面加载后发生的错误。
每当步骤标记为失败时,模块都会捕获截图。请参考上述配置部分以了解如何设置截图路径。
如果您无法使用上述方法收集的信息进行调试,可以通过添加以下步骤来延迟步骤执行:
And I put a breakpoint
这将停止测试的执行,直到您在终端中按下回车键。当您想查看浏览器中的错误或开发者控制台,或者想手动与会话页面进行交互时,这非常有用。
我可以通过 XDebug 设置断点吗?
如果您已经设置了 XDebug,那么断点就是您的朋友。问题是您只能将调试器连接到 CLI 中的 PHP 执行,或者连接到浏览器,但不能同时连接。
首先,确保将 xdebug.remote_autostart
设置为 Off
,否则您将始终在 CLI 中有一个活动的调试会话,而不是在浏览器中。
然后您可以选择为当前的 CLI 运行启用 XDebug
XDEBUG_CONFIG="idekey=macgdbp" vendor/bin/behat
或者您可以使用 TESTSESSION_PARAMS
环境变量将额外的参数传递给 dev/testsession/start
,并在浏览器中调试。
TESTSESSION_PARAMS="XDEBUG_SESSION_START=macgdbp" vendor/bin/behat @app
macgdbp
IDE 密钥需要与您的 php.ini 设置中的 xdebug.idekey
相匹配。
我如何通过 Travis 设置持续集成?
请查看 silverstripe/framework
中的 travis.yml,以了解如何通过 travis-ci.org 设置 Behat 测试的示例。
速查表
这是一个手动分类的列表,列出了安装了 cms
和 framework
模块时可以使用的可用命令。它基于 vendor/bin/behat -di @cms
的输出。
基础知识
Then /^(?:|I )should see "(?P<text>(?:[^"]|\\")*)"$/ - Checks, that page contains specified text. Then /^(?:|I )should not see "(?P<text>(?:[^"]|\\")*)"$/ - Checks, that page doesn't contain specified text. Then /^(?:|I )should see text matching (?P<pattern>"(?:[^"]|\\")*")$/ - Checks, that page contains text matching specified pattern. Then /^(?:|I )should not see text matching (?P<pattern>"(?:[^"]|\\")*")$/ - Checks, that page doesn't contain text matching specified pattern. Then /^the response should contain "(?P<text>(?:[^"]|\\")*)"$/ - Checks, that HTML response contains specified string. Then /^the response should not contain "(?P<text>(?:[^"]|\\")*)"$/ - Checks, that HTML response doesn't contain specified string. Then /^(?:|I )should see "(?P<text>(?:[^"]|\\")*)" in the "(?P<element>[^"]*)" element$/ - Checks, that element with specified CSS contains specified text. Then /^(?:|I )should not see "(?P<text>(?:[^"]|\\")*)" in the "(?P<element>[^"]*)" element$/ - Checks, that element with specified CSS doesn't contain specified text. Then /^the "(?P<element>[^"]*)" element should contain "(?P<value>(?:[^"]|\\")*)"$/ - Checks, that element with specified CSS contains specified HTML. Then /^(?:|I )should see an? "(?P<element>[^"]*)" element$/ - Checks, that element with specified CSS exists on page. Then /^(?:|I )should not see an? "(?P<element>[^"]*)" element$/ - Checks, that element with specified CSS doesn't exist on page. Then /^(?:|I )should be on "(?P<page>[^"]+)"$/ - Checks, that current page PATH is equal to specified. Then /^the (?i)url(?-i) should match (?P<pattern>"([^"]|\\")*")$/ - Checks, that current page PATH matches regular expression. Then /^the response status code should be (?P<code>\d+)$/ - Checks, that current page response status is equal to specified. Then /^the response status code should not be (?P<code>\d+)$/ - Checks, that current page response status is not equal to specified. Then /^(?:|I )should see (?P<num>\d+) "(?P<element>[^"]*)" elements?$/ - Checks, that (?P<num>\d+) CSS elements exist on the page Then /^print last response$/ - Prints last response to console. Then /^show last response$/ - Opens last response content in browser. Then /^I should be redirected to "([^"]+)"/ Given /^I wait (?:for )?([\d\.]+) second(?:s?)$/ Then /^the "([^"]*)" table should contain "([^"]*)"$/ Then /^the "([^"]*)" table should not contain "([^"]*)"$/ Given /^I click on "([^"]*)" in the "([^"]*)" table$/
导航
Given /^(?:|I )am on homepage$/ - Opens homepage. When /^(?:|I )go to homepage$/ - Opens homepage. Given /^(?:|I )am on "(?P<page>[^"]+)"$/ - Opens specified page. When /^(?:|I )go to "(?P<page>[^"]+)"$/ - Opens specified page. When /^(?:|I )reload the page$/ - Reloads current page. When /^(?:|I )move backward one page$/ - Moves backward one page in history. When /^(?:|I )move forward one page$/ - Moves forward one page in history
表单
When /^(?:|I )press "(?P<button>(?:[^"]|\\")*)"$/ - Presses button with specified id|name|title|alt|value. When /^(?:|I )follow "(?P<link>(?:[^"]|\\")*)"$/ - Clicks link with specified id|title|alt|text. When /^(?:|I )fill in "(?P<field>(?:[^"]|\\")*)" with "(?P<value>(?:[^"]|\\")*)"$/ - Fills in form field with specified id|name|label|value. When /^(?:|I )fill in "(?P<value>(?:[^"]|\\")*)" for "(?P<field>(?:[^"]|\\")*)"$/ - Fills in form field with specified id|name|label|value. When /^(?:|I )fill in the following:$/ - Fills in form fields with provided table. When /^(?:|I )select "(?P<option>(?:[^"]|\\")*)" from "(?P<select>(?:[^"]|\\")*)"$/ - Selects option in select field with specified id|name|label|value. When /^(?:|I )additionally select "(?P<option>(?:[^"]|\\")*)" from "(?P<select>(?:[^"]|\\")*)"$/ - Selects additional option in select field with specified id|name|label|value. When /^I select the "([^"]*)" radio button$/ - Selects a radio button with the given id|name|label|value When /^(?:|I )check "(?P<option>(?:[^"]|\\")*)"$/ - Checks checkbox with specified id|name|label|value. When /^(?:|I )uncheck "(?P<option>(?:[^"]|\\")*)"$/ - Unchecks checkbox with specified id|name|label|value. When /^(?:|I )attach the file "(?P[^"]*)" to "(?P<field>(?:[^"]|\\")*)"$/ - Attaches file to field with specified id|name|label|value. Then /^the "(?P<field>(?:[^"]|\\")*)" field should contain "(?P<value>(?:[^"]|\\")*)"$/ - Checks, that form field with specified id|name|label|value has specified value. Then /^the "(?P<field>(?:[^"]|\\")*)" field should not contain "(?P<value>(?:[^"]|\\")*)"$/ - Checks, that form field with specified id|name|label|value doesn't have specified value. Then /^the "(?P<checkbox>(?:[^"]|\\")*)" checkbox should be checked$/ - Checks, that checkbox with specified in|name|label|value is checked. Then /^the "(?P<checkbox>(?:[^"]|\\")*)" checkbox should not be checked$/ - Checks, that checkbox with specified in|name|label|value is unchecked. When /^I fill in the "(?P<field>([^"]*))" HTML field with "(?P<value>([^"]*))"$/ When /^I fill in "(?P<value>([^"]*))" for the "(?P<field>([^"]*))" HTML field$/ When /^I append "(?P<value>([^"]*))" to the "(?P<field>([^"]*))" HTML field$/ Then /^the "(?P<locator>([^"]*))" HTML field should contain "(?P<html>([^"]*))"$/ When /^(?:|I )fill in the "(?P<field>(?:[^"]|\\")*)" dropdown with "(?P<value>(?:[^"]|\\")*)"$/ - Workaround for chosen.js dropdowns or tree dropdowns which hide the original dropdown field. When /^(?:|I )fill in "(?P<value>(?:[^"]|\\")*)" for "(?P<field>(?:[^"]|\\")*)" dropdown$/ - Workaround for chosen.js dropdowns or tree dropdowns which hide the original dropdown field. Given /^I select "([^"]*)" from "([^"]*)" input group$/ - Check an individual input button from a group of inputs - Example: I select "Admins" from "Groups" input group (where "Groups" is the title of the CheckboxSetField or OptionsetField form field)
交互
Given /^I press the "([^"]*)" button$/ Given /^I (click|double click) "([^"]*)" in the "([^"]*)" element$/ Given /^I type "([^"]*)" into the dialog$/ Given /^I (?:press|follow) the "([^"]*)" (?:button|link), confirming the dialog$/ Given /^I (?:press|follow) the "([^"]*)" (?:button|link), dismissing the dialog$/ Given /^I (click|double click) "([^"]*)" in the "([^"]*)" element, confirming the dialog$/ Given /^I (click|double click) "([^"]*)" in the "([^"]*)" element, dismissing the dialog$/ Given /^I confirm the dialog$/ Given /^I dismiss the dialog$/
登录
Given /^I am logged in with "([^"]*)" permissions$/ - Creates a member in a group with the correct permissions. Given /^I am not logged in$/ When /^I log in with "(?<username>[^"]*)" and "(?<password>[^"]*)"$/ Given /^I should see a log-in form$/ Then /^I will see a "bad" log-in message$/
CMS UI
Then /^I should see an edit page form$/ Then /^I should see the CMS$/ Then /^I should see a "([^"]*)" message$/ Given /^I should see a "([^"]*)" button in CMS Content Toolbar$/ When /^I should see "([^"]*)" in CMS Tree$/ When /^I should not see "([^"]*)" in CMS Tree$/ When /^I expand the "([^"]*)" CMS Panel$/ When /^I click the "([^"]*)" CMS tab$/ Then /^I can see the preview panel$/ Given /^the preview contains "([^"]*)"$/ Given /^the preview does not contain "([^"]*)"$/
测试数据
Given /^(?:(an|a|the) )"(?<type>[^"]+)" "(?<id>[^"]+)" (:?which )?redirects to (?:(an|a|the) )"(?<targetType>[^"]+)" "(?<targetId>[^"]+)"$/ - Find or create a redirector page and link to another existing page. Given /^(?:(an|a|the) )"(?<type>[^"]+)" "(?<id>[^"]+)"$/ - Example: Given a "page" "Page 1" Given /^(?:(an|a|the) )"(?<type>[^"]+)" "(?<id>[^"]+)" with (?<data>.*)$/ - Example: Given a "page" "Page 1" with "URLSegment"="page-1" and "Content"="my page 1" Given /^(?:(an|a|the) )"(?<type>[^"]+)" "(?<id>[^"]+)" has the following data$/ - Example: And the "page" "Page 2" has the following data Given /^(?:(an|a|the) )"(?<type>[^"]+)" "(?<id>[^"]+)" is a (?<relation>[^\s]*) of (?:(an|a|the) )"(?<relationType>[^"]+)" "(?<relationId>[^"]+)"/ - Example: Given the "page" "Page 1.1" is a child of the "page" "Page1" Note that this change is not published by default Given /^(?:(an|a|the) )"(?<type>[^"]+)" "(?<id>[^"]+)" is (?<state>[^"]*)$/ - Example: Given the "page" "Page 1" is not published - Example: Given the "page" "Page 1" is published - Example: Given the "page" "Page 1" is deleted Given /^there are the following ([^\s]*) records$/ - Accepts YAML fixture definitions similar to the ones used in Silverstripe unit testing. Given /^(?:(an|a|the) )"member" "(?<id>[^"]+)" belonging to "(?<groupId>[^"]+)"$/ - Example: Given a "member" "Admin" belonging to "Admin Group" Given /^(?:(an|a|the) )"member" "(?<id>[^"]+)" belonging to "(?<groupId>[^"]+)" with (?<data>.*)$/ Given /^(?:(an|a|the) )"group" "(?<id>[^"]+)" (?:(with|has)) permissions (?<permissionStr>.*)$/ - Example: Given a "group" "Admin" with permissions "Access to 'Pages' section" and "Access to 'Files' section" Given /^I assign (?:(an|a|the) )"(?<type>[^"]+)" "(?<value>[^"]+)" to (?:(an|a|the) )"(?<relationType>[^"]+)" "(?<relationId>[^"]+)"$/ - Example: I assign the "TaxonomyTerm" "For customers" to the "Page" "Page1" Given /^I assign (?:(an|a|the) )"(?<type>[^"]+)" "(?<value>[^"]+)" to (?:(an|a|the) )"(?<relationType>[^"]+)" "(?<relationId>[^"]+)" in the "(?<relationName>[^"]+)" relation$ - Example: I assign the "TaxonomyTerm" "For customers" to the "Page" "Page1" in the "Terms" relation Given /^the CMS settings have the following data$/ - Example: Given the CMS settings has the following data - Note: It only works with the Silverstripe CMS module installed
环境
Given /^the current date is "([^"]*)"$/ Given /^the current time is "([^"]*)"$/
电子邮件
Given /^there should (not |)be an email (to|from) "([^"]*)"$/ Given /^there should (not |)be an email (to|from) "([^"]*)" titled "([^"]*)"$/ Given /^the email should (not |)contain "([^"]*)"$/ - Example: Given the email should contain "Thank you for registering!" When /^I click on the "([^"]*)" link in the email (to|from) "([^"]*)"$/ When /^I click on the "([^"]*)" link in the email (to|from) "([^"]*)" titled "([^"]*)"$/ When /^I click on the "([^"]*)" link in the email"$/ Given /^I clear all emails$/ Then /^the email should (not |)contain the following data:$/ Example: Then the email should contain the following data: Then /^there should (not |)be an email titled "([^"]*)"$/ Then /^the email should (not |)be sent from "([^"]*)"$/ Then /^the email should (not |)be sent to "([^"]*)"$/ When /^I click on the http link "([^"]*)" in the email$/ - Example: When I click on the http link "http://localhost/changepassword" in the email
转换
Behat 转换 有能力根据其原始值更改步骤参数,例如将匹配 \d
正则表达式的任何参数转换为实际的 PHP 整数。
/^(?:(the|a)) time of (?<val>.*)$/
:转换与 strtotime() 兼容的相对时间语句。例如:“1小时前的时间”如果当前时间是“23:00:00”,则可能返回“22:00:00”。/^(?:(the|a)) date of (?<val>.*)$/
:转换与 strtotime() 兼容的相对日期语句。例如:“2天前的日期”如果当前是2013年10月12日,则可能返回“2013-10-10”。/^(?:(the|a)) datetime of (?<val>.*)$/
:将与strtotime()兼容的相对日期和时间语句转换。示例:"2天前的日期时间"如果当前是2013年10月12日,可能会返回"2013-10-10 23:00:00"。