date_ap_style-8.x-1.x-dev/tests/src/Kernel/FieldFormatterStrictTypesTest.php

tests/src/Kernel/FieldFormatterStrictTypesTest.php
<?php

declare(strict_types=1);

namespace Drupal\Tests\date_ap_style\Kernel;

use Drupal\views\Views;
use Drupal\Component\Serialization\Yaml;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\KernelTests\KernelTestBase;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;

/**
 * Tests field formatter compatibility with strict_types declaration.
 *
 * This test ensures that the AP Style field formatters properly handle:
 * - Timestamp values that come as strings from the database
 * - Boolean options that come as integers (0/1) from form submissions.
 *
 * @group date_ap_style
 */
class FieldFormatterStrictTypesTest extends KernelTestBase {

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'system',
    'user',
    'node',
    'field',
    'text',
    'datetime',
    'datetime_range',
    'date_ap_style',
    'views',
  ];

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

    $this->installEntitySchema('user');
    $this->installEntitySchema('node');
    $this->installSchema('node', ['node_access']);
    $this->installConfig(['system', 'node', 'field', 'date_ap_style']);

    // Create a content type.
    NodeType::create([
      'type' => 'article',
      'name' => 'Article',
    ])->save();
  }

  /**
   * Tests timestamp field formatter with string values.
   *
   * This reproduces the issue where timestamp values come through as strings
   * from the database, but the formatter expects integers with strict_types.
   */
  public function testTimestampFieldFormatterWithStringValue(): void {
    // Create a node with a created timestamp.
    $node = Node::create([
      'type' => 'article',
      'title' => 'Test Article',
      'created' => time(),
    ]);
    $node->save();

    // Configure the view display to use AP Style formatter.
    $display = EntityViewDisplay::create([
      'targetEntityType' => 'node',
      'bundle' => 'article',
      'mode' => 'default',
      'status' => TRUE,
    ]);

    // Configure the created field with AP Style formatter.
    // Use integer values (0/1) for boolean settings to simulate form
    // submission.
    $display->setComponent('created', [
      'type' => 'timestamp_ap_style',
      'settings' => [
        // Integer, not boolean.
        'always_display_year' => 1,
        'use_today' => 0,
        'cap_today' => 0,
        'display_day' => 1,
        'display_time' => 0,
        'hide_date' => 0,
        'time_before_date' => 0,
        'use_all_day' => 0,
        'month_only' => 0,
        'display_noon_and_midnight' => 0,
        'capitalize_noon_and_midnight' => 0,
        'timezone' => '',
      ],
    ]);
    $display->save();

    // Build the node view. This should NOT throw a TypeError.
    $view_builder = \Drupal::entityTypeManager()->getViewBuilder('node');
    $build = $view_builder->view($node, 'default');

    // Render the output.
    $renderer = \Drupal::service('renderer');
    $output = (string) $renderer->renderRoot($build);

    // Assert that we got output without errors.
    $this->assertNotEmpty($output);
    $this->assertStringContainsString('Test Article', $output);
  }

  /**
   * Tests datetime field formatter with integer boolean options.
   */
  public function testDatetimeFieldFormatterWithIntegerBooleans(): void {
    // Create a datetime field.
    FieldStorageConfig::create([
      'field_name' => 'field_test_date',
      'entity_type' => 'node',
      'type' => 'datetime',
      'settings' => [
        'datetime_type' => 'datetime',
      ],
    ])->save();

    FieldConfig::create([
      'field_name' => 'field_test_date',
      'entity_type' => 'node',
      'bundle' => 'article',
      'label' => 'Test Date',
    ])->save();

    // Create a node with a date value.
    $node = Node::create([
      'type' => 'article',
      'title' => 'Test Article with Date',
      'field_test_date' => '2024-01-15T10:30:00',
    ]);
    $node->save();

    // Configure the view display.
    $display = EntityViewDisplay::create([
      'targetEntityType' => 'node',
      'bundle' => 'article',
      'mode' => 'default',
      'status' => TRUE,
    ]);

    // Configure with integer boolean values (simulating form submission).
    $display->setComponent('field_test_date', [
      'type' => 'timestamp_ap_style',
      'settings' => [
        'always_display_year' => 1,
        'use_today' => 1,
        'cap_today' => 1,
        'display_day' => 0,
        'display_time' => 1,
        'hide_date' => 0,
        'time_before_date' => 0,
        'use_all_day' => 0,
        'month_only' => 0,
        'display_noon_and_midnight' => 1,
        'capitalize_noon_and_midnight' => 1,
        'timezone' => '',
      ],
    ]);
    $display->save();

    // Build and render the view.
    $view_builder = \Drupal::entityTypeManager()->getViewBuilder('node');
    $build = $view_builder->view($node, 'default');

    $renderer = \Drupal::service('renderer');
    $output = (string) $renderer->renderRoot($build);

    // Assert successful rendering without TypeError.
    $this->assertNotEmpty($output);
    $this->assertStringContainsString('Test Article with Date', $output);
  }

  /**
   * Tests daterange field formatter with string timestamps.
   */
  public function testDateRangeFieldFormatterWithStringValues(): void {
    // Create a daterange field.
    FieldStorageConfig::create([
      'field_name' => 'field_date_range',
      'entity_type' => 'node',
      'type' => 'daterange',
      'settings' => [
        'datetime_type' => 'datetime',
      ],
    ])->save();

    FieldConfig::create([
      'field_name' => 'field_date_range',
      'entity_type' => 'node',
      'bundle' => 'article',
      'label' => 'Date Range',
    ])->save();

    // Create a node with a date range.
    $node = Node::create([
      'type' => 'article',
      'title' => 'Test Article with Range',
      'field_date_range' => [
        'value' => '2024-01-15T10:00:00',
        'end_value' => '2024-01-15T16:00:00',
      ],
    ]);
    $node->save();

    // Configure the view display.
    $display = EntityViewDisplay::create([
      'targetEntityType' => 'node',
      'bundle' => 'article',
      'mode' => 'default',
      'status' => TRUE,
    ]);

    // Configure with integer boolean values.
    $display->setComponent('field_date_range', [
      'type' => 'daterange_ap_style',
      'settings' => [
        'always_display_year' => 1,
        'use_today' => 0,
        'cap_today' => 0,
        'display_day' => 0,
        'display_time' => 1,
        'hide_date' => 0,
        'time_before_date' => 0,
        'use_all_day' => 0,
        'month_only' => 0,
        'display_noon_and_midnight' => 0,
        'capitalize_noon_and_midnight' => 0,
        'separator' => 'to',
        'timezone' => '',
      ],
    ]);
    $display->save();

    // Build and render the view.
    $view_builder = \Drupal::entityTypeManager()->getViewBuilder('node');
    $build = $view_builder->view($node, 'default');

    $renderer = \Drupal::service('renderer');
    $output = (string) $renderer->renderRoot($build);

    // Assert successful rendering without TypeError.
    $this->assertNotEmpty($output);
    $this->assertStringContainsString('Test Article with Range', $output);
  }

  /**
   * Tests that Views with integer boolean settings work correctly.
   *
   * This test loads a view configuration that has integer values (0/1)
   * for boolean settings, which is what causes the TypeError with strict_types.
   */
  public function testViewsWithIntegerBooleanSettings(): void {
    // Import the test view with integer boolean values.
    $config_path = __DIR__ . '/../../fixtures/views.view.test_strict_types.yml';
    $view_config = Yaml::decode(file_get_contents($config_path));

    $config_storage = \Drupal::service('config.storage');
    $config_storage->write('views.view.test_strict_types', $view_config);

    // Clear cache to load the new view.
    \Drupal::service('views.views_data')->clear();

    // Create some test nodes.
    for ($i = 0; $i < 3; $i++) {
      Node::create([
        'type' => 'article',
        'title' => 'Test Node ' . $i,
        'created' => time() - ($i * 86400),
      ])->save();
    }

    // Load and execute the view.
    $view = Views::getView('test_strict_types');
    $this->assertNotNull($view, 'View should be loaded');

    // This should NOT throw a TypeError even with integer boolean settings.
    $view->setDisplay('page_1');
    $view->preExecute();
    $view->execute();

    // Render the view.
    $renderer = \Drupal::service('renderer');
    $build = $view->buildRenderable('page_1');
    $output = (string) $renderer->renderRoot($build);

    $this->assertNotEmpty($output);
    $this->assertStringContainsString('Test Node', $output);
  }

}

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

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