openfoodfoundation/openfoodnetwork

View on GitHub
engines/dfc_provider/spec/services/supplied_product_builder_spec.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

require_relative "../spec_helper"

RSpec.describe SuppliedProductBuilder do
  include FileHelper

  subject(:builder) { described_class }
  let(:variant) {
    build(:variant, id: 5, product: spree_product, primary_taxon: taxon)
  }
  let(:spree_product) {
    create(:product, id: 6, supplier:)
  }
  let(:supplier) {
    build(:supplier_enterprise, id: 7)
  }
  let(:taxon) {
    build(
      :taxon,
      name: "Soft Drink",
      dfc_id: "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/productTypes.rdf#soft-drink"
    )
  }

  describe ".supplied_product" do
    it "assigns a semantic id" do
      product = builder.supplied_product(variant)

      expect(product.semanticId).to eq(
        "http://test.host/api/dfc/enterprises/7/supplied_products/5"
      )
    end

    it "assigns a quantity" do
      product = builder.supplied_product(variant)

      expect(product.quantity.value).to eq 1.0
      expect(product.quantity.unit.semanticId).to eq "dfc-m:Gram"
    end

    it "assigns the product name by default" do
      variant.product.name = "Apple"
      product = builder.supplied_product(variant)

      expect(product.name).to eq "Apple"
    end

    it "assigns the variant name if present" do
      variant.product.name = "Apple"
      variant.display_name = "Granny Smith"
      product = builder.supplied_product(variant)

      expect(product.name).to eq "Apple - Granny Smith"
    end

    context "product_type mapping" do
      subject(:product) { builder.supplied_product(variant) }

      it "assigns a product type" do
        soft_drink = DfcLoader.connector.PRODUCT_TYPES.DRINK.SOFT_DRINK

        expect(product.productType).to eq soft_drink
      end
    end

    it "assigns an image_url type" do
      Spree::Image.create!(
        attachment: white_logo_file,
        viewable_id: variant.product.id,
        viewable_type: 'Spree::Product'
      )
      product = builder.supplied_product(variant)

      expect(product.image).to eq variant.product.image.url(:product)
    end

    it "assigns the product uri" do
      product = builder.supplied_product(variant)

      expect(product.spree_product_uri).to eq(
        "http://test.host/api/dfc/enterprises/7?spree_product_id=6"
      )
    end
  end

  describe ".import_product" do
    let(:supplied_product) do
      DataFoodConsortium::Connector::SuppliedProduct.new(
        "https://example.net/tomato",
        name: "Tomato",
        description: "Awesome tomato",
        quantity: DataFoodConsortium::Connector::QuantitativeValue.new(
          unit: DfcLoader.connector.MEASURES.KILOGRAM,
          value: 2,
        ),
        productType: product_type,
      )
    end
    let(:product_type) { DfcLoader.connector.PRODUCT_TYPES.VEGETABLE.NON_LOCAL_VEGETABLE }
    let!(:taxon) {
      create(
        :taxon,
        name: "Non local vegetable",
        dfc_id: "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/productTypes.rdf#non-local-vegetable"
      )
    }

    it "creates a new Spree::Product" do
      product = builder.import_product(supplied_product)

      expect(product).to be_a(Spree::Product)
      expect(product.name).to eq("Tomato")
      expect(product.description).to eq("Awesome tomato")
      expect(product.variant_unit).to eq("weight")
    end

    describe "taxon" do
      it "assigns the taxon matching the DFC product type" do
        product = builder.import_product(supplied_product)

        expect(product.variants.first.primary_taxon).to eq(taxon)
      end
    end
  end

  describe ".import_variant" do
    let(:imported_variant) { builder.import_variant(supplied_product, supplier) }
    let(:supplied_product) do
      DfcProvider::SuppliedProduct.new(
        "https://example.net/tomato",
        name: "Tomato",
        description: "Awesome tomato",
        quantity: DataFoodConsortium::Connector::QuantitativeValue.new(
          unit: DfcLoader.connector.MEASURES.KILOGRAM,
          value: 2,
        ),
        productType: product_type,
      )
    end
    let(:product_type) { DfcLoader.connector.PRODUCT_TYPES.VEGETABLE.NON_LOCAL_VEGETABLE }

    it "creates a new Spree::Product and variant" do
      create(:taxon)

      expect(imported_variant).to be_a(Spree::Variant)
      expect(imported_variant).to be_valid
      expect(imported_variant.id).to be_nil
      expect(imported_variant.semantic_links.size).to eq 1

      link = imported_variant.semantic_links[0]
      expect(link.semantic_id).to eq "https://example.net/tomato"

      imported_product = imported_variant.product
      expect(imported_product).to be_a(Spree::Product)
      expect(imported_product).to be_valid
      expect(imported_product.id).to be_nil
      expect(imported_product.name).to eq("Tomato")
      expect(imported_product.description).to eq("Awesome tomato")
      expect(imported_product.variant_unit).to eq("weight")
    end

    context "with spree_product_id supplied" do
      let(:imported_variant) { builder.import_variant(supplied_product, supplier) }

      let(:supplied_product) do
        DfcProvider::SuppliedProduct.new(
          "https://example.net/tomato",
          name: "Tomato",
          description: "Better Awesome tomato",
          quantity: DataFoodConsortium::Connector::QuantitativeValue.new(
            unit: DfcLoader.connector.MEASURES.KILOGRAM,
            value: 2,
          ),
          productType: product_type,
          spree_product_id: variant.product.id
        )
      end
      let(:product_type) { DfcLoader.connector.PRODUCT_TYPES.DRINK.SOFT_DRINK }
      let!(:new_taxon) {
        create(
          :taxon,
          name: "Soft Drink",
          dfc_id: "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/productTypes.rdf#soft-drink"
        )
      }

      it "update an existing Spree::Product" do
        imported_product = imported_variant.product
        expect(imported_product.id).to eq(spree_product.id)
        expect(imported_product.description).to eq("Better Awesome tomato")
        expect(imported_variant.primary_taxon).to eq(new_taxon)
      end

      context "when spree_product_uri doesn't match the server host" do
        let(:supplied_product) do
          DfcProvider::SuppliedProduct.new(
            "https://example.net/tomato",
            name: "Tomato",
            description: "Awesome tomato",
            quantity: DataFoodConsortium::Connector::QuantitativeValue.new(
              unit: DfcLoader.connector.MEASURES.KILOGRAM,
              value: 2,
            ),
            productType: product_type,
            spree_product_uri: "http://another.host/api/dfc/enterprises/10/supplied_products/50"
          )
        end

        it "creates a new Spree::Product and variant" do
          expect(imported_variant).to be_a(Spree::Variant)
          expect(imported_variant.id).to be_nil

          imported_product = imported_variant.product
          expect(imported_product).to be_a(Spree::Product)
          expect(imported_product.id).to be_nil
          expect(imported_product.name).to eq("Tomato")
          expect(imported_product.description).to eq("Awesome tomato")
          expect(imported_product.variant_unit).to eq("weight")
        end
      end
    end
  end

  describe ".referenced_spree_product" do
    let(:result) { builder.referenced_spree_product(supplied_product, supplier) }
    let(:supplied_product) do
      DfcProvider::SuppliedProduct.new(
        "https://example.net/tomato",
        name: "Tomato",
      )
    end

    it "returns nil when no reference is given" do
      expect(result).to eq nil
    end

    it "returns a product referenced by URI" do
      variant.save!
      supplied_product.spree_product_uri =
        "http://test.host/api/dfc/enterprises/7?spree_product_id=6"
      expect(result).to eq spree_product
    end

    it "doesn't return a product of another enterprise" do
      variant.save!
      create(:product, id: 8, supplier: create(:enterprise))

      supplied_product.spree_product_uri =
        "http://test.host/api/dfc/enterprises/7?spree_product_id=8"
      expect(result).to eq nil
    end

    it "doesn't return a foreign product referenced by URI" do
      variant.save!
      supplied_product.spree_product_uri =
        "http://another.host/api/dfc/enterprises/7?spree_product_id=6"
      expect(result).to eq nil
    end

    it "returns a product referenced by id" do
      variant.save!
      supplied_product.spree_product_id = "6"
      expect(result).to eq spree_product
    end
  end
end