Fixing failing Elixir tests - Part 13


VueJS Typescript stutorial

Other articles in the series

  • Making our UI user friendly - Part 15
  • Deploying Phoenix VueJS application using Docker - Part 14
  • Fixing failing Elixir tests - Part 13
  • Adding new features to Order Management - Part 12
  • Add Order Management - Part 11
  • Refactoring and adding tests for Phoenix - Part 10
  • Refactoring VueJS with Typescript- Part 9
  • Add Customer Management - Part 8
  • Writing tests with Jest and Typescript - Part 7
  • Adding Vuex to Vue using Typescript - Part 6
  • Building our Homepage view component - Part 5
  • Add Multi-language support to Vue Typescript - Part 4
  • Generate Vue Typescript Application - Part 3
  • Setting up Models with Ecto and Adding Routing . Part 2
  • Setting up Your Phoenix Application - Part 1
  • Tutorial Series for building a VueJS (Typescript) and Phoenix(Elixir) Shop Management Application - Part 0

  • The backend related code for this post is available here.
    The front-end related code for this post is available at here.

    In this post, we will fix the failing tests. Let’s take a look at a failing test and see how to fix it. Maybe it can also be a bug in our code.

    mix test test/ms/order_management_test.exs

    Consider the below error message.

    test order_items update_order_item/2 with invalid data returns error changeset (Ms.OrderManagementTest)
         test/ms/order_management_test.exs:126
         ** (MatchError) no match of right hand side value: {:error, #Ecto.Changeset<action: :insert, changes: %{amount: 42, order_id: 1973, unit_price: 120.5}, errors: [product_id: {"can't be blank", [validation: :required]}], data: #Ms.OrderManagement.OrderItem<>, valid?: false>}
         code: order_item = order_item_fixture()
         stacktrace:
           test/ms/order_management_test.exs:89: Ms.OrderManagementTest.order_item_fixture/1
           test/ms/order_management_test.exs:127: (test)

    As you can see test complains about missing product_id which is required. This is because our order item requires a reference to a product. In order to fix this lets add a function to build a product, so that its product id can be passed to the order item. So the product fixture in test/ms/order_management_test.exs is as follows.

      @valid_attrs_product %{name: "some name", price: 120.5, stock: 42, tax: 120.5}
    
      def product_fixture(attrs \\ %{}) do
        {:ok, product} =
          attrs
          |> Enum.into(@valid_attrs_product)
          |> InventoryManagement.create_product()
    
        product
      end

    Since we use create_product from InventoryManagement, we need to alias alias Ms.InventoryManagement at the top of the file.

    And now in to our order_item_fixture function add product_id as follows.

      def order_item_fixture(attrs \\ %{}) do
        order = order_fixture()
        product = product_fixture()
        valid_attrs = Map.merge(@valid_attrs, %{"order_id" => order.id, "product_id" => product.id})
        
        {:ok, order_item} =
          attrs
          |> Enum.into(valid_attrs)
          |> OrderManagement.create_order_item()
     
        order_item
      end

    This should fix 6 out of 7 failures, leaving create_order_item with valid data as the only failing one. As you notice the error is the same like before. Fix is similar to previous fixes. Take a look at code to see exactly how.

    Now lets take a look at failing tests in test/ms_web/controllers/order_item_controller_test.exs.

    mix test test/ms_web/controllers/order_item_controller_test.exs
    

    The partial result is as follows.

    test create order_item renders order_item when data is valid (MsWeb.OrderItemControllerTest)
         test/ms_web/controllers/order_item_controller_test.exs:59
         ** (RuntimeError) expected response with status 201, got: 422, with body:
         {"errors":{"product_id":["can't be blank"]}}
         code: assert %{"id" => id} = json_response(conn, 201)["data"]
         stacktrace:
           (phoenix) lib/phoenix/test/conn_test.ex:373: Phoenix.ConnTest.response/2
           (phoenix) lib/phoenix/test/conn_test.ex:419: Phoenix.ConnTest.json_response/2
           test/ms_web/controllers/order_item_controller_test.exs:63: (test)

    The error is similar to previous case, where we lack product_id. Here too we add a function to create a product and an order. See the code below.

    defp create_order(_) do
      order= order_fixture()
      {:ok, order: order}
    end
    
    defp create_product(_) do
      product = product_fixture()
      {:ok, product: product}
    end
    
    @create_attrs_product %{
      name: "some name",
      price: 120.5,
      stock: 42,
      tax: 120.5
    }
    
    def product_fixture() do
      {:ok, product} = InventoryManagement.create_product(@create_attrs_product)
      product
    end

    Also make sure we add alias Ms.InventoryManagement to the top of the file, as we use order_fixture and create_product from Ms.InventoryManagement.

    Now we just change the test as follows.

    describe "create order_item" do
      setup [:create_product, :create_order]
    
      test "renders order_item when data is valid", %{conn: conn, product: product, order: order} do
        create_attrs = Map.merge(@create_attrs_order_item, %{"order_id": order.id, "product_id": product.id})
        conn = post(conn, Routes.order_item_path(conn, :create), order_item: create_attrs)
        assert %{"id" => id} = json_response(conn, 201)["data"]
    
        conn = get(conn, Routes.order_item_path(conn, :show, id))
        assert %{
                 "id" => id,
                 "amount" => 42,
                 "unit_price" => 120.5
               } = json_response(conn, 200)["data"]
      end

    Here the setup [:create_product, :create_order] line says that the result of create_product and create_order is passed as input to the test. In this case it is %{conn: conn, product: product, order: order}. The conn: conn is automatically injected.

    After applying a bit more polish, like renaming attributes to more meaningful names and fixing all compile errors, all our tests will pass. As the code changes are pretty trivial please take a look at the commit.

    That’s all folks for this part. In next part, we will see how to deploy our app to the real world. Stay tuned :)