Chris@0: entityTypeId = 'node';
Chris@0: $this->bundle = 'article';
Chris@0: parent::setUp();
Chris@0:
Chris@0: // Ensure the help message is shown even with prefixed paths.
Chris@0: $this->drupalPlaceBlock('help_block', ['region' => 'content']);
Chris@0:
Chris@0: // Display the language selector.
Chris@0: $this->drupalLogin($this->administrator);
Chris@0: $edit = ['language_configuration[language_alterable]' => TRUE];
Chris@0: $this->drupalPostForm('admin/structure/types/manage/article', $edit, t('Save content type'));
Chris@0: $this->drupalLogin($this->translator);
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Tests the basic translation UI.
Chris@0: */
Chris@0: public function testTranslationUI() {
Chris@0: parent::testTranslationUI();
Chris@0: $this->doUninstallTest();
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Tests changing the published status on a node without fields.
Chris@0: */
Chris@0: public function testPublishedStatusNoFields() {
Chris@0: // Test changing the published status of an article without fields.
Chris@0: $this->drupalLogin($this->administrator);
Chris@0: // Delete all fields.
Chris@0: $this->drupalGet('admin/structure/types/manage/article/fields');
Chris@0: $this->drupalPostForm('admin/structure/types/manage/article/fields/node.article.' . $this->fieldName . '/delete', [], t('Delete'));
Chris@0: $this->drupalPostForm('admin/structure/types/manage/article/fields/node.article.field_tags/delete', [], t('Delete'));
Chris@0: $this->drupalPostForm('admin/structure/types/manage/article/fields/node.article.field_image/delete', [], t('Delete'));
Chris@0:
Chris@0: // Add a node.
Chris@0: $default_langcode = $this->langcodes[0];
Chris@0: $values[$default_langcode] = ['title' => [['value' => $this->randomMachineName()]]];
Chris@0: $this->entityId = $this->createEntity($values[$default_langcode], $default_langcode);
Chris@0: $storage = $this->container->get('entity_type.manager')
Chris@0: ->getStorage($this->entityTypeId);
Chris@0: $storage->resetCache([$this->entityId]);
Chris@0: $entity = $storage->load($this->entityId);
Chris@0:
Chris@0: // Add a content translation.
Chris@0: $langcode = 'fr';
Chris@0: $language = ConfigurableLanguage::load($langcode);
Chris@0: $values[$langcode] = ['title' => [['value' => $this->randomMachineName()]]];
Chris@0:
Chris@0: $entity_type_id = $entity->getEntityTypeId();
Chris@0: $add_url = Url::fromRoute("entity.$entity_type_id.content_translation_add", [
Chris@0: $entity->getEntityTypeId() => $entity->id(),
Chris@0: 'source' => $default_langcode,
Chris@17: 'target' => $langcode,
Chris@0: ], ['language' => $language]);
Chris@0: $edit = $this->getEditValues($values, $langcode);
Chris@0: $edit['status[value]'] = FALSE;
Chris@0: $this->drupalPostForm($add_url, $edit, t('Save (this translation)'));
Chris@0:
Chris@0: $storage->resetCache([$this->entityId]);
Chris@0: $entity = $storage->load($this->entityId);
Chris@0: $translation = $entity->getTranslation($langcode);
Chris@0: // Make sure we unpublished the node correctly.
Chris@0: $this->assertFalse($this->manager->getTranslationMetadata($translation)->isPublished(), 'The translation has been correctly unpublished.');
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * {@inheritdoc}
Chris@0: */
Chris@0: protected function getTranslatorPermissions() {
Chris@0: return array_merge(parent::getTranslatorPermissions(), ['administer nodes', "edit any $this->bundle content"]);
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * {@inheritdoc}
Chris@0: */
Chris@0: protected function getEditorPermissions() {
Chris@0: return ['administer nodes', 'create article content'];
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * {@inheritdoc}
Chris@0: */
Chris@0: protected function getAdministratorPermissions() {
Chris@0: return array_merge(parent::getAdministratorPermissions(), ['access administration pages', 'administer content types', 'administer node fields', 'access content overview', 'bypass node access', 'administer languages', 'administer themes', 'view the administration theme']);
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * {@inheritdoc}
Chris@0: */
Chris@0: protected function getNewEntityValues($langcode) {
Chris@0: return ['title' => [['value' => $this->randomMachineName()]]] + parent::getNewEntityValues($langcode);
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * {@inheritdoc}
Chris@0: */
Chris@0: protected function doTestPublishedStatus() {
Chris@0: $storage = $this->container->get('entity_type.manager')
Chris@0: ->getStorage($this->entityTypeId);
Chris@0: $storage->resetCache([$this->entityId]);
Chris@0: $entity = $storage->load($this->entityId);
Chris@0: $languages = $this->container->get('language_manager')->getLanguages();
Chris@0:
Chris@0: $statuses = [
Chris@0: TRUE,
Chris@0: FALSE,
Chris@0: ];
Chris@0:
Chris@0: foreach ($statuses as $index => $value) {
Chris@0: // (Un)publish the node translations and check that the translation
Chris@0: // statuses are (un)published accordingly.
Chris@0: foreach ($this->langcodes as $langcode) {
Chris@0: $options = ['language' => $languages[$langcode]];
Chris@18: $url = $entity->toUrl('edit-form', $options);
Chris@0: $this->drupalPostForm($url, ['status[value]' => $value], t('Save') . $this->getFormSubmitSuffix($entity, $langcode), $options);
Chris@0: }
Chris@0: $storage->resetCache([$this->entityId]);
Chris@0: $entity = $storage->load($this->entityId);
Chris@0: foreach ($this->langcodes as $langcode) {
Chris@0: // The node is created as unpublished thus we switch to the published
Chris@0: // status first.
Chris@0: $status = !$index;
Chris@0: $translation = $entity->getTranslation($langcode);
Chris@0: $this->assertEqual($status, $this->manager->getTranslationMetadata($translation)->isPublished(), 'The translation has been correctly unpublished.');
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * {@inheritdoc}
Chris@0: */
Chris@0: protected function doTestAuthoringInfo() {
Chris@0: $storage = $this->container->get('entity_type.manager')
Chris@0: ->getStorage($this->entityTypeId);
Chris@0: $storage->resetCache([$this->entityId]);
Chris@0: $entity = $storage->load($this->entityId);
Chris@0: $languages = $this->container->get('language_manager')->getLanguages();
Chris@0: $values = [];
Chris@0:
Chris@0: // Post different base field information for each translation.
Chris@0: foreach ($this->langcodes as $langcode) {
Chris@0: $user = $this->drupalCreateUser();
Chris@0: $values[$langcode] = [
Chris@0: 'uid' => $user->id(),
Chris@0: 'created' => REQUEST_TIME - mt_rand(0, 1000),
Chris@0: 'sticky' => (bool) mt_rand(0, 1),
Chris@0: 'promote' => (bool) mt_rand(0, 1),
Chris@0: ];
Chris@18: /** @var \Drupal\Core\Datetime\DateFormatterInterface $date_formatter */
Chris@18: $date_formatter = $this->container->get('date.formatter');
Chris@0: $edit = [
Chris@18: 'uid[0][target_id]' => $user->getAccountName(),
Chris@18: 'created[0][value][date]' => $date_formatter->format($values[$langcode]['created'], 'custom', 'Y-m-d'),
Chris@18: 'created[0][value][time]' => $date_formatter->format($values[$langcode]['created'], 'custom', 'H:i:s'),
Chris@0: 'sticky[value]' => $values[$langcode]['sticky'],
Chris@0: 'promote[value]' => $values[$langcode]['promote'],
Chris@0: ];
Chris@0: $options = ['language' => $languages[$langcode]];
Chris@18: $url = $entity->toUrl('edit-form', $options);
Chris@0: $this->drupalPostForm($url, $edit, $this->getFormSubmitAction($entity, $langcode), $options);
Chris@0: }
Chris@0:
Chris@0: $storage->resetCache([$this->entityId]);
Chris@0: $entity = $storage->load($this->entityId);
Chris@0: foreach ($this->langcodes as $langcode) {
Chris@0: $translation = $entity->getTranslation($langcode);
Chris@0: $metadata = $this->manager->getTranslationMetadata($translation);
Chris@0: $this->assertEqual($metadata->getAuthor()->id(), $values[$langcode]['uid'], 'Translation author correctly stored.');
Chris@0: $this->assertEqual($metadata->getCreatedTime(), $values[$langcode]['created'], 'Translation date correctly stored.');
Chris@0: $this->assertEqual($translation->isSticky(), $values[$langcode]['sticky'], 'Sticky of Translation correctly stored.');
Chris@0: $this->assertEqual($translation->isPromoted(), $values[$langcode]['promote'], 'Promoted of Translation correctly stored.');
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Tests that translation page inherits admin status of edit page.
Chris@0: */
Chris@0: public function testTranslationLinkTheme() {
Chris@0: $this->drupalLogin($this->administrator);
Chris@0: $article = $this->drupalCreateNode(['type' => 'article', 'langcode' => $this->langcodes[0]]);
Chris@0:
Chris@0: // Set up Seven as the admin theme and use it for node editing.
Chris@0: $this->container->get('theme_handler')->install(['seven']);
Chris@0: $edit = [];
Chris@0: $edit['admin_theme'] = 'seven';
Chris@0: $edit['use_admin_theme'] = TRUE;
Chris@0: $this->drupalPostForm('admin/appearance', $edit, t('Save configuration'));
Chris@0: $this->drupalGet('node/' . $article->id() . '/translations');
Chris@0: $this->assertRaw('core/themes/seven/css/base/elements.css', 'Translation uses admin theme if edit is admin.');
Chris@0:
Chris@0: // Turn off admin theme for editing, assert inheritance to translations.
Chris@0: $edit['use_admin_theme'] = FALSE;
Chris@0: $this->drupalPostForm('admin/appearance', $edit, t('Save configuration'));
Chris@0: $this->drupalGet('node/' . $article->id() . '/translations');
Chris@0: $this->assertNoRaw('core/themes/seven/css/base/elements.css', 'Translation uses frontend theme if edit is frontend.');
Chris@0:
Chris@0: // Assert presence of translation page itself (vs. DisabledBundle below).
Chris@0: $this->assertResponse(200);
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Tests that no metadata is stored for a disabled bundle.
Chris@0: */
Chris@0: public function testDisabledBundle() {
Chris@0: // Create a bundle that does not have translation enabled.
Chris@0: $disabledBundle = $this->randomMachineName();
Chris@0: $this->drupalCreateContentType(['type' => $disabledBundle, 'name' => $disabledBundle]);
Chris@0:
Chris@0: // Create a node for each bundle.
Chris@0: $node = $this->drupalCreateNode([
Chris@0: 'type' => $this->bundle,
Chris@0: 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
Chris@0: ]);
Chris@0:
Chris@0: // Make sure that nothing was inserted into the {content_translation} table.
Chris@0: $rows = db_query('SELECT nid, count(nid) AS count FROM {node_field_data} WHERE type <> :type GROUP BY nid HAVING count(nid) >= 2', [':type' => $this->bundle])->fetchAll();
Chris@0: $this->assertEqual(0, count($rows));
Chris@0:
Chris@0: // Ensure the translation tab is not accessible.
Chris@0: $this->drupalGet('node/' . $node->id() . '/translations');
Chris@0: $this->assertResponse(403);
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Tests that translations are rendered properly.
Chris@0: */
Chris@0: public function testTranslationRendering() {
Chris@0: $default_langcode = $this->langcodes[0];
Chris@0: $values[$default_langcode] = $this->getNewEntityValues($default_langcode);
Chris@0: $this->entityId = $this->createEntity($values[$default_langcode], $default_langcode);
Chris@0: $node = \Drupal::entityManager()->getStorage($this->entityTypeId)->load($this->entityId);
Chris@0: $node->setPromoted(TRUE);
Chris@0:
Chris@0: // Create translations.
Chris@0: foreach (array_diff($this->langcodes, [$default_langcode]) as $langcode) {
Chris@0: $values[$langcode] = $this->getNewEntityValues($langcode);
Chris@0: $translation = $node->addTranslation($langcode, $values[$langcode]);
Chris@0: // Publish and promote the translation to frontpage.
Chris@0: $translation->setPromoted(TRUE);
Chris@17: $translation->setPublished();
Chris@0: }
Chris@0: $node->save();
Chris@0:
Chris@0: // Test that the frontpage view displays the correct translations.
Chris@0: \Drupal::service('module_installer')->install(['views'], TRUE);
Chris@0: $this->rebuildContainer();
Chris@0: $this->doTestTranslations('node', $values);
Chris@0:
Chris@0: // Enable the translation language renderer.
Chris@0: $view = \Drupal::entityManager()->getStorage('view')->load('frontpage');
Chris@0: $display = &$view->getDisplay('default');
Chris@0: $display['display_options']['rendering_language'] = '***LANGUAGE_entity_translation***';
Chris@0: $view->save();
Chris@0:
Chris@0: // Need to check from the beginning, including the base_path, in the url
Chris@0: // since the pattern for the default language might be a substring of
Chris@0: // the strings for other languages.
Chris@0: $base_path = base_path();
Chris@0:
Chris@0: // Check the frontpage for 'Read more' links to each translation.
Chris@0: // See also assertTaxonomyPage() in NodeAccessBaseTableTest.
Chris@0: $node_href = 'node/' . $node->id();
Chris@0: foreach ($this->langcodes as $langcode) {
Chris@0: $this->drupalGet('node', ['language' => \Drupal::languageManager()->getLanguage($langcode)]);
Chris@0: $num_match_found = 0;
Chris@0: if ($langcode == 'en') {
Chris@0: // Site default language does not have langcode prefix in the URL.
Chris@0: $expected_href = $base_path . $node_href;
Chris@0: }
Chris@0: else {
Chris@0: $expected_href = $base_path . $langcode . '/' . $node_href;
Chris@0: }
Chris@0: $pattern = '|^' . $expected_href . '$|';
Chris@0: foreach ($this->xpath("//a[text()='Read more']") as $link) {
Chris@0: if (preg_match($pattern, $link->getAttribute('href'), $matches) == TRUE) {
Chris@0: $num_match_found++;
Chris@0: }
Chris@0: }
Chris@0: $this->assertTrue($num_match_found == 1, 'There is 1 Read more link, ' . $expected_href . ', for the ' . $langcode . ' translation of a node on the frontpage. (Found ' . $num_match_found . '.)');
Chris@0: }
Chris@0:
Chris@0: // Check the frontpage for 'Add new comment' links that include the
Chris@0: // language.
Chris@0: $comment_form_href = 'node/' . $node->id() . '#comment-form';
Chris@0: foreach ($this->langcodes as $langcode) {
Chris@0: $this->drupalGet('node', ['language' => \Drupal::languageManager()->getLanguage($langcode)]);
Chris@0: $num_match_found = 0;
Chris@0: if ($langcode == 'en') {
Chris@0: // Site default language does not have langcode prefix in the URL.
Chris@0: $expected_href = $base_path . $comment_form_href;
Chris@0: }
Chris@0: else {
Chris@0: $expected_href = $base_path . $langcode . '/' . $comment_form_href;
Chris@0: }
Chris@0: $pattern = '|^' . $expected_href . '$|';
Chris@0: foreach ($this->xpath("//a[text()='Add new comment']") as $link) {
Chris@0: if (preg_match($pattern, $link->getAttribute('href'), $matches) == TRUE) {
Chris@0: $num_match_found++;
Chris@0: }
Chris@0: }
Chris@0: $this->assertTrue($num_match_found == 1, 'There is 1 Add new comment link, ' . $expected_href . ', for the ' . $langcode . ' translation of a node on the frontpage. (Found ' . $num_match_found . '.)');
Chris@0: }
Chris@0:
Chris@0: // Test that the node page displays the correct translations.
Chris@0: $this->doTestTranslations('node/' . $node->id(), $values);
Chris@0:
Chris@0: // Test that the node page has the correct alternate hreflang links.
Chris@18: $this->doTestAlternateHreflangLinks($node->toUrl());
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Tests that the given path displays the correct translation values.
Chris@0: *
Chris@0: * @param string $path
Chris@0: * The path to be tested.
Chris@0: * @param array $values
Chris@0: * The translation values to be found.
Chris@0: */
Chris@0: protected function doTestTranslations($path, array $values) {
Chris@0: $languages = $this->container->get('language_manager')->getLanguages();
Chris@0: foreach ($this->langcodes as $langcode) {
Chris@0: $this->drupalGet($path, ['language' => $languages[$langcode]]);
Chris@0: $this->assertText($values[$langcode]['title'][0]['value'], format_string('The %langcode node translation is correctly displayed.', ['%langcode' => $langcode]));
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Tests that the given path provides the correct alternate hreflang links.
Chris@0: *
Chris@0: * @param \Drupal\Core\Url $url
Chris@0: * The path to be tested.
Chris@0: */
Chris@0: protected function doTestAlternateHreflangLinks(Url $url) {
Chris@0: $languages = $this->container->get('language_manager')->getLanguages();
Chris@0: $url->setAbsolute();
Chris@0: $urls = [];
Chris@0: foreach ($this->langcodes as $langcode) {
Chris@0: $language_url = clone $url;
Chris@0: $urls[$langcode] = $language_url->setOption('language', $languages[$langcode]);
Chris@0: }
Chris@0: foreach ($this->langcodes as $langcode) {
Chris@0: $this->drupalGet($urls[$langcode]);
Chris@0: foreach ($urls as $alternate_langcode => $language_url) {
Chris@0: // Retrieve desired link elements from the HTML head.
Chris@0: $links = $this->xpath('head/link[@rel = "alternate" and @href = :href and @hreflang = :hreflang]',
Chris@0: [':href' => $language_url->toString(), ':hreflang' => $alternate_langcode]);
Chris@0: $this->assert(isset($links[0]), format_string('The %langcode node translation has the correct alternate hreflang link for %alternate_langcode: %link.', ['%langcode' => $langcode, '%alternate_langcode' => $alternate_langcode, '%link' => $url->toString()]));
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * {@inheritdoc}
Chris@0: */
Chris@0: protected function getFormSubmitSuffix(EntityInterface $entity, $langcode) {
Chris@0: if (!$entity->isNew() && $entity->isTranslatable()) {
Chris@0: $translations = $entity->getTranslationLanguages();
Chris@0: if ((count($translations) > 1 || !isset($translations[$langcode])) && ($field = $entity->getFieldDefinition('status'))) {
Chris@0: return ' ' . ($field->isTranslatable() ? t('(this translation)') : t('(all translations)'));
Chris@0: }
Chris@0: }
Chris@0: return '';
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Tests uninstalling content_translation.
Chris@0: */
Chris@0: protected function doUninstallTest() {
Chris@0: // Delete all the nodes so there is no data.
Chris@0: $nodes = Node::loadMultiple();
Chris@0: foreach ($nodes as $node) {
Chris@0: $node->delete();
Chris@0: }
Chris@0: $language_count = count(\Drupal::configFactory()->listAll('language.content_settings.'));
Chris@0: \Drupal::service('module_installer')->uninstall(['content_translation']);
Chris@0: $this->rebuildContainer();
Chris@0: $this->assertEqual($language_count, count(\Drupal::configFactory()->listAll('language.content_settings.')), 'Languages have been fixed rather than deleted during content_translation uninstall.');
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * {@inheritdoc}
Chris@0: */
Chris@0: protected function doTestTranslationEdit() {
Chris@0: $storage = $this->container->get('entity_type.manager')
Chris@0: ->getStorage($this->entityTypeId);
Chris@0: $storage->resetCache([$this->entityId]);
Chris@0: $entity = $storage->load($this->entityId);
Chris@0: $languages = $this->container->get('language_manager')->getLanguages();
Chris@0: $type_name = node_get_type_label($entity);
Chris@0:
Chris@0: foreach ($this->langcodes as $langcode) {
Chris@0: // We only want to test the title for non-english translations.
Chris@0: if ($langcode != 'en') {
Chris@0: $options = ['language' => $languages[$langcode]];
Chris@18: $url = $entity->toUrl('edit-form', $options);
Chris@0: $this->drupalGet($url);
Chris@0:
Chris@0: $title = t('Edit @type @title [%language translation]', [
Chris@0: '@type' => $type_name,
Chris@0: '@title' => $entity->getTranslation($langcode)->label(),
Chris@0: '%language' => $languages[$langcode]->getName(),
Chris@0: ]);
Chris@0: $this->assertRaw($title);
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Tests that revision translations are rendered properly.
Chris@0: */
Chris@0: public function testRevisionTranslationRendering() {
Chris@0: $storage = \Drupal::entityTypeManager()->getStorage('node');
Chris@0:
Chris@0: // Create a node.
Chris@0: $nid = $this->createEntity(['title' => 'First rev en title'], 'en');
Chris@0: $node = $storage->load($nid);
Chris@0: $original_revision_id = $node->getRevisionId();
Chris@0:
Chris@0: // Add a French translation.
Chris@0: $translation = $node->addTranslation('fr');
Chris@0: $translation->title = 'First rev fr title';
Chris@0: $translation->setNewRevision(FALSE);
Chris@0: $translation->save();
Chris@0:
Chris@0: // Create a new revision.
Chris@0: $node->title = 'Second rev en title';
Chris@0: $node->setNewRevision(TRUE);
Chris@0: $node->save();
Chris@0:
Chris@0: // Get an English view of this revision.
Chris@0: $original_revision = $storage->loadRevision($original_revision_id);
Chris@0: $original_revision_url = $original_revision->toUrl('revision')->toString();
Chris@0:
Chris@0: // Should be different from regular node URL.
Chris@0: $this->assertNotIdentical($original_revision_url, $original_revision->toUrl()->toString());
Chris@0: $this->drupalGet($original_revision_url);
Chris@0: $this->assertResponse(200);
Chris@0:
Chris@0: // Contents should be in English, of correct revision.
Chris@0: $this->assertText('First rev en title');
Chris@0: $this->assertNoText('First rev fr title');
Chris@0:
Chris@0: // Get a French view.
Chris@0: $url_fr = $original_revision->getTranslation('fr')->toUrl('revision')->toString();
Chris@0:
Chris@0: // Should have different URL from English.
Chris@0: $this->assertNotIdentical($url_fr, $original_revision->toUrl()->toString());
Chris@0: $this->assertNotIdentical($url_fr, $original_revision_url);
Chris@0: $this->drupalGet($url_fr);
Chris@0: $this->assertResponse(200);
Chris@0:
Chris@0: // Contents should be in French, of correct revision.
Chris@0: $this->assertText('First rev fr title');
Chris@0: $this->assertNoText('First rev en title');
Chris@0: }
Chris@0:
Chris@17: /**
Chris@17: * Test that title is not escaped (but XSS-filtered) for details form element.
Chris@17: */
Chris@17: public function testDetailsTitleIsNotEscaped() {
Chris@17: $this->drupalLogin($this->administrator);
Chris@17: // Make the image field a multi-value field in order to display a
Chris@17: // details form element.
Chris@17: $edit = ['cardinality_number' => 2];
Chris@17: $this->drupalPostForm('admin/structure/types/manage/article/fields/node.article.field_image/storage', $edit, t('Save field settings'));
Chris@17:
Chris@17: // Make the image field non-translatable.
Chris@17: $edit = ['settings[node][article][fields][field_image]' => FALSE];
Chris@17: $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
Chris@17:
Chris@17: // Create a node.
Chris@17: $nid = $this->createEntity(['title' => 'Node with multi-value image field en title'], 'en');
Chris@17:
Chris@17: // Add a French translation and assert the title markup is not escaped.
Chris@17: $this->drupalGet("node/$nid/translations/add/en/fr");
Chris@17: $markup = 'Image (all languages)';
Chris@17: $this->assertSession()->assertNoEscaped($markup);
Chris@17: $this->assertSession()->responseContains($markup);
Chris@17: }
Chris@17:
Chris@0: }