766748f84f65922695bc9f5f10c2eaee8e832a05
[yaffs-website] / web / modules / contrib / embed / src / Tests / EmbedTestBase.php
1 <?php
2
3 namespace Drupal\embed\Tests;
4
5 use Drupal\editor\Entity\Editor;
6 use Drupal\file\Entity\File;
7 use Drupal\filter\Entity\FilterFormat;
8 use Drupal\simpletest\WebTestBase;
9
10 /**
11  * Base class for all embed tests.
12  */
13 abstract class EmbedTestBase extends WebTestBase {
14
15   /**
16    * Modules to enable.
17    *
18    * @var array
19    */
20   public static $modules = [
21     'block',
22     'embed',
23     'embed_test',
24     'editor',
25     'ckeditor',
26   ];
27
28   /**
29    * The test administrative user.
30    *
31    * @var \Drupal\user\UserInterface
32    */
33   protected $adminUser;
34
35   /**
36    * The test administrative user.
37    *
38    * @var \Drupal\user\UserInterface
39    */
40   protected $webUser;
41
42   /**
43    * {@inheritdoc}
44    */
45   protected function setUp() {
46     parent::setUp();
47
48     // Create Filtered HTML text format and enable entity_embed filter.
49     $format = FilterFormat::create([
50       'format' => 'embed_test',
51       'name' => 'Embed format',
52       'filters' => [],
53     ]);
54     $format->save();
55
56     $editor_group = [
57       'name' => 'Embed',
58       'items' => [
59         'embed_test_default',
60       ],
61     ];
62     $editor = Editor::create([
63       'format' => 'embed_test',
64       'editor' => 'ckeditor',
65       'settings' => [
66         'toolbar' => [
67           'rows' => [[$editor_group]],
68         ],
69       ],
70     ]);
71     $editor->save();
72
73     // Create a user with required permissions.
74     $this->adminUser = $this->drupalCreateUser([
75       'administer embed buttons',
76       'use text format embed_test',
77     ]);
78
79     // Create a user with required permissions.
80     $this->webUser = $this->drupalCreateUser([
81       'use text format embed_test',
82     ]);
83
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');
88   }
89
90   /**
91    * Retrieves a sample file of the specified type.
92    *
93    * @return \Drupal\file\FileInterface
94    */
95   protected function getTestFile($type_name, $size = NULL) {
96     // Get a file to upload.
97     $file = current($this->drupalGetTestFiles($type_name, $size));
98
99     // Add a filesize property to files as would be read by
100     // \Drupal\file\Entity\File::load().
101     $file->filesize = filesize($file->uri);
102
103     $file = File::create((array) $file);
104     $file->save();
105     return $file;
106   }
107
108   /**
109    * {@inheritdoc}
110    *
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.
114    */
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',
120     );
121     // DOM can load HTML soup. But, HTML soup can throw warnings, suppress
122     // them.
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)) {
130         continue;
131       }
132       switch ($command['command']) {
133         case 'settings':
134           $drupal_settings = NestedArray::mergeDeepArray([$drupal_settings, $command['settings']], TRUE);
135           break;
136
137         case 'insert':
138           $wrapperNode = NULL;
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);
142           }
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);
147           }
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);
154           }
155           if ($wrapperNode) {
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,
159             // suppress them.
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.
167             switch ($method) {
168               case 'replaceWith':
169                 $wrapperNode->parentNode->replaceChild($newNode, $wrapperNode);
170                 break;
171               case 'append':
172                 $wrapperNode->appendChild($newNode);
173                 break;
174               case 'prepend':
175                 // If no firstChild, insertBefore() falls back to
176                 // appendChild().
177                 $wrapperNode->insertBefore($newNode, $wrapperNode->firstChild);
178                 break;
179               case 'before':
180                 $wrapperNode->parentNode->insertBefore($newNode, $wrapperNode);
181                 break;
182               case 'after':
183                 // If no nextSibling, insertBefore() falls back to
184                 // appendChild().
185                 $wrapperNode->parentNode->insertBefore($newNode, $wrapperNode->nextSibling);
186                 break;
187               case 'html':
188                 foreach ($wrapperNode->childNodes as $childNode) {
189                   $wrapperNode->removeChild($childNode);
190                 }
191                 $wrapperNode->appendChild($newNode);
192                 break;
193             }
194           }
195           break;
196
197         // @todo Add suitable implementations for these commands in order to
198         //   have full test coverage of what ajax.js can do.
199         case 'remove':
200           break;
201         case 'changed':
202           break;
203         case 'css':
204           break;
205         case 'data':
206           break;
207         case 'restripe':
208           break;
209         case 'add_css':
210           break;
211         case 'update_build_id':
212           $buildId = $xpath->query('//input[@name="form_build_id" and @value="' . $command['old'] . '"]')->item(0);
213           if ($buildId) {
214             $buildId->setAttribute('value', $command['new']);
215           }
216           break;
217       }
218     }
219     $content = $dom->saveHTML();
220     $this->setRawContent($content);
221     $this->setDrupalSettings($drupal_settings);
222   }
223
224 }