chriscohen / codeception-drupal-content-types
一个提供 Drupal 内容类型支持的 Codeception 模块。
This package is not auto-updated.
Last update: 2022-02-01 12:39:54 UTC
README
一个 Codeception 模块,提供一组封装 Drupal 内容类型的类。这使得快速测试与内容类型相关的标准 Drupal 功能变得容易得多,同时考虑到它们在您网站上的存在。
它将测试许多事情,例如内容类型管理页面、每个内容类型的“管理字段”页面,并提供一个有用的 createNode() 方法,可以快速创建测试节点,您可以使用特定值、随机值或范围值(其中一个随机选择)来提供测试数据。
安装
使用 composer 安装,如下所示
{ "repositories": [ { "type": "vcs", "url": "https://github.com/chriscohen/codeception-drupal-content-types.git" } ], "require": { "codeception/codeception": "2.*", "chriscohen/codeception-drupal-content-types": "dev-master", }, }
将模块添加到套件配置中
modules: enabled: - DrupalContentTypeRegistry
配置
无。
contentTypes.yml
在测试根目录中放置一个 contentTypes.yml(除非您想要为每个套件创建特定的 contentTypes.yml,在这种情况下,请参阅以下内容)。
以下是一个示例文件
GlobalFields: body: machineName: body label: Body type: Long text and summary selector: "#edit-body-und-0-value" widget: Text area with a summary required: true ContentTypes: news: entityType: node humanName: News machineName: news fields: globals: - body field_image: machineName: field_image label: Image type: Image selector: "#edit-field-image" widget: Media file selector required: true testData: "image1.png" field_icon: machineName: field_icon label: Icon type: Text selector: "#edit-field-icon" widget: Text field skipRoles: - editor - publisher testData: - smiley - grumpy - happy - wacky preSteps: - ["click", ["#button"]] - ["fillField", ["#the-field", "the-value"]] postSteps: - ["waitForJs", ["return jQuery.active == 0;"]] submit: "#edit-submit-me-please"
全局字段
在第一部分,您可以定义将在网站上的所有内容类型中使用的字段。这对于像标题和正文字段这样的东西很有用,这样您就不必在每个内容类型上重新定义确切的字段。
全局字段通过机器名称键入(这应该是 Drupal 字段机器名称的相同名称)并且值与它们作为内容类型字段声明时的值相同(见下文)。
全局额外信息
与上面的全局字段一样,您可以为网站上的所有内容类型定义将使用的额外信息。例如,如果您总是想填写节点的发布状态,无论其类型如何,这很有用。有关更多信息,请参阅下面的“额外信息”部分。
内容类型
每个内容类型应根据其机器名称键入(尽管这只是提示,因为 machineName 负责实际的命名,因此您可以给内容类型任何键)。
- entityType 是 Drupal 实体类型的机器名称。大多数是节点,但也可以使用其他类型。“node”是默认值,除非指定了其他值。
- humanName 是内容类型在用户界面中的命名方式(并且区分大小写)。
- machineName 是内容类型在 Drupal 中的命名方式,并且应与 Drupal 中设置的名称相匹配。
- fields 是内容类型上所有字段的列表及其属性。
- globalFields 是该类型“复用”字段的简单列表。如果您的内容类型有一个字段只是简单地重复另一个内容类型的字段,请在上面的 GlobalFields 中设置它,并在这里仅引用它。例外情况是如果它略有不同,例如,当您设置相同的字段,但将标签从“Foo”更改为其他内容时。在这种情况下,它不能成为全局字段。
- properties:字段可以有以下属性...
- machineName 是 Drupal 看到的字段的机器名称。通常这些名称以 field_ 开头,但可能存在例外,例如正文字段。
- label 是此字段的名称(标签),应与 UI 中设置的完全一致,包括大小写敏感性。
- type 是 Drupal UI 中的字段类型,在“管理字段”页面上设置。大小写敏感。
- selector 是用于在节点创建或编辑页面上选择此字段元素的 CSS 或 XPath 选择器。请注意,这通常是可选的,如果省略,则将从字段名称派生,这通常足够。
- widget 是此字段在 Drupal UI 中设置的小部件名称,在“管理字段”页面上设置。大小写敏感。一些字段没有小部件,所以只需省略它。一些字段在节点编辑页面上有小部件,但在“管理字段”页面上没有列出。如果这种情况,请在此处设置小部件,但使用下面的 widgetNameVisible 来表示它不在“管理字段”中可见。在这些情况下,您必须自己确定小部件。例如,节点标题小部件是“文本字段”小部件,即使在“管理字段”页面上没有说明。
- widgetNameVisible 允许您指定在“管理字段”页面上,此行在“小部件”列中没有内容。这适用于标题字段等。
- required 如果该字段是必需的,则可以将其设置为“true”。如果不是,则完全省略。
- pre 可以用来指定在填充字段之前应点击的元素的 XPath 选择器。如果设置了此值,则将点击该元素,然后填充字段。如果没有设置,则在填充字段之前不会点击任何内容。这可以用于位于垂直选项卡后面的元素,并且除非首先选择垂直选项卡,否则用户看不到这些元素。
- skippedRoles 是一个角色名称数组,这些角色将无法看到此字段,也不应尝试填充它。
- testData 应包含用于测试此字段的虚拟数据。可以指示每个字段使用测试数据来自动填充自身,此数据将被使用。请注意,除非字段是必需的,并且 Drupal 为字段提供默认值,否则可以将 testData 从 yaml 中省略。如果提供了值数组,Field 类可以随机选择一个。也可以在此处使用特殊值。请参阅下面的“特殊值”。
- preSteps 是在填充字段之前运行的可选步骤。这是对 pre 选项的扩展,但可以运行任何方法,而不仅仅是点击。格式是两个元素的数组。第一个元素是方法名称,第二个元素是要传递给方法的参数数组。例如,
["checkOption", ["#checkbox-name"]]
将在填充字段之前调用$I->checkOption("#checkbox-name")
。 - postSteps 是在填充字段后运行的可选步骤。例如,
["waitForJs", ["return jQuery.active == 0;"]]
将在填充字段后等待 AJAX 调用完成,然后再继续。
- extras 是所有额外元素(在节点编辑表单上交互的元素)的列表,它们本身不是字段。更多信息请见下文。
- globalExtras 是此类型上“重复使用”的额外元素的列表。这与 globalFields 的工作方式相同,但针对节点表单上的非实际字段。
- submit 是用于在节点添加或编辑表单上查找提交按钮的 CSS 或 XPath。Drupal 默认为 "#edit-submit",如果您正在使用网站上默认的值,则可以省略。
特殊值
您可以使用特殊值,该值将在创建字段时每次替换。例如,如果您想插入一个随机值,这很有用。所有特殊值都以标识符 special:: 开头,然后跟特殊值的类型。类型如下所示
- randomText 使用八个随机字母数字字符。
示例
testData: "special::randomText"
标准默认必填字段
每种实体类型都有一组标准字段,这些字段始终出现在该实体类型上。例如,节点实体上始终有一个“标题”字段,您必须拥有它。
实体类型已经知道它们的默认字段是什么,因为它们是在 EntityType::getRequiredFields() 方法中表达的,该方法由每个 EntityType 对象提供。
这意味着只要它是必填字段,您就不需要在 contentTypes.yml 中提及它,因为它们已经定义。如果您想的话,您可以在 contentTypes.yml 中提及它们,那些您在那里提及的将覆盖默认值。
实现自己的标准默认必填字段
如果您有一个情况,其中您有一个自定义 Drupal 实体,并且它有自己的必填字段,您应该定义自己的 EntityType 子类并实现 EntityType::getRequiredFields() 方法来在那里定义必填字段。在 contentTypes.yml 中使用您的自定义实体类型的内容将自动获取这些并查找它们。
特定小部件类型
AddressWidget
将此小部件的选择器设置为小部件内每个单个地址字段选择器的第一部分。例如,如果机器名称为 field_address,则您会设置选择器如下所示
selector: "#edit-field-address-und-0"
您需要定义组成地址小部件的各个元素,因为这些可以在每个小部件的基础上定义不同。
您可以使用 elements 键来完成此操作。数组键是每个字段的标签,值是用于连接上述描述的选择器的选择器的末尾。
elements: Company: "-organisation" Address 1: "-thoroughfare" Address 2: "-locality" "Town/City": "-locality"
如果您需要为此字段设置 testData,您需要按照以下方式将每个测试元素组包裹起来
testData: address1: Company: Test location Address 1: Test location thoroughfare Address 2: Test location locality "Town/City": Test location city County: Test location county Postcode: Test location postal code # Then, if necessary: address2: Company: Test location 2 Address 1: Test location thoroughfare 2 Address 2: Test location locality 2 "Town/City": Test location city 2 County: Test location county 2 Postcode: Test location postal code 2
CheckboxesWidget
请记住,您只需要设置 testData,如果每个或任何复选框的值需要更改。
如果您需要为 CheckboxesWidget 设置 testData,请确保按照以下方式将每个复选框组放入自己的包装器中
testData: values1: Grapefruit: true Melon: false Avocado: true values2: "Big Hairy Kiwi Fruit/Kiwi Fruits": true
WysiwygWidget
用于 WYSIWYG 字段。选择器应该是此字段的文本区域元素的 ID,但不要包含末尾的 "-value" 部分。例如,对于正文字段,您可能使用
selector: "#edit-body-und-0"
当前小部件将切换到纯文本格式以输入数据。
套件特定的contentTypes.yml
如果您愿意,可以在每个套件文件夹中放置一个单独的contentTypes.yml文件,并且这些文件可以覆盖主contentTypes.yml文件(或者在测试根文件夹中不创建主文件)。
如果您这样做,您需要在您的套件的_bootstrap.php中添加以下内容:
\Codeception\Module\Drupal\ContentTypeRegistry\SuiteSettings::$suiteName = 'mysuite';
套件名称应与套件所在的目录名称匹配。这是因为Codeception没有其他方式知道在它尝试查找contentTypes.yml文件时应查看哪个目录。它知道根测试目录的位置,并有一个要运行的套件列表,但无法确定当前套件运行的目录。如果将来在Codeception中开发了这样做的方法,这个额外步骤可以被省略。
实体类型
您通常想要添加已知实体(如用户、分类术语和节点)的字段和类型。但有时您需要添加更多的实体类型,例如您定义的自定义实体。您需要创建一个继承自Codeception\Module\Drupal\ContentTypeRegistry\EntityTypes\EntityType并实现Codeception\Module\Drupal\ContentTypeRegistry\EntityTypes\EntityTypeInterface的类,然后您可以定义类型名称以及为该实体类型执行“管理字段”的页面。
添加新的实体类型
如果您的网站有一个自定义实体类型,它不在这个模块的实体类型集合中管理,您可以为其创建一个自定义类,并使用yaml配置指定它。
EntityTypes: banana: "Codeception\\MyTestSuite\\EntityTypes\\Banana"
请注意,您需要完全命名空间您的自定义类,并使用示例中所示的双反斜杠表示法。
您的自定义类应扩展EntityType并实现EntityTypeInterface。通常,您可以复制现有的实体类型子类,并根据您的需求对其进行修改。
<?php /** * @file * Represents the banana entity type. */ namespace Codeception\MyTestSuite\EntityTypes; use Codeception\Module\Drupal\ContentTypeRegistry\EntityTypes\EntityType; use Codeception\Module\Drupal\ContentTypeRegistry\EntityTypes\EntityTypeInterface; class Banana extends EntityType implements EntityTypeInterface { /** * {@inheritdoc} */ public function getManageFieldsUrl($bundle = '') { return 'admin/structure/fruit-types/manage/' . $this->getEntityType() . '/fields'; } }
别忘了,您需要确保这个类通过Codeception的自动加载系统或通过手动使用require_once等方法在您的产品中的_bootstrap.php中加载。
附加内容
有时,您可能想要模拟用户在节点编辑表单上点击实际不是字段的东西。这就是附加内容发挥作用的地方。您可以通过这种方式设置节点的粘性状态或发布状态。以下是一个示例:
ContentTypes: news: entityType: node humanName: News machineName: news fields: globals: - body field_image: machineName: field_image label: Image type: Image selector: "#edit-field-image" widget: Media file selector required: true testData: "image1.png" extras: published: machineName: published label: Published type: List (text) selector: "#edit-published" widget: Select list testData: Published submit: "#edit-submit-me-please"
如你所见,这些与字段并排。您通常需要手动设置这些的选择器,因为适用于字段的命名约定不适用于这里。您仍然可以使用widget属性来告诉此模块正在使用哪种类型的表单小部件。
节点创建/删除
在createNode/deleteNode期间,通过在元素中查找标准Drupal消息来检查成功状态,例如.messages
。
某些主题可能有不同的选择器,或者根本不会显示这些消息。如果是这种情况,您可以在您的套件辅助程序中实现seeCreateNodeWasSuccessful()
和/或seeDeleteNodeWasSuccessful()
。
例如。
class AcceptanceHelper extends \Codeception\Module { /** * Check a node creation was successful. * * This overrides the default since the css selectors are different in * this site's theme. * * @see DrupalContentTypeRegistry::seeCreateNodeWasSuccessful() * * @param WebInterface $I * A reference to the Actor being used. * @param string $msg * The success message that should be displayed by Drupal. * @param int $nid * The created nid. */ public function seeCreateNodeWasSuccessful($I, $msg, $nid) { $I->see($msg, ".messages"); $I->dontSee(" ", ".messages.error"); } /** * Check a node deletion was successful. * * This overrides the default since this site redirects to the * homepage on node deletion and does not show a message. We * therefore do a check by editing the node and make sure it's * not found. * * @see DrupalContentTypeRegistry::seeDeleteNodeWasSuccessful() * * @param AuthenticatedSteps $I * A reference to the Actor being used. * @param int $nid * The deleted nid. */ public function seeDeleteNodeWasSuccessful($I, $nid) { $I->amOnPage(NodePage::route($nid, true)); $I->see("we can't find this page", "h1"); } }