Chris@0: drupalPlaceBlock('system_breadcrumb_block'); Chris@0: Chris@0: // Create a content type, with underscores. Chris@0: $type_name = strtolower($this->randomMachineName(8)) . '_test'; Chris@0: $type = $this->drupalCreateContentType(['name' => $type_name, 'type' => $type_name]); Chris@0: $this->type = $type->id(); Chris@0: Chris@0: // Create test user. Chris@0: $admin_user = $this->drupalCreateUser([ Chris@0: 'access content', Chris@0: 'administer node fields', Chris@0: 'administer node display', Chris@0: 'administer views', Chris@0: 'create ' . $type_name . ' content', Chris@0: 'edit own ' . $type_name . ' content', Chris@0: ]); Chris@0: $this->drupalLogin($admin_user); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the Entity Reference Admin UI. Chris@0: */ Chris@0: public function testFieldAdminHandler() { Chris@0: $bundle_path = 'admin/structure/types/manage/' . $this->type; Chris@0: Chris@0: // First step: 'Add new field' on the 'Manage fields' page. Chris@0: $this->drupalGet($bundle_path . '/fields/add-field'); Chris@0: Chris@0: // Check if the commonly referenced entity types appear in the list. Chris@0: $this->assertOption('edit-new-storage-type', 'field_ui:entity_reference:node'); Chris@0: $this->assertOption('edit-new-storage-type', 'field_ui:entity_reference:user'); Chris@0: Chris@0: $this->drupalPostForm(NULL, [ Chris@0: 'label' => 'Test label', Chris@0: 'field_name' => 'test', Chris@0: 'new_storage_type' => 'entity_reference', Chris@0: ], t('Save and continue')); Chris@0: Chris@0: // Node should be selected by default. Chris@0: $this->assertFieldByName('settings[target_type]', 'node'); Chris@0: Chris@0: // Check that all entity types can be referenced. Chris@0: $this->assertFieldSelectOptions('settings[target_type]', array_keys(\Drupal::entityManager()->getDefinitions())); Chris@0: Chris@0: // Second step: 'Field settings' form. Chris@0: $this->drupalPostForm(NULL, [], t('Save field settings')); Chris@0: Chris@0: // The base handler should be selected by default. Chris@0: $this->assertFieldByName('settings[handler]', 'default:node'); Chris@0: Chris@0: // The base handler settings should be displayed. Chris@0: $entity_type_id = 'node'; Chris@0: $bundles = $this->container->get('entity_type.bundle.info')->getBundleInfo($entity_type_id); Chris@0: foreach ($bundles as $bundle_name => $bundle_info) { Chris@0: $this->assertFieldByName('settings[handler_settings][target_bundles][' . $bundle_name . ']'); Chris@0: } Chris@0: Chris@0: reset($bundles); Chris@0: Chris@0: // Test the sort settings. Chris@0: // Option 0: no sort. Chris@0: $this->assertFieldByName('settings[handler_settings][sort][field]', '_none'); Chris@0: $this->assertNoFieldByName('settings[handler_settings][sort][direction]'); Chris@0: // Option 1: sort by field. Chris@0: $this->drupalPostAjaxForm(NULL, ['settings[handler_settings][sort][field]' => 'nid'], 'settings[handler_settings][sort][field]'); Chris@0: $this->assertFieldByName('settings[handler_settings][sort][direction]', 'ASC'); Chris@0: Chris@0: // Test that a non-translatable base field is a sort option. Chris@0: $this->assertFieldByXPath("//select[@name='settings[handler_settings][sort][field]']/option[@value='nid']"); Chris@0: // Test that a translatable base field is a sort option. Chris@0: $this->assertFieldByXPath("//select[@name='settings[handler_settings][sort][field]']/option[@value='title']"); Chris@0: // Test that a configurable field is a sort option. Chris@0: $this->assertFieldByXPath("//select[@name='settings[handler_settings][sort][field]']/option[@value='body.value']"); Chris@0: Chris@0: // Set back to no sort. Chris@0: $this->drupalPostAjaxForm(NULL, ['settings[handler_settings][sort][field]' => '_none'], 'settings[handler_settings][sort][field]'); Chris@0: $this->assertNoFieldByName('settings[handler_settings][sort][direction]'); Chris@0: Chris@0: // Third step: confirm. Chris@0: $this->drupalPostForm(NULL, [ Chris@0: 'required' => '1', Chris@0: 'settings[handler_settings][target_bundles][' . key($bundles) . ']' => key($bundles), Chris@0: ], t('Save settings')); Chris@0: Chris@0: // Check that the field appears in the overview form. Chris@0: $this->assertFieldByXPath('//table[@id="field-overview"]//tr[@id="field-test"]/td[1]', 'Test label', 'Field was created and appears in the overview page.'); Chris@0: Chris@0: // Check that the field settings form can be submitted again, even when the Chris@0: // field is required. Chris@0: // The first 'Edit' link is for the Body field. Chris@0: $this->clickLink(t('Edit'), 1); Chris@0: $this->drupalPostForm(NULL, [], t('Save settings')); Chris@0: Chris@0: // Switch the target type to 'taxonomy_term' and check that the settings Chris@0: // specific to its selection handler are displayed. Chris@0: $field_name = 'node.' . $this->type . '.field_test'; Chris@0: $edit = [ Chris@0: 'settings[target_type]' => 'taxonomy_term', Chris@0: ]; Chris@0: $this->drupalPostForm($bundle_path . '/fields/' . $field_name . '/storage', $edit, t('Save field settings')); Chris@0: $this->drupalGet($bundle_path . '/fields/' . $field_name); Chris@0: $this->assertFieldByName('settings[handler_settings][auto_create]'); Chris@0: Chris@0: // Switch the target type to 'user' and check that the settings specific to Chris@0: // its selection handler are displayed. Chris@0: $field_name = 'node.' . $this->type . '.field_test'; Chris@0: $edit = [ Chris@0: 'settings[target_type]' => 'user', Chris@0: ]; Chris@0: $this->drupalPostForm($bundle_path . '/fields/' . $field_name . '/storage', $edit, t('Save field settings')); Chris@0: $this->drupalGet($bundle_path . '/fields/' . $field_name); Chris@0: $this->assertFieldByName('settings[handler_settings][filter][type]', '_none'); Chris@0: Chris@0: // Switch the target type to 'node'. Chris@0: $field_name = 'node.' . $this->type . '.field_test'; Chris@0: $edit = [ Chris@0: 'settings[target_type]' => 'node', Chris@0: ]; Chris@0: $this->drupalPostForm($bundle_path . '/fields/' . $field_name . '/storage', $edit, t('Save field settings')); Chris@0: Chris@0: // Try to select the views handler. Chris@0: $edit = [ Chris@0: 'settings[handler]' => 'views', Chris@0: ]; Chris@0: $this->drupalPostAjaxForm($bundle_path . '/fields/' . $field_name, $edit, 'settings[handler]'); Chris@0: $this->assertRaw(t('No eligible views were found. Create a view with an Entity Reference display, or add such a display to an existing view.', [ Chris@0: ':create' => \Drupal::url('views_ui.add'), Chris@0: ':existing' => \Drupal::url('entity.view.collection'), Chris@0: ])); Chris@0: $this->drupalPostForm(NULL, $edit, t('Save settings')); Chris@0: // If no eligible view is available we should see a message. Chris@0: $this->assertText('The views entity selection mode requires a view.'); Chris@0: Chris@0: // Enable the entity_reference_test module which creates an eligible view. Chris@0: $this->container->get('module_installer')->install(['entity_reference_test']); Chris@0: $this->resetAll(); Chris@0: $this->drupalGet($bundle_path . '/fields/' . $field_name); Chris@0: $this->drupalPostAjaxForm($bundle_path . '/fields/' . $field_name, $edit, 'settings[handler]'); Chris@0: $edit = [ Chris@0: 'settings[handler_settings][view][view_and_display]' => 'test_entity_reference:entity_reference_1', Chris@0: ]; Chris@0: $this->drupalPostForm(NULL, $edit, t('Save settings')); Chris@0: $this->assertResponse(200); Chris@0: Chris@0: // Switch the target type to 'entity_test'. Chris@0: $edit = [ Chris@0: 'settings[target_type]' => 'entity_test', Chris@0: ]; Chris@0: $this->drupalPostForm($bundle_path . '/fields/' . $field_name . '/storage', $edit, t('Save field settings')); Chris@0: $this->drupalGet($bundle_path . '/fields/' . $field_name); Chris@0: $edit = [ Chris@0: 'settings[handler]' => 'views', Chris@0: ]; Chris@0: $this->drupalPostAjaxForm($bundle_path . '/fields/' . $field_name, $edit, 'settings[handler]'); Chris@0: $edit = [ Chris@0: 'required' => FALSE, Chris@0: 'settings[handler_settings][view][view_and_display]' => 'test_entity_reference_entity_test:entity_reference_1', Chris@0: ]; Chris@0: $this->drupalPostForm(NULL, $edit, t('Save settings')); Chris@0: $this->assertResponse(200); Chris@0: Chris@0: // Create a new view and display it as a entity reference. Chris@0: $edit = [ Chris@0: 'id' => 'node_test_view', Chris@0: 'label' => 'Node Test View', Chris@0: 'show[wizard_key]' => 'node', Chris@0: 'show[sort]' => 'none', Chris@0: 'page[create]' => 1, Chris@0: 'page[title]' => 'Test Node View', Chris@0: 'page[path]' => 'test/node/view', Chris@0: 'page[style][style_plugin]' => 'default', Chris@0: 'page[style][row_plugin]' => 'fields', Chris@0: ]; Chris@0: $this->drupalPostForm('admin/structure/views/add', $edit, t('Save and edit')); Chris@0: $this->drupalPostForm(NULL, [], t('Duplicate as Entity Reference')); Chris@0: $this->clickLink(t('Settings')); Chris@0: $edit = [ Chris@0: 'style_options[search_fields][title]' => 'title', Chris@0: ]; Chris@0: $this->drupalPostForm(NULL, $edit, t('Apply')); Chris@0: Chris@0: // Set sort to NID ascending. Chris@0: $edit = [ Chris@0: 'name[node_field_data.nid]' => 1, Chris@0: ]; Chris@0: $this->drupalPostForm('admin/structure/views/nojs/add-handler/node_test_view/entity_reference_1/sort', $edit, t('Add and configure sort criteria')); Chris@0: $this->drupalPostForm(NULL, NULL, t('Apply')); Chris@0: Chris@0: $this->drupalPostForm('admin/structure/views/view/node_test_view/edit/entity_reference_1', [], t('Save')); Chris@0: $this->clickLink(t('Settings')); Chris@0: Chris@0: // Create a test entity reference field. Chris@0: $field_name = 'test_entity_ref_field'; Chris@0: $edit = [ Chris@0: 'new_storage_type' => 'field_ui:entity_reference:node', Chris@0: 'label' => 'Test Entity Reference Field', Chris@0: 'field_name' => $field_name, Chris@0: ]; Chris@0: $this->drupalPostForm($bundle_path . '/fields/add-field', $edit, t('Save and continue')); Chris@0: Chris@0: // Set to unlimited. Chris@0: $edit = [ Chris@0: 'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, Chris@0: ]; Chris@0: $this->drupalPostForm(NULL, $edit, t('Save field settings')); Chris@0: Chris@0: // Add the view to the test field. Chris@0: $edit = [ Chris@0: 'settings[handler]' => 'views', Chris@0: ]; Chris@0: $this->drupalPostAjaxForm(NULL, $edit, 'settings[handler]'); Chris@0: $edit = [ Chris@0: 'required' => FALSE, Chris@0: 'settings[handler_settings][view][view_and_display]' => 'node_test_view:entity_reference_1', Chris@0: ]; Chris@0: $this->drupalPostForm(NULL, $edit, t('Save settings')); Chris@0: Chris@0: // Create nodes. Chris@0: $node1 = Node::create([ Chris@0: 'type' => $this->type, Chris@0: 'title' => 'Foo Node', Chris@0: ]); Chris@0: $node1->save(); Chris@0: $node2 = Node::create([ Chris@0: 'type' => $this->type, Chris@0: 'title' => 'Foo Node', Chris@0: ]); Chris@0: $node2->save(); Chris@0: Chris@0: // Try to add a new node and fill the entity reference field. Chris@0: $this->drupalGet('node/add/' . $this->type); Chris@0: $result = $this->xpath('//input[@name="field_test_entity_ref_field[0][target_id]" and contains(@data-autocomplete-path, "/entity_reference_autocomplete/node/views/")]'); Chris@0: $target_url = $this->getAbsoluteUrl($result[0]['data-autocomplete-path']); Chris@0: $this->drupalGet($target_url, ['query' => ['q' => 'Foo']]); Chris@0: $this->assertRaw($node1->getTitle() . ' (' . $node1->id() . ')'); Chris@0: $this->assertRaw($node2->getTitle() . ' (' . $node2->id() . ')'); Chris@0: Chris@0: // Try to add a new node, fill the entity reference field and submit the Chris@0: // form. Chris@0: $this->drupalPostForm('node/add/' . $this->type, [], t('Add another item')); Chris@0: $edit = [ Chris@0: 'title[0][value]' => 'Example', Chris@0: 'field_test_entity_ref_field[0][target_id]' => 'Foo Node (' . $node1->id() . ')', Chris@0: 'field_test_entity_ref_field[1][target_id]' => 'Foo Node (' . $node2->id() . ')', Chris@0: ]; Chris@0: $this->drupalPostForm(NULL, $edit, t('Save')); Chris@0: $this->assertResponse(200); Chris@0: Chris@0: $edit = [ Chris@0: 'title[0][value]' => 'Example', Chris@0: 'field_test_entity_ref_field[0][target_id]' => 'Test' Chris@0: ]; Chris@0: $this->drupalPostForm('node/add/' . $this->type, $edit, t('Save')); Chris@0: Chris@0: // Assert that entity reference autocomplete field is validated. Chris@0: $this->assertText(t('There are no entities matching "@entity"', ['@entity' => 'Test'])); Chris@0: Chris@0: $edit = [ Chris@0: 'title[0][value]' => 'Test', Chris@0: 'field_test_entity_ref_field[0][target_id]' => $node1->getTitle() Chris@0: ]; Chris@0: $this->drupalPostForm('node/add/' . $this->type, $edit, t('Save')); Chris@0: Chris@0: // Assert the results multiple times to avoid sorting problem of nodes with Chris@0: // the same title. Chris@0: $this->assertText(t('Multiple entities match this reference;')); Chris@0: $this->assertText(t("@node1", ['@node1' => $node1->getTitle() . ' (' . $node1->id() . ')'])); Chris@0: $this->assertText(t("@node2", ['@node2' => $node2->getTitle() . ' (' . $node2->id() . ')'])); Chris@0: $this->assertText(t('Specify the one you want by appending the id in parentheses, like "@example".', ['@example' => $node2->getTitle() . ' (' . $node2->id() . ')'])); Chris@0: Chris@0: $edit = [ Chris@0: 'title[0][value]' => 'Test', Chris@0: 'field_test_entity_ref_field[0][target_id]' => $node1->getTitle() . ' (' . $node1->id() . ')' Chris@0: ]; Chris@0: $this->drupalPostForm('node/add/' . $this->type, $edit, t('Save')); Chris@0: $this->assertLink($node1->getTitle()); Chris@0: Chris@0: // Tests adding default values to autocomplete widgets. Chris@0: Vocabulary::create(['vid' => 'tags', 'name' => 'tags'])->save(); Chris@0: $taxonomy_term_field_name = $this->createEntityReferenceField('taxonomy_term', ['tags']); Chris@0: $field_path = 'node.' . $this->type . '.field_' . $taxonomy_term_field_name; Chris@0: $this->drupalGet($bundle_path . '/fields/' . $field_path . '/storage'); Chris@0: $edit = [ Chris@0: 'cardinality' => -1, Chris@0: ]; Chris@0: $this->drupalPostForm(NULL, $edit, t('Save field settings')); Chris@0: $this->drupalGet($bundle_path . '/fields/' . $field_path); Chris@0: $term_name = $this->randomString(); Chris@0: $edit = [ Chris@0: // This must be set before new entities will be auto-created. Chris@0: 'settings[handler_settings][auto_create]' => 1, Chris@0: ]; Chris@0: $this->drupalPostForm(NULL, $edit, t('Save settings')); Chris@0: $this->drupalGet($bundle_path . '/fields/' . $field_path); Chris@0: $edit = [ Chris@0: // A term that doesn't yet exist. Chris@0: 'default_value_input[field_' . $taxonomy_term_field_name . '][0][target_id]' => $term_name, Chris@0: ]; Chris@0: $this->drupalPostForm(NULL, $edit, t('Save settings')); Chris@0: // The term should now exist. Chris@0: $term = taxonomy_term_load_multiple_by_name($term_name, 'tags')[1]; Chris@0: $this->assertIdentical(1, count($term), 'Taxonomy term was auto created when set as field default.'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the formatters for the Entity References. Chris@0: */ Chris@0: public function testAvailableFormatters() { Chris@0: // Create a new vocabulary. Chris@0: Vocabulary::create(['vid' => 'tags', 'name' => 'tags'])->save(); Chris@0: Chris@0: // Create entity reference field with taxonomy term as a target. Chris@0: $taxonomy_term_field_name = $this->createEntityReferenceField('taxonomy_term', ['tags']); Chris@0: Chris@0: // Create entity reference field with user as a target. Chris@0: $user_field_name = $this->createEntityReferenceField('user'); Chris@0: Chris@0: // Create entity reference field with node as a target. Chris@0: $node_field_name = $this->createEntityReferenceField('node', [$this->type]); Chris@0: Chris@0: // Create entity reference field with date format as a target. Chris@0: $date_format_field_name = $this->createEntityReferenceField('date_format'); Chris@0: Chris@0: // Display all newly created Entity Reference configuration. Chris@0: $this->drupalGet('admin/structure/types/manage/' . $this->type . '/display'); Chris@0: Chris@0: // Check for Taxonomy Term select box values. Chris@0: // Test if Taxonomy Term Entity Reference Field has the correct formatters. Chris@0: $this->assertFieldSelectOptions('fields[field_' . $taxonomy_term_field_name . '][type]', [ Chris@0: 'entity_reference_label', Chris@0: 'entity_reference_entity_id', Chris@0: 'entity_reference_rss_category', Chris@0: 'entity_reference_entity_view', Chris@0: ]); Chris@0: Chris@0: // Test if User Reference Field has the correct formatters. Chris@0: // Author should be available for this field. Chris@0: // RSS Category should not be available for this field. Chris@0: $this->assertFieldSelectOptions('fields[field_' . $user_field_name . '][type]', [ Chris@0: 'author', Chris@0: 'entity_reference_entity_id', Chris@0: 'entity_reference_entity_view', Chris@0: 'entity_reference_label', Chris@0: ]); Chris@0: Chris@0: // Test if Node Entity Reference Field has the correct formatters. Chris@0: // RSS Category should not be available for this field. Chris@0: $this->assertFieldSelectOptions('fields[field_' . $node_field_name . '][type]', [ Chris@0: 'entity_reference_label', Chris@0: 'entity_reference_entity_id', Chris@0: 'entity_reference_entity_view', Chris@0: ]); Chris@0: Chris@0: // Test if Date Format Reference Field has the correct formatters. Chris@0: // RSS Category & Entity View should not be available for this field. Chris@0: // This could be any field without a ViewBuilder. Chris@0: $this->assertFieldSelectOptions('fields[field_' . $date_format_field_name . '][type]', [ Chris@0: 'entity_reference_label', Chris@0: 'entity_reference_entity_id', Chris@0: ]); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests field settings for an entity reference field when the field has Chris@0: * multiple target bundles and is set to auto-create the target entity. Chris@0: */ Chris@0: public function testMultipleTargetBundles() { Chris@0: /** @var \Drupal\taxonomy\Entity\Vocabulary[] $vocabularies */ Chris@0: $vocabularies = []; Chris@0: for ($i = 0; $i < 2; $i++) { Chris@0: $vid = Unicode::strtolower($this->randomMachineName()); Chris@0: $vocabularies[$i] = Vocabulary::create([ Chris@0: 'name' => $this->randomString(), Chris@0: 'vid' => $vid, Chris@0: ]); Chris@0: $vocabularies[$i]->save(); Chris@0: } Chris@0: Chris@0: // Create a new field pointing to the first vocabulary. Chris@0: $field_name = $this->createEntityReferenceField('taxonomy_term', [$vocabularies[0]->id()]); Chris@0: $field_name = "field_$field_name"; Chris@0: $field_id = 'node.' . $this->type . '.' . $field_name; Chris@0: $path = 'admin/structure/types/manage/' . $this->type . '/fields/' . $field_id; Chris@0: Chris@0: $this->drupalGet($path); Chris@0: Chris@0: // Expect that there's no 'auto_create_bundle' selected. Chris@0: $this->assertNoFieldByName('settings[handler_settings][auto_create_bundle]'); Chris@0: Chris@0: $edit = [ Chris@0: 'settings[handler_settings][target_bundles][' . $vocabularies[1]->id() . ']' => TRUE, Chris@0: ]; Chris@0: // Enable the second vocabulary as a target bundle. Chris@0: $this->drupalPostAjaxForm($path, $edit, key($edit)); Chris@0: // Expect a select element with the two vocabularies as options. Chris@0: $this->assertFieldByXPath("//select[@name='settings[handler_settings][auto_create_bundle]']/option[@value='" . $vocabularies[0]->id() . "']"); Chris@0: $this->assertFieldByXPath("//select[@name='settings[handler_settings][auto_create_bundle]']/option[@value='" . $vocabularies[1]->id() . "']"); Chris@0: Chris@0: $edit = [ Chris@0: 'settings[handler_settings][auto_create]' => TRUE, Chris@0: 'settings[handler_settings][auto_create_bundle]' => $vocabularies[1]->id(), Chris@0: ]; Chris@0: $this->drupalPostForm(NULL, $edit, t('Save settings')); Chris@0: Chris@0: /** @var \Drupal\field\Entity\FieldConfig $field_config */ Chris@0: $field_config = FieldConfig::load($field_id); Chris@0: // Expect that the target bundle has been saved in the backend. Chris@0: $this->assertEqual($field_config->getSetting('handler_settings')['auto_create_bundle'], $vocabularies[1]->id()); Chris@0: Chris@0: // Delete the other bundle. Field config should not be affected. Chris@0: $vocabularies[0]->delete(); Chris@0: $field_config = FieldConfig::load($field_id); Chris@0: $this->assertTrue($field_config->getSetting('handler_settings')['auto_create']); Chris@0: $this->assertIdentical($field_config->getSetting('handler_settings')['auto_create_bundle'], $vocabularies[1]->id()); Chris@0: Chris@0: // Delete the bundle set for entity auto-creation. Auto-created settings Chris@0: // should be reset (no auto-creation). Chris@0: $vocabularies[1]->delete(); Chris@0: $field_config = FieldConfig::load($field_id); Chris@0: $this->assertFalse($field_config->getSetting('handler_settings')['auto_create']); Chris@0: $this->assertFalse(isset($field_config->getSetting('handler_settings')['auto_create_bundle'])); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Creates a new Entity Reference fields with a given target type. Chris@0: * Chris@0: * @param string $target_type Chris@0: * The name of the target type Chris@0: * @param string[] $bundles Chris@0: * A list of bundle IDs. Defaults to []. Chris@0: * Chris@0: * @return string Chris@0: * Returns the generated field name Chris@0: */ Chris@0: protected function createEntityReferenceField($target_type, $bundles = []) { Chris@0: // Generates a bundle path for the newly created content type. Chris@0: $bundle_path = 'admin/structure/types/manage/' . $this->type; Chris@0: Chris@0: // Generate a random field name, must be only lowercase characters. Chris@0: $field_name = strtolower($this->randomMachineName()); Chris@0: Chris@0: $storage_edit = $field_edit = []; Chris@0: $storage_edit['settings[target_type]'] = $target_type; Chris@0: foreach ($bundles as $bundle) { Chris@0: $field_edit['settings[handler_settings][target_bundles][' . $bundle . ']'] = TRUE; Chris@0: } Chris@0: Chris@0: $this->fieldUIAddNewField($bundle_path, $field_name, NULL, 'entity_reference', $storage_edit, $field_edit); Chris@0: Chris@0: // Returns the generated field name. Chris@0: return $field_name; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Checks if a select element contains the specified options. Chris@0: * Chris@0: * @param string $name Chris@0: * The field name. Chris@0: * @param array $expected_options Chris@0: * An array of expected options. Chris@0: * Chris@0: * @return bool Chris@0: * TRUE if the assertion succeeded, FALSE otherwise. Chris@0: */ Chris@0: protected function assertFieldSelectOptions($name, array $expected_options) { Chris@0: $xpath = $this->buildXPathQuery('//select[@name=:name]', [':name' => $name]); Chris@0: $fields = $this->xpath($xpath); Chris@0: if ($fields) { Chris@0: $field = $fields[0]; Chris@0: $options = $this->getAllOptionsList($field); Chris@0: Chris@0: sort($options); Chris@0: sort($expected_options); Chris@0: Chris@0: return $this->assertIdentical($options, $expected_options); Chris@0: } Chris@0: else { Chris@0: return $this->fail('Unable to find field ' . $name); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Extracts all options from a select element. Chris@0: * Chris@0: * @param \SimpleXMLElement $element Chris@0: * The select element field information. Chris@0: * Chris@0: * @return array Chris@0: * An array of option values as strings. Chris@0: */ Chris@0: protected function getAllOptionsList(\SimpleXMLElement $element) { Chris@0: $options = []; Chris@0: // Add all options items. Chris@0: foreach ($element->option as $option) { Chris@0: $options[] = (string) $option['value']; Chris@0: } Chris@0: Chris@0: // Loops trough all the option groups Chris@0: foreach ($element->optgroup as $optgroup) { Chris@0: $options = array_merge($this->getAllOptionsList($optgroup), $options); Chris@0: } Chris@0: Chris@0: return $options; Chris@0: } Chris@0: Chris@0: }