text: import json
  
  import graphene
  import pytest
  from django.shortcuts import reverse
  from prices import Money
  
  from saleor.product.models import Category, Product, ProductAttribute
  
  from .utils import get_graphql_content
  
  
  def test_category_query(client, product_in_stock):
      category = Category.objects.first()
      query = '''
      query {
          category(id: "%(category_pk)s") {
              id
              name
              ancestors {
                  edges {
                      node {
                          name
                      }
                  }
              }
              children {
                  edges {
                      node {
                          name
                      }
                  }
              }
              siblings {
                  edges {
                      node {
                          name
                      }
                  }
              }
          }
      }
      ''' % {'category_pk': graphene.Node.to_global_id('Category', category.pk)}
      response = client.post(reverse('api'), {'query': query})
      content = get_graphql_content(response)
      assert 'errors' not in content
      category_data = content['data']['category']
      assert category_data is not None
      assert category_data['name'] == category.name
      assert (
          len(category_data['ancestors']['edges']) ==
          category.get_ancestors().count())
      assert (
          len(category_data['children']['edges']) ==
          category.get_children().count())
      assert (
          len(category_data['siblings']['edges']) ==
          category.get_siblings().count())
  
  
  def test_fetch_all_products(client, product_in_stock):
      query = '''
      query {
          products {
              totalCount
              edges {
                  node {
                      id
                  }
              }
          }
      }
      '''
      response = client.post(reverse('api'), {'query': query})
      content = get_graphql_content(response)
      assert 'errors' not in content
      num_products = Product.objects.count()
      assert content['data']['products']['totalCount'] == num_products
      assert len(content['data']['products']['edges']) == num_products
  
  
  @pytest.mark.djangodb
  def test_fetch_unavailable_products(client, product_in_stock):
      Product.objects.update(is_published=False)
      query = '''
      query {
          products {
              totalCount
              edges {
                  node {
                      id
                  }
              }
          }
      }
      '''
      response = client.post(reverse('api'), {'query': query})
      content = get_graphql_content(response)
      assert 'errors' not in content
      assert content['data']['products']['totalCount'] == 0
      assert not content['data']['products']['edges']
  
  
  def test_product_query(client, product_in_stock):
      category = Category.objects.first()
      product = category.products.first()
      query = '''
      query {
          category(id: "%(category_id)s") {
              products {
                  edges {
                      node {
                          id
                          name
                          url
                          thumbnailUrl
                          images { url }
                          variants {
                              name
                              stockQuantity
                          }
                          availability {
                              available,
                              priceRange {
                                  start {
                                      gross {
                                          amount
                                          currency
                                          localized
                                      }
                                      net {
                                          amount
                                          currency
                                          localized
                                      }
                                      currency
                                  }
                              }
                          }
                      }
                  }
              }
          }
      }
      ''' % {'category_id': graphene.Node.to_global_id('Category', category.id)}
      response = client.post(reverse('api'), {'query': query})
      content = get_graphql_content(response)
      assert 'errors' not in content
      assert content['data']['category'] is not None
      product_edges_data = content['data']['category']['products']['edges']
      assert len(product_edges_data) == category.products.count()
      product_data = product_edges_data[0]['node']
      assert product_data['name'] == product.name
      assert product_data['url'] == product.get_absolute_url()
      gross = product_data['availability']['priceRange']['start']['gross']
      assert float(gross['amount']) == float(product.price.amount)
  
  
  def test_filter_product_by_category(client, product_in_stock):
      category = product_in_stock.category
      query = '''
      query getProducts($categoryId: ID) {
          products(category: $categoryId) {
              edges {
                  node {
                      name
                  }
              }
          }
      }
      '''
      response = client.post(
          reverse('api'),
          {
              'query': query,
              'variables': json.dumps(
                  {
                      'categoryId': graphene.Node.to_global_id(
                          'Category', category.id)}),
              'operationName': 'getProducts'})
      content = get_graphql_content(response)
      assert 'errors' not in content
      product_data = content['data']['products']['edges'][0]['node']
      assert product_data['name'] == product_in_stock.name
  
  
  def test_fetch_product_by_id(client, product_in_stock):
      query = '''
      query ($productId: ID!) {
          node(id: $productId) {
              ... on Product {
                  name
              }
          }
      }
      '''
      response = client.post(
          reverse('api'),
          {
              'query': query,
              'variables': json.dumps(
                  {
                      'productId': graphene.Node.to_global_id(
                          'Product', product_in_stock.id)})})
      content = get_graphql_content(response)
      assert 'errors' not in content
      product_data = content['data']['node']
      assert product_data['name'] == product_in_stock.name
  
  
  def test_filter_product_by_attributes(client, product_in_stock):
      product_attr = product_in_stock.product_type.product_attributes.first()
      category = product_in_stock.category
      attr_value = product_attr.values.first()
      filter_by = '%s:%s' % (product_attr.slug, attr_value.slug)
      query = '''
      query {
          category(id: "%(category_id)s") {
              products(attributes: ["%(filter_by)s"]) {
                  edges {
                      node {
                          name
                      }
                  }
              }
          }
      }
      ''' % {
          'category_id': graphene.Node.to_global_id('Category', category.id),
          'filter_by': filter_by}
      response = client.post(reverse('api'), {'query': query})
      content = get_graphql_content(response)
      assert 'errors' not in content
      product_data = content['data']['category']['products']['edges'][0]['node']
      assert product_data['name'] == product_in_stock.name
  
  
  def test_sort_products(client, product_in_stock):
      # set price of the first product
      product_in_stock.price = Money('10.00', 'USD')
      product_in_stock.save()
  
      # create the second product with higher price
      product_in_stock.pk = None
      product_in_stock.price = Money('20.00', 'USD')
      product_in_stock.save()
  
      query = '''
      query {
          products(sortBy: "%(sort_by)s") {
              edges {
                  node {
                      price {
                          amount
                      }
                  }
              }
          }
      }
      '''
  
      asc_price_query = query % {'sort_by': 'price'}
      response = client.post(reverse('api'), {'query': asc_price_query})
      content = get_graphql_content(response)
      assert 'errors' not in content
      product_data = content['data']['products']['edges'][0]['node']
      price_0 = content['data']['products']['edges'][0]['node']['price']['amount']
      price_1 = content['data']['products']['edges'][1]['node']['price']['amount']
      assert price_0 < price_1
  
      desc_price_query = query % {'sort_by': '-price'}
      response = client.post(reverse('api'), {'query': desc_price_query})
      content = get_graphql_content(response)
      assert 'errors' not in content
      product_data = content['data']['products']['edges'][0]['node']
      price_0 = content['data']['products']['edges'][0]['node']['price']['amount']
      price_1 = content['data']['products']['edges'][1]['node']['price']['amount']
      assert price_0 > price_1
  
  
  def test_attributes_query(client, product_in_stock):
      attributes = ProductAttribute.objects.prefetch_related('values')
      query = '''
      query {
          attributes {
              edges {
                  node {
                      id
                      name
                      slug
                      values {
                          id
                          name
                          slug
                      }
                  }
              }
          }
      }
      '''
      response = client.post(reverse('api'), {'query': query})
      content = get_graphql_content(response)
      assert 'errors' not in content
      attributes_data = content['data']['attributes']['edges']
      assert len(attributes_data) == attributes.count()
  
  
  def test_attributes_in_category_query(client, product_in_stock):
      category = Category.objects.first()
      query = '''
      query {
          attributes(inCategory: "%(category_id)s") {
              edges {
                  node {
                      id
                      name
                      slug
                      values {
                          id
                          name
                          slug
                      }
                  }
              }
          }
      }
      ''' % {'category_id': graphene.Node.to_global_id('Category', category.id)}
      response = client.post(reverse('api'), {'query': query})
      content = get_graphql_content(response)
      assert 'errors' not in content
      attributes_data = content['data']['attributes']['edges']
      assert len(attributes_data) == ProductAttribute.objects.count()
  
  
  def test_real_query(client, product_in_stock):
      category = product_in_stock.category
      product_attr = product_in_stock.product_type.product_attributes.first()
      category = product_in_stock.category
      attr_value = product_attr.values.first()
      filter_by = '%s:%s' % (product_attr.slug, attr_value.slug)
      query = '''
      query Root($categoryId: ID!, $sortBy: String, $first: Int, $attributesFilter: [AttributeScalar], $minPrice: Float, $maxPrice: Float) {
          category(id: $categoryId) {
              ...CategoryPageFragmentQuery
              __typename
          }
          attributes(inCategory: $categoryId) {
              edges {
                  node {
                      ...ProductFiltersFragmentQuery
                      __typename
                  }
              }
          }
      }
  
      fragment CategoryPageFragmentQuery on Category {
          id
          name
          url
          ancestors {
              edges {
                  node {
                      name
                      id
                      url
                      __typename
                  }
              }
          }
          children {
              edges {
                  node {
                      name
                      id
                      url
                      slug
                      __typename
                  }
              }
          }
          products(first: $first, sortBy: $sortBy, attributes: $attributesFilter, price_Gte: $minPrice, price_Lte: $maxPrice) {
              ...ProductListFragmentQuery
              __typename
          }
          __typename
      }
  
      fragment ProductListFragmentQuery on ProductCountableConnection {
          edges {
              node {
                  ...ProductFragmentQuery
                  __typename
              }
              __typename
          }
          pageInfo {
              hasNextPage
              __typename
          }
          __typename
      }
  
      fragment ProductFragmentQuery on Product {
          id
          name
          price {
              amount
              currency
              localized
              __typename
          }
          availability {
              ...ProductPriceFragmentQuery
              __typename
          }
          thumbnailUrl1x: thumbnailUrl(size: "255x255")
          thumbnailUrl2x: thumbnailUrl(size: "510x510")
          url
          __typename
      }
  
      fragment ProductPriceFragmentQuery on ProductAvailability {
          available
          discount {
              gross {
                  amount
                  currency
                  __typename
              }
              __typename
          }
          priceRange {
              stop {
                  gross {
                      amount
                      currency
                      localized
                      __typename
                  }
                  currency
                  __typename
              }
              start {
                  gross {
                      amount
                      currency
                      localized
                      __typename
                  }
                  currency
                  __typename
              }
              __typename
          }
          __typename
      }
  
      fragment ProductFiltersFragmentQuery on ProductAttribute {
          id
          name
          slug
          values {
              id
              name
              slug
              color
              __typename
          }
          __typename
      }
      '''
      response = client.post(
          reverse('api'), {
              'query': query,
              'variables': json.dumps(
                  {
                      'categoryId': graphene.Node.to_global_id(
                          'Category', category.id),
                      'sortBy': 'name',
                      'first': 1,
                      'attributesFilter': [filter_by]})})
      content = get_graphql_content(response)
      assert 'errors' not in content
  
  
  def test_page_query(client, page):
      page.is_visible = True
      query = """
      query PageQuery($id: ID!) {
          page(id: $id) {
              title
              slug
          }
      }
      """
      variables = json.dumps({
          'id': graphene.Node.to_global_id('Page', page.id)})
      response = client.post(
          reverse('api'), {'query': query, 'variables': variables})
      content = get_graphql_content(response)
      assert 'errors' not in content
      page_data = content['data']['page']
      assert page_data['title'] == page.title
      assert page_data['slug'] == page.slug
  