From 2657d8b254521a32b5c6b2eab31d8c6b552b0891 Mon Sep 17 00:00:00 2001 From: Daniel Montgomery Date: Tue, 29 May 2018 13:09:28 -0500 Subject: [PATCH 01/18] Add support for loading nodes and fields. Nodes can be loaded by type / title. Fields can be loaded. Entity references are loaded. Special handling is used for fields with "nothing" values, they are checked to see if they are empty. Example: ``` Scenario: Blog post exists Given I examine the "blog_post" node with title "My post" Then entity property "title" should be "My post" And entity field "field_simple_example" should contain "test" And entity field "field_is_a_thing" should contain "nothing" # Example entity reference And entity field "field_authors" should contain "John Smith" ``` --- .../Context/EntityDataContext.php | 57 +++++++++---------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php index d013167..0b16b24 100644 --- a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php +++ b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php @@ -44,8 +44,6 @@ class EntityDataContext extends SharedDrupalContext */ public function assertNodeByTitle($contentType, $title) { - throw new NotUpdatedException('Method not yet updated for Drupal 8.'); - $node = $this->findNodeByTitle($contentType, $title); $this->currentEntity = $node; @@ -109,10 +107,7 @@ public function assertUserByName($userName) */ public function assertEntityPropertyValue($property, $value) { - throw new NotUpdatedException('Method not yet updated for Drupal 8.'); - - $wrapper = entity_metadata_wrapper($this->currentEntityType, $this->currentEntity); - if ($wrapper->$property->value() !== $value) { + if ($this->currentEntity->$property->value !== $value) { throw new \Exception(sprintf('Property "%s" is not "%s"', $property, $value)); } @@ -281,34 +276,40 @@ public function assertNotEntityPropertyValue($property, $value) * * @return void */ - public function assertEntityFieldValue($field, $value) + public function assertEntityFieldValue($field_name, $value) { - throw new NotUpdatedException('Method not yet updated for Drupal 8.'); + $field = $this->currentEntity->get($field_name); - if (empty($field) === true || empty($value) === true) { - return; - } + /** + * @var $definition \Drupal\Core\Field\BaseFieldDefinition + */ + $definition = $field->getFieldDefinition(); - // Use a per-field-type test method, if it is present. - $field_info = field_info_field($field); - if (empty($field_info) === true) { - throw new \Exception(sprintf('Field "%s" does not exist', $field)); - } + $field_type = $definition->get('field_type'); - $method_name = 'assertEntityFieldValue'.str_replace(' ', '', ucwords(str_replace('_', ' ', $field_info['type']))); + // If a method exists to handle this field type, use it. + $method_name = 'assertEntityFieldValue'.str_replace(' ', '', ucwords(str_replace('_', ' ', $field_type))); if (method_exists($this, $method_name) === true) { return $this->$method_name($field, $value); } - $wrapper = entity_metadata_wrapper($this->currentEntityType, $this->currentEntity); + $field_value = $field->getValue(); + + // Special case for expecting nothing + if ($value === 'nothing') { + if (!empty($field_value)) { + throw new \Exception(sprintf('Field "%s" has a value of "%s" and does not contain "%s"', $field_name, json_encode($field_value), $value)); + } + + return; + } - $field_value = $wrapper->$field->value(); if (is_array($field_value) === false) { $field_value = array($field_value); } if (in_array($value, $field_value) === false) { - throw new \Exception(sprintf('Field "%s" does not contain "%s"', $field, $value)); + throw new \Exception(sprintf('Field "%s" has a value of "%s" and does not contain "%s"', $field_name, json_encode($field_value), $value)); } }//end assertEntityFieldValue() @@ -506,22 +507,20 @@ public function assertEntityFieldValueTaxonomyTermReference($field, $value) */ public function assertEntityFieldValueEntityReference($field, $value) { - throw new NotUpdatedException('Method not yet updated for Drupal 8.'); + $entities = $field->referencedEntities(); - $field_info = field_info_field($field); - $items = field_get_items($this->currentEntityType, $this->currentEntity, $field); + if (empty($entities) === false) { + $titles = []; - if (empty($items) === false) { - foreach ($items as $item) { - $entities = entity_load($field_info['settings']['target_type'], $item); - $label = entity_label($field_info['settings']['target_type'], current($entities)); + foreach ($entities as $entity) { + $titles[] = $entity->title->value; - if ($label === $value) { + if ($entity->title->value === $value) { return; } } - throw new \Exception(sprintf('Field "%s" does not contain entity with label "%s" (has "%s" instead).', $field, $value, $label)); + throw new \Exception(sprintf('Field does not contain entity with title "%s" (has "%s" titles instead).', $value, json_encode($titles))); } throw new \Exception(sprintf('Field "%s" is empty.', $field)); From 3cf98aeb9df86c3e896893af58ea56ec196f198b Mon Sep 17 00:00:00 2001 From: Daniel Montgomery Date: Tue, 29 May 2018 13:22:14 -0500 Subject: [PATCH 02/18] Exclude field name since the step already states it and it's harder to get. --- .../PalantirBehatExtension/Context/EntityDataContext.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php index 0b16b24..0038153 100644 --- a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php +++ b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php @@ -523,7 +523,7 @@ public function assertEntityFieldValueEntityReference($field, $value) throw new \Exception(sprintf('Field does not contain entity with title "%s" (has "%s" titles instead).', $value, json_encode($titles))); } - throw new \Exception(sprintf('Field "%s" is empty.', $field)); + throw new \Exception('Field is empty.'); }//end assertEntityFieldValueEntityReference() From 7f9e1412067c6d198731a3223cd40c61861cffcc Mon Sep 17 00:00:00 2001 From: Daniel Montgomery Date: Wed, 30 May 2018 10:49:52 -0500 Subject: [PATCH 03/18] Use one method for properties and fields. Since properties and fields are accessed the same way. --- .../PalantirBehatExtension/Context/EntityDataContext.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php index 0038153..aad1740 100644 --- a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php +++ b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php @@ -107,9 +107,8 @@ public function assertUserByName($userName) */ public function assertEntityPropertyValue($property, $value) { - if ($this->currentEntity->$property->value !== $value) { - throw new \Exception(sprintf('Property "%s" is not "%s"', $property, $value)); - } + // Properties and fields are accessed in the same way in Drupal 8. + $this->assertEntityFieldValue($property, $value); }//end assertEntityPropertyValue() From 6792658f71e54b781df5eb3d77206abb57ba71dc Mon Sep 17 00:00:00 2001 From: Daniel Montgomery Date: Wed, 30 May 2018 10:51:05 -0500 Subject: [PATCH 04/18] Handle field values better. After testing on more examples. --- .../PalantirBehatExtension/Context/EntityDataContext.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php index aad1740..deda7f3 100644 --- a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php +++ b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php @@ -277,6 +277,9 @@ public function assertNotEntityPropertyValue($property, $value) */ public function assertEntityFieldValue($field_name, $value) { + /** + * @var $field \Drupal\Core\Field\FieldItemList + */ $field = $this->currentEntity->get($field_name); /** @@ -284,7 +287,7 @@ public function assertEntityFieldValue($field_name, $value) */ $definition = $field->getFieldDefinition(); - $field_type = $definition->get('field_type'); + $field_type = $definition->getType(); // If a method exists to handle this field type, use it. $method_name = 'assertEntityFieldValue'.str_replace(' ', '', ucwords(str_replace('_', ' ', $field_type))); @@ -292,7 +295,7 @@ public function assertEntityFieldValue($field_name, $value) return $this->$method_name($field, $value); } - $field_value = $field->getValue(); + $field_value = $field->value; // Special case for expecting nothing if ($value === 'nothing') { From d91624ad36caabeb42b3172572cb8f3f8e53b0a1 Mon Sep 17 00:00:00 2001 From: Daniel Montgomery Date: Wed, 30 May 2018 10:51:36 -0500 Subject: [PATCH 05/18] Remove termreference since all entity references are shared in D8. --- .../Context/EntityDataContext.php | 36 ------------------- 1 file changed, 36 deletions(-) diff --git a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php index deda7f3..7d32db4 100644 --- a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php +++ b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php @@ -461,42 +461,6 @@ public function assertEntityFieldValueImage($field, $value) }//end assertEntityFieldValueImage() - /** - * Test a taxonomy term reference field for a term name. - * - * @param string $field A Drupal field name. - * @param mixed $value The value to look for. - * - * @throws \Exception - * - * @return void - */ - public function assertEntityFieldValueTaxonomyTermReference($field, $value) - { - throw new NotUpdatedException('Method not yet updated for Drupal 8.'); - - $wrapper = entity_metadata_wrapper($this->currentEntityType, $this->currentEntity); - - $field_value = $wrapper->$field->value(); - - if (empty($field_value) === false) { - // Term field values are term objects. - if (is_array($field_value) === false) { - $field_value = array($field_value); - } - - foreach ($field_value as $term) { - if (is_object($term) === true && empty($term->name) === false && $term->name === $value) { - return; - } - } - } - - throw new \Exception(sprintf('Field "%s" does not contain term "%s"', $field, $value)); - - }//end assertEntityFieldValueTaxonomyTermReference() - - /** * Test an entity reference field for an entity label. * From e150136bc49d2a245edc7f079fa85ba842a17c66 Mon Sep 17 00:00:00 2001 From: Daniel Montgomery Date: Wed, 30 May 2018 10:53:03 -0500 Subject: [PATCH 06/18] Handle different types of entity references. Fix docs around input parameters Add docs for $currentEntity --- .../Context/EntityDataContext.php | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php index 7d32db4..a81172a 100644 --- a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php +++ b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php @@ -28,6 +28,9 @@ class EntityDataContext extends SharedDrupalContext { + /** + * @var $currentEntity \Drupal\Core\Entity\EntityInterface + */ protected $currentEntity = null; protected $currentEntityType = null; @@ -464,7 +467,7 @@ public function assertEntityFieldValueImage($field, $value) /** * Test an entity reference field for an entity label. * - * @param string $field A Drupal field name. + * @param object $field A Drupal field object. * @param mixed $value The value to look for. * * @throws \Exception @@ -478,10 +481,24 @@ public function assertEntityFieldValueEntityReference($field, $value) if (empty($entities) === false) { $titles = []; + /** + * @var $entity \Drupal\Core\Entity\EntityInterface + */ foreach ($entities as $entity) { - $titles[] = $entity->title->value; - if ($entity->title->value === $value) { + switch ($entity->getEntityTypeId()) { + case 'taxonomy_term': + case 'user': + $title = $entity->name->value; + break; + default: + $title = $entity->title->value; + break; + } + + $titles[] = $title; + + if ($title === $value) { return; } } From 69014fcc6227f072523cc099a534a80af1d331e2 Mon Sep 17 00:00:00 2001 From: Daniel Montgomery Date: Wed, 30 May 2018 11:33:14 -0500 Subject: [PATCH 07/18] Update functions since we pass field as an object. --- .../Context/EntityDataContext.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php index a81172a..c06a6dd 100644 --- a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php +++ b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php @@ -273,7 +273,7 @@ public function assertNotEntityPropertyValue($property, $value) * * @Then entity field :field should contain :value * - * @param string $field A Drupal field name. + * @param string $field_name A Drupal field name. * @param mixed $value The value to look for. * * @return void @@ -350,7 +350,7 @@ public function assertNotEntityFieldValue($field, $value) /** * Test a link field for its URL value. * - * @param string $field A Drupal field name. + * @param \Drupal\Core\Field\FieldItemList $field A Drupal field name. * @param mixed $value The value to look for. * * @return void @@ -382,7 +382,7 @@ public function assertEntityFieldValueLinkField($field, $value) /** * Test a text field for a partial string. * - * @param string $field A Drupal field name. + * @param \Drupal\Core\Field\FieldItemList $field A Drupal field name. * @param mixed $value The value to look for. * * @throws \Exception @@ -413,7 +413,7 @@ public function assertEntityFieldValueTextLong($field, $value) /** * Test a file field for a Drupal stream wrapper URI. * - * @param string $field A Drupal field name. + * @param \Drupal\Core\Field\FieldItemList $field A Drupal field name. * @param mixed $value The value to look for. * * @throws \Exception @@ -448,7 +448,7 @@ public function assertEntityFieldValueFile($field, $value) /** * Test an image field for a Drupal stream wrapper URI. * - * @param string $field A Drupal field name. + * @param \Drupal\Core\Field\FieldItemList $field A Drupal field name. * @param mixed $value The value to look for. * * @throws \Exception @@ -467,7 +467,7 @@ public function assertEntityFieldValueImage($field, $value) /** * Test an entity reference field for an entity label. * - * @param object $field A Drupal field object. + * @param \Drupal\Core\Field\FieldItemList $field A Drupal field object. * @param mixed $value The value to look for. * * @throws \Exception @@ -514,7 +514,7 @@ public function assertEntityFieldValueEntityReference($field, $value) /** * Test a date field for some date. * - * @param string $field A Drupal field name. + * @param \Drupal\Core\Field\FieldItemList $field A Drupal field name. * @param mixed $value The value to look for. * * @throws \Exception From d2b8892963ff5914973432b526858e6aa856d545 Mon Sep 17 00:00:00 2001 From: Daniel Montgomery Date: Wed, 30 May 2018 11:44:34 -0500 Subject: [PATCH 08/18] Add support for long text. --- .../Context/EntityDataContext.php | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php index c06a6dd..e2781ba 100644 --- a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php +++ b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php @@ -391,21 +391,11 @@ public function assertEntityFieldValueLinkField($field, $value) */ public function assertEntityFieldValueTextLong($field, $value) { - throw new NotUpdatedException('Method not yet updated for Drupal 8.'); - - $items = field_get_items($this->currentEntityType, $this->currentEntity, $field); - - if ($items === false) { - throw new \Exception(sprintf('No field data available for "%s".', $field)); - } - - foreach ($items as $item) { - if (strpos($item['value'], $value) !== false) { - return; - } + if (strpos($field->value, $value) !== false) { + return; } - throw new \Exception(sprintf('Field "%s" does not contain partial text "%s"', $field, $value)); + throw new \Exception(sprintf('Field does not contain partial text "%s", contains "%s"', $value, json_encode($field->value))); }//end assertEntityFieldValueTextLong() From 37232564a2c09fc57a903f94dfc1758fb1e4fcaa Mon Sep 17 00:00:00 2001 From: Daniel Montgomery Date: Wed, 30 May 2018 12:03:33 -0500 Subject: [PATCH 09/18] Add very basic support for date comparisons. --- .../Context/EntityDataContext.php | 43 ++----------------- 1 file changed, 4 insertions(+), 39 deletions(-) diff --git a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php index e2781ba..74f4026 100644 --- a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php +++ b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php @@ -512,52 +512,17 @@ public function assertEntityFieldValueEntityReference($field, $value) * @return void * * @todo : Update method to handle date fields with start and end dates - * The call to $wrapper->$field->value() returns either an array or a scalar - * because entity_metadata_wrapper() makes the date field values array - * unpredictable. When working with date fields that have both a start and - * end time, an array is returned instead of a scalar. If we want to test - * for start and end dates, we would want to use Behat syntax similar to + * If we want to test for start and end dates, we would want to use Behat syntax * "Then entity field ":field should contain " - ". - * This method would need to be updated to handle that approach. */ public function assertEntityFieldValueDatetime($field, $value) { - throw new NotUpdatedException('Method not yet updated for Drupal 8.'); - - $wrapper = entity_metadata_wrapper($this->currentEntityType, $this->currentEntity); - $field_value = $wrapper->$field->value(); - if (is_scalar($field_value) === true) { - $field_value = array($field_value); - } - - if (is_array($field_value) === false) { - $field_value = array(); + if (strtotime($field->value) === strtotime($value)) { + return; } - foreach ($field_value as $v) { - if (is_array($v) === true) { - // The value may exist as either the start date ('value') or the end - // date ('value2'). - if (array_key_exists('value', $v) === true) { - if (strtotime($value) === strtotime($v['value'])) { - return; - } - } - - if (array_key_exists('value2', $v) === true) { - if (strtotime($value) === strtotime($v['value2'])) { - return; - } - } - } - - if (strtotime($value) === $v) { - return; - } - }//end foreach - - throw new \Exception(sprintf('Field "%s" does not contain datetime "%s" (%s)', $field, strtotime($value), $value)); + throw new \Exception(sprintf('Field does not contain datetime "%s" (%s), contains "%s".', strtotime($value), $value, strtotime($field->value))); }//end assertEntityFieldValueDatetime() From 3aba751d54790279628a5ed3b15e7698c6c2e640 Mon Sep 17 00:00:00 2001 From: Daniel Montgomery Date: Wed, 30 May 2018 12:10:19 -0500 Subject: [PATCH 10/18] Handle media file references. The default seems to be `name` rather than `title` which is used for nodes. --- .../PalantirBehatExtension/Context/EntityDataContext.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php index 74f4026..6b182ae 100644 --- a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php +++ b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php @@ -477,12 +477,15 @@ public function assertEntityFieldValueEntityReference($field, $value) foreach ($entities as $entity) { switch ($entity->getEntityTypeId()) { + case 'node': + $title = $entity->title->value; + break; + case 'taxonomy_term': case 'user': - $title = $entity->name->value; - break; + case 'media': default: - $title = $entity->title->value; + $title = $entity->name->value; break; } From c25f9edd7b3b7358b68167597e5b18a58738e7d0 Mon Sep 17 00:00:00 2001 From: Daniel Montgomery Date: Wed, 30 May 2018 14:04:51 -0500 Subject: [PATCH 11/18] Handle paragraph fields Paragraphs don't have titles, but we can check the type. A new pattern has been added. Paragraphs are entity references, so we throw an error when the general field pattern is being used since we aren't checking for value / title. --- .../Context/EntityDataContext.php | 55 ++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php index 6b182ae..ea636d8 100644 --- a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php +++ b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php @@ -346,6 +346,39 @@ public function assertNotEntityFieldValue($field, $value) }//end assertNotEntityFieldValue() + /** + * Verify that a field contains a value. + * + * @Then paragraph field :field should be of type :type + * + * @param string $field_name A Drupal field name. + * @param mixed $type The type of paragraph. + * + * @return void + */ + public function assertEntityFieldValueParagraph($field_name, $type) + { + /** + * @var $field \Drupal\Core\Field\FieldItemList + */ + $field = $this->currentEntity->get($field_name); + + $types = []; + + /** + * @var $entity \Drupal\paragraphs\Entity\Paragraph + */ + foreach ($field->referencedEntities() as $entity) { + $types[] = $entity->getType(); + } + + if (!in_array($type, $types)) { + throw new \Exception(sprintf('Paragraph does not have type "%s", has types "%s".', $type, json_encode($types))); + } + + + }//end assertEntityFieldValue() + /** * Test a link field for its URL value. @@ -472,7 +505,7 @@ public function assertEntityFieldValueEntityReference($field, $value) $titles = []; /** - * @var $entity \Drupal\Core\Entity\EntityInterface + * @var $entity \Drupal\Core\Entity\ContentEntityBase */ foreach ($entities as $entity) { @@ -481,6 +514,10 @@ public function assertEntityFieldValueEntityReference($field, $value) $title = $entity->title->value; break; + case 'paragraph': + throw new \Exception('Paragraphs do not have titles, so they must be tested by a different method.'); + break; + case 'taxonomy_term': case 'user': case 'media': @@ -504,6 +541,22 @@ public function assertEntityFieldValueEntityReference($field, $value) }//end assertEntityFieldValueEntityReference() + /** + * Passes handling to the generic Entity Reference method. + * + * @param \Drupal\Core\Field\FieldItemList $field A Drupal field object. + * @param mixed $value The value to look for. + * + * @throws \Exception + * + * @return void + */ + public function assertEntityFieldValueEntityReferenceRevisions($field, $value) + { + $this->assertEntityFieldValueEntityReference($field, $value); + }//end assertEntityFieldValueEntityReferenceRevisions() + + /** * Test a date field for some date. * From 9d38fb993afdc142143815e6ebf811a14b12d17e Mon Sep 17 00:00:00 2001 From: Daniel Montgomery Date: Wed, 30 May 2018 14:41:03 -0500 Subject: [PATCH 12/18] Update node lookup method. This was needed before, but I forgot to export it. --- .../Context/SharedDrupalContext.php | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/Palantirnet/PalantirBehatExtension/Context/SharedDrupalContext.php b/src/Palantirnet/PalantirBehatExtension/Context/SharedDrupalContext.php index a3c5613..88885e6 100644 --- a/src/Palantirnet/PalantirBehatExtension/Context/SharedDrupalContext.php +++ b/src/Palantirnet/PalantirBehatExtension/Context/SharedDrupalContext.php @@ -38,19 +38,23 @@ class SharedDrupalContext extends RawDrupalContext */ public function findNodeByTitle($contentType, $title) { - throw new NotUpdatedException('Method not yet updated for Drupal 8.'); + /** + * @var $query \Drupal\Core\Entity\Query\QueryInterface + */ + $query = \Drupal::entityQuery('node'); + + $entities = $query + ->condition('type', $contentType) + ->condition('title', $title) + ->execute(); - $query = new \EntityFieldQuery(); + if (count($entities) === 1) { + $node_storage = \Drupal::entityManager()->getStorage('node'); - $entities = $query->entityCondition('entity_type', 'node') - ->entityCondition('bundle', $contentType) - ->propertyCondition('title', $title) - ->execute(); + $nid = array_shift($entities); - if (empty($entities['node']) === false && count($entities['node']) === 1) { - $nid = key($entities['node']); - return node_load($nid); - } else if (empty($entities['node']) === false && count($entities['node']) > 1) { + return $node_storage->load($nid); + } else if (count($entities) > 1) { throw new \Exception(sprintf('Found more than one "%s" node entitled "%s"', $contentType, $title)); } else { throw new \Exception(sprintf('No "%s" node entitled "%s" exists', $contentType, $title)); From 2ed17e9043f9a530d445a0e9e89cd075d1fc6dc6 Mon Sep 17 00:00:00 2001 From: Daniel Montgomery Date: Tue, 5 Jun 2018 11:23:12 -0500 Subject: [PATCH 13/18] Add paragraph examine step. Can be used like this ``` When I examine the "page" node with title "My page" And I examine paragraph "5" on the "field_paragraphs" field Then entity field "field_content" should contain "Example" ``` --- .../Context/EntityDataContext.php | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php index ea636d8..c836f28 100644 --- a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php +++ b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php @@ -98,6 +98,33 @@ public function assertUserByName($userName) }//end assertUserByName() + /** + * @When I examine paragraph ":fieldWeight" on the ":fieldName" field + * + * This can drill down into a paragraph on a loaded entity. + */ + public function assertParagraphByWeight($fieldWeight, $fieldName) + { + if (!$this->currentEntity->hasField($fieldName)) { + throw new \Exception('Could not load the field'); + } + + $field = $this->currentEntity->get($fieldName); + + $paragraphs = $field->referencedEntities(); + + if (!(is_array($paragraphs) && isset($paragraphs[$fieldWeight - 1]))){ + throw new \Exception('Could not find the paragraph in the field.'); + } + + $paragraph = $paragraphs[$fieldWeight - 1]; + + $this->currentEntity = $paragraph; + $this->currentEntityType = 'paragraph'; + + }//end assertParagraphByWeight() + + /** * Verify that an entity property is equal to a particular value. * From 7d0ec83f63829ed01e51f781a4c34aad12ee0a71 Mon Sep 17 00:00:00 2001 From: Russom Woldezghi Date: Tue, 12 Jun 2018 15:04:18 -0400 Subject: [PATCH 14/18] Link URL field behat context testing --- .../Context/EntityDataContext.php | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php index c836f28..07a6080 100644 --- a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php +++ b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php @@ -417,26 +417,16 @@ public function assertEntityFieldValueParagraph($field_name, $type) * * @throws \Exception */ - public function assertEntityFieldValueLinkField($field, $value) + public function assertEntityFieldValueLink($field, $value) { - throw new NotUpdatedException('Method not yet updated for Drupal 8.'); - - $wrapper = entity_metadata_wrapper($this->currentEntityType, $this->currentEntity); - - $field_value = $wrapper->$field->value(); - if (isset($field_value['url']) === true) { - $field_value = array($field_value); - } + if (strpos($field->getValue()[0]['uri'], $value) !== false) { + return; + } - foreach ($field_value as $f) { - if ($f['url'] === $value) { - return; - } - } + throw new \Exception(sprintf('Field does not contain the url "%s", contains "%s"', $value, json_encode($field->getValue()[0]['uri']))); - throw new \Exception(sprintf('Field "%s" does not contain "%s"', $field, $value)); + }//end assertEntityFieldValueLink() - }//end assertEntityFieldValueLinkField() /** From d4f733b695ae1c2022e4bfbfd54e558d199a20f1 Mon Sep 17 00:00:00 2001 From: Russom Woldezghi Date: Tue, 12 Jun 2018 16:32:16 -0400 Subject: [PATCH 15/18] Updating composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 57c7332..7c58d64 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "palantirnet/palantir-behat-extension", + "name": "palantirnet/palantir-behat-extension": "dev-feature/entity-context", "description": "Additional step definitions for testing Drupal sites using Behat.", "type": "behat-extension", "keywords": [ From 97279ea0f4d9f58f8bee4a498c26b555a68c050a Mon Sep 17 00:00:00 2001 From: Russom Woldezghi Date: Tue, 12 Jun 2018 16:42:59 -0400 Subject: [PATCH 16/18] Revert "Updating composer.json" This reverts commit d4f733b695ae1c2022e4bfbfd54e558d199a20f1. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 7c58d64..57c7332 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "palantirnet/palantir-behat-extension": "dev-feature/entity-context", + "name": "palantirnet/palantir-behat-extension", "description": "Additional step definitions for testing Drupal sites using Behat.", "type": "behat-extension", "keywords": [ From 90669a28722cedc9ef1bfa8d639e13d266c928e0 Mon Sep 17 00:00:00 2001 From: Daniel Montgomery Date: Tue, 19 Jun 2018 10:24:10 -0500 Subject: [PATCH 17/18] Add support for testing translations, including paragraph translations. --- .../Context/EntityDataContext.php | 26 +++++++++++++++++++ .../Context/SharedDrupalContext.php | 15 +++++++++-- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php index 07a6080..8e247a8 100644 --- a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php +++ b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php @@ -33,6 +33,7 @@ class EntityDataContext extends SharedDrupalContext */ protected $currentEntity = null; protected $currentEntityType = null; + protected $currentEntityLanguage = null; /** @@ -54,6 +55,27 @@ public function assertNodeByTitle($contentType, $title) }//end assertNodeByTitle() + /** + * Verify field and property values of a node entity in a language. + * + * @When I examine the :contentType( node) with title :title in :language + * + * @param string $contentType A Drupal content type machine name. + * @param string $title The title of a Drupal node. + * @param string $language A language code + * + * @return void + */ + public function assertNodeByTitleAndLanguage($contentType, $title, $language) + { + $node = $this->findNodeByTitle($contentType, $title, $language); + + $this->currentEntity = $node; + $this->currentEntityType = 'node'; + $this->currentEntityLanguage = $language; + + }//end assertNodeByTitleAndLanguage() + /** * Verify field and property values of a taxonomy term entity. @@ -119,6 +141,10 @@ public function assertParagraphByWeight($fieldWeight, $fieldName) $paragraph = $paragraphs[$fieldWeight - 1]; + if (isset($this->currentEntityLanguage) && $paragraph->hasTranslation($this->currentEntityLanguage)){ + $paragraph = $paragraph->getTranslation($this->currentEntityLanguage); + } + $this->currentEntity = $paragraph; $this->currentEntityType = 'paragraph'; diff --git a/src/Palantirnet/PalantirBehatExtension/Context/SharedDrupalContext.php b/src/Palantirnet/PalantirBehatExtension/Context/SharedDrupalContext.php index 88885e6..4c6a26f 100644 --- a/src/Palantirnet/PalantirBehatExtension/Context/SharedDrupalContext.php +++ b/src/Palantirnet/PalantirBehatExtension/Context/SharedDrupalContext.php @@ -36,7 +36,7 @@ class SharedDrupalContext extends RawDrupalContext * @return stdclass * The Drupal node object, if it exists. */ - public function findNodeByTitle($contentType, $title) + public function findNodeByTitle($contentType, $title, $language = NULL) { /** * @var $query \Drupal\Core\Entity\Query\QueryInterface @@ -53,7 +53,18 @@ public function findNodeByTitle($contentType, $title) $nid = array_shift($entities); - return $node_storage->load($nid); + $node = $node_storage->load($nid); + + if (!is_null($language)) { + if ($node->hasTranslation($language)) { + $node = $node->getTranslation($language); + } + else { + throw new \Exception('The node is not available in that language.'); + } + } + + return $node; } else if (count($entities) > 1) { throw new \Exception(sprintf('Found more than one "%s" node entitled "%s"', $contentType, $title)); } else { From 9d3bbe52d5c4a82d96be5da16abc07611c339339 Mon Sep 17 00:00:00 2001 From: Daniel Montgomery Date: Wed, 27 Jun 2018 09:22:19 -0500 Subject: [PATCH 18/18] Address review feedback. - Update paragraph assert method description. - Replace switch statement with generalized `$entity->label()`. - Add comment around node loading logic. --- .../Context/EntityDataContext.php | 28 ++++++------------- .../Context/SharedDrupalContext.php | 5 ++++ 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php index 8e247a8..53deb26 100644 --- a/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php +++ b/src/Palantirnet/PalantirBehatExtension/Context/EntityDataContext.php @@ -400,7 +400,7 @@ public function assertNotEntityFieldValue($field, $value) }//end assertNotEntityFieldValue() /** - * Verify that a field contains a value. + * Verify that a paragraph field contains a paragraph of a certain type. * * @Then paragraph field :field should be of type :type * @@ -552,31 +552,21 @@ public function assertEntityFieldValueEntityReference($field, $value) */ foreach ($entities as $entity) { - switch ($entity->getEntityTypeId()) { - case 'node': - $title = $entity->title->value; - break; - - case 'paragraph': - throw new \Exception('Paragraphs do not have titles, so they must be tested by a different method.'); - break; - - case 'taxonomy_term': - case 'user': - case 'media': - default: - $title = $entity->name->value; - break; + if ($entity->getEntityTypeId() === 'paragraph') { + throw new \Exception('Paragraphs do not have meaningful labels, so they must be tested by a different method.'); + // If we get a single paragraph reference, we will assume + // that the rest are also paragraphs and exit the method. + return; } - $titles[] = $title; + $labels[] = $entity->label(); - if ($title === $value) { + if ($entity->label() === $value) { return; } } - throw new \Exception(sprintf('Field does not contain entity with title "%s" (has "%s" titles instead).', $value, json_encode($titles))); + throw new \Exception(sprintf('Field does not contain entity with label "%s" (has "%s" labels instead).', $value, json_encode($labels))); } throw new \Exception('Field is empty.'); diff --git a/src/Palantirnet/PalantirBehatExtension/Context/SharedDrupalContext.php b/src/Palantirnet/PalantirBehatExtension/Context/SharedDrupalContext.php index 4c6a26f..2e79a18 100644 --- a/src/Palantirnet/PalantirBehatExtension/Context/SharedDrupalContext.php +++ b/src/Palantirnet/PalantirBehatExtension/Context/SharedDrupalContext.php @@ -51,6 +51,11 @@ public function findNodeByTitle($contentType, $title, $language = NULL) if (count($entities) === 1) { $node_storage = \Drupal::entityManager()->getStorage('node'); + // `entityQuery` will return an array of node IDs with key and + // value equal to the nids. + // Example: `[123 => '123', 456 => '456']`. For this reason, even + // though there is only a single element, we cannot access the + // first element using `$entities[0]`. $nid = array_shift($entities); $node = $node_storage->load($nid);