xero-8.x-2.x-dev/tests/src/Kernel/XeroItemManagerTest.php

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

namespace Drupal\Tests\xero\Kernel;

use Drupal\KernelTests\KernelTestBase;
use Drupal\xero\TypedData\XeroComplexItemInterface;
use Drupal\xero\XeroItemManager;
use Drupal\xero\XeroQuery;
use Drupal\xero\XeroQueryFactory;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;

/**
 * Tests the Xero item manager.
 *
 * @coversDefaultClass \Drupal\xero\XeroItemManager
 * @group xero
 */
class XeroItemManagerTest extends KernelTestBase {

  use ProphecyTrait;

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'serialization',
    'user',
    'xero',
  ];

  /**
   * The Xero Item Manager.
   *
   * @var \Drupal\xero\XeroItemManager
   */
  protected $itemManager;

  /**
   * The Xero query factory.
   *
   * @var \Drupal\xero\XeroQueryFactory
   */
  protected $xeroQueryFactory;

  /**
   * The ContactID of the test contact.
   *
   * @var string
   */
  protected $xeroId = 'bd2270c3-8706-4c11-9cfb-000b551c3f51';

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

    $this->xeroQueryFactory = $this->createMock(XeroQueryFactory::class);
    $typedDataManager = \Drupal::service('typed_data_manager');

    $loggerProphet = $this->prophesize('\Drupal\Core\Logger\LoggerChannelInterface');
    $loggerProphet->error(Argument::any(), Argument::any());
    $loggerFactoryProphet = $this->prophesize('\Drupal\Core\Logger\LoggerChannelFactoryInterface');
    $loggerFactoryProphet->get('xero')->willReturn($loggerProphet->reveal());

    $this->itemManager = new XeroItemManager($typedDataManager, $this->xeroQueryFactory, $loggerFactoryProphet->reveal());
  }

  /**
   * Test the createItem and updateItem methods.
   *
   * @param string $call
   *   The method to call.
   * @param string $method
   *   The HTTP method to use.
   * @param string $type
   *   The xero type to create.
   * @param mixed $value
   *   The value to set on the data type.
   * @param array|bool $expected
   *   The expected return class, instance, or FALSE.
   *
   * @dataProvider sendItemProvider
   *
   * @covers \Drupal\xero\XeroItemManager::createItem
   * @covers \Drupal\xero\XeroItemManager::updateItem
   */
  public function testSendItem($call, $method, $type, $value, $expected) {
    $item = $this->buildXeroItem('xero_contact', $value);
    $result = $expected ? $this->buildXeroItem($type, $expected) : $expected;

    $expectations = [
      ['method' => $method, 'item' => $item, 'result' => $result],
    ];
    $this->setSendQueryExpectations($expectations);
    $this->assertEquals($this->itemManager->{$call}($item), $result);
  }

  /**
   * Data provider for testSendItem() method.
   *
   * @return array[]
   *   Test scenarios.
   */
  public static function sendItemProvider() {
    return [
      [
        'call' => 'createItem',
        'method' => 'put',
        'type' => 'xero_contact',
        'value' => [
          'ContactNumber' => '12345',
          'Name' => 'ABC Company',
          'EmailAddress' => 'test@example.com',
        ],
        'expected' => [
          'ContactID' => 'bd2270c3-8706-4c11-9cfb-000b551c3f51',
          'ContactNumber' => '12345',
          'Name' => 'ABC Company',
          'EmailAddress' => 'test@example.com',
          'Status' => 'ACTIVE',
          'UpdatedDateUTC' => '2020-01-01T00:00:00.000',
        ],
      ],
      [
        'call' => 'createItem',
        'method' => 'put',
        'type' => 'xero_contact',
        'value' => [
          'EmailAddress' => 'test@example.com',
        ],
        'expected' => FALSE,
      ],
      [
        'call' => 'updateItem',
        'method' => 'post',
        'type' => 'xero_contact',
        'value' => [
          'Name' => 'XYZ Company',
          'ContactID' => 'bd2270c3-8706-4c11-9cfb-000b551c3f51',
        ],
        'expected' => [
          'ContactID' => 'bd2270c3-8706-4c11-9cfb-000b551c3f51',
          'ContactNumber' => '12345',
          'Name' => 'XYZ Company',
          'EmailAddress' => 'test@example.com',
          'Status' => 'ACTIVE',
          'UpdatedDateUTC' => '2020-01-01T00:00:00.000',
        ],
      ],
      [
        'call' => 'updateItem',
        'method' => 'post',
        'type' => 'xero_contact',
        'value' => [
          'EmailAddress' => 'test@example.com',
        ],
        'expected' => FALSE,
      ],
    ];
  }

  /**
   * Test the reloadItem method.
   *
   * @param string $type
   *   The xero type to build.
   * @param array|bool $value
   *   The data to set.
   * @param string|bool $expected
   *   The expected class or FALSE.
   *
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \Drupal\Core\TypedData\Exception\MissingDataException
   * @throws \Throwable
   *
   * @dataProvider loadItemProvider
   *
   * @covers \Drupal\xero\XeroItemManager::loadItem
   */
  public function testLoadItem($type, $value, $expected) {
    $this->buildLoadExpectations($type, $value);
    $actual = $this->itemManager->loadItem('xero_contact', $this->xeroId);
    if ($expected) {
      $this->assertInstanceOf($expected, $actual);
    }
    else {
      $this->assertFalse($actual);
    }
  }

  /**
   * Test the reloadItem method.
   *
   * @param string $type
   *   The xero type to build.
   * @param array|bool $value
   *   The data to set.
   * @param string|bool $expected
   *   The expected class or FALSE.
   *
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \Drupal\Core\TypedData\Exception\MissingDataException
   * @throws \Throwable
   *
   * @dataProvider loadItemProvider
   *
   * @covers \Drupal\xero\XeroItemManager::reloadItem
   */
  public function testReloadItem($type, $value, $expected) {
    $this->buildLoadExpectations($type, $value);
    $item = $this->buildXeroItem($type, $value);
    $actual = $this->itemManager->reloadItem($item);
    if ($expected) {
      $this->assertInstanceOf($expected, $actual);
    }
    else {
      $this->assertFalse($actual);
    }

  }

  /**
   * Helper method to build expectations for load tests.
   *
   * @param string $type
   *   The xero type.
   * @param array|bool $value
   *   The value to set on the type.
   */
  public function buildLoadExpectations($type, $value) {
    $result = $value ? $this->buildXeroItem($type, $value) : FALSE;
    $query = $this->buildMockQuery($type, $result);
    $definition = \Drupal::typedDataManager()->createDataDefinition($type);
    $class = $definition->getClass();

    $query->expects($this->once())
      ->method('setId')
      ->with($this->xeroId)
      ->willReturn($query);

    $this->xeroQueryFactory->expects($this->once())
      ->method('get')
      ->willReturn($query);
  }

  /**
   * Data provider for testLoadItem() and testReloadItem() methods.
   *
   * @return array[]
   *   Test scenarios.
   */
  public static function loadItemProvider() {
    return [
      [
        'type' => 'xero_contact',
        'value' => [
          'ContactID' => 'bd2270c3-8706-4c11-9cfb-000b551c3f51',
          'ContactNumber' => '12345',
          'Name' => 'ABC Company',
          'EmailAddress' => 'test@example.com',
          'Status' => 'ACTIVE',
          'UpdatedDateUTC' => '2020-01-01T00:00:00.000',
        ],
        'expected' => '\Drupal\xero\Plugin\DataType\Contact',
      ],
      [
        'type' => 'xero_contact',
        'value' => [],
        'expected' => FALSE,
      ],
    ];
  }

  /**
   * Test the findItem method.
   *
   * @param array $conditions
   *   The query conditions to test.
   * @param bool|null $unique
   *   The unique parameter.
   * @param string $type
   *   The xero data type.
   * @param array|bool|null $value
   *   The value to set the data.
   * @param string|bool $expected
   *   Success indicator to assert.
   *
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \Drupal\Core\TypedData\Exception\MissingDataException
   *
   * @dataProvider findItemProvider
   *
   * @covers \Drupal\xero\XeroItemManager::findItem
   */
  public function testFindItem(array $conditions, $unique, $type, $value, $expected) {
    $results = $value;
    if ($value) {
      $results = [];
      foreach ($value as $i => $result) {
        $results[] = $this->buildXeroItem($type, $result);
      }
    }

    $query = $this->buildMockQuery($type, $results);
    // Do we really need to test conditions because PHPUnit is making it hard.
    $query->method('addCondition')->willReturn($query);

    $this->xeroQueryFactory
      ->expects($this->once())
      ->method('get')
      ->willReturn($query);

    $actual = $this->itemManager->findItem('xero_contact', $conditions, $unique);
    if ($expected) {
      $this->assertInstanceOf($expected, $actual);
    }
    else {
      $this->assertEquals($expected, $actual);
    }
  }

  /**
   * Data provider for testFindItem() method.
   *
   * @return array<string,mixed>[]
   *   Test scenarios.
   */
  public static function findItemProvider() {
    return [
      'no result for unique' => [
        'conditions' => [
          ['EmailAddress', 'test@example.com', '=='],
        ],
        'unique' => TRUE,
        'type' => 'xero_contact',
        'value' => FALSE,
        'expected' => FALSE,
      ],
      'no result for not unique' => [
        'conditions' => [
          ['EmailAddress', 'test@example.com', '=='],
        ],
        'unique' => FALSE,
        'type' => 'xero_contact',
        'value' => FALSE,
        'expected' => FALSE,
      ],
      'null result for unique' => [
        'conditions' => [
          ['EmailAddress', 'test@example.com', '=='],
        ],
        'unique' => TRUE,
        'type' => 'xero_contact',
        'value' => NULL,
        'expected' => NULL,
      ],
      'null result for not unique' => [
        'conditions' => [
          ['EmailAddress', 'test@example.com', '=='],
        ],
        'unique' => FALSE,
        'type' => 'xero_contact',
        'value' => NULL,
        'expected' => NULL,
      ],
      'result for unique' => [
        'conditions' => [
          ['EmailAddress', 'test@example.com', '=='],
        ],
        'unique' => TRUE,
        'type' => 'xero_contact',
        'value' => [
          [
            'ContactID' => 'bd2270c3-8706-4c11-9cfb-000b551c3f51',
            'ContactNumber' => '12345',
            'Name' => 'ABC Company',
            'EmailAddress' => 'test@example.com',
            'Status' => 'ACTIVE',
            'UpdatedDateUTC' => '2020-01-01T00:00:00.000',
          ],
        ],
        'expected' => '\Drupal\xero\Plugin\DataType\Contact',
      ],
      'result for not unique' => [
        'conditions' => [
          ['EmailAddress', 'test@example.com', '=='],
        ],
        'unique' => FALSE,
        'type' => 'xero_contact',
        'value' => [
          [
            'ContactID' => 'bd2270c3-8706-4c11-9cfb-000b551c3f51',
            'ContactNumber' => '12345',
            'Name' => 'ABC Company',
            'EmailAddress' => 'test@example.com',
            'Status' => 'ACTIVE',
            'UpdatedDateUTC' => '2020-01-01T00:00:00.000',
          ],
        ],
        'expected' => '\Drupal\xero\Plugin\DataType\Contact',
      ],
      'multiple results for unique' => [
        'conditions' => [
          ['EmailAddress', 'test@example.com', '=='],
        ],
        'unique' => TRUE,
        'type' => 'xero_contact',
        'value' => [
          [
            'ContactID' => 'bd2270c3-8706-4c11-9cfb-000b551c3f51',
            'ContactNumber' => '12345',
            'Name' => 'ABC Company',
            'EmailAddress' => 'test@example.com',
            'Status' => 'ACTIVE',
            'UpdatedDateUTC' => '2020-01-01T00:00:00.000',
          ],
          [
            'ContactID' => 'ebd06280-af70-4bed-97c6-7451a454ad85',
            'ContactNumber' => '67890',
            'FirstName' => 'Sam',
            'LastName' => 'Gutierrez',
            'EmailAddress' => 'test@example.com',
            'Status' => 'ACTIVE',
            'UpdatedDateUTC' => '2020-01-01T00:00:00.000',
          ],
        ],
        'expected' => FALSE,
      ],
      'multiple results for not unique' => [
        'conditions' => [
          ['EmailAddress', 'test@example.com', '=='],
        ],
        'unique' => FALSE,
        'type' => 'xero_contact',
        'value' => [
          [
            'ContactID' => 'bd2270c3-8706-4c11-9cfb-000b551c3f51',
            'ContactNumber' => '12345',
            'Name' => 'ABC Company',
            'EmailAddress' => 'test@example.com',
            'Status' => 'ACTIVE',
            'UpdatedDateUTC' => '2020-01-01T00:00:00.000',
          ],
          [
            'ContactID' => 'ebd06280-af70-4bed-97c6-7451a454ad85',
            'ContactNumber' => '67890',
            'FirstName' => 'Sam',
            'LastName' => 'Gutierrez',
            'EmailAddress' => 'test@example.com',
            'Status' => 'ACTIVE',
            'UpdatedDateUTC' => '2020-01-01T00:00:00.000',
          ],
        ],
        'expected' => '\Drupal\xero\Plugin\DataType\Contact',
      ],
      'result with multiple conditions without unique' => [
        'conditions' => [
          ['EmailAddress', 'test@example.com', '=='],
          ['ContactNumber', '5', 'NOT NULL'],
        ],
        'unique' => NULL,
        'type' => 'xero_contact',
        'value' => [
          [
            'ContactID' => 'bd2270c3-8706-4c11-9cfb-000b551c3f51',
            'ContactNumber' => '12345',
            'Name' => 'ABC Company',
            'EmailAddress' => 'test@example.com',
            'Status' => 'ACTIVE',
            'UpdatedDateUTC' => '2020-01-01T00:00:00.000',
          ],
        ],
        'expected' => '\Drupal\xero\Plugin\DataType\Contact',
      ],
    ];
  }

  /**
   * Setup expectations about the query used to send data to Xero.
   *
   * @param array $expectations
   *   An array of expectations, one per expected query.
   */
  protected function setSendQueryExpectations(array $expectations) {
    $willReturn = [];
    foreach ($expectations as $index => $expectation) {
      if (!isset($expectation['type'])) {
        $expectation['type'] = 'xero_contact';
      }

      $query = $this->buildMockQuery(
        $expectation['type'],
        $expectation['result'],
        $expectation['method'],
        $expectation['item']
      );
      $willReturn[] = $query;
    }

    $this->xeroQueryFactory
      ->method('get')
      ->willReturnOnConsecutiveCalls(...$willReturn);
  }

  /**
   * Builds a mock Xero query object, with expectations.
   *
   * @param string $type
   *   The typed to be expected to be set on the query.
   * @param mixed $result
   *   The result the query is expected to return. Result values have these
   *   meanings:
   *   - FALSE means the query returns FALSE.
   *   - NULL means the query returns an empty results list.
   *   - an item means the query returns a list with the item as first value.
   *   - an array of items means the query returns a list with those items.
   * @param string|null $method
   *   The method to be expected to be set on the query.
   * @param \Drupal\xero\TypedData\XeroComplexItemInterface|null $item
   *   The item to expect to be set as the query's data.
   *
   * @return \PHPUnit\Framework\MockObject\MockObject
   *   A mock Xero query.
   */
  protected function buildMockQuery($type, $result, $method = NULL, $item = NULL) {
    if ($result !== FALSE) {
      $resultsProphet = $this->prophesize('\Drupal\xero\Plugin\DataType\XeroItemList');
      if (is_null($result)) {
        $resultsProphet->count()->willReturn(0);
      }
      else {
        if (!is_array($result)) {
          $resultItems = [$result];
        }
        else {
          $resultItems = $result;
        }
        $resultsProphet->count()->willReturn(count($resultItems));
        $resultsProphet->get(0)->willReturn($resultItems[0]);
      }
      $result = $resultsProphet->reveal();
    }

    $mock = $this->createMock(XeroQuery::class);
    $mock->expects($this->once())
      ->method('setType')
      ->with($type)
      ->willReturn($mock);
    if ($method) {
      $mock->expects($this->once())
        ->method('setMethod')
        ->with($method)
        ->willReturn($mock);
    }
    if ($item) {
      $mock->expects($this->once())
        ->method('setData')
        ->with($this->callback(function ($data) use ($item) {
          // We can't simply test for the equality of the objects,
          // because a list's don't store the child objects internally,
          // only their values. The child items are recreated when extracted.
          $sameProperties = TRUE;
          $itemProperties = array_keys($item->getSpecifiedProperties());
          sort($itemProperties);
          $dataProperties = array_keys($data->get(0)->getSpecifiedProperties());
          sort($dataProperties);
          $sameSpecified = $itemProperties === $dataProperties;
          foreach ($itemProperties as $property) {
            $sameProperty = $data->get(0)->get($property)->getString() === $item->get($property)->getString();
            $sameProperties = $sameProperties && $sameProperty;
          }
          $single = $data->count() === 1;
          return $single && $sameSpecified && $sameProperties;
        }))
        ->willReturn($mock);
    }
    $mock->expects($this->once())
      ->method('execute')
      ->willReturn($result);
    return $mock;
  }

  /**
   * Construct a typed data representation of a Xero item.
   *
   * @param string $type
   *   The Xero type.
   * @param array $properties
   *   The properties to initialise the item with.
   *
   * @return \Drupal\xero\TypedData\XeroComplexItemInterface
   *   The constructed item.
   */
  protected function buildXeroItem($type, array $properties = []) {
    $definition = \Drupal::typedDataManager()->createDataDefinition($type);
    if (empty($properties)) {
      $class = $definition->getClass();
      $prop = $class::getXeroProperty('guid_name');
      $properties[$prop] = $this->xeroId;
    }
    $item = \Drupal::typedDataManager()->create($definition, $properties);
    $this->assertInstanceOf(XeroComplexItemInterface::class, $item);
    return $item;
  }

}

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

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