From a80e264298677c1c8715963e4fca37e5e3e5ccf1 Mon Sep 17 00:00:00 2001 From: Nghia Tran Date: Thu, 17 Oct 2024 15:50:26 +0700 Subject: [PATCH] MOL-477: Add Cypress test + Fix bugs --- .../e2e/method-details-availability.cy.ts | 130 ++++++ .../cypress/fixtures/fetch-project.json | 423 ++++++++++++++++++ .../cypress/fixtures/objects-paginated.json | 11 +- .../availability/details-form.tsx | 9 +- .../method-details/availability/details.tsx | 9 +- .../method-details/availability/list.tsx | 3 +- .../method-details/availability/validate.ts | 4 + application/src/i18n/data/core.json | 1 + application/src/i18n/data/de.json | 1 + application/src/i18n/data/en.json | 1 + application/src/types.ts | 4 +- processor/src/service/payment.service.ts | 2 +- .../tests/service/payment.service.spec.ts | 1 - 13 files changed, 588 insertions(+), 11 deletions(-) create mode 100644 application/cypress/e2e/method-details-availability.cy.ts create mode 100644 application/cypress/fixtures/fetch-project.json diff --git a/application/cypress/e2e/method-details-availability.cy.ts b/application/cypress/e2e/method-details-availability.cy.ts new file mode 100644 index 0000000..8c73003 --- /dev/null +++ b/application/cypress/e2e/method-details-availability.cy.ts @@ -0,0 +1,130 @@ +/// +/// +/// + +import { + entryPointUriPath, + APPLICATION_BASE_ROUTE, +} from '../support/constants'; + +let customObjects; +beforeEach(() => { + cy.loginToMerchantCenter({ + entryPointUriPath, + initialRoute: APPLICATION_BASE_ROUTE, + }); + + cy.fixture('forward-to').then((response) => { + cy.intercept('GET', '/proxy/forward-to', { + statusCode: 200, + body: response, + }); + }); + + cy.fixture('objects-paginated').then((response) => { + customObjects = response; + cy.intercept('/graphql', (req) => { + if (req.body.operationName === 'FetchCustomObjects') { + req.reply({ + data: { + customObjects: { + results: response.results, + count: response.results.length, + offset: 0, + total: response.results.length, + __typename: 'CustomObjectQueryResult', + }, + }, + }); + } else if (req.body.operationName === 'FetchCustomObjectDetails') { + req.reply({ + data: { + customObject: response.results[0], // Should be "Apple Pay" to align with the below test cases + }, + }); + } else { + req.continue(); + } + }); + }); +}); + +describe('Test method details - availability tab', () => { + it('should be fully functional', () => { + const LOCALE = Cypress.env('LOCALE'); + const paymentMethods = 'Apple Pay'; + + cy.findByText(paymentMethods).click(); + cy.url().should('contain', 'general'); + // cy.wait(10000); + // console.log(cy.findAllByLabelText('Availability')); + cy.findByText('Availability').should('exist').click(); + + cy.findByText('EUR'); + cy.findByText('DE'); + cy.findByText(333); + cy.findByText(999); + + // Create new records + cy.findByTestId('availability-add-configuration-button').click(); + + cy.findByTestId('select-country'); + cy.findByTestId('select-currency'); + + // Error message displayed + cy.findByTestId('money-field-minAmount').type('20'); + cy.findByTestId('money-field-maxAmount').type('10'); + cy.findByText('Maximum amount has to be higher then minimum amount.'); + + // Start creating new record + const newAvailability = { + countryCode: 'GB', + currencyCode: 'GBP', + minAmount: 100, + maxAmount: 444, + }; + + cy.findByTestId('money-field-maxAmount').type( + newAvailability.maxAmount.toString() + ); + cy.findByTestId('money-field-minAmount').type( + newAvailability.minAmount.toString() + ); + cy.findByText( + 'Maximum amount has to be higher then minimum amount.' + ).should('not.exist'); + + const updatedPricingConstraints = + customObjects.results[0].value.pricingConstraints ?? []; + updatedPricingConstraints.push(newAvailability); + + let updatedMethodDetailsObject = Object.assign( + {}, + customObjects.results[0] + ); + updatedMethodDetailsObject.value.pricingConstraints = + updatedPricingConstraints; + + cy.intercept('/graphql', (req) => { + if (req.body.operationName === 'UpdateCustomObjectDetails') { + req.reply({ + data: { + createOrUpdateCustomObject: updatedMethodDetailsObject, + }, + }); + } else { + req.continue(); + } + }); + + cy.findByTestId('availability-save-button').click(); + cy.url().should('contain', 'availability'); + + updatedMethodDetailsObject.value.pricingConstraints.forEach((item) => { + cy.findByText(item.countryCode).should('exist'); + cy.findByText(item.currencyCode).should('exist'); + cy.findByText(item.minAmount.toString()).should('exist'); + cy.findByText(item.maxAmount.toString()).should('exist'); + }); + }); +}); diff --git a/application/cypress/fixtures/fetch-project.json b/application/cypress/fixtures/fetch-project.json new file mode 100644 index 0000000..bf40513 --- /dev/null +++ b/application/cypress/fixtures/fetch-project.json @@ -0,0 +1,423 @@ +{ + "data": { + "project": { + "key": "shopm-adv-dev", + "version": 16, + "name": "shopm-adv-dev", + "countries": [ + "GB", + "DE", + "US", + "IT", + "AT", + "PL" + ], + "currencies": [ + "EUR", + "GBP", + "USD", + "PLN" + ], + "languages": [ + "en-GB", + "de-DE", + "en-US", + "de-AT", + "it-IT", + "pl-PL" + ], + "initialized": true, + "expiry": { + "isActive": false, + "daysLeft": 29, + "__typename": "ProjectExpiry" + }, + "suspension": { + "isActive": false, + "reason": null, + "__typename": "ProjectSuspension" + }, + "isProductionProject": false, + "allAppliedPermissions": [ + { + "name": "canViewMollie", + "value": true, + "__typename": "AppliedPermission" + }, + { + "name": "canManageMollie", + "value": true, + "__typename": "AppliedPermission" + } + ], + "allAppliedActionRights": [ + { + "group": "products", + "name": "canAddPrices", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "products", + "name": "canAddProducts", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "products", + "name": "canDeletePrices", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "products", + "name": "canDeleteProducts", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "products", + "name": "canEditPrices", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "products", + "name": "canPublishProducts", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "products", + "name": "canUnpublishProducts", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "products", + "name": "canEditAttributes:all", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "orders", + "name": "canAddOrders", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "orders", + "name": "canAddDiscountCodes", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "orders", + "name": "canCreateReturns", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "quotes", + "name": "canSendQuote", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "quotes", + "name": "canCreateDraftQuote", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "standalonePrices", + "name": "canAddPrices", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "standalonePrices", + "name": "canDeletePrices", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "standalonePrices", + "name": "canEditPrices", + "value": false, + "__typename": "AppliedActionRight" + } + ], + "allAppliedDataFences": [], + "allPermissionsForAllApplications": { + "allAppliedPermissions": [ + { + "name": "canViewMollie", + "value": true, + "__typename": "AppliedPermission" + }, + { + "name": "canManageMollie", + "value": true, + "__typename": "AppliedPermission" + } + ], + "allAppliedActionRights": [ + { + "group": "products", + "name": "canAddPrices", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "products", + "name": "canAddProducts", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "products", + "name": "canDeletePrices", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "products", + "name": "canDeleteProducts", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "products", + "name": "canEditPrices", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "products", + "name": "canPublishProducts", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "products", + "name": "canUnpublishProducts", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "products", + "name": "canEditAttributes:all", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "orders", + "name": "canAddOrders", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "orders", + "name": "canAddDiscountCodes", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "orders", + "name": "canCreateReturns", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "quotes", + "name": "canSendQuote", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "quotes", + "name": "canCreateDraftQuote", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "standalonePrices", + "name": "canAddPrices", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "standalonePrices", + "name": "canDeletePrices", + "value": false, + "__typename": "AppliedActionRight" + }, + { + "group": "standalonePrices", + "name": "canEditPrices", + "value": false, + "__typename": "AppliedActionRight" + } + ], + "allAppliedMenuVisibilities": [ + { + "name": "hideDashboard", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideProductsList", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideModifiedProducts", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideAddProduct", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideProductSelectionsList", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideAddProductSelection", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideDirectAccess", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideCategoriesList", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideCategoriesSearch", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideAddCategory", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideCustomersList", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideAddCustomer", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideCustomerGroupsList", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideAddCustomerGroup", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideBusinessUnitsList", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideAddBusinessUnit", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideOrdersList", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideAddOrder", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideQuotes", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideProductDiscountsList", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideCartDiscountsList", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideDiscountCodesList", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideAddDiscounts", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideGenerateDiscountCodes", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideProjectSettings", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideProductTypes", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideDeveloperSettings", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideStandalonePriceList", + "value": false, + "__typename": "AppliedMenuVisibilities" + }, + { + "name": "hideAddStandalonePrice", + "value": false, + "__typename": "AppliedMenuVisibilities" + } + ], + "allAppliedDataFences": [], + "__typename": "AllPermissionsForAllApplications" + }, + "owner": { + "id": "9adf9042-7177-4ea0-a928-a8e194c63009", + "name": "Shopmacher", + "__typename": "Organization" + }, + "sampleDataImportDataset": "B2CLIFESTYLE", + "isUserAdminOfCurrentProject": true, + "__typename": "Project" + } + } +} \ No newline at end of file diff --git a/application/cypress/fixtures/objects-paginated.json b/application/cypress/fixtures/objects-paginated.json index 4d2a73f..b34e58e 100644 --- a/application/cypress/fixtures/objects-paginated.json +++ b/application/cypress/fixtures/objects-paginated.json @@ -6,6 +6,7 @@ "key": "applepay", "value": { "id": "applepay", + "displayOrder": 2, "name": { "en-GB": "Apple Pay" }, @@ -13,7 +14,15 @@ "en-GB": "" }, "imageUrl": "https://www.mollie.com/external/icons/payment-methods/applepay.svg", - "status": "Inactive" + "status": "Inactive", + "pricingConstraints": [ + { + "currencyCode": "EUR", + "countryCode": "DE", + "minAmount": 333, + "maxAmount": 999 + } + ] }, "__typename": "CustomObject" }, diff --git a/application/src/components/method-details/availability/details-form.tsx b/application/src/components/method-details/availability/details-form.tsx index 8bdef5e..ff08869 100644 --- a/application/src/components/method-details/availability/details-form.tsx +++ b/application/src/components/method-details/availability/details-form.tsx @@ -147,6 +147,7 @@ const AvailabilityDetailsForm = (props: TAvailabilityDetailsFormProps) => { horizontalConstraint={15} controlShouldRenderValue={true} isSearchable={false} + data-testid="select-country" > { horizontalConstraint={15} controlShouldRenderValue={true} isSearchable={false} + data-testid="select-currency" > { @@ -206,6 +209,7 @@ const AvailabilityDetailsForm = (props: TAvailabilityDetailsFormProps) => { /> { @@ -222,7 +226,8 @@ const AvailabilityDetailsForm = (props: TAvailabilityDetailsFormProps) => { : projectCurrencies } value={{ - amount: formik.values[selectedCountry][selectedCurrency].maxAmount, + amount: + formik.values[selectedCountry][selectedCurrency].maxAmount ?? '', currencyCode: selectedCurrency, }} onChange={(event) => { @@ -248,7 +253,7 @@ const AvailabilityDetailsForm = (props: TAvailabilityDetailsFormProps) => { }} renderError={(errorKey) => { if (errorKey === 'invalidValue') { - return intl.formatMessage(messages.fieldMethodNameInvalidLength); + return intl.formatMessage(messages.fieldMaxAmountInvalidValue); } return null; }} diff --git a/application/src/components/method-details/availability/details.tsx b/application/src/components/method-details/availability/details.tsx index bb6e6e9..8e9d087 100644 --- a/application/src/components/method-details/availability/details.tsx +++ b/application/src/components/method-details/availability/details.tsx @@ -76,7 +76,7 @@ const AvailabilityDetails = (props: TAvailabilityDetailFormProps) => { // Set the currency object with min and max amount acc[countryCode][currencyCode] = { minAmount: minAmount.toString(), - maxAmount: maxAmount.toString(), + maxAmount: maxAmount?.toString(), }; return acc; @@ -125,7 +125,7 @@ const AvailabilityDetails = (props: TAvailabilityDetailFormProps) => { Object.entries(currencies ?? {}).forEach( ([currency, { minAmount, maxAmount }]) => { const nMinAmount = convertCurrencyStringToNumber(minAmount); - const nMaxAmount = convertCurrencyStringToNumber(maxAmount); + const nMaxAmount = convertCurrencyStringToNumber(maxAmount ?? ''); if (nMinAmount === 0 && nMaxAmount === 0) return; @@ -133,7 +133,7 @@ const AvailabilityDetails = (props: TAvailabilityDetailFormProps) => { countryCode: country, currencyCode: currency, minAmount: nMinAmount, - maxAmount: nMaxAmount, + maxAmount: nMaxAmount > 0 ? nMaxAmount : undefined, }); } ); @@ -224,6 +224,9 @@ const AvailabilityDetails = (props: TAvailabilityDetailFormProps) => { formProps.submitForm(); }} isDisabled={!props?.identifier?.countryCode} + dataAttributes={{ + 'data-testid': 'availability-delete-button', + }} /> } diff --git a/application/src/components/method-details/availability/list.tsx b/application/src/components/method-details/availability/list.tsx index 0711313..d8d5920 100644 --- a/application/src/components/method-details/availability/list.tsx +++ b/application/src/components/method-details/availability/list.tsx @@ -120,6 +120,7 @@ const AvailabilityList = (props: TCustomObjectDetailsFormProps) => { formModalState.openModal(); }} isDisabled={false} + data-testid="availability-add-configuration-button" /> {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */} @@ -133,7 +134,7 @@ const AvailabilityList = (props: TCustomObjectDetailsFormProps) => { case 'currencyCode': return item.currencyCode ?? ''; case 'maxAmount': - return item.maxAmount; + return item?.maxAmount ?? ''; case 'minAmount': return item.minAmount; case 'countryCode': diff --git a/application/src/components/method-details/availability/validate.ts b/application/src/components/method-details/availability/validate.ts index ec5914e..71ca4d9 100644 --- a/application/src/components/method-details/availability/validate.ts +++ b/application/src/components/method-details/availability/validate.ts @@ -21,6 +21,10 @@ const validate = ( for (const currencies of Object.values(formikValues)) { for (const { minAmount, maxAmount } of Object.values(currencies)) { + if (maxAmount === '') { + continue; + } + const nMinAmount = convertCurrencyStringToNumber(minAmount); const nMaxAmount = convertCurrencyStringToNumber(maxAmount); diff --git a/application/src/i18n/data/core.json b/application/src/i18n/data/core.json index 784afcf..8181045 100644 --- a/application/src/i18n/data/core.json +++ b/application/src/i18n/data/core.json @@ -18,6 +18,7 @@ "MethodDetails.Availability.headerMaxAmount": "Max amount", "MethodDetails.Availability.headerMinAmount": "Min amount", "MethodDetails.Availability.headerSurchargeCost": "Surcharge transaction cost", + "MethodDetails.fieldMaxAmountInvalidValue": "Maximum amount has to be higher then minimum amount.", "MethodDetails.fieldMethodDescription": "Payment description", "MethodDetails.fieldMethodDescriptionDescription": "Describe payment method in their corresponding locals.", "MethodDetails.fieldMethodDescriptionInvalidLength": "Maximum 100 characters allowed.", diff --git a/application/src/i18n/data/de.json b/application/src/i18n/data/de.json index 784afcf..8181045 100644 --- a/application/src/i18n/data/de.json +++ b/application/src/i18n/data/de.json @@ -18,6 +18,7 @@ "MethodDetails.Availability.headerMaxAmount": "Max amount", "MethodDetails.Availability.headerMinAmount": "Min amount", "MethodDetails.Availability.headerSurchargeCost": "Surcharge transaction cost", + "MethodDetails.fieldMaxAmountInvalidValue": "Maximum amount has to be higher then minimum amount.", "MethodDetails.fieldMethodDescription": "Payment description", "MethodDetails.fieldMethodDescriptionDescription": "Describe payment method in their corresponding locals.", "MethodDetails.fieldMethodDescriptionInvalidLength": "Maximum 100 characters allowed.", diff --git a/application/src/i18n/data/en.json b/application/src/i18n/data/en.json index 784afcf..8181045 100644 --- a/application/src/i18n/data/en.json +++ b/application/src/i18n/data/en.json @@ -18,6 +18,7 @@ "MethodDetails.Availability.headerMaxAmount": "Max amount", "MethodDetails.Availability.headerMinAmount": "Min amount", "MethodDetails.Availability.headerSurchargeCost": "Surcharge transaction cost", + "MethodDetails.fieldMaxAmountInvalidValue": "Maximum amount has to be higher then minimum amount.", "MethodDetails.fieldMethodDescription": "Payment description", "MethodDetails.fieldMethodDescriptionDescription": "Describe payment method in their corresponding locals.", "MethodDetails.fieldMethodDescriptionInvalidLength": "Maximum 100 characters allowed.", diff --git a/application/src/types.ts b/application/src/types.ts index a797812..a8164df 100644 --- a/application/src/types.ts +++ b/application/src/types.ts @@ -42,7 +42,7 @@ export type TAvailabilityObjectValueFormValues = { export type TAvailabilityAmount = { minAmount: string; - maxAmount: string; + maxAmount?: string; }; export type TAmountPerCurrency = { @@ -58,7 +58,7 @@ export type TPricingConstraintItem = { countryCode: string; currencyCode: string; minAmount: number; - maxAmount: number; + maxAmount?: number; surchargeCost?: string; }; diff --git a/processor/src/service/payment.service.ts b/processor/src/service/payment.service.ts index c005402..aae4221 100644 --- a/processor/src/service/payment.service.ts +++ b/processor/src/service/payment.service.ts @@ -75,7 +75,7 @@ type PricingConstraintItem = { countryCode: string; currencyCode: string; minAmount: number; - maxAmount: number; + maxAmount?: number; surchargeCost?: string; }; diff --git a/processor/tests/service/payment.service.spec.ts b/processor/tests/service/payment.service.spec.ts index 15624b9..a6730ee 100644 --- a/processor/tests/service/payment.service.spec.ts +++ b/processor/tests/service/payment.service.spec.ts @@ -285,7 +285,6 @@ describe('Test listPaymentMethodsByPayment', () => { currencyCode: 'EUR', countryCode: 'DE', minAmount: 1000, - maxAmount: 300000, surchargeCost: '2%', }, ],