Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[E2E] [TEST] Adding test for a line item refund type #5003

Merged
merged 3 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .changeset/cool-doors-drum.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
"saleor-dashboard": minor
"saleor-dashboard": patch
yellowee marked this conversation as resolved.
Show resolved Hide resolved
---

You can now run e2e tests without flakiness
5 changes: 5 additions & 0 deletions .changeset/stale-students-unite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"saleor-dashboard": minor
---

You can now run E2E tests for refunds
6 changes: 3 additions & 3 deletions .github/actions/prepare-tests-variables/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ runs:
uses: ./.github/actions/prepare-api-variables
with:
MODE: ${{ inputs.MODE }}
VERSION: ${{ inputs.VERSION || ''}}
VERSION: ${{ inputs.VERSION || ''}}

- name: Generate backup
id: backup
uses: ./.github/actions/prepare-backups-variables
Expand All @@ -79,4 +79,4 @@ runs:
echo "::notice title=POOL_INSTANCE::${POOL_INSTANCE}"
echo "::notice title=BACKUP_NAMESPACE::${BACKUP_NAMESPACE}"
echo "::notice title=SNAPSHOT::backup_id=${BACKUP_ID}, version=${BACKUP_VER}, name=${BACKUP_NAME}"
echo "::notice title=SALEOR_CLOUD_SERVICE::${SALEOR_CLOUD_SERVICE}"
echo "::notice title=SALEOR_CLOUD_SERVICE::${SALEOR_CLOUD_SERVICE}"
35 changes: 35 additions & 0 deletions playwright/data/e2eTestData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,41 @@ export const ORDERS = {
orderNotFulfilledToChangeShippingAddress: {
id: "T3JkZXI6ZWFhZjA0MzgtNzkyYi00ZTdlLWIyODUtMTBkMjViMjM0MzRk",
},
fullyPaidOrdersWithSingleTransaction: {
first: {
id: "T3JkZXI6ZjZjZWUxMzItNDk2Zi00MWUyLWJkNTItYTk1MDM1YTVlZmVm",
lineItems: [
{
name: "Bean Juice",
quantity: "1",
},
{ name: "Lake Tunes", quantity: "2" },
],
},
second: {
id: "T3JkZXI6YzI4YjFmYmEtZWU1NS00YmU5LTg5MjktNTMyYzk5MDlkZGVk",
lineItems: ["Blue Hoodie 2", "Black Hoodie", "Mustard Hoodie", "White Hoodie"],
},
},
fullyPaidOrderWithSeveralTransactions: {
id: "T3JkZXI6MTVhYTEwMzYtZWE3OS00MzJiLTliODctNDhlYTMwYmU1NmNl",
},
partiallyPaidOrder: {
id: "T3JkZXI6NmVlMDMwMTctZTViOS00OGNmLWFkYTQtODg4YTQ5MDI3ZjNk",
},
orderWithRefunds: {
id: "T3JkZXI6Y2YyY2EwNWYtZmQ3Yy00ODk5LThjZTktMzQ4NjYxYThjZDkx",
refunds: [
{
lineOrderRefundId: "T3JkZXJHcmFudGVkUmVmdW5kOjE=",
amount: 4.5,
},
{
manualRefundId: "",
amount: 22.0,
},
],
},
};

