bibcite_footnotes-8.x-1.0-beta3/tests/src/Functional/ReferenceFootnotesFilterTest.php

tests/src/Functional/ReferenceFootnotesFilterTest.php
<?php

namespace Drupal\Tests\bibcite_footnotes\Functional;

use Drupal\Tests\BrowserTestBase;
use Drupal\filter\Entity\FilterFormat;
use Drupal\Tests\bibcite_entity\Traits\EntityCreationTrait;

/**
 * Functional tests for the ReferenceFootnotesFilter.
 *
 * @group bibcite_footnotes
 */
class ReferenceFootnotesFilterTest extends BrowserTestBase
{

  use EntityCreationTrait;

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'node',
    'filter',
    'bibcite',
    'bibcite_entity',
    'bibcite_footnotes',
    'text',
  ];

  protected $allowedHtml = '<p> <bibcite-footnote> <div class> <h2> <h3><span class> <a id href class> <sup>';

  /**
   * {@inheritdoc}
   */
  protected $defaultTheme = 'stark';

  /**
   * A user with administrative privileges.
   *
   * @var \Drupal\user\UserInterface
   */
  protected $adminUser;

  /**
   * Test reference entities.
   *
   * @var \Drupal\bibcite_entity\Entity\ReferenceInterface[]
   */
  protected $references = [];

  /**
   * Test filter format.
   *
   * @var \Drupal\filter\FilterFormatInterface
   */
  protected $filterFormat;

  /**
   * {@inheritdoc}
   */
  protected function setUp(): void
  {
    parent::setUp();

    // Create a content type.
    $this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']);

    // Create test reference entities.
    $this->references[] = $this->createReference([
      'title' => 'Anne of Green Gables',
      'bibcite_year' => 1908,
      'type' => 'book',
    ]);

    $this->references[] = $this->createReference([
      'title' => 'The Fort Bragg Cartel',
      'bibcite_year' => 2025,
      'type' => 'book',
    ]);

    // Create a text format with our filter.
    $this->filterFormat = FilterFormat::create([
      'format' => 'test_format',
      'name' => 'Test format',
      'filters' => [
        'filter_reference_footnotes' => [
          'status' => 1,
          'weight' => 0,
          'settings' => [
            'enable_bidirectional_links' => TRUE,
            'backlink_symbol' => '↑',
            'backlink_position' => 'after',
          ],
        ],
        'filter_html' => [
          'status' => 1,
          'weight' => 1,
          'settings' => [
            'allowed_html' => $this->allowedHtml,
          ],
        ],
      ],
    ]);
    $this->filterFormat->save();

    // Create an admin user.
    $this->adminUser = $this->drupalCreateUser([
      'administer filters',
      'create article content',
      'edit any article content',
      'use text format test_format',
    ]);

    $this->drupalLogin($this->adminUser);
  }

  /**
   * Gets the expected citation label for a reference.
   */
  private function getCitationLabel($reference)
  {
    // The citation label is typically 'bibcite_' followed by the reference ID.
    return 'bibcite_' . $reference->id();
  }

  /**
   * Tests filter configuration.
   */
  public function testFilterConfiguration()
  {
    // Go to the filter administration page.
    $this->drupalGet('admin/config/content/formats/manage/test_format');
    $this->assertSession()->statusCodeEquals(200);

    // Check that our filter is enabled.
    $this->assertSession()->checkboxChecked('filters[filter_reference_footnotes][status]');

    // Verify the filter description.
    $this->assertSession()->pageTextContains('Convert bibcite-footnote tags to rendered citations.');

    // Check that bidirectional links setting is present and enabled by default.
    $this->assertSession()->fieldExists('filters[filter_reference_footnotes][settings][enable_bidirectional_links]');
    $this->assertSession()->checkboxChecked('filters[filter_reference_footnotes][settings][enable_bidirectional_links]');

    // Check that backlink symbol field is present with default value.
    $this->assertSession()->fieldValueEquals('filters[filter_reference_footnotes][settings][backlink_symbol]', '↑');

    // Check that backlink position field is present with default value.
    $this->assertSession()->fieldValueEquals('filters[filter_reference_footnotes][settings][backlink_position]', 'after');
  }

  /**
   * Tests bidirectional linking functionality.
   */
  public function testBidirectionalLinking()
  {
    $reference = $this->references[0];
    $citation_label = $this->getCitationLabel($reference);

    // Create a test node with multiple footnotes to the same reference.
    $body = [
      'value' => '<p>First citation <bibcite-footnote data-entity-id="' . $reference->id() . '" data-page-range="12"></bibcite-footnote>.</p><p>Second citation <bibcite-footnote data-entity-id="' . $reference->id() . '" data-page-range="34"></bibcite-footnote>.</p>',
      'format' => 'test_format',
    ];

    $node = $this->drupalCreateNode([
      'type' => 'article',
      'title' => 'Test Bidirectional Links',
      'body' => $body,
    ]);

    $this->drupalGet('node/' . $node->id());
    $this->assertSession()->statusCodeEquals(200);

    // Check that citations have unique IDs and link to bibliography.
    $this->assertSession()->responseMatches('/<a[^>]*id="' . preg_quote($citation_label) . '_cite_1"[^>]*href="#' . preg_quote($citation_label) . '"[^>]*>.*?<\/a>/');
    $this->assertSession()->responseMatches('/<a[^>]*id="' . preg_quote($citation_label) . '_cite_2"[^>]*href="#' . preg_quote($citation_label) . '"[^>]*>.*?<\/a>/');

    // Check that bibliography has backlinks to citations.
    $this->assertSession()->responseContains('bibcite-backlinks');
    $this->assertSession()->responseContains('bibcite-backlink');
    $this->assertSession()->responseContains('↑');

    // Verify backlinks point to the correct citation IDs.
    $this->assertSession()->responseMatches('/<a[^>]*href="#' . preg_quote($citation_label) . '_cite_1"[^>]*>↑<\/a>/');
    $this->assertSession()->responseMatches('/<a[^>]*href="#' . preg_quote($citation_label) . '_cite_2"[^>]*>↑<\/a>/');
  }

  /**
   * Tests bidirectional linking with multiple references.
   */
  public function testBidirectionalLinkingMultipleReferences()
  {
    $reference1 = $this->references[0];
    $reference2 = $this->references[1];
    $citation_label1 = $this->getCitationLabel($reference1);
    $citation_label2 = $this->getCitationLabel($reference2);

    $body = [
      'value' => '<p>First reference <bibcite-footnote data-entity-id="' . $reference1->id() . '"></bibcite-footnote> and second reference <bibcite-footnote data-entity-id="' . $reference2->id() . '"></bibcite-footnote>.</p><p>Another citation to first <bibcite-footnote data-entity-id="' . $reference1->id() . '"></bibcite-footnote>.</p>',
      'format' => 'test_format',
    ];

    $node = $this->drupalCreateNode([
      'type' => 'article',
      'title' => 'Test Multiple References Bidirectional',
      'body' => $body,
    ]);

    $this->drupalGet('node/' . $node->id());
    $this->assertSession()->statusCodeEquals(200);

    // Check that each reference has correct backlinks.
    // First reference should have 2 backlinks.
    $this->assertSession()->responseMatches('/<a[^>]*href="#' . preg_quote($citation_label1) . '_cite_1"[^>]*>↑<\/a>/');
    $this->assertSession()->responseMatches('/<a[^>]*href="#' . preg_quote($citation_label1) . '_cite_2"[^>]*>↑<\/a>/');

    // Second reference should have 1 backlink.
    $this->assertSession()->responseMatches('/<a[^>]*href="#' . preg_quote($citation_label2) . '_cite_1"[^>]*>↑<\/a>/');
  }

  /**
   * Tests bidirectional linking disabled.
   */
  public function testBidirectionalLinkingDisabled()
  {
    // Create a text format with bidirectional links disabled.
    $disabledFormat = FilterFormat::create([
      'format' => 'disabled_format',
      'name' => 'Disabled bidirectional format',
      'filters' => [
        'filter_reference_footnotes' => [
          'status' => 1,
          'weight' => 0,
          'settings' => [
            'enable_bidirectional_links' => FALSE,
            'backlink_symbol' => '↑',
            'backlink_position' => 'after',
          ],
        ],
        'filter_html' => [
          'status' => 1,
          'weight' => 1,
          'settings' => [
            'allowed_html' => $this->allowedHtml,
          ],
        ],
      ],
    ]);
    $disabledFormat->save();

    // Grant permission to use the new format.
    $this->adminUser->addRole('administrator');
    $this->adminUser->save();

    $reference = $this->references[0];
    $citation_label = $this->getCitationLabel($reference);

    $body = [
      'value' => '<p>Citation <bibcite-footnote data-entity-id="' . $reference->id() . '" data-page-range="12"></bibcite-footnote>.</p>',
      'format' => 'disabled_format',
    ];

    $node = $this->drupalCreateNode([
      'type' => 'article',
      'title' => 'Test Disabled Bidirectional',
      'body' => $body,
    ]);

    $this->drupalGet('node/' . $node->id());
    $this->assertSession()->statusCodeEquals(200);

    // Citations should still link to bibliography.
    $this->assertSession()->responseMatches('/<a[^>]*href="#' . preg_quote($citation_label) . '"[^>]*>.*?<\/a>/');

    // But should not have unique IDs for bidirectional linking.
    $this->assertSession()->responseNotMatches('/<a[^>]*id="' . preg_quote($citation_label) . '_cite_1"[^>]*>/');

    // Bibliography should not have backlinks.
    $this->assertSession()->responseNotContains('bibcite-backlinks');
    $this->assertSession()->responseNotContains('bibcite-backlink');
  }

  /**
   * Tests custom backlink symbol.
   */
  public function testCustomBacklinkSymbol()
  {
    // Create a text format with custom backlink symbol.
    $customFormat = FilterFormat::create([
      'format' => 'custom_format',
      'name' => 'Custom symbol format',
      'filters' => [
        'filter_reference_footnotes' => [
          'status' => 1,
          'weight' => 0,
          'settings' => [
            'enable_bidirectional_links' => TRUE,
            'backlink_symbol' => '↩',
            'backlink_position' => 'after',
          ],
        ],
        'filter_html' => [
          'status' => 1,
          'weight' => 1,
          'settings' => [
            'allowed_html' => $this->allowedHtml,
          ],
        ],
      ],
    ]);
    $customFormat->save();

    // Grant permission to use the new format.
    $this->adminUser->addRole('administrator');
    $this->adminUser->save();

    $reference = $this->references[0];

    $body = [
      'value' => '<p>Citation <bibcite-footnote data-entity-id="' . $reference->id() . '"></bibcite-footnote>.</p>',
      'format' => 'custom_format',
    ];

    $node = $this->drupalCreateNode([
      'type' => 'article',
      'title' => 'Test Custom Backlink Symbol',
      'body' => $body,
    ]);

    $this->drupalGet('node/' . $node->id());
    $this->assertSession()->statusCodeEquals(200);

    // Should use custom backlink symbol.
    $this->assertSession()->responseContains('↩');
    $this->assertSession()->responseNotContains('↑');
  }

  /**
   * Tests backlink position setting.
   */
  public function testBacklinkPosition()
  {
    // Create a text format with backlinks before entries.
    $beforeFormat = FilterFormat::create([
      'format' => 'before_format',
      'name' => 'Backlinks before format',
      'filters' => [
        'filter_reference_footnotes' => [
          'status' => 1,
          'weight' => 0,
          'settings' => [
            'enable_bidirectional_links' => TRUE,
            'backlink_symbol' => '↑',
            'backlink_position' => 'before',
          ],
        ],
        'filter_html' => [
          'status' => 1,
          'weight' => 1,
          'settings' => [
            'allowed_html' => $this->allowedHtml,
          ],
        ],
      ],
    ]);
    $beforeFormat->save();

    // Grant permission to use the new format.
    $this->adminUser->addRole('administrator');
    $this->adminUser->save();

    $reference = $this->references[0];

    $body = [
      'value' => '<p>Citation <bibcite-footnote data-entity-id="' . $reference->id() . '"></bibcite-footnote>.</p>',
      'format' => 'before_format',
    ];

    $node = $this->drupalCreateNode([
      'type' => 'article',
      'title' => 'Test Backlink Position',
      'body' => $body,
    ]);

    $this->drupalGet('node/' . $node->id());
    $this->assertSession()->statusCodeEquals(200);

    // Backlinks should be present (we can't easily test position in functional test,
    // but we can verify the feature doesn't break when position is set to 'before').
    $this->assertSession()->responseContains('bibcite-backlinks');
    $this->assertSession()->responseContains('↑');
  }

  /**
   * Tests that bidirectional links work with complex content.
   */
  public function testBidirectionalLinksComplexContent()
  {
    $reference1 = $this->references[0];
    $reference2 = $this->references[1];
    $citation_label1 = $this->getCitationLabel($reference1);
    $citation_label2 = $this->getCitationLabel($reference2);

    // Create complex content with multiple paragraphs and citations.
    $body = [
      'value' => '
        <h2>Introduction</h2>
        <p>First mention of reference one<bibcite-footnote data-entity-id="' . $reference1->id() . '" data-page-range="10"></bibcite-footnote>.</p>
        <p>Some intermediate text without citations.</p>
        <h2>Methods</h2>
        <p>Reference two mentioned here<bibcite-footnote data-entity-id="' . $reference2->id() . '" data-page-range="25"></bibcite-footnote>.</p>
        <p>Another citation to reference one<bibcite-footnote data-entity-id="' . $reference1->id() . '" data-page-range="15"></bibcite-footnote>.</p>
        <p>And another to reference two<bibcite-footnote data-entity-id="' . $reference2->id() . '" data-page-range="30"></bibcite-footnote>.</p>
        <h2>Conclusion</h2>
        <p>Final citation to reference one<bibcite-footnote data-entity-id="' . $reference1->id() . '" data-page-range="20"></bibcite-footnote>.</p>
      ',
      'format' => 'test_format',
    ];

    $node = $this->drupalCreateNode([
      'type' => 'article',
      'title' => 'Test Complex Content',
      'body' => $body,
    ]);

    $this->drupalGet('node/' . $node->id());
    $this->assertSession()->statusCodeEquals(200);

    // Should have 5 total citations.
    $citation_count = substr_count($this->getSession()->getPage()->getHtml(), 'bibcite-citation');
    $this->assertEquals(5, $citation_count, "Expected 5 citations but found $citation_count");

    // Reference 1 should have 3 backlinks.
    $this->assertSession()->responseMatches('/<a[^>]*href="#' . preg_quote($citation_label1) . '_cite_1"[^>]*>↑<\/a>/');
    $this->assertSession()->responseMatches('/<a[^>]*href="#' . preg_quote($citation_label1) . '_cite_3"[^>]*>↑<\/a>/');
    $this->assertSession()->responseMatches('/<a[^>]*href="#' . preg_quote($citation_label1) . '_cite_3"[^>]*>↑<\/a>/');

    // Reference 2 should have 2 backlinks.
    $this->assertSession()->responseMatches('/<a[^>]*href="#' . preg_quote($citation_label2) . '_cite_1"[^>]*>↑<\/a>/');
    $this->assertSession()->responseMatches('/<a[^>]*href="#' . preg_quote($citation_label2) . '_cite_2"[^>]*>↑<\/a>/');
  }

  /**
   * Tests filter settings form validation.
   */
  public function testFilterSettingsValidation()
  {
    $this->drupalGet('admin/config/content/formats/manage/test_format');

    // Test that valid values are accepted.
    $edit = [
      'filters[filter_reference_footnotes][settings][backlink_symbol]' => '↖',
      'filters[filter_reference_footnotes][settings][backlink_position]' => 'before',
    ];
    $this->submitForm($edit, 'Save configuration');

    // Should save successfully.
    $this->assertSession()->pageTextContains('The text format Test format has been updated.');
  }

  /**
   * Tests basic footnote rendering with real entities.
   */
  public function testBasicFootnoteRendering()
  {
    $reference = $this->references[0];

    // Create a test node with footnote markup.
    $body = [
      'value' => '<p>Test content with <bibcite-footnote data-entity-id="' . $reference->id() . '" data-page-range="12"></bibcite-footnote> a citation.</p>',
      'format' => 'test_format',
    ];

    $node = $this->drupalCreateNode([
      'type' => 'article',
      'title' => 'Test Footnote Article',
      'body' => $body,
    ]);

    // View the node.
    $this->drupalGet('node/' . $node->id());
    $this->assertSession()->statusCodeEquals(200);

    // Check that the footnote markup is processed.
    $this->assertSession()->responseNotContains('<bibcite-footnote');
    $this->assertSession()->responseContains('bibcite-citation');

    // Check that bibliography section is present.
    $this->assertSession()->responseContains('bibcite-footnotes-section');
    $this->assertSession()->responseContains('Footnotes');
  }

  /**
   * Tests multiple footnotes with same reference.
   */
  public function testMultipleFootnotesSameReference()
  {
    $reference = $this->references[0];

    $body = [
      'value' => '<p>First citation <bibcite-footnote data-entity-id="' . $reference->id() . '" data-page-range="12"></bibcite-footnote> and second citation <bibcite-footnote data-entity-id="' . $reference->id() . '" data-page-range="34"></bibcite-footnote>.</p>',
      'format' => 'test_format',
    ];

    $node = $this->drupalCreateNode([
      'type' => 'article',
      'title' => 'Test Multiple Footnotes',
      'body' => $body,
    ]);

    $this->drupalGet('node/' . $node->id());
    $this->assertSession()->statusCodeEquals(200);

    // Should have two citations rendered.
    $this->assertEquals(2, substr_count($this->getSession()->getPage()->getHtml(), 'bibcite-citation'));
  }

  /**
   * Tests footnotes with different references.
   */
  public function testFootnotesDifferentReferences()
  {
    $reference1 = $this->references[0];
    $reference2 = $this->references[1];

    $body = [
      'value' => '<p>First <bibcite-footnote data-entity-id="' . $reference1->id() . '" data-page-range="12"></bibcite-footnote> and second <bibcite-footnote data-entity-id="' . $reference2->id() . '" data-page-range="22"></bibcite-footnote> citation.</p>',
      'format' => 'test_format',
    ];

    $node = $this->drupalCreateNode([
      'type' => 'article',
      'title' => 'Test Different References',
      'body' => $body,
    ]);

    $this->drupalGet('node/' . $node->id());
    $this->assertSession()->statusCodeEquals(200);

    // Should have two citations and bibliography entries.
    $this->assertEquals(2, substr_count($this->getSession()->getPage()->getHtml(), 'bibcite-citation'));
  }

  /**
   * Tests footnote without entity-id.
   */
  public function testFootnoteWithoutEntityId()
  {
    $body = [
      'value' => '<p>Test <bibcite-footnote data-page-range="12"></bibcite-footnote> invalid citation.</p>',
      'format' => 'test_format',
    ];

    $node = $this->drupalCreateNode([
      'type' => 'article',
      'title' => 'Test Invalid Footnote',
      'body' => $body,
    ]);

    $this->drupalGet('node/' . $node->id());
    $this->assertSession()->statusCodeEquals(200);

    // Invalid footnote should be ignored/removed.
    $this->assertSession()->responseNotContains('bibcite-footnote');
    $this->assertSession()->responseNotContains('bibcite-citation');
  }

  /**
   * Tests text without footnotes.
   */
  public function testTextWithoutFootnotes()
  {
    $body = [
      'value' => '<p>This is a simple paragraph without any footnotes.</p>',
      'format' => 'test_format',
    ];

    $node = $this->drupalCreateNode([
      'type' => 'article',
      'title' => 'Test No Footnotes',
      'body' => $body,
    ]);

    $this->drupalGet('node/' . $node->id());
    $this->assertSession()->statusCodeEquals(200);

    // Should not contain any citation markup.
    $this->assertSession()->responseNotContains('bibcite-citation');
    $this->assertSession()->responseNotContains('bibcite-footnotes-section');
  }
}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc