graphql_core_schema-1.0.x-dev/tests/src/Kernel/SchemaExtension/ViewsExtensionTest.php

tests/src/Kernel/SchemaExtension/ViewsExtensionTest.php
<?php

declare(strict_types=1);

namespace Drupal\Tests\graphql_core_schema\Kernel\SchemaExtension;

use Drupal\Core\PageCache\ChainRequestPolicy;
use Drupal\Core\PageCache\RequestPolicy\NoSessionOpen;
use Drupal\node\Entity\Node;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\node\Entity\NodeType;
use Drupal\node\NodeInterface;
use Drupal\graphql\Cache\RequestPolicy\GetOnly;
use Drupal\Tests\graphql_core_schema\Kernel\CoreComposableKernelTestBase;
use Drupal\Tests\graphql\Traits\DataProducerExecutionTrait;
use Drupal\Tests\graphql\Traits\HttpRequestTrait;
use Drupal\Tests\graphql\Traits\MockingTrait;
use Drupal\Tests\graphql\Traits\QueryFileTrait;
use Drupal\Tests\graphql\Traits\QueryResultAssertionTrait;
use Drupal\Tests\graphql\Traits\SchemaPrinterTrait;
use Drupal\Tests\user\Traits\UserCreationTrait;
use Prophecy\PhpUnit\ProphecyTrait;
use Drupal\graphql_core_schema\ViewsSchemaBuilder;
use GraphQL\Type\Definition\InputObjectType;
use GraphQL\Type\Definition\ListOfType;
use GraphQL\Type\Definition\StringType;
use GraphQL\Type\Definition\Type;

/**
 * Tests the views extension.
 *
 * @group graphql_core_schema
 */
class ViewsExtensionTest extends CoreComposableKernelTestBase {