export const SHIPPING_METHODS = {
Expand Down
21 changes: 21 additions & 0 deletions playwright/pages/dialogs/lineRefundReasonDialog.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { Page } from "@playwright/test";

export class AddLineRefundReasonDialog {
readonly page: Page;

constructor(
page: Page,
readonly lineRefundReasonInput = page.getByTestId("line-refund-reason-input"),
readonly confirmButton = page.getByTestId("confirm-button"),
) {
this.page = page;
}

async provideLineRefundReason(reason: string) {
await this.lineRefundReasonInput.fill(reason);
}

async submitLineRefundReason() {
await this.confirmButton.click();
}
}
24 changes: 24 additions & 0 deletions playwright/pages/dialogs/orderRefundDialog.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { BasePage } from "@pages/basePage";
import { Page } from "@playwright/test";

export class OrderRefundDialog extends BasePage {
constructor(
page: Page,
readonly standardRefund = page.getByTestId("standard-refund"),
readonly manualRefund = page.getByTestId("manual-refund"),
readonly backButton = page.getByTestId("back-button"),
readonly proceedButton = page.getByTestId("proceed-button"),
) {
super(page);
}

async pickLineItemsRefund() {
await this.standardRefund.click();
await this.proceedButton.click();
}

async pickManualRefund() {
await this.manualRefund.click();
await this.proceedButton.click();
}
}
30 changes: 28 additions & 2 deletions playwright/pages/ordersPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { OrderCreateDialog } from "@pages/dialogs/orderCreateDialog";
import { ShippingAddressDialog } from "@pages/dialogs/shippingMethodDialog";
import { Page } from "@playwright/test";

import { OrderRefundDialog } from "./dialogs/orderRefundDialog";

export class OrdersPage extends BasePage {
orderCreateDialog: OrderCreateDialog;

Expand All @@ -29,6 +31,8 @@ export class OrdersPage extends BasePage {

rightSideDetailsPage: RightSideDetailsPage;

orderRefundDialog: OrderRefundDialog;

constructor(
page: Page,
readonly createOrderButton = page.getByTestId("create-order-button"),
Expand All @@ -47,8 +51,12 @@ export class OrdersPage extends BasePage {
readonly salesChannel = page.getByTestId("salesChannel"),
readonly addShippingCarrierLink = page.getByTestId("add-shipping-carrier"),
readonly finalizeButton = page.getByTestId("button-bar-confirm"),

readonly addRefundButton = page.getByTestId("add-new-refund-button"),
readonly customerEmail = page.getByTestId("customer-email"),
readonly orderRefundModal = page.getByTestId("order-refund-dialog"),
readonly orderRefundSection = page.getByTestId("order-refund-section"),
readonly orderRefundList = page.getByTestId("refund-list"),
readonly editRefundButton = page.getByTestId("edit-refund-button"),
) {
super(page);
this.markOrderAsPaidDialog = new MarkOrderAsPaidDialog(page);
Expand All @@ -60,6 +68,7 @@ export class OrdersPage extends BasePage {
this.manualTransactionDialog = new ManualTransactionDialog(page);
this.addTrackingDialog = new AddTrackingDialog(page);
this.rightSideDetailsPage = new RightSideDetailsPage(page);
this.orderRefundDialog = new OrderRefundDialog(page);
}

async clickCreateOrderButton() {
Expand Down Expand Up @@ -104,6 +113,23 @@ export class OrdersPage extends BasePage {

await console.log("Navigating to order details view: " + orderLink);
await this.page.goto(orderLink);
await this.waitForGrid();
await this.waitForDOMToFullyLoad();
}

async clickAddRefundButton() {
await this.addRefundButton.click();
await this.orderRefundModal.waitFor({ state: "visible" });
}

async clickEditRefundButton(refundInfo: string) {
const refund = await this.orderRefundList.locator("tr").filter({ hasText: refundInfo });

await refund.locator(this.editRefundButton).click();
}

async assertRefundOnList(refundInfo: string) {
const refund = await this.orderRefundList.locator("tr").filter({ hasText: refundInfo });

await refund.waitFor({ state: "visible" });
}
}
84 changes: 84 additions & 0 deletions playwright/pages/refundPage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { URL_LIST } from "@data/url";
import { AddLineRefundReasonDialog } from "@pages/dialogs/lineRefundReasonDialog";
import { OrdersPage } from "@pages/ordersPage";
import { expect, Page } from "@playwright/test";

export class RefundPage extends OrdersPage {
addLineRefundReasonDialog: AddLineRefundReasonDialog;

constructor(
page: Page,
readonly allButton = page.getByTestId("all-button"),
readonly productQuantityInput = page.getByTestId("product-quantity-input"),
readonly maxLineRefundQuantity = page.getByTestId("max-line-refund-quantity"),
readonly refundReasonInput = page.getByTestId("refund-reason-input"),
readonly lineRefundReasonDialog = page.getByTestId("refund-reason-dialog"),
readonly lineRefundReasonButton = page.getByTestId("line-refund-reason-button"),
) {
super(page);
this.addLineRefundReasonDialog = new AddLineRefundReasonDialog(page);
}

async getProductRow(productName: string) {
return await this.page.locator("table tr").filter({ hasText: productName });
}

async expectLineItemsRefundPageOpen(orderId: string) {
const orderLink = `${URL_LIST.orders}${orderId}/refund`;

await expect(this.page).toHaveURL(orderLink);
await this.waitForDOMToFullyLoad();
await expect(this.pageHeader).toContainText("Create refund with line items");
}

async expectManualRefundPageOpen(orderId: string) {
const orderLink = `${URL_LIST.orders}${orderId}/manual-refund`;

await expect(this.page).toHaveURL(orderLink);
await expect(this.pageHeader).toContainText("Refund with manual amount");
}

async pickAllProductQuantityToRefund(productName: string) {
const productRow = await this.getProductRow(productName);

await productRow.locator(this.allButton).click();

const maxLineRefundQuantityText = await productRow
.locator(this.maxLineRefundQuantity)
.first()
.innerText();
const value = maxLineRefundQuantityText.slice(-1);

await expect(productRow.locator(this.productQuantityInput)).toHaveValue(value);
}

async provideRefundReason(reason: string) {
await this.refundReasonInput.fill(reason);
}

async clickLineRefundReasonButton(productName: string) {
const productRow = await this.getProductRow(productName);

await productRow.locator(this.lineRefundReasonButton).click();
await this.lineRefundReasonDialog.waitFor({ state: "visible" });
}

async inputProductLineQuantity(productName: string, amount: string) {
const productRow = await this.getProductRow(productName);

await productRow.locator(this.productQuantityInput).fill(amount);
await expect(productRow.locator(this.productQuantityInput)).toHaveValue(amount);
}

async saveDraft() {
await expect(this.saveButton).toHaveText("Save draft");
await this.clickSaveButton();
await this.waitForDOMToFullyLoad();
}

async transferFunds() {
await expect(this.saveButton).toHaveText("Transfer funds");
await this.clickSaveButton();
await this.waitForDOMToFullyLoad();
}
}
36 changes: 36 additions & 0 deletions playwright/tests/orders.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { DraftOrdersPage } from "@pages/draftOrdersPage";
import { AddressForm } from "@pages/forms/addressForm";
import { FulfillmentPage } from "@pages/fulfillmentPage";
import { OrdersPage } from "@pages/ordersPage";
import { RefundPage } from "@pages/refundPage";
import { expect, test } from "@playwright/test";

test.use({ storageState: "./playwright/.auth/admin.json" });
Expand All @@ -16,6 +17,7 @@ let fulfillmentPage: FulfillmentPage;
let addressDialog: AddressDialog;
let addressForm: AddressForm;
let addressesListPage: AddressesListPage;
let refundPage: RefundPage;

test.beforeEach(({ page }) => {
ordersPage = new OrdersPage(page);
Expand All @@ -24,6 +26,7 @@ test.beforeEach(({ page }) => {
addressDialog = new AddressDialog(page);
addressesListPage = new AddressesListPage(page);
addressForm = new AddressForm(page);
refundPage = new RefundPage(page);
});

const variantSKU = PRODUCTS.productAvailableWithTransactionFlow.variant1sku;
Expand Down Expand Up @@ -252,3 +255,36 @@ test("TC: SALEOR_84 Create draft order @e2e @draft", async () => {
await draftOrdersPage.clickFinalizeButton();
await draftOrdersPage.expectSuccessBannerMessage("finalized");
});

test("TC: SALEOR_191 Refund products from the fully paid order @e2e @refunds", async () => {
const order = ORDERS.fullyPaidOrdersWithSingleTransaction.first;

await ordersPage.goToExistingOrderPage(order.id);
await ordersPage.clickAddRefundButton();
await ordersPage.orderRefundDialog.pickLineItemsRefund();
await ordersPage.orderRefundModal.waitFor({ state: "hidden" });
await refundPage.expectLineItemsRefundPageOpen(order.id);
await refundPage.pickAllProductQuantityToRefund(order.lineItems[0].name);

const productRow = await refundPage.getProductRow(order.lineItems[0].name);

expect(productRow.locator(refundPage.productQuantityInput)).toHaveValue(
order.lineItems[0].quantity,
);

const refundReason = "Expectations not met";

await refundPage.inputProductLineQuantity(order.lineItems[1].name, "1");
await refundPage.clickLineRefundReasonButton(order.lineItems[0].name);
await refundPage.addLineRefundReasonDialog.provideLineRefundReason("Item is damaged");
await refundPage.addLineRefundReasonDialog.submitLineRefundReason();
await refundPage.provideRefundReason(refundReason);
await refundPage.saveDraft();
await refundPage.expectSuccessBanner();
await ordersPage.goToExistingOrderPage(order.id);
await ordersPage.orderRefundSection.waitFor({ state: "visible" });
await ordersPage.assertRefundOnList(refundReason);
await ordersPage.clickEditRefundButton(refundReason);
await refundPage.transferFunds();
await refundPage.expectSuccessBannerMessage("Refund has been sent");
});
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export const OrderDetailsRefundLine: React.FC<OrderDetailsRefundLineProps> = ({
<Box display="flex" justifyContent="flex-end">
{isEditable ? (
<Link to={orderTransactionRefundEditUrl(orderId, refund.id)}>
<Button icon={<EditIcon />} variant="secondary" />
<Button data-test-id="edit-refund-button" icon={<EditIcon />} variant="secondary" />
</Link>
) : (
<Tooltip>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,15 @@ export const OrderDetailsRefundTable: React.FC<OrderDetailsRefundTableProps> = (
});

return (
<DashboardCard>
<DashboardCard data-test-id="order-refund-section">
<Box paddingTop={6} display="flex" justifyContent="space-between" paddingX={6}>
<Text size={5} fontWeight="bold">
<FormattedMessage {...refundGridMessages.refundSection} />
</Text>
<Tooltip>
<Tooltip.Trigger>
<Button
data-test-id="add-new-refund-button"
variant="secondary"
onClick={onRefundAdd}
disabled={!isRefundPossible.canRefund}
Expand All @@ -56,7 +57,7 @@ export const OrderDetailsRefundTable: React.FC<OrderDetailsRefundTableProps> = (
)}
</Tooltip>
</Box>
<GridTable height="100%" paddingX={6}>
<GridTable data-test-id="refund-list" height="100%" paddingX={6}>
<GridTable.Colgroup>
<GridTable.Col __width="1%" />
<GridTable.Col __width="10%" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const OrderRefundDialog = ({

return (
<DashboardModal open={open} onChange={onClose}>
<DashboardModal.Content __width="400px">
<DashboardModal.Content __width="400px" data-test-id="order-refund-dialog">
<DashboardModal.Title>
{intl.formatMessage(orderRefundDialogMesages.title)}
</DashboardModal.Title>
Expand Down Expand Up @@ -71,10 +71,13 @@ export const OrderRefundDialog = ({
</Box>
</RadioTiles>
<DashboardModal.Actions>
<Button onClick={onClose} variant="secondary">
<Button onClick={onClose} variant="secondary" data-test-id="back-button">
<Text fontWeight="medium">{intl.formatMessage(buttonMessages.back)}</Text>
</Button>
<Button onClick={selectedRefundType === "standard" ? onStandardRefund : onManualRefund}>
<Button
onClick={selectedRefundType === "standard" ? onStandardRefund : onManualRefund}
data-test-id="proceed-button"
>
<Text fontWeight="medium" color="buttonDefaultPrimary">
{intl.formatMessage(buttonMessages.proceed)}
</Text>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const OrderTransactionReason: React.FC<OrderTransactionReasonProps> = ({
<FormattedMessage {...transactionRefundReasonMessages.reasonForRefund} />
</Text>
<Textarea
data-test-id="refund-reason-input"
placeholder={intl.formatMessage(transactionRefundReasonMessages.optionalPlaceholder)}
size="medium"
rows={4}
Expand Down
Loading
Loading