3 namespace Drupal\metatag\Tests;
5 use Drupal\Component\Render\FormattableMarkup;
6 use Drupal\Component\Utility\Html;
7 use Drupal\simpletest\WebTestBase;
8 use Symfony\Component\DependencyInjection\Container;
11 * Base class to test all of the meta tags that are in a specific module.
13 abstract class MetatagTagsTestBase extends WebTestBase {
15 use MetatagHelperTrait;
20 public static $modules = [
21 // This is needed for the 'access content' permission.
30 // This module will be used to load a static page which will inherit the
31 // global defaults, without loading values from other configs.
32 'metatag_test_custom_route',
36 * All of the meta tags defined by this module which will be tested.
43 * The tag to look for when testing the output.
47 private $testTag = 'meta';
54 private $testNameAttribute = 'name';
57 * The attribute to look for when testing the output.
61 private $testValueAttribute = 'content';
66 protected function setUp() {
69 // Use the test page as the front page.
70 $this->config('system.site')->set('page.front', '/test-page')->save();
72 // Initiate session with a user who can manage meta tags and access content.
74 'administer site configuration',
75 'administer meta tags',
78 $account = $this->drupalCreateUser($permissions);
79 $this->drupalLogin($account);
83 * Tests that this module's tags are available.
85 public function testTagsArePresent() {
86 // Load the global config.
87 $this->drupalGet('admin/config/search/metatag/global');
88 $this->assertResponse(200);
90 // Confirm the various meta tags are available.
91 foreach ($this->tags as $tag) {
92 // Look for a custom method named "{$tagname}TestFieldXpath", if found
93 // use that method to get the xpath definition for this meta tag,
94 // otherwise it defaults to just looking for a text input field.
95 $method = $this->getMethodFromTagCallback($tag, 'test_field_xpath');
96 if (method_exists($this, $method)) {
97 $xpath = $this->$method();
100 $xpath = "//input[@name='{$tag}' and @type='text']";
103 $this->assertFieldByXPath($xpath, NULL, new FormattableMarkup('Found the @tag meta tag field.', ['@tag' => $tag]));
106 $this->drupalLogout();
110 * Confirm that each tag can be saved and that the output is correct.
112 public function testTagsInputOutput() {
113 // Create a content type to test with.
114 $this->createContentType(['type' => 'page']);
115 $node = $this->drupalCreateNode([
116 'title' => t('Hello, world!'),
120 // Test a non-entity path and an entity path. The non-entity path inherits
121 // the global meta tags, the entity path inherits from its entity config.
124 'admin/config/search/metatag/global',
125 'metatag_test_custom_route',
126 'Saved the Global Metatag defaults.',
129 'admin/config/search/metatag/node',
131 'Saved the Content Metatag defaults',
135 foreach ($paths as $item) {
136 list($path1, $path2, $save_message) = $item;
138 // Load the global config.
139 $this->drupalGet($path1);
140 $this->assertResponse(200);
142 // Update the Global defaults and test them.
143 $all_values = $values = [];
144 foreach ($this->tags as $tag_name) {
145 // Look for a custom method named "{$tagname}TestKey", if found use
146 // that method to get the test string for this meta tag, otherwise it
147 // defaults to the meta tag's name.
148 $method = $this->getMethodFromTagCallback($tag_name, 'TestKey');
149 if (method_exists($this, $method)) {
150 $test_key = $this->$method();
153 $test_key = $tag_name;
156 // Look for a custom method named "{$tagname}TestValue", if found use
157 // that method to get the test string for this meta tag, otherwise it
158 // defaults to just generating a random string.
159 $method = $this->getMethodFromTagCallback($tag_name, 'TestValue');
160 if (method_exists($this, $method)) {
161 $test_value = $this->$method();
164 // Generate a random string. Generating two words of 8 characters each
165 // with simple machine name -style strings.
166 $test_value = $this->randomMachineName() . ' ' . $this->randomMachineName();
169 $values[$test_key] = $test_value;
170 $all_values[$tag_name] = $test_value;
172 $this->drupalPostForm(NULL, $values, 'Save');
173 $this->assertText($save_message);
175 // Load the test page.
176 $this->drupalGet($path2);
177 $this->assertResponse(200);
179 // Look for the values.
180 foreach ($this->tags as $tag_name) {
181 // Look for a custom method named "{$tag_name}TestOutputXpath", if
182 // found use that method to get the xpath definition for this meta tag,
183 // otherwise it defaults to just looking for a meta tag matching:
184 // <$testTag $testNameAttribute=$tag_name $testValueAttribute=$value />
185 $method = $this->getMethodFromTagCallback($tag_name, 'TestOutputXpath');
186 if (method_exists($this, $method)) {
187 $xpath_string = $this->$method();
190 // Look for a custom method named "{$tag_name}TestTag", if
191 // found use that method to get the xpath definition for this meta
192 // tag, otherwise it defaults to $this->testTag.
193 $method = $this->getMethodFromTagCallback($tag_name, 'TestTag');
194 if (method_exists($this, $method)) {
195 $xpath_tag = $this->$method();
198 $xpath_tag = $this->testTag;
201 // Look for a custom method named "{$tag_name}TestNameAttribute",
202 // if found use that method to get the xpath definition for this meta
203 // tag, otherwise it defaults to $this->testNameAttribute.
204 $method = $this->getMethodFromTagCallback($tag_name, 'TestNameAttribute');
205 if (method_exists($this, $method)) {
206 $xpath_name_attribute = $this->$method();
209 $xpath_name_attribute = $this->testNameAttribute;
212 // Look for a custom method named "{$tag_name}TestTagName", if
213 // found use that method to get the xpath definition for this meta
214 // tag, otherwise it defaults to $tag_name.
215 $method = $this->getMethodFromTagCallback($tag_name, 'TestTagName');
216 if (method_exists($this, $method)) {
217 $xpath_name_tag = $this->$method();
220 $xpath_name_tag = $this->getTestTagName($tag_name);
223 // Compile the xpath.
224 $xpath_string = "//{$xpath_tag}[@{$xpath_name_attribute}='{$xpath_name_tag}']";
227 // Look for a custom method named "{$tag_name}TestValueAttribute", if
228 // found use that method to get the xpath definition for this meta tag,
229 // otherwise it defaults to $this->testValueAttribute.
230 $method = $this->getMethodFromTagCallback($tag_name, 'TestValueAttribute');
231 if (method_exists($this, $method)) {
232 $xpath_value_attribute = $this->$method();
235 $xpath_value_attribute = $this->testValueAttribute;
238 // Extract the meta tag from the HTML.
239 $xpath = $this->xpath($xpath_string);
240 $this->assertEqual(count($xpath), 1, new FormattableMarkup('One @name tag found.', ['@name' => $tag_name]));
241 if (count($xpath) !== 1) {
242 $this->verbose($xpath, $tag_name . ': ' . $xpath_string);
245 // Run various tests on the output variables.
246 // Most meta tags have an attribute, but some don't.
247 if (!empty($xpath_value_attribute)) {
248 $this->assertTrue($xpath_value_attribute);
249 $this->assertTrue(isset($xpath[0][$xpath_value_attribute]));
250 // Help with debugging.
251 if (!isset($xpath[0][$xpath_value_attribute])) {
252 $this->verbose($xpath, $tag_name . ': ' . $xpath_string);
255 if ((string) $xpath[0][$xpath_value_attribute] != $all_values[$tag_name]) {
256 $this->verbose($xpath, $tag_name . ': ' . $xpath_string);
258 $this->assertTrue($xpath[0][$xpath_value_attribute]);
259 $this->assertEqual($xpath[0][$xpath_value_attribute], $all_values[$tag_name], "The meta tag was found with the expected value.");
263 $this->verbose($xpath, $tag_name . ': ' . $xpath_string);
264 $this->assertTrue((string) $xpath[0]);
265 $this->assertEqual((string) $xpath[0], $all_values[$tag_name], "The meta tag was found with the expected value.");
270 $this->drupalLogout();
274 * Convert a tag's internal name to the string which is actually used in HTML.
276 * The meta tag internal name will be machine names, i.e. only contain a-z,
277 * A-Z, 0-9 and the underline character. Meta tag names will actually contain
278 * any possible character.
280 * @param string $tag_name
281 * The tag name to be converted.
284 * The converted tag name.
286 private function getTestTagName($tag_name) {
291 * Generate a random value for testing meta tag fields.
293 * As a reasonable default, this will generating two words of 8 characters
294 * each with simple machine name -style strings.
299 private function getTestTagValue() {
300 return $this->randomMachineName() . ' ' . $this->randomMachineName();
304 * Generate a URL for an image.
307 * An absolute URL to a non-existant image.
309 private function randomImageUrl() {
310 return 'http://www.example.com/images/' . $this->randomMachineName() . '.png';
314 * Convert a tag name with a callback to a lowerCamelCase method name.
316 * @param string $tag_name
318 * @param string $callback
319 * The callback that is to be used.
322 * The tag name and callback concatenated together and converted to
325 private function getMethodFromTagCallback($tag_name, $callback) {
326 return lcfirst(Container::camelize($tag_name . '_' . $callback));