3 namespace Drupal\embed\Tests;
5 use Drupal\editor\Entity\Editor;
6 use Drupal\file\Entity\File;
7 use Drupal\filter\Entity\FilterFormat;
8 use Drupal\simpletest\WebTestBase;
11 * Base class for all embed tests.
13 abstract class EmbedTestBase extends WebTestBase {
20 public static $modules = [
29 * The test administrative user.
31 * @var \Drupal\user\UserInterface
36 * The test administrative user.
38 * @var \Drupal\user\UserInterface
45 protected function setUp() {
48 // Create Filtered HTML text format and enable entity_embed filter.
49 $format = FilterFormat::create([
50 'format' => 'embed_test',
51 'name' => 'Embed format',
62 $editor = Editor::create([
63 'format' => 'embed_test',
64 'editor' => 'ckeditor',
67 'rows' => [[$editor_group]],
73 // Create a user with required permissions.
74 $this->adminUser = $this->drupalCreateUser([
75 'administer embed buttons',
76 'use text format embed_test',
79 // Create a user with required permissions.
80 $this->webUser = $this->drupalCreateUser([
81 'use text format embed_test',
84 // Set up some standard blocks for the testing theme (Classy).
85 // @see https://www.drupal.org/node/507488?page=1#comment-10291517
86 $this->drupalPlaceBlock('local_tasks_block');
87 $this->drupalPlaceBlock('local_actions_block');
91 * Retrieves a sample file of the specified type.
93 * @return \Drupal\file\FileInterface
95 protected function getTestFile($type_name, $size = NULL) {
96 // Get a file to upload.
97 $file = current($this->drupalGetTestFiles($type_name, $size));
99 // Add a filesize property to files as would be read by
100 // \Drupal\file\Entity\File::load().
101 $file->filesize = filesize($file->uri);
103 $file = File::create((array) $file);
111 * This is a duplicate of WebTestBase::drupalProcessAjaxResponse() that
112 * includes the fix from https://www.drupal.org/node/2554449 for using ID
113 * selectors in AJAX commands.
115 protected function drupalProcessAjaxResponse($content, array $ajax_response, array $ajax_settings, array $drupal_settings) {
116 // ajax.js applies some defaults to the settings object, so do the same
117 // for what's used by this function.
118 $ajax_settings += array(
119 'method' => 'replaceWith',
121 // DOM can load HTML soup. But, HTML soup can throw warnings, suppress
123 $dom = new \DOMDocument();
124 @$dom->loadHTML($content);
125 // XPath allows for finding wrapper nodes better than DOM does.
126 $xpath = new \DOMXPath($dom);
127 foreach ($ajax_response as $command) {
128 // Error messages might be not commands.
129 if (!is_array($command)) {
132 switch ($command['command']) {
134 $drupal_settings = NestedArray::mergeDeepArray([$drupal_settings, $command['settings']], TRUE);
139 // When a command specifies a specific selector, use it.
140 if (!empty($command['selector']) && strpos($command['selector'], '#') === 0) {
141 $wrapperNode = $xpath->query('//*[@id="' . substr($command['selector'], 1) . '"]')->item(0);
143 // When a command doesn't specify a selector, use the
144 // #ajax['wrapper'] which is always an HTML ID.
145 elseif (!empty($ajax_settings['wrapper'])) {
146 $wrapperNode = $xpath->query('//*[@id="' . $ajax_settings['wrapper'] . '"]')->item(0);
148 // @todo Ajax commands can target any jQuery selector, but these are
149 // hard to fully emulate with XPath. For now, just handle 'head'
150 // and 'body', since these are used by
151 // \Drupal\Core\Ajax\AjaxResponse::ajaxRender().
152 elseif (in_array($command['selector'], array('head', 'body'))) {
153 $wrapperNode = $xpath->query('//' . $command['selector'])->item(0);
156 // ajax.js adds an enclosing DIV to work around a Safari bug.
157 $newDom = new \DOMDocument();
158 // DOM can load HTML soup. But, HTML soup can throw warnings,
160 @$newDom->loadHTML('<div>' . $command['data'] . '</div>');
161 // Suppress warnings thrown when duplicate HTML IDs are encountered.
162 // This probably means we are replacing an element with the same ID.
163 $newNode = @$dom->importNode($newDom->documentElement->firstChild->firstChild, TRUE);
164 $method = isset($command['method']) ? $command['method'] : $ajax_settings['method'];
165 // The "method" is a jQuery DOM manipulation function. Emulate
166 // each one using PHP's DOMNode API.
169 $wrapperNode->parentNode->replaceChild($newNode, $wrapperNode);
172 $wrapperNode->appendChild($newNode);
175 // If no firstChild, insertBefore() falls back to
177 $wrapperNode->insertBefore($newNode, $wrapperNode->firstChild);
180 $wrapperNode->parentNode->insertBefore($newNode, $wrapperNode);
183 // If no nextSibling, insertBefore() falls back to
185 $wrapperNode->parentNode->insertBefore($newNode, $wrapperNode->nextSibling);
188 foreach ($wrapperNode->childNodes as $childNode) {
189 $wrapperNode->removeChild($childNode);
191 $wrapperNode->appendChild($newNode);
197 // @todo Add suitable implementations for these commands in order to
198 // have full test coverage of what ajax.js can do.
211 case 'update_build_id':
212 $buildId = $xpath->query('//input[@name="form_build_id" and @value="' . $command['old'] . '"]')->item(0);
214 $buildId->setAttribute('value', $command['new']);
219 $content = $dom->saveHTML();
220 $this->setRawContent($content);
221 $this->setDrupalSettings($drupal_settings);