invoicemgmt-1.0.0/tests/src/Kernel/InvoiceMgmtHooksTest.php

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

declare(strict_types=1);

namespace Drupal\Tests\invoicemgmt\Kernel;

use Drupal\Core\Form\FormState;
use Drupal\KernelTests\KernelTestBase;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
use Drupal\paragraphs\Entity\Paragraph;
use Drupal\paragraphs\Entity\ParagraphsType;

/**
 * Kernel tests for invoicemgmt module hooks.
 *
 * @group invoicemgmt
 */
class InvoiceMgmtHooksTest extends KernelTestBase {

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'system',
    'user',
    'field',
    'text',
    'node',
    'paragraphs',
    'entity_reference_revisions',
    'file',
    'invoicemgmt',
  ];

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

    $this->installEntitySchema('user');
    $this->installEntitySchema('node');
    $this->installEntitySchema('paragraph');
    $this->installEntitySchema('file');
    $this->installSchema('system', ['sequences']);
    $this->installSchema('node', ['node_access']);
    $this->installSchema('file', ['file_usage']);
    $this->installConfig(['system', 'field', 'node', 'paragraphs']);

    // Create content types.
    $this->createInvoiceContentType();
    $this->createClientContentType();
    $this->createInvoiceItemParagraphType();
  }

  /**
   * Tests hook_entity_presave for invoice number generation.
   *
   * @covers invoicemgmt_entity_presave
   */
  public function testEntityPresaveInvoiceNumberGeneration(): void {
    $invoice = Node::create([
      'type' => 'invoice',
      'title' => 'Test Invoice',
    ]);

    // Invoice number should be empty before save.
    $this->assertTrue($invoice->get('field_invoice_number')->isEmpty());

    // Save the invoice to trigger hook_entity_presave.
    $invoice->save();

    // Invoice number should be generated after save.
    $this->assertFalse($invoice->get('field_invoice_number')->isEmpty());
    $invoice_number = $invoice->get('field_invoice_number')->value;
    $this->assertMatchesRegularExpression('/^INV-\d{6}-\d{3}$/', $invoice_number);
  }

  /**
   * Tests hook_entity_presave for grand total calculation.
   *
   * @covers invoicemgmt_entity_presave
   */
  public function testEntityPresaveGrandTotalCalculation(): void {
    // Create invoice items (paragraphs).
    $item1 = Paragraph::create([
      'type' => 'invoice_item',
      'field_amount' => 100.50,
    ]);
    $item1->save();

    $item2 = Paragraph::create([
      'type' => 'invoice_item',
      'field_amount' => 200.25,
    ]);
    $item2->save();

    // Create invoice with items.
    $invoice = Node::create([
      'type' => 'invoice',
      'title' => 'Test Invoice with Items',
      'field_items' => [
        ['target_id' => $item1->id(), 'target_revision_id' => $item1->getRevisionId()],
        ['target_id' => $item2->id(), 'target_revision_id' => $item2->getRevisionId()],
      ],
    ]);

    // Grand total should be empty before save.
    $this->assertTrue($invoice->get('field_grand_total')->isEmpty());

    // Save the invoice to trigger hook_entity_presave.
    $invoice->save();

    // Grand total should be calculated after save.
    $this->assertFalse($invoice->get('field_grand_total')->isEmpty());
    $grand_total = (float) $invoice->get('field_grand_total')->value;
    $this->assertEquals(300.75, $grand_total);
  }

  /**
   * Tests hook_entity_presave with empty invoice items.
   *
   * @covers invoicemgmt_entity_presave
   */
  public function testEntityPresaveWithEmptyItems(): void {
    $invoice = Node::create([
      'type' => 'invoice',
      'title' => 'Test Invoice without Items',
    ]);

    $invoice->save();

    // Grand total should be 0 when no items exist.
    $grand_total = (float) $invoice->get('field_grand_total')->value;
    $this->assertEquals(0.0, $grand_total);
  }

  /**
   * Tests hook_entity_presave with items having no amount.
   *
   * @covers invoicemgmt_entity_presave
   */
  public function testEntityPresaveWithItemsWithoutAmount(): void {
    // Create invoice item without amount.
    $item = Paragraph::create([
      'type' => 'invoice_item',
    ]);
    $item->save();

    $invoice = Node::create([
      'type' => 'invoice',
      'title' => 'Test Invoice with Item without Amount',
      'field_items' => [
        ['target_id' => $item->id(), 'target_revision_id' => $item->getRevisionId()],
      ],
    ]);

    $invoice->save();

    // Grand total should be 0 when items have no amount.
    $grand_total = (float) $invoice->get('field_grand_total')->value;
    $this->assertEquals(0.0, $grand_total);
  }

  /**
   * Tests hook_entity_presave only affects invoice nodes.
   *
   * @covers invoicemgmt_entity_presave
   */
  public function testEntityPresaveOnlyAffectsInvoices(): void {
    $client = Node::create([
      'type' => 'client',
      'title' => 'Test Client',
    ]);

    // Should not throw any errors for non-invoice nodes.
    $this->expectNotToPerformAssertions();
    $client->save();
  }

  /**
   * Tests hook_form_alter for invoice forms.
   *
   * @covers invoicemgmt_form_alter
   */
  public function testFormAlterInvoiceForm(): void {
    $form = [];
    $form_state = new FormState();
    
    // Add fields that should be altered.
    $form['field_invoice_number'] = [
      'widget' => [
        0 => [
          'value' => ['#attributes' => []],
        ],
      ],
    ];
    $form['field_grand_total'] = [
      'widget' => [
        0 => [
          'value' => ['#attributes' => []],
        ],
      ],
    ];
    $form['field_client'] = [
      'widget' => [
        0 => [],
      ],
    ];

    // Call the form alter hook.
    invoicemgmt_form_alter($form, $form_state, 'node_invoice_form');

    // Check that invoice number field is disabled.
    $this->assertTrue($form['field_invoice_number']['#disabled']);
    $this->assertEquals('readonly', $form['field_invoice_number']['widget'][0]['value']['#attributes']['readonly']);
    $this->assertStringContainsString('automatically generated', (string) $form['field_invoice_number']['#description']);

    // Check that grand total field is disabled.
    $this->assertTrue($form['field_grand_total']['#disabled']);
    $this->assertEquals('readonly', $form['field_grand_total']['widget'][0]['value']['#attributes']['readonly']);
    $this->assertStringContainsString('automatically calculated', (string) $form['field_grand_total']['#description']);

    // Check that client field has add client link.
    $this->assertArrayHasKey('#suffix', $form['field_client']['widget'][0]);
  }

  /**
   * Tests hook_form_alter for invoice edit form.
   *
   * @covers invoicemgmt_form_alter
   */
  public function testFormAlterInvoiceEditForm(): void {
    $form = [];
    $form_state = new FormState();
    
    $form['field_invoice_number'] = [
      'widget' => [
        0 => [
          'value' => ['#attributes' => []],
        ],
      ],
    ];

    invoicemgmt_form_alter($form, $form_state, 'node_invoice_edit_form');

    $this->assertTrue($form['field_invoice_number']['#disabled']);
  }

  /**
   * Tests hook_form_alter doesn't affect other forms.
   *
   * @covers invoicemgmt_form_alter
   */
  public function testFormAlterDoesNotAffectOtherForms(): void {
    $form = [
      'field_invoice_number' => [
        'widget' => [
          0 => [
            'value' => ['#attributes' => []],
          ],
        ],
      ],
    ];
    $form_state = new FormState();

    invoicemgmt_form_alter($form, $form_state, 'node_article_form');

    // Field should not be disabled for non-invoice forms.
    $this->assertArrayNotHasKey('#disabled', $form['field_invoice_number']);
  }

  /**
   * Tests hook_theme implementation.
   *
   * @covers invoicemgmt_theme
   */
  public function testThemeHook(): void {
    $theme_info = invoicemgmt_theme([], '', '', '');

    $this->assertArrayHasKey('node__invoice__full', $theme_info);
    $this->assertEquals('node--invoice--full', $theme_info['node__invoice__full']['template']);
    $this->assertEquals('node', $theme_info['node__invoice__full']['base hook']);

    $this->assertArrayHasKey('entity_print__invoice', $theme_info);
    $this->assertEquals('entity-print--invoice', $theme_info['entity_print__invoice']['template']);
    $this->assertArrayHasKey('variables', $theme_info['entity_print__invoice']);
  }

  /**
   * Creates invoice content type for testing.
   */
  protected function createInvoiceContentType(): void {
    $invoice_type = NodeType::create([
      'type' => 'invoice',
      'name' => 'Invoice',
    ]);
    $invoice_type->save();

    // Create required fields.
    $this->createTextField('node', 'invoice', 'field_invoice_number', 'Invoice Number', 1);
    $this->createDecimalField('node', 'invoice', 'field_grand_total', 'Grand Total', 1);
    $this->createEntityReferenceRevisionsField('node', 'invoice', 'field_items', 'Invoice Items', 'paragraph', -1);
    $this->createEntityReferenceField('node', 'invoice', 'field_client', 'Client', 'node', 1, ['client']);
  }

  /**
   * Creates client content type for testing.
   */
  protected function createClientContentType(): void {
    $client_type = NodeType::create([
      'type' => 'client',
      'name' => 'Client',
    ]);
    $client_type->save();
  }

  /**
   * Creates invoice item paragraph type for testing.
   */
  protected function createInvoiceItemParagraphType(): void {
    $paragraph_type = ParagraphsType::create([
      'id' => 'invoice_item',
      'label' => 'Invoice Item',
    ]);
    $paragraph_type->save();

    $this->createDecimalField('paragraph', 'invoice_item', 'field_amount', 'Amount', 1);
  }

  /**
   * Helper method to create text fields.
   */
  protected function createTextField(string $entity_type, string $bundle, string $field_name, string $label, int $cardinality): void {
    $field_storage = \Drupal::entityTypeManager()->getStorage('field_storage_config')->create([
      'field_name' => $field_name,
      'entity_type' => $entity_type,
      'type' => 'string',
      'cardinality' => $cardinality,
    ]);
    $field_storage->save();

    $field_config = \Drupal::entityTypeManager()->getStorage('field_config')->create([
      'field_name' => $field_name,
      'entity_type' => $entity_type,
      'bundle' => $bundle,
      'label' => $label,
    ]);
    $field_config->save();
  }

  /**
   * Helper method to create decimal fields.
   */
  protected function createDecimalField(string $entity_type, string $bundle, string $field_name, string $label, int $cardinality): void {
    $field_storage = \Drupal::entityTypeManager()->getStorage('field_storage_config')->create([
      'field_name' => $field_name,
      'entity_type' => $entity_type,
      'type' => 'decimal',
      'cardinality' => $cardinality,
      'settings' => [
        'precision' => 10,
        'scale' => 2,
      ],
    ]);
    $field_storage->save();

    $field_config = \Drupal::entityTypeManager()->getStorage('field_config')->create([
      'field_name' => $field_name,
      'entity_type' => $entity_type,
      'bundle' => $bundle,
      'label' => $label,
    ]);
    $field_config->save();
  }

  /**
   * Helper method to create entity reference revisions fields.
   */
  protected function createEntityReferenceRevisionsField(string $entity_type, string $bundle, string $field_name, string $label, string $target_type, int $cardinality): void {
    $field_storage = \Drupal::entityTypeManager()->getStorage('field_storage_config')->create([
      'field_name' => $field_name,
      'entity_type' => $entity_type,
      'type' => 'entity_reference_revisions',
      'cardinality' => $cardinality,
      'settings' => [
        'target_type' => $target_type,
      ],
    ]);
    $field_storage->save();

    $field_config = \Drupal::entityTypeManager()->getStorage('field_config')->create([
      'field_name' => $field_name,
      'entity_type' => $entity_type,
      'bundle' => $bundle,
      'label' => $label,
      'settings' => [
        'handler' => 'default:' . $target_type,
        'handler_settings' => [
          'target_bundles' => ['invoice_item'],
        ],
      ],
    ]);
    $field_config->save();
  }

  /**
   * Helper method to create entity reference fields.
   */
  protected function createEntityReferenceField(string $entity_type, string $bundle, string $field_name, string $label, string $target_type, int $cardinality, array $target_bundles): void {
    $field_storage = \Drupal::entityTypeManager()->getStorage('field_storage_config')->create([
      'field_name' => $field_name,
      'entity_type' => $entity_type,
      'type' => 'entity_reference',
      'cardinality' => $cardinality,
      'settings' => [
        'target_type' => $target_type,
      ],
    ]);
    $field_storage->save();

    $field_config = \Drupal::entityTypeManager()->getStorage('field_config')->create([
      'field_name' => $field_name,
      'entity_type' => $entity_type,
      'bundle' => $bundle,
      'label' => $label,
      'settings' => [
        'handler' => 'default:' . $target_type,
        'handler_settings' => [
          'target_bundles' => array_combine($target_bundles, $target_bundles),
        ],
      ],
    ]);
    $field_config->save();
  }

}

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

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