  use DataProducerExecutionTrait;
  use HttpRequestTrait;
  use QueryFileTrait;
  use QueryResultAssertionTrait;
  use SchemaPrinterTrait;
  use MockingTrait;
  use UserCreationTrait;
  use ProphecyTrait;

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'graphql_core_schema_views_test',
    'views',
    'views_ui',
  ];

  /**
   * {@inheritdoc}
   */
  protected function setUp(): void {
    parent::setUp();
    // The default admin content view is extended with an optional node id
    // contextual filter to narrow down the result set to a single node.
    $this->installConfig('graphql_core_schema_views_test');

    ConfigurableLanguage::create([
      'id' => 'fr',
      'weight' => 1,
      'label' => 'French',
    ])->save();

    NodeType::create(['type' => 'article'])->save();
    NodeType::create(['type' => 'page'])->save();

    for ($i = 1; $i <= 150; $i++) {
      $node = Node::create([
        'type' => 'article',
        'title' => 'Test ' . $i,
        'status' => NodeInterface::PUBLISHED,
      ]);
      $node->save();
    }

    $this->server = $this
      ->getCoreComposableServerBuilder()
      ->enableValueFields()
      ->enableExtension('views')
      ->enableBaseEntityField('label')
      ->enableEntityType('view', ['status'])
      ->enableEntityType('node', [], ['article'])
      ->createServer();

    $this->server->schema_configuration['core_composable']['extension_views']['enabled_views'] = [
      'content:default' => 'content:default',
      'content:page_1' => 'content:page_1',
    ];
    $this->server->save();

    $this->setUpCurrentUser([], $this->userPermissions());
  }

  /**
   * Test views properties.
   */
  public function testViewsProperties(): void {
    $query = $this->getQueryFromFile('views.gql');
    $rows = [];
    // This query will fetch the 20 rows on page 2.
    for ($i = 110; $i >= 91; $i--) {
      $rows[] = [
        'label' => 'Test ' . $i,
        'id' => $i,
      ];
    }
    $metatags = $this->defaultCacheMetaData();
    $tags = [];
    for ($i = 91; $i <= 110; $i++) {
      $tags[] = 'node:' . $i;
    }
    $metatags->addCacheTags($tags);

    $this->assertResults($query, [], [
      'getView' => [
        'executable' => [
          'execute' => [
            'total_rows' => 150,
            'rows' => $rows,
          ],
          'filters' => [
            [
              'adminLabel' => 'Content: Title',
              'adminLabelShort' => 'Content: Title',
              'adminSummary' => 'exposed',
              'alwaysRequired' => FALSE,
              'baseId' => 'string',
              'field' => 'title',
              'groupInfo' => [
                'defaultGroup' => 'All',
                'description' => '',
                'groupItems' => [],
                'identifier' => '',
                'label' => '',
                'multiple' => FALSE,
                'optional' => TRUE,
                'remember' => FALSE,
                'widget' => 'select',
              ],
              'isAGroup' => FALSE,
              'isExposed' => TRUE,
              'noOperator' => FALSE,
              'operator' => 'contains',
              'options' => [
                'id' => 'title',
                'table' => 'node_field_data',
                'field' => 'title',
                'relationship' => 'none',
                'group_type' => 'group',
                'admin_label' => '',
                'operator' => 'contains',
                'value' => '',
                'group' => 1,
                'exposed' => TRUE,
                'expose' => [
                  'operator_id' => 'title_op',
                  'label' => 'Title',
                  'description' => '',
                  'use_operator' => FALSE,
                  'operator' => 'title_op',
                  'operator_limit_selection' => FALSE,
                  'operator_list' => [],
                  'identifier' => 'title',
                  'required' => FALSE,
                  'remember' => FALSE,
                  'multiple' => FALSE,
                  'remember_roles' => [
                    'authenticated' => 'authenticated',
                  ],
                  'placeholder' => '',
                ],
                'is_grouped' => FALSE,
                'group_info' => [
                  'label' => '',
                  'description' => '',
                  'identifier' => '',
                  'optional' => TRUE,
                  'widget' => 'select',
                  'multiple' => FALSE,
                  'remember' => FALSE,
                  'default_group' => 'All',
                  'default_group_multiple' => [],
                  'group_items' => [],
                ],
                'entity_type' => 'node',
                'entity_field' => 'title',
                'plugin_id' => 'string',
              ],
              'pluginId' => 'string',
              'realField' => 'title',
              'table' => 'node_field_data',
              'value' => '',
            ],
            [
              'adminLabel' => 'Content: Content type',
              'adminLabelShort' => 'Content: Content type',
              'adminSummary' => 'exposed',
              'alwaysRequired' => FALSE,
              'baseId' => 'bundle',
              'field' => 'type',
              'groupInfo' => [
                'defaultGroup' => 'All',
                'description' => '',
                'groupItems' => [],
                'identifier' => '',
                'label' => '',
                'multiple' => FALSE,
                'optional' => TRUE,
                'remember' => FALSE,
                'widget' => 'select',
              ],
              'isAGroup' => FALSE,
              'isExposed' => TRUE,
              'noOperator' => FALSE,
              'operator' => 'in',
              'options' => [
                'id' => 'type',
                'table' => 'node_field_data',
                'field' => 'type',
                'relationship' => 'none',
                'group_type' => 'group',
                'admin_label' => '',
                'operator' => 'in',
                'value' => [],
                'group' => 1,
                'exposed' => TRUE,
                'expose' => [
                  'operator_id' => 'type_op',
                  'label' => 'Content type',
                  'description' => '',
                  'use_operator' => FALSE,
                  'operator' => 'type_op',
                  'operator_limit_selection' => FALSE,
                  'operator_list' => [],
                  'identifier' => 'type',
                  'required' => FALSE,
                  'remember' => FALSE,
                  'multiple' => TRUE,
                  'remember_roles' => [
                    'authenticated' => 'authenticated',
                  ],
                  'reduce' => FALSE,
                ],
                'is_grouped' => FALSE,
                'group_info' => [
                  'label' => '',
                  'description' => '',
                  'identifier' => '',
                  'optional' => TRUE,
                  'widget' => 'select',
                  'multiple' => FALSE,
                  'remember' => FALSE,
                  'default_group' => 'All',
                  'default_group_multiple' => [],
                  'group_items' => [],
                ],
                'entity_type' => 'node',
                'entity_field' => 'type',
                'plugin_id' => 'bundle',
              ],
              'pluginId' => 'bundle',
              'realField' => 'type',
              'table' => 'node_field_data',
              'value' => [],
            ],
            [
              'adminLabel' => 'Content: Published',
              'adminLabelShort' => 'Content: Published',
              'adminSummary' => 'grouped',
              'alwaysRequired' => FALSE,
              'baseId' => 'boolean',
              'field' => 'status',
              'groupInfo' => [
                'defaultGroup' => 'All',
                'description' => '',
                'groupItems' => [
                  [
                    'operator' => '=',
                    'title' => 'Published',
                    'value' => '1',
                  ],
                  [
                    'operator' => '=',
                    'title' => 'Unpublished',
                    'value' => '0',
                  ],
                ],
                'identifier' => 'status',
                'label' => 'Published status',
                'multiple' => FALSE,
                'optional' => TRUE,
                'remember' => FALSE,
                'widget' => 'select',
              ],
              'isAGroup' => TRUE,
              'isExposed' => TRUE,
              'noOperator' => FALSE,
              'operator' => '=',
              'options' => [
                'id' => 'status',
                'table' => 'node_field_data',
                'field' => 'status',
                'relationship' => 'none',
                'group_type' => 'group',
                'admin_label' => '',
                'operator' => '=',
                'value' => '1',
                'group' => 1,
                'exposed' => TRUE,
                'expose' => [
                  'operator_id' => '',
                  'label' => 'Status',
                  'description' => '',
                  'use_operator' => FALSE,
                  'operator' => 'status_op',
                  'operator_limit_selection' => FALSE,
                  'operator_list' => [],
                  'identifier' => 'status',
                  'required' => FALSE,
                  'remember' => FALSE,
                  'multiple' => FALSE,
                  'remember_roles' => [
                    'authenticated' => 'authenticated',
                  ],
                ],
                'is_grouped' => TRUE,
                'group_info' => [
                  'label' => 'Published status',
                  'description' => '',
                  'identifier' => 'status',
                  'optional' => TRUE,
                  'widget' => 'select',
                  'multiple' => FALSE,
                  'remember' => FALSE,
                  'default_group' => 'All',
                  'default_group_multiple' => [],
                  'group_items' => [
                    '1' => [
                      'title' => 'Published',
                      'operator' => '=',
                      'value' => '1',
                    ],
                    '2' => [
                      'title' => 'Unpublished',
                      'operator' => '=',
                      'value' => '0',
                    ],
                  ],
                ],
                'entity_type' => 'node',
                'entity_field' => 'status',
                'plugin_id' => 'boolean',
              ],
              'pluginId' => 'boolean',
              'realField' => 'status',
              'table' => 'node_field_data',
              'value' => '1',
            ],
            [
              'adminLabel' => 'Content: Translation language',
              'adminLabelShort' => 'Content: Translation language',
              'adminSummary' => 'exposed',
              'alwaysRequired' => FALSE,
              'baseId' => 'language',
              'field' => 'langcode',
              'groupInfo' => [
                'defaultGroup' => 'All',
                'description' => '',
                'groupItems' => [],
                'identifier' => '',
                'label' => '',
                'multiple' => FALSE,
                'optional' => TRUE,
                'remember' => FALSE,
                'widget' => 'select',
              ],
              'isAGroup' => FALSE,
              'isExposed' => TRUE,
              'noOperator' => FALSE,
              'operator' => 'in',
              'options' => [
                'id' => 'langcode',
                'table' => 'node_field_data',
                'field' => 'langcode',
                'relationship' => 'none',
                'group_type' => 'group',
                'admin_label' => '',
                'operator' => 'in',
                'value' => [],
                'group' => 1,
                'exposed' => TRUE,
                'expose' => [
                  'operator_id' => 'langcode_op',
                  'label' => 'Language',
                  'description' => '',
                  'use_operator' => FALSE,
                  'operator' => 'langcode_op',
                  'operator_limit_selection' => FALSE,
                  'operator_list' => [],
                  'identifier' => 'langcode',
                  'required' => FALSE,
                  'remember' => FALSE,
                  'multiple' => FALSE,
                  'remember_roles' => [
                    'authenticated' => 'authenticated',
                  ],
                  'reduce' => FALSE,
                ],
                'is_grouped' => FALSE,
                'group_info' => [
                  'label' => '',
                  'description' => '',
                  'identifier' => '',
                  'optional' => TRUE,
                  'widget' => 'select',
                  'multiple' => FALSE,
                  'remember' => FALSE,
                  'default_group' => 'All',
                  'default_group_multiple' => [],
                  'group_items' => [],
                ],
                'entity_type' => 'node',
                'entity_field' => 'langcode',
                'plugin_id' => 'language',
              ],
              'pluginId' => 'language',
              'realField' => 'langcode',
              'table' => 'node_field_data',
              'value' => [],
            ],
          ],
          'pager' => [
            'perPage' => 50,
            'totalItems' => 0,
          ],
          'sorts' => [
            [
              'baseId' => 'standard',
              'field' => 'title',
              'pluginId' => 'standard',
              'realField' => 'title',
            ],
            [
              'baseId' => 'standard',
              'field' => 'nid',
              'pluginId' => 'standard',
              'realField' => 'nid',
            ],
          ],
        ],
        'id' => 'content',
        'label' => 'Content',
        'status' => TRUE,
      ],
    ], $metatags);
  }

  /**
   * Ensure filters argument exposes single and multiple input fields.
   */
  public function testExecuteFiltersArgumentTypes(): void {
    $schema = $this->getSchema($this->server);

    /** @var \Drupal\views\ViewEntityInterface $view */
    $view = $this->container->get('entity_type.manager')->getStorage('view')->load('content');
    $executable = $view->getExecutable();
    $executable->setDisplay('page_1');
    $typeName = ViewsSchemaBuilder::getGraphqlTypeName($executable);

    /** @var \GraphQL\Type\Definition\ObjectType $viewType */
    $viewType = $schema->getType($typeName);
    $this->assertNotNull($viewType);

    $executeField = $viewType->getField('execute');
    $this->assertNotNull($executeField);

    $filtersArgument = $executeField->getArg('filters');
    $this->assertNotNull($filtersArgument);

    $filtersType = Type::getNullableType($filtersArgument->getType());
    $this->assertInstanceOf(InputObjectType::class, $filtersType);

    $fields = $filtersType->getFields();
    $this->assertArrayHasKey('title', $fields);
    $this->assertArrayHasKey('type', $fields);

    $titleFieldType = Type::getNullableType($fields['title']->getType());
    $this->assertInstanceOf(StringType::class, $titleFieldType);

    $typeFieldType = Type::getNullableType($fields['type']->getType());
    $this->assertInstanceOf(ListOfType::class, $typeFieldType);
    $this->assertInstanceOf(StringType::class, Type::getNullableType($typeFieldType->getWrappedType()));
  }

  /**
   * Test views with a contextual filter and a query parameter.
   */
  public function testViewsWithQueryParameterAndContextualFilterProperties(): void {
    $query = $this->getQueryFromFile('views_contextual_and_query_pm.gql');
    $rows = [];

    $metadata = $this->defaultCacheMetaData();
    $tags = [];
    // This query will fetch 1 row on page 0.
    // @see This must match the contextualFilters value in
    // views_contextual_and_*.gql.
    $i = 129;
    $rows[] = [
      'label' => 'Test ' . $i,
      'id' => $i,
    ];
    $tags[] = 'node:' . $i;
    $metadata->addCacheTags($tags);

    $this->assertResults($query, [], [
      'getView' => [
        'executable' => [
          'execute' => [
            'total_rows' => 1,
            'rows' => $rows,
          ],
        ],
      ],
    ], $metadata);

    // Test the same thing with filters instead of query parameters.
    $query = $this->getQueryFromFile('views_contextual_and_filter.gql');
    $this->assertResults($query, [], [
      'getView' => [
        'executable' => [
          'execute' => [
            'total_rows' => 1,
            'rows' => $rows,
          ],
        ],
      ],
    ], $metadata);
  }

  /**
   * Test views with query parameters.
   */
  public function testViewsWithQueryParameterProperties(): void {
    $query = $this->getQueryFromFile('views_query_pm.gql');
    $rows = [];

    $metadata = $this->defaultCacheMetaData();
    $tags = [];
    // This query will fetch the 10 rows on page 0.
    for ($i = 129; $i >= 120; $i--) {
      $rows[] = [
        'label' => 'Test ' . $i,
        'id' => $i,
      ];
      $tags[] = 'node:' . $i;
    }
    $metadata->addCacheTags($tags);

    $this->assertResults($query, [], [
      'getView' => [
        'executable' => [
          'execute' => [
            'total_rows' => 11,
            'rows' => $rows,
          ],
        ],
      ],
    ], $metadata);

    // Test the same thing with filters instead of query parameters.
    $query = $this->getQueryFromFile('views_filter.gql');
    $this->assertResults($query, [], [
      'getView' => [
        'executable' => [
          'execute' => [
            'total_rows' => 11,
            'rows' => $rows,
          ],
        ],
      ],
    ], $metadata);
  }

  /**
   * Configures core's cache policy.
   *
   * Modifies the DefaultRequestPolicy classes, which always add in the
   * CommandLineOrUnsafeMethod policy which will always result in DENY in a
   * Kernel test because we're running via the command line.
   *
   * @param int $max_age
   *   Max age to cache responses.
   */
  protected function configureCachePolicy(int $max_age = 900): void {
    $this->container->set('dynamic_page_cache_request_policy', (new ChainRequestPolicy())
      ->addPolicy(new GetOnly()));
    $this->container->set('page_cache_request_policy', (new ChainRequestPolicy())
      ->addPolicy(new NoSessionOpen($this->container->get('session_configuration')))
      ->addPolicy(new GetOnly()));
    // Turn on caching.
    $this->config('system.performance')->set('cache.page.max_age', $max_age)->save();
  }

  /**
   * Returns the default cache maximum age for the test.
   */
  protected function defaultCacheMaxAge(): int {
    // Views with exposed filters are not cached.
    return 0;
  }

  /**
   * Returns the default cache tags used in assertions for this test.
   *
   * @return string[]
   *   The list of cache tags.
   */
  protected function defaultCacheTags(): array {
    $tags = ['graphql_response'];
    if (isset($this->server)) {
      array_push($tags, "config:graphql.graphql_servers.{$this->server->id()}");
    }

    $tags[] = 'config:views.view.content';
    $tags[] = 'node_list';
    $tags[] = 'user_list';
    $tags[] = 'user:0';
    return $tags;
  }

  /**
   * Returns the default cache contexts used in assertions for this test.
   *
   * @return string[]
   *   The list of cache contexts.
   */
  protected function defaultCacheContexts(): array {
    return [
      'user.permissions',
      'languages:language_interface',
      'url.query_args',
    ];
  }

  /**
   * Provides the user permissions that the test user is set up with.
   *
   * @return string[]
   *   List of user permissions.
   */
  protected function userPermissions(): array {
    return [
      'access content',
      'access content overview',
      'bypass graphql access',
      'administer views',
    ];
  }

}

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

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