Skip to content

Commit

Permalink
New home sidebar integration tests (#5285)
Browse files Browse the repository at this point in the history
* Init test

* base tests

* Improve mocks and fix tests

* Add name check

* Add changeset

* Revert check for name

* Remove comments
  • Loading branch information
poulch committed Nov 29, 2024
1 parent 24691c4 commit 0c2971b
Show file tree
Hide file tree
Showing 12 changed files with 199 additions and 15 deletions.
5 changes: 5 additions & 0 deletions .changeset/nervous-games-change.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"saleor-dashboard": patch
---

Add integration test for new home sidebar
13 changes: 13 additions & 0 deletions src/fragments/orders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -733,3 +733,16 @@ export const fragmentOrderDetailsGrantRefund = gql`
}
}
`;

export const fragmentActivities = gql`
fragment Activities on OrderEvent {
date
email
message
orderNumber
type
user {
email
}
}
`;
12 changes: 12 additions & 0 deletions src/graphql/hooks.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2223,6 +2223,18 @@ ${OrderFulfillmentGrantRefundFragmentDoc}
${MoneyFragmentDoc}
${OrderDetailsGrantedRefundFragmentDoc}
${TransactionItemFragmentDoc}`;
export const ActivitiesFragmentDoc = gql`
fragment Activities on OrderEvent {
date
email
message
orderNumber
type
user {
email
}
}
`;
export const PageTypeFragmentDoc = gql`
fragment PageType on PageType {
id
Expand Down
2 changes: 2 additions & 0 deletions src/graphql/types.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10338,6 +10338,8 @@ export type OrderFulfillmentGrantRefundFragment = { __typename: 'Fulfillment', i

export type OrderDetailsGrantRefundFragment = { __typename: 'Order', id: string, number: string, lines: Array<{ __typename: 'OrderLine', id: string, productName: string, quantity: number, quantityToFulfill: number, variantName: string, thumbnail: { __typename: 'Image', url: string } | null, unitPrice: { __typename: 'TaxedMoney', gross: { __typename: 'Money', amount: number, currency: string } } }>, fulfillments: Array<{ __typename: 'Fulfillment', id: string, fulfillmentOrder: number, status: FulfillmentStatus, lines: Array<{ __typename: 'FulfillmentLine', id: string, quantity: number, orderLine: { __typename: 'OrderLine', id: string, productName: string, quantity: number, quantityToFulfill: number, variantName: string, thumbnail: { __typename: 'Image', url: string } | null, unitPrice: { __typename: 'TaxedMoney', gross: { __typename: 'Money', amount: number, currency: string } } } | null }> | null }>, shippingPrice: { __typename: 'TaxedMoney', gross: { __typename: 'Money', amount: number, currency: string } }, total: { __typename: 'TaxedMoney', gross: { __typename: 'Money', amount: number, currency: string } }, grantedRefunds: Array<{ __typename: 'OrderGrantedRefund', id: string, reason: string | null, shippingCostsIncluded: boolean, status: OrderGrantedRefundStatusEnum, amount: { __typename: 'Money', amount: number, currency: string }, transaction: { __typename: 'TransactionItem', id: string } | null, lines: Array<{ __typename: 'OrderGrantedRefundLine', id: string, quantity: number, reason: string | null, orderLine: { __typename: 'OrderLine', id: string, isShippingRequired: boolean, productName: string, productSku: string | null, isGift: boolean | null, quantity: number, quantityFulfilled: number, quantityToFulfill: number, unitDiscountValue: any, unitDiscountReason: string | null, unitDiscountType: DiscountValueTypeEnum | null, allocations: Array<{ __typename: 'Allocation', id: string, quantity: number, warehouse: { __typename: 'Warehouse', id: string, name: string } }> | null, variant: { __typename: 'ProductVariant', id: string, name: string, quantityAvailable: number | null, preorder: { __typename: 'PreorderData', endDate: any | null } | null, stocks: Array<{ __typename: 'Stock', id: string, quantity: number, quantityAllocated: number, warehouse: { __typename: 'Warehouse', id: string, name: string } }> | null, product: { __typename: 'Product', id: string, isAvailableForPurchase: boolean | null } } | null, totalPrice: { __typename: 'TaxedMoney', net: { __typename: 'Money', amount: number, currency: string }, gross: { __typename: 'Money', amount: number, currency: string } }, unitDiscount: { __typename: 'Money', amount: number, currency: string }, undiscountedUnitPrice: { __typename: 'TaxedMoney', currency: string, gross: { __typename: 'Money', amount: number, currency: string }, net: { __typename: 'Money', amount: number, currency: string } }, unitPrice: { __typename: 'TaxedMoney', gross: { __typename: 'Money', amount: number, currency: string }, net: { __typename: 'Money', amount: number, currency: string } }, thumbnail: { __typename: 'Image', url: string } | null } }> | null }>, transactions: Array<{ __typename: 'TransactionItem', pspReference: string, externalUrl: string, createdAt: any, id: string, name: string, actions: Array<TransactionActionEnum>, events: Array<{ __typename: 'TransactionEvent', externalUrl: string, id: string, pspReference: string, type: TransactionEventTypeEnum | null, message: string, createdAt: any, createdBy: { __typename: 'App', id: string, name: string | null } | { __typename: 'User', id: string, email: string, firstName: string, isActive: boolean, lastName: string, avatar: { __typename: 'Image', url: string } | null } | null, amount: { __typename: 'Money', amount: number, currency: string } }>, authorizedAmount: { __typename: 'Money', amount: number, currency: string }, chargedAmount: { __typename: 'Money', amount: number, currency: string }, refundedAmount: { __typename: 'Money', amount: number, currency: string }, canceledAmount: { __typename: 'Money', amount: number, currency: string }, authorizePendingAmount: { __typename: 'Money', amount: number, currency: string }, chargePendingAmount: { __typename: 'Money', amount: number, currency: string }, refundPendingAmount: { __typename: 'Money', amount: number, currency: string }, cancelPendingAmount: { __typename: 'Money', amount: number, currency: string } }> };

export type ActivitiesFragment = { __typename: 'OrderEvent', date: any | null, email: string | null, message: string | null, orderNumber: string | null, type: OrderEventsEnum | null, user: { __typename: 'User', email: string } | null };

export type PageInfoFragment = { __typename: 'PageInfo', endCursor: string | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor: string | null };

export type PageTypeFragment = { __typename: 'PageType', id: string, name: string, hasPages: boolean | null };
Expand Down
137 changes: 137 additions & 0 deletions src/welcomePage/WelcomePageSidebar/WelcmePageSidebar.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { useUserPermissions } from "@dashboard/auth/hooks/useUserPermissions";
import { channelsList } from "@dashboard/channels/fixtures";
import { ChannelFragment, PermissionEnum } from "@dashboard/graphql";
import { act, render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import React from "react";

import { activities } from "../fixtures";
import { WelcomePageSidebar } from "./WelcomePageSidebar";

jest.mock("@dashboard/auth/hooks/useUserPermissions");
jest.mock("./components/WelcomePageActivities/useWelcomePageActivities", () => ({
useWelcomePageActivities: jest.fn(() => ({ activities, loading: false })),
}));
jest.mock("./components/WelcomePageSalesAnalytics/useWelcomePageSalesAnalytics", () => ({
useWelcomePageSalesAnalytics: jest.fn(() => ({
analytics: {
sales: {
amount: 1000,
currency: "USD",
},
},
loading: false,
})),
}));
jest.mock("./components/WelcomePageStocksAnalytics/useWelcomePageStocksAnalytics", () => ({
useWelcomePageStocksAnalytics: jest.fn(() => ({
analytics: {
productsOutOfStock: 10,
},
loading: false,
})),
}));

jest.mock("react-intl", () => ({
useIntl: jest.fn(() => ({
formatMessage: jest.fn(x => x.defaultMessage),
})),
defineMessages: jest.fn(x => x),
FormattedMessage: ({ defaultMessage }: { defaultMessage: string }) => <>{defaultMessage}</>,
}));

jest.mock("@dashboard/hooks/useNotifier", () => ({
__esModule: true,
default: jest.fn(() => () => undefined),
}));

afterEach(() => {
jest.clearAllMocks();
});

describe("WelcomePageSidebar", () => {
it("should render chanel select, analytics and activities when user has permission to manage orders ", async () => {
// Arrange
(useUserPermissions as jest.Mock).mockReturnValue([{ code: PermissionEnum.MANAGE_ORDERS }]);

const channel = channelsList[0] as ChannelFragment;
const setChannel = jest.fn();

render(
<WelcomePageSidebar
channel={channel}
setChannel={setChannel}
channels={channelsList}
hasPermissionToManageOrders={true}
/>,
);

// Assert
expect(screen.getByTestId("app-channel-select")).toBeInTheDocument();

// Check sales analytics
expect(screen.getByTestId("sales-analytics")).toHaveTextContent("1,000.00");
expect(screen.getByTestId("sales-analytics")).toHaveTextContent("USD");

// Check out-of-stock analytics
expect(screen.getByTestId("out-of-stock-analytics")).toHaveTextContent("10");

// Check activities
expect(screen.getByTestId("activity-card")).toBeInTheDocument();
expect(
screen.getByText("Order #{orderId} was placed from draft by {userEmail}"),
).toBeInTheDocument();
expect(screen.getByText("Order #{orderId} was fully paid")).toBeInTheDocument();
});

it("should render only channel select when user has no permission to manage orders ", async () => {
// Arrange
(useUserPermissions as jest.Mock).mockReturnValue([]);

const channel = channelsList[0] as ChannelFragment;
const setChannel = jest.fn();

render(
<WelcomePageSidebar
channel={channel}
setChannel={setChannel}
channels={channelsList}
hasPermissionToManageOrders={false}
/>,
);

// Assert
expect(screen.getByTestId("app-channel-select")).toBeInTheDocument();
expect(screen.queryByTestId("sales-analytics")).not.toBeInTheDocument();
expect(screen.queryByTestId("out-of-stock-analytics")).not.toBeInTheDocument();
expect(screen.queryByTestId("activity-card")).not.toBeInTheDocument();
});

it("should allow to change channel", async () => {
// Arrange
const channel = channelsList[0] as ChannelFragment;
const setChannel = jest.fn();

render(
<WelcomePageSidebar
channel={channel}
setChannel={setChannel}
channels={channelsList}
hasPermissionToManageOrders={true}
/>,
);

// Act

await act(async () => {
await userEvent.click(screen.getByRole("combobox"));
});

await act(async () => {
await userEvent.click(screen.getAllByTestId("select-option")[1]);
});

// Assert
expect(setChannel).toHaveBeenCalledWith(channelsList[1].id);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import { useIntl } from "react-intl";

import { welcomePageMessages } from "../../messages";
import { WelcomePageAnalyticsCard } from "../WelcomePageAnalyticsCard";
import { useHomeSalesAnalytics } from "./useHomeSalesAnalytics";
import { useWelcomePageSalesAnalytics } from "./useWelcomePageSalesAnalytics";

export const WelcomePageSalesAnalytics = () => {
const intl = useIntl();
const { channel } = useAppChannel();
const noChannel = !channel && typeof channel !== "undefined";
const { analytics, loading, hasError } = useHomeSalesAnalytics();
const { analytics, loading, hasError } = useWelcomePageSalesAnalytics();

return (
<WelcomePageAnalyticsCard
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useWelcomePageAnalyticsQuery } from "@dashboard/graphql";

import { useWelcomePageSidebarContext } from "../../context/welcomePageSidebarContext";

export const useHomeSalesAnalytics = () => {
export const useWelcomePageSalesAnalytics = () => {
const { selectedChannel, hasNoChannels, hasPermissionToManageOrders } =
useWelcomePageSidebarContext();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import { useIntl } from "react-intl";
import { useWelcomePageSidebarContext } from "../../context/welcomePageSidebarContext";
import { welcomePageMessages } from "../../messages";
import { WelcomePageAnalyticsCard } from "../WelcomePageAnalyticsCard";
import { useHomeStocksAnalytics } from "./useHomeStocksAnalytics";
import { useWelcomePageStocksAnalytics } from "./useWelcomePageStocksAnalytics";

export const WelcomePageStocksAnalytics = () => {
const intl = useIntl();
const { hasNoChannels } = useWelcomePageSidebarContext();
const { analytics, loading, hasError } = useHomeStocksAnalytics();
const { analytics, loading, hasError } = useWelcomePageStocksAnalytics();

return (
<WelcomePageAnalyticsCard
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import useAppChannel from "@dashboard/components/AppLayout/AppChannelContext";
import { useWelcomePageNotificationsQuery } from "@dashboard/graphql";

export const useHomeStocksAnalytics = () => {
export const useWelcomePageStocksAnalytics = () => {
const { channel } = useAppChannel();
const noChannel = !channel && typeof channel !== "undefined";

Expand Down
22 changes: 22 additions & 0 deletions src/welcomePage/fixtures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ActivitiesFragment, OrderEventsEnum } from "@dashboard/graphql";

export const activities = [
{
date: "2024-06-17T09:54:02.215733+00:00",
email: null,
message: null,
orderNumber: "3268",
type: OrderEventsEnum.PLACED_FROM_DRAFT,
user: {
email: "renata.gajzlerowicz@saleor.io",
},
},
{
date: "2024-06-17T09:56:22.893415+00:00",
email: null,
message: null,
orderNumber: "3268",
type: OrderEventsEnum.ORDER_FULLY_PAID,
user: null,
},
] as ActivitiesFragment[];
9 changes: 1 addition & 8 deletions src/welcomePage/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,7 @@ export const welcomePageActivities = gql`
activities: homepageEvents(last: 10) @include(if: $hasPermissionToManageOrders) {
edges {
node {
date
email
message
orderNumber
type
user {
email
}
...Activities
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion testUtils/ApolloMockedProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const mocks: MockedResponse[] = [
];

interface ApolloMockedProviderProps {
children: React.ReactNode
children: React.ReactNode;
}

export const ApolloMockedProvider = ({ children }: ApolloMockedProviderProps) => (
Expand Down

0 comments on commit 0c2971b

Please sign in to comment.