diff --git a/.changeset/slow-mangos-beg.md b/.changeset/slow-mangos-beg.md
new file mode 100644
index 00000000000..6f64d2be29c
--- /dev/null
+++ b/.changeset/slow-mangos-beg.md
@@ -0,0 +1,5 @@
+---
+"saleor-dashboard": patch
+---
+
+You can now provide 0 variant price value during product creation
diff --git a/src/products/components/ProductVariantPrice/ProductVariantPrice.test.tsx b/src/products/components/ProductVariantPrice/ProductVariantPrice.test.tsx
new file mode 100644
index 00000000000..4c51e89e548
--- /dev/null
+++ b/src/products/components/ProductVariantPrice/ProductVariantPrice.test.tsx
@@ -0,0 +1,87 @@
+import { ChannelData } from "@dashboard/channels/utils";
+import { ThemeWrapper } from "@test/themeWrapper";
+import { fireEvent, render, screen } from "@testing-library/react";
+import React from "react";
+
+import { ProductVariantPrice } from "./ProductVariantPrice";
+
+const wrapper = ({ children }: { children: React.ReactNode }) => (
+ {children}
+);
+
+jest.mock("react-intl", () => ({
+ useIntl: jest.fn(() => ({
+ formatMessage: jest.fn(x => x.defaultMessage),
+ })),
+ defineMessages: jest.fn(x => x),
+ FormattedMessage: ({ defaultMessage }: { defaultMessage: string }) => <>{defaultMessage}>,
+}));
+
+describe("ProductVariantPrice", () => {
+ it("should render not assign info text when variant is not assigned to any channel", () => {
+ // Arrange
+ render(, { wrapper });
+
+ // Assert
+ expect(
+ screen.getByText(
+ "Assign this variant to a channel in the product channel manager to define prices",
+ ),
+ ).toBeInTheDocument();
+ });
+
+ it("should allow to display 0 value", async () => {
+ // Arrange
+ const listing = [
+ {
+ id: "1",
+ currency: "USD",
+ price: 0,
+ preorderThreshold: 0,
+ },
+ ] as unknown as ChannelData[];
+
+ render(, {
+ wrapper,
+ });
+
+ // Assert
+ expect(screen.getByTestId("price-field")).toHaveValue(0);
+ });
+
+ it("should allow to set price value", () => {
+ // Arrange
+ const onChange = jest.fn();
+ const listing = [
+ {
+ id: "1",
+ currency: "USD",
+ price: "",
+ preorderThreshold: 0,
+ },
+ ] as unknown as ChannelData[];
+
+ render(
+ ,
+ {
+ wrapper,
+ },
+ );
+
+ const input = screen.getByTestId("price-field");
+
+ // Act
+ fireEvent.change(input, { target: { value: 0 } });
+
+ // Assert
+ expect(onChange).toHaveBeenCalledWith("1", {
+ price: 0,
+ preorderThreshold: 0,
+ costPrice: undefined,
+ });
+ });
+});
diff --git a/src/products/components/ProductVariantPrice/ProductVariantPrice.tsx b/src/products/components/ProductVariantPrice/ProductVariantPrice.tsx
index 9ae465d92db..495fb7ba7ab 100644
--- a/src/products/components/ProductVariantPrice/ProductVariantPrice.tsx
+++ b/src/products/components/ProductVariantPrice/ProductVariantPrice.tsx
@@ -148,7 +148,7 @@ export const ProductVariantPrice: React.FC = props =>
priceApiError ? getProductErrorMessage(priceApiError, intl) : ""
}
name={fieldName}
- value={listing.price || ""}
+ value={listing.price ?? ""}
currencySymbol={listing.currency}
onChange={e =>
onChange(listing.id, {
@@ -159,6 +159,7 @@ export const ProductVariantPrice: React.FC = props =>
}
disabled={loading}
required
+ data-test-id="price-field"
/>
) : (
@@ -172,7 +173,7 @@ export const ProductVariantPrice: React.FC = props =>
})}
error={!!costPriceError}
name={`${listing.id}-channel-costPrice`}
- value={listing.costPrice || ""}
+ value={listing.costPrice ?? ""}
currencySymbol={listing.currency}
onChange={e =>
onChange(listing.id, {
@@ -183,6 +184,7 @@ export const ProductVariantPrice: React.FC = props =>
}
disabled={loading}
hint={costPriceError ? getProductErrorMessage(costPriceError, intl) : ""}
+ data-test-id="cost-price-field"
/>
) : (