From d96222c7a8bd16ad0ad02cf2985844cc2d68e622 Mon Sep 17 00:00:00 2001 From: shashwata Halder Date: Fri, 1 Nov 2024 10:35:18 +0600 Subject: [PATCH] add live chat module tests (#2426) * Add live chat settings * Add action secret reference * Fix live chat tests * Fix pr reviews --- tests/pw/feature-map/feature-map.yml | 19 +++-- tests/pw/pages/basePage.ts | 14 +++- tests/pw/pages/liveChatPage.ts | 94 +++++++++++++++++++++++ tests/pw/pages/productsPage.ts | 2 +- tests/pw/pages/selectors.ts | 81 ++++++++++++------- tests/pw/pages/settingsPage.ts | 24 ++++++ tests/pw/pages/singleProductPage.ts | 2 +- tests/pw/pages/singleStorePage.ts | 2 +- tests/pw/pages/storeSupportsPage.ts | 2 +- tests/pw/pages/vendorSettingsPage.ts | 9 +++ tests/pw/tests/e2e/_env.setup.ts | 4 + tests/pw/tests/e2e/liveChat.spec.ts | 78 +++++++++++++++++++ tests/pw/tests/e2e/settings.spec.ts | 4 + tests/pw/tests/e2e/vendorSettings.spec.ts | 4 + tests/pw/types/environment.d.ts | 2 + tests/pw/utils/dbData.ts | 15 ++-- tests/pw/utils/interfaces.ts | 14 ++++ tests/pw/utils/testData.ts | 28 ++++++- 18 files changed, 346 insertions(+), 52 deletions(-) create mode 100644 tests/pw/pages/liveChatPage.ts create mode 100644 tests/pw/tests/e2e/liveChat.spec.ts diff --git a/tests/pw/feature-map/feature-map.yml b/tests/pw/feature-map/feature-map.yml index 31adab7382..b5cb1cb49c 100644 --- a/tests/pw/feature-map/feature-map.yml +++ b/tests/pw/feature-map/feature-map.yml @@ -486,6 +486,7 @@ admin can set Dokan social api settings: true admin can set Dokan shipping status settings: true admin can set Dokan quote settings: true + admin can set Dokan live chat settings: true admin can set Dokan rma settings: true admin can set Dokan wholesale settings: true admin can set Dokan eu compliance settings: true @@ -762,16 +763,18 @@ - page: 'Live Chat' features: admin: - admin can set chat provider: false - admin can enable chat button on vendor page: false - admin can enable chat button on product page: false + # admin can set Dokan live chat settings [duplicate]: true + admin can enable chat button on vendor page: true + admin can disable chat button on vendor page: true + admin can enable chat button on product page (above_tab): true + admin can enable chat button on product page (inside_tab): true + admin can disable chat button on product page: true vendor: - # vendor can set live chat settings [duplicate]: false - vendor can set inbox menu page: false - vendor can view inbox menu page: false - vendor can chat with customer: false + # vendor can set live chat settings [duplicate]: true + vendor can view inbox menu page: true + vendor can reply to customer message: true customer: - customer can chat with vendor: false + customer can send message to vendor: true - page: 'Live Search' features: diff --git a/tests/pw/pages/basePage.ts b/tests/pw/pages/basePage.ts index ab8caba65d..347183cf8f 100644 --- a/tests/pw/pages/basePage.ts +++ b/tests/pw/pages/basePage.ts @@ -977,6 +977,12 @@ export class BasePage { // await locator.pressSequentially(text); } + async clickFrameSelectorAndWaitForResponse(frame: string, subUrl: string, frameSelector: string, code = 200): Promise { + const locator = this.page.frameLocator(frame).locator(frameSelector); + const [response] = await Promise.all([this.page.waitForResponse(resp => resp.url().includes(subUrl) && resp.status() === code), locator.click()]); + return response; + } + /** * Locator methods [using playwright locator class] */ @@ -1553,7 +1559,13 @@ export class BasePage { }, options); } - // assert element to contain text + // assert frame element to be visible + async toBeVisibleFrameLocator(frame: string, frameSelector: string, options?: { timeout?: number; visible?: boolean } | undefined) { + const locator = this.page.frameLocator(frame).locator(frameSelector); + await expect(locator).toBeVisible(options); + } + + // assert frame element to contain text async toContainTextFrameLocator(frame: string, frameSelector: string, text: string | RegExp, options?: { timeout?: number; intervals?: number[] }): Promise { await this.toPass(async () => { const locator = this.page.frameLocator(frame).locator(frameSelector); diff --git a/tests/pw/pages/liveChatPage.ts b/tests/pw/pages/liveChatPage.ts new file mode 100644 index 0000000000..040bc8abbd --- /dev/null +++ b/tests/pw/pages/liveChatPage.ts @@ -0,0 +1,94 @@ +import { Page } from '@playwright/test'; +import { BasePage } from '@pages/basePage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { helpers } from '@utils/helpers'; + +// selectors +const liveChatVendor = selector.vendor.vInbox; +const liveChatCustomer = selector.customer.cLiveChat; +const singleStoreCustomer = selector.customer.cSingleStore; +const singleProductCustomer = selector.customer.cSingleProduct; + +export class LiveChatPage extends BasePage { + constructor(page: Page) { + super(page); + } + + async gotoSingleStore(storeName: string, force = false): Promise { + await this.goIfNotThere(data.subUrls.frontend.vendorDetails(helpers.slugify(storeName)), 'networkidle', force); + } + + async goToProductDetails(productName: string, force = false): Promise { + await this.goIfNotThere(data.subUrls.frontend.productDetails(helpers.slugify(productName)), 'domcontentloaded', force); + } + + // vendor + + // vendor inbox render properly + async vendorInboxRenderProperly(): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.inbox); + + // chat persons, chat box, chat text box, send button is visible + await this.toBeVisibleFrameLocator(liveChatVendor.liveChatIframe, liveChatVendor.chatPersons); + await this.toBeVisibleFrameLocator(liveChatVendor.liveChatIframe, liveChatVendor.chatBox); + await this.toBeVisibleFrameLocator(liveChatVendor.liveChatIframe, liveChatVendor.chatTextBox); + await this.toBeVisibleFrameLocator(liveChatVendor.liveChatIframe, liveChatVendor.sendButton); + } + + // vendor send message to customer + async sendMessageToCustomer(chatPerson: string, message: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.inbox); + await this.clickFrameSelector(liveChatVendor.liveChatIframe, liveChatVendor.chatPerson(chatPerson)); + await this.typeFrameSelector(liveChatVendor.liveChatIframe, liveChatVendor.chatTextBox, message); + await this.clickFrameSelectorAndWaitForResponse(liveChatVendor.liveChatIframe, data.subUrls.frontend.talkjs, liveChatVendor.sendButton); + await this.toBeVisibleFrameLocator(liveChatVendor.liveChatIframe, liveChatVendor.sentMessage(message)); + } + + // customer + + // customer send message to vendor + async sendMessageToVendor(storename: string, message: string): Promise { + await this.gotoSingleStore(storename, true); + await this.click(singleStoreCustomer.storeTabs.chatNow); + await this.toBeVisible(liveChatCustomer.liveChatIframe); + await this.typeFrameSelector(liveChatCustomer.liveChatIframe, liveChatCustomer.chatTextBox, message); + await this.clickFrameSelectorAndWaitForResponse(liveChatCustomer.liveChatIframe, data.subUrls.frontend.talkjs, liveChatCustomer.sendButton); + await this.toBeVisibleFrameLocator(liveChatCustomer.liveChatIframe, liveChatCustomer.sentMessage(message)); + } + + // view chat button on vendor page + async viewLiveChatButtonOnStore(storename: string, disable = false): Promise { + await this.gotoSingleStore(storename, true); + if (!disable) { + await this.toBeVisible(singleStoreCustomer.storeTabs.chatNow); + } else { + await this.notToBeVisible(singleStoreCustomer.storeTabs.chatNow); + } + } + + // view chat button on product page + async viewLiveChatButtonOnProduct(productName: string, option: 'above-tab' | 'inside-tab' | 'dont-show'): Promise { + await this.goToProductDetails(productName, true); + + switch (option) { + case 'above-tab': + await this.toBeVisible(singleProductCustomer.productDetails.chatNow); + break; + + case 'inside-tab': + await this.click(singleProductCustomer.menus.vendorInfo); + await this.toBeVisible(singleProductCustomer.productDetails.chatNow); + break; + + case 'dont-show': + await this.notToBeVisible(singleProductCustomer.productDetails.chatNow); + await this.click(singleProductCustomer.menus.vendorInfo); + await this.notToBeVisible(singleProductCustomer.productDetails.chatNow); + break; + + default: + break; + } + } +} diff --git a/tests/pw/pages/productsPage.ts b/tests/pw/pages/productsPage.ts index 5c6877e3e2..e983387b5c 100644 --- a/tests/pw/pages/productsPage.ts +++ b/tests/pw/pages/productsPage.ts @@ -680,7 +680,7 @@ export class ProductsPage extends AdminPage { await this.hover(productsVendor.productCell(productName)); await this.clickAndWaitForLoadState(productsVendor.view(productName)); await expect(this.page).toHaveURL(data.subUrls.frontend.productDetails(helpers.slugify(productName)) + '/'); - const { quantity, addToCart, viewCart, euComplianceData, productAddedSuccessMessage, productWithQuantityAddedSuccessMessage, ...productDetails } = selector.customer.cSingleProduct.productDetails; + const { quantity, addToCart, viewCart, chatNow, euComplianceData, productAddedSuccessMessage, productWithQuantityAddedSuccessMessage, ...productDetails } = selector.customer.cSingleProduct.productDetails; await this.multipleElementVisible(productDetails); } diff --git a/tests/pw/pages/selectors.ts b/tests/pw/pages/selectors.ts index 80dc91f7f3..563ea4ae8c 100644 --- a/tests/pw/pages/selectors.ts +++ b/tests/pw/pages/selectors.ts @@ -2417,25 +2417,22 @@ export const selector = { // Live Chat liveChat: { - enableLiveChat: '#dokan_live_chat\\[enable\\]', - chatProviderFacebookMessenger: '#dokan_live_chat\\[provider\\]\\[messenger\\]', - chatProviderTalkJs: '#dokan_live_chat\\[provider\\]\\[talkjs\\]', - chatProviderTawkTo: '#dokan_live_chat\\[provider\\]\\[tawkto\\]', - chatProviderWhatsApp: '#dokan_live_chat\\[provider\\]\\[whatsapp\\]', + enableLiveChat: '//label[@for="dokan_live_chat[enable]"]', + chatProvider: (provider: string) => `//label[contains(@for,'${provider}-provider')]`, // Fb - messengerColor: '.button > span', + messengerColor: 'div.color-picker-container span.dashicons', // Talkjs - talkJsAppId: '#dokan_live_chat\\[app_id\\]', - talkJsAppSecret: '#dokan_live_chat\\[app_secret\\]', + talkJsAppId: 'input#dokan_live_chat\\[app_id\\]', + talkJsAppSecret: 'input#dokan_live_chat\\[app_secret\\]', // Whatsapp - openingPattern: '#dokan_live_chat\\[wa_opening_method\\]', - preFilledMessage: '#dokan_live_chat\\[wa_pre_filled_message\\]', + openingPattern: 'select#dokan_live_chat\\[wa_opening_method\\]', + preFilledMessage: 'textarea#dokan_live_chat\\[wa_pre_filled_message\\]', // Chat Button - chatButtonOnVendorPage: '#dokan_live_chat\\[chat_button_seller_page\\]', + chatButtonOnVendorPage: '//label[@for="dokan_live_chat[chat_button_seller_page]"]', chatButtonOnProductPage: '#dokan_live_chat\\[chat_button_product_page\\]', liveChatSaveChanges: '#submit', }, @@ -5913,7 +5910,7 @@ export const selector = { }, }, - // Settings + // settings vSettings: { store: '.store > a', addons: '.product-addon > a', @@ -5927,12 +5924,25 @@ export const selector = { storeSEO: '.seo > a', }, - // Store Settings + // inbox + vInbox: { + chatPersons: 'div#hub', + chatPerson: (personName: string) => `//div[@class="ConversationListItem__conversation-name" and normalize-space(text())="${personName}"]/../../..`, + liveChatIframe: '(//iframe[@name="____talkjs__chat__ui_internal"])[last()]', + liveChatLauncher: 'a#__talkjs_launcher', + + chatBox: 'div#chat-box', + chatTextBox: '//div[@role="textbox"]', + sendButton: 'button.send-button', + sentMessage: (message: string) => `//div[@id="chat-box"]//span[@class="EntityTreeRenderer" and normalize-space(text())="${message}"]`, + }, + + // store settings vStoreSettings: { settingsText: '.dokan-settings-content h1', visitStore: '//a[normalize-space()="Visit Store"]', - // Wp Image Upload + // wp image upload wpUploadFiles: '#menu-item-upload', uploadedMedia: '.attachment-preview', selectFiles: '//div[@class="supports-drag-drop" and @style="position: relative;"]//button[@class="browser button button-hero"]', @@ -5950,7 +5960,7 @@ export const selector = { uploadedProfilePicture: 'div#dokan-profile-picture-wrapper div.gravatar-wrap', removeProfilePictureImage: '.dokan-close.dokan-remove-gravatar-image', - // Basic Store Info + // basic store Info storeName: '#dokan_store_name', phoneNo: '#setting_phone', @@ -5967,7 +5977,7 @@ export const selector = { editLocation: '.store-pickup-location-edit-btn', locationName: '#store-location-name-input', - // Address + // address address: { street: '#dokan_address\\[street_1\\]', street2: '#dokan_address\\[street_2\\]', @@ -5980,7 +5990,7 @@ export const selector = { deleteSaveLocation: '.store-pickup-location-delete-btn', }, - // Company Info + // company info companyInfo: { companyName: '#settings_dokan_company_name', companyId: '#settings_dokan_company_id_number', @@ -5989,18 +5999,18 @@ export const selector = { bankIban: '#setting_bank_iban', }, - // Email + // email email: '//label[contains(text(), "Email")]/..//input[@type="checkbox"]', - // Map + // map map: '#dokan-map-add', - // Terms and Conditions + // terms and conditions termsAndConditions: '//label[contains(text(), "Terms and Conditions")]/..//input[@type="checkbox"]', termsAndConditionsIframe: '#dokan_tnc_text iframe', termsAndConditionsHtmlBody: '#tinymce', - // Store Opening Closing Time + // store opening closing time storeOpeningClosingTime: '#dokan-store-time-enable', // lite locators @@ -6021,7 +6031,7 @@ export const selector = { storeOpenNotice: '//input[@name="dokan_store_open_notice"]', storeCloseNotice: '//input[@name="dokan_store_close_notice"]', - // Vacation + // vacation goToVacation: '#dokan-seller-vacation-activate', closingStyle: 'label .form-control', setVacationMessageInstantly: '//textarea[@id="dokan-seller-vacation-message" and @name="setting_vacation_message"]', @@ -6043,21 +6053,24 @@ export const selector = { hideProductPrice: 'input#catalog_mode_hide_product_price', enableRequestQuoteSupport: 'input#catalog_mode_request_a_quote_support', - // Discount + // discount enableStoreWideDiscount: '#lbl_setting_minimum_quantity', minimumOrderAmount: '#setting_minimum_order_amount', percentage: '#setting_order_percentage', - // Biography + // biography biographyIframe: '#wp-vendor_biography-wrap iframe', biographyHtmlBody: '#tinymce', - // Store Support + // store support showSupportButtonInStore: '#support_checkbox', showSupportButtonInSingleProduct: '#support_checkbox_product', supportButtonText: '#dokan_support_btn_name', - // Min-Max + // live chat + liveChat: 'input#live_chat', + + // min-max minMax: { minimumAmountToPlaceAnOrder: 'input#min_amount_to_order', maximumAmountToPlaceAnOrder: 'input#max_amount_to_order', @@ -6962,6 +6975,7 @@ export const selector = { price: '//div[@class="summary entry-summary"]//p[@class="price"]', quantity: 'div.quantity input.qty', addToCart: 'button.single_add_to_cart_button', + chatNow: 'button.dokan-live-chat', viewCart: '.woocommerce .woocommerce-message > .button', category: '.product_meta .posted_in', @@ -7310,9 +7324,10 @@ export const selector = { // Store Tabs storeTabs: { - follow: '.dokan-follow-store-button', + follow: 'button.dokan-follow-store-button', getSupport: 'button.dokan-store-support-btn', - share: '.dokan-share-btn', + chatNow: 'button.dokan-live-chat', + share: 'button.dokan-share-btn', products: '//div[@class="dokan-store-tabs"]//a[contains(text(),"Products")]', toc: '//div[@class="dokan-store-tabs"]//a[contains(text(),"Terms and Conditions")]', @@ -7801,6 +7816,16 @@ export const selector = { searchResultWithCategory: (productName: string, category: string) => `//div[@id="dokan-ajax-search-suggestion-result"]//h3[normalize-space(text())='${productName}']//..//span[normalize-space(text())='${category}']`, }, + cLiveChat: { + liveChatIframe: '(//div[ contains(@id, "__talkjs_popup_container") and not (@style="display: none;") ]//iframe[@name="____talkjs__chat__ui_internal"])[last()]', + // liveChatIframe: '(//iframe[@name="____talkjs__chat__ui_internal"])[last()]', + liveChatLauncher: 'a#__talkjs_launcher', + chatBox: 'div#chat-box', + chatTextBox: '//div[@role="textbox"]', + sendButton: 'button.send-button', + sentMessage: (message: string) => `//span[@class="EntityTreeRenderer" and normalize-space(text())="${message}"]`, + }, + cOrderReceived: { orderReceivedHeading: '//h1[normalize-space()="Order received"]', orderReceivedSuccessMessage: '.woocommerce-notice.woocommerce-notice--success.woocommerce-thankyou-order-received', diff --git a/tests/pw/pages/settingsPage.ts b/tests/pw/pages/settingsPage.ts index 459c2cb721..9eef3b853b 100644 --- a/tests/pw/pages/settingsPage.ts +++ b/tests/pw/pages/settingsPage.ts @@ -465,6 +465,30 @@ export class SettingsPage extends AdminPage { await this.toContainText(settingsAdmin.dokanUpdateSuccessMessage, quote.saveSuccessMessage); } + // Admin Set Dokan live chat Settings + async setDokanLiveChatSettings(liveChat: dokanSettings['liveChat']) { + await this.goToDokanSettings(); + await this.click(settingsAdmin.menus.liveChat); + + // liveChat Settings + await this.enableSwitcher(settingsAdmin.liveChat.enableLiveChat); + await this.click(settingsAdmin.liveChat.chatProvider(liveChat.chatProvider)); + await this.clearAndType(settingsAdmin.liveChat.talkJsAppId, liveChat.talkJsAppId); + await this.clearAndType(settingsAdmin.liveChat.talkJsAppSecret, liveChat.talkJsAppSecret); + await this.enableSwitcher(settingsAdmin.liveChat.chatButtonOnVendorPage); + await this.selectByValue(settingsAdmin.liveChat.chatButtonOnProductPage, liveChat.chatButtonPosition); + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, settingsAdmin.liveChat.liveChatSaveChanges); + + await this.toHaveBackgroundColor(settingsAdmin.liveChat.enableLiveChat + '//span', 'rgb(0, 144, 255)'); + await this.toHaveClass(settingsAdmin.liveChat.chatProvider(liveChat.chatProvider), 'checked'); + await this.toHaveValue(settingsAdmin.liveChat.talkJsAppId, liveChat.talkJsAppId); + await this.toHaveValue(settingsAdmin.liveChat.talkJsAppSecret, liveChat.talkJsAppSecret); + await this.toHaveBackgroundColor(settingsAdmin.liveChat.chatButtonOnVendorPage + '//span', 'rgb(0, 144, 255)'); + await this.toHaveSelectedValue(settingsAdmin.liveChat.chatButtonOnProductPage, liveChat.chatButtonPosition); + } + // Admin Set Dokan Rma Settings async setDokanRmaSettings(rma: dokanSettings['rma']) { await this.goToDokanSettings(); diff --git a/tests/pw/pages/singleProductPage.ts b/tests/pw/pages/singleProductPage.ts index 029634ebae..951147d02b 100644 --- a/tests/pw/pages/singleProductPage.ts +++ b/tests/pw/pages/singleProductPage.ts @@ -21,7 +21,7 @@ export class SingleProductPage extends CustomerPage { await this.goToProductDetails(productName); // basic details are visible - const { viewCart, euComplianceData, productAddedSuccessMessage, productWithQuantityAddedSuccessMessage, ...productDetails } = singleProductCustomer.productDetails; + const { viewCart, chatNow, euComplianceData, productAddedSuccessMessage, productWithQuantityAddedSuccessMessage, ...productDetails } = singleProductCustomer.productDetails; await this.multipleElementVisible(productDetails); // description elements are visible diff --git a/tests/pw/pages/singleStorePage.ts b/tests/pw/pages/singleStorePage.ts index 4f280c7f77..d7c6efb460 100644 --- a/tests/pw/pages/singleStorePage.ts +++ b/tests/pw/pages/singleStorePage.ts @@ -30,7 +30,7 @@ export class SingleStorePage extends CustomerPage { await this.toBeVisible(singleStoreCustomer.storeTabs.products); // await this.toBeVisible(singleStoreCustomer.storeTabs.toc); // todo: need vendor toc } else { - const { toc, ...storeTabs } = singleStoreCustomer.storeTabs; + const { toc, chatNow, ...storeTabs } = singleStoreCustomer.storeTabs; await this.multipleElementVisible(storeTabs); // eu compliance data is visible diff --git a/tests/pw/pages/storeSupportsPage.ts b/tests/pw/pages/storeSupportsPage.ts index ef1a546aa5..a85c3bf632 100644 --- a/tests/pw/pages/storeSupportsPage.ts +++ b/tests/pw/pages/storeSupportsPage.ts @@ -424,7 +424,7 @@ export class StoreSupportsPage extends AdminPage { await this.toBeVisible(supportsTicketsCustomer.supportTicketDetails.orderReference.orderReferenceLink(orderId)); } - // customer send message to support ticket + // customer send message to support ticket async sendMessageToSupportTicket(supportTicketId: string, supportTicket: customer['supportTicket']): Promise { const message = supportTicket.message(); await this.goIfNotThere(data.subUrls.frontend.supportTicketDetails(supportTicketId)); diff --git a/tests/pw/pages/vendorSettingsPage.ts b/tests/pw/pages/vendorSettingsPage.ts index 69cda561f5..a63feca8e8 100644 --- a/tests/pw/pages/vendorSettingsPage.ts +++ b/tests/pw/pages/vendorSettingsPage.ts @@ -236,6 +236,10 @@ export class VendorSettingsPage extends VendorPage { await this.storeSupportSettings(vendorInfo.supportButtonText); break; + case 'liveChat': + await this.liveChatSettings(vendorInfo.liveChat); + break; + case 'min-max': await this.minMaxSettings(vendorInfo.minMax); break; @@ -423,6 +427,11 @@ export class VendorSettingsPage extends VendorPage { } } + // vendor set liveChat settings + async liveChatSettings(liveChat: vendor['vendorInfo']['liveChat']): Promise { + await this.check(settingsVendor.liveChat); + } + // vendor set minmax settings async minMaxSettings(minMax: vendor['vendorInfo']['minMax']): Promise { await this.clearAndType(settingsVendor.minMax.minimumAmountToPlaceAnOrder, minMax.minimumAmount); diff --git a/tests/pw/tests/e2e/_env.setup.ts b/tests/pw/tests/e2e/_env.setup.ts index fd5016d68e..07e7737e6b 100644 --- a/tests/pw/tests/e2e/_env.setup.ts +++ b/tests/pw/tests/e2e/_env.setup.ts @@ -233,6 +233,10 @@ setup.describe('setup dokan settings', () => { await dbUtils.setOptionValue(dbData.dokan.optionName.quote, dbData.dokan.quoteSettings); }); + setup('admin set dokan live chat settings', { tag: ['@pro'] }, async () => { + await dbUtils.setOptionValue(dbData.dokan.optionName.liveChat, dbData.dokan.liveChatSettings); + }); + setup('admin set dokan rma settings', { tag: ['@pro'] }, async () => { await dbUtils.setOptionValue(dbData.dokan.optionName.rma, dbData.dokan.rmaSettings); }); diff --git a/tests/pw/tests/e2e/liveChat.spec.ts b/tests/pw/tests/e2e/liveChat.spec.ts new file mode 100644 index 0000000000..4324caa3cf --- /dev/null +++ b/tests/pw/tests/e2e/liveChat.spec.ts @@ -0,0 +1,78 @@ +import { test, Page } from '@playwright/test'; +import { LiveChatPage } from '@pages/liveChatPage'; +import { dbUtils } from '@utils/dbUtils'; +import { data } from '@utils/testData'; +import { dbData } from '@utils/dbData'; + +const { VENDOR_ID } = process.env; + +test.describe('Live chat test', () => { + let vendor: LiveChatPage; + let customer: LiveChatPage; + let vPage: Page, cPage: Page; + + test.beforeAll(async ({ browser }) => { + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new LiveChatPage(vPage); + + const customerContext = await browser.newContext(data.auth.customerAuth); + cPage = await customerContext.newPage(); + customer = new LiveChatPage(cPage); + + await dbUtils.updateUserMeta(VENDOR_ID, 'dokan_profile_settings', { live_chat: 'yes' }); + }); + + test.afterAll(async () => { + await dbUtils.setOptionValue(dbData.dokan.optionName.liveChat, dbData.dokan.liveChatSettings); + await vPage.close(); + await cPage.close(); + }); + + // admin + + test('admin can enable chat button on vendor page', { tag: ['@pro', '@admin'] }, async () => { + await dbUtils.updateOptionValue(dbData.dokan.optionName.liveChat, { chat_button_seller_page: 'on' }); + await customer.viewLiveChatButtonOnStore(data.predefined.vendorInfo.shopName); + }); + + test('admin can disable chat button on vendor page', { tag: ['@pro', '@admin'] }, async () => { + await dbUtils.updateOptionValue(dbData.dokan.optionName.liveChat, { chat_button_seller_page: 'off' }); + await customer.viewLiveChatButtonOnStore(data.predefined.vendorInfo.shopName, true); + + // reset + await dbUtils.updateOptionValue(dbData.dokan.optionName.liveChat, { chat_button_seller_page: 'on' }); + }); + + test('admin can enable chat button on product page (above_tab)', { tag: ['@pro', '@admin'] }, async () => { + await dbUtils.updateOptionValue(dbData.dokan.optionName.liveChat, { chat_button_product_page: 'above_tab' }); + await customer.viewLiveChatButtonOnProduct(data.predefined.simpleProduct.product1.name, 'above-tab'); + }); + + test('admin can enable chat button on product page (inside_tab)', { tag: ['@pro', '@admin'] }, async () => { + await dbUtils.updateOptionValue(dbData.dokan.optionName.liveChat, { chat_button_product_page: 'inside_tab' }); + await customer.viewLiveChatButtonOnProduct(data.predefined.simpleProduct.product1.name, 'inside-tab'); + }); + + test('admin can disable chat button on product page', { tag: ['@pro', '@admin'] }, async () => { + await dbUtils.updateOptionValue(dbData.dokan.optionName.liveChat, { chat_button_product_page: 'dont_show' }); + await customer.viewLiveChatButtonOnProduct(data.predefined.simpleProduct.product1.name, 'dont-show'); + }); + + // vendor + + test('vendor can view inbox menu page', { tag: ['@pro', '@exploratory', '@vendor'] }, async () => { + await vendor.vendorInboxRenderProperly(); + }); + + test('vendor can reply to customer message', { tag: ['@pro', '@customer'] }, async () => { + await customer.sendMessageToVendor('vendor1store', data.uniqueId.nanoIdRandom()); + await vendor.sendMessageToCustomer(data.predefined.customerInfo.username1, data.uniqueId.nanoIdRandom()); + }); + + // customer + + test('customer can send message to vendor', { tag: ['@pro', '@customer'] }, async () => { + await customer.sendMessageToVendor(data.predefined.vendorInfo.shopName, data.uniqueId.nanoIdRandom()); + }); +}); diff --git a/tests/pw/tests/e2e/settings.spec.ts b/tests/pw/tests/e2e/settings.spec.ts index 83e0f8a246..50807347cf 100644 --- a/tests/pw/tests/e2e/settings.spec.ts +++ b/tests/pw/tests/e2e/settings.spec.ts @@ -104,6 +104,10 @@ test.describe('Settings test', () => { await admin.setDokanQuoteSettings(data.dokanSettings.quote); }); + test('admin can set Dokan live chat settings', { tag: ['@pro', '@admin'] }, async () => { + await admin.setDokanLiveChatSettings(data.dokanSettings.liveChat); + }); + test('admin can set Dokan rma settings', { tag: ['@pro', '@admin'] }, async () => { await admin.setDokanRmaSettings(data.dokanSettings.rma); }); diff --git a/tests/pw/tests/e2e/vendorSettings.spec.ts b/tests/pw/tests/e2e/vendorSettings.spec.ts index 57c3fc151c..611624476a 100644 --- a/tests/pw/tests/e2e/vendorSettings.spec.ts +++ b/tests/pw/tests/e2e/vendorSettings.spec.ts @@ -106,6 +106,10 @@ test.describe('Vendor settings test', () => { await vendor.setStoreSettings(data.vendor.vendorInfo, 'store-support'); }); + test('vendor can set live chat settings', { tag: ['@pro', '@vendor'] }, async () => { + await vendor.setStoreSettings(data.vendor.vendorInfo, 'liveChat'); + }); + test('vendor can set min-max settings', { tag: ['@pro', '@vendor'] }, async () => { await vendor.setStoreSettings(data.vendor.vendorInfo, 'min-max'); // disable min-max diff --git a/tests/pw/types/environment.d.ts b/tests/pw/types/environment.d.ts index a11ea10da0..9e6f5969c3 100644 --- a/tests/pw/types/environment.d.ts +++ b/tests/pw/types/environment.d.ts @@ -30,6 +30,8 @@ declare global { VONAGE_API_SECRET: string; FB_APP_ID: string; FB_APP_SECRET: string; + TALKJS_APP_ID: string; + TALKJS_APP_SECRET: string; DOKAN_PRO: boolean; SITE_LANGUAGE: string; SITE_TITLE: string; diff --git a/tests/pw/utils/dbData.ts b/tests/pw/utils/dbData.ts index 6ccde5ddf2..f212f1ef36 100644 --- a/tests/pw/utils/dbData.ts +++ b/tests/pw/utils/dbData.ts @@ -1,4 +1,4 @@ -const { BASE_URL, GMAP, MAPBOX, LICENSE_KEY } = process.env; +const { BASE_URL, GMAP, MAPBOX, LICENSE_KEY, TALKJS_APP_ID, TALKJS_APP_SECRET } = process.env; export const dbData = { dokan: { @@ -20,7 +20,7 @@ export const dbData = { // socialApi: 'dokan_social_api', shippingStatus: 'dokan_shipping_status_setting', quote: 'dokan_quote_settings', - // liveChat: 'dokan_live_chat', + liveChat: 'dokan_live_chat', rma: 'dokan_rma', wholesale: 'dokan_wholesale', euCompliance: 'dokan_germanized', @@ -898,15 +898,16 @@ export const dbData = { }, liveChatSettings: { - enable: 'off', - provider: 'messenger', + enable: 'on', + provider: 'talkjs', theme_color: '#0084FF', - app_id: '', - app_secret: '', + app_id: TALKJS_APP_ID, + app_secret: TALKJS_APP_SECRET, wa_opening_method: 'in_app', wa_pre_filled_message: 'Hello {store_name}, I have an enquiry regarding your store at {store_url}', chat_button_seller_page: 'on', - chat_button_product_page: 'above_tab', + chat_button_product_page: 'above_tab', // above_tab, inside_tab, dont_show + dashboard_menu_manager: [], }, rmaSettings: { diff --git a/tests/pw/utils/interfaces.ts b/tests/pw/utils/interfaces.ts index 802005d1bf..334a199342 100644 --- a/tests/pw/utils/interfaces.ts +++ b/tests/pw/utils/interfaces.ts @@ -815,6 +815,10 @@ export interface vendor { discountPercentage: string; }; + liveChat: { + pageId: string; + }; + minMax: { minimumProductQuantity: string; maximumProductQuantity: string; @@ -1721,6 +1725,16 @@ export interface dokanSettings { saveSuccessMessage: string; }; + // Rma Settings + liveChat: { + settingTitle: string; + chatProvider: string; + talkJsAppId: string; + talkJsAppSecret: string; + chatButtonPosition: string; + saveSuccessMessage: string; + }; + // Rma Settings rma: { settingTitle: string; diff --git a/tests/pw/utils/testData.ts b/tests/pw/utils/testData.ts index d50717128b..f360922792 100644 --- a/tests/pw/utils/testData.ts +++ b/tests/pw/utils/testData.ts @@ -27,6 +27,8 @@ const { VONAGE_API_SECRET, FB_APP_ID, FB_APP_SECRET, + TALKJS_APP_ID, + TALKJS_APP_SECRET, } = process.env; const basicAuth = (username: string, password: string) => 'Basic ' + Buffer.from(username + ':' + password).toString('base64'); @@ -1008,10 +1010,10 @@ export const data = { storeListingSort: 'store-listing/?stores_orderby', cart: 'cart', checkout: 'checkout', - addToCart: '?wc-ajax=add_to_cart', - applyCoupon: '?wc-ajax=apply_coupon', - removeCoupon: '?wc-ajax=remove_coupon', - refreshedFragment: '?wc-ajax=get_refreshed_fragments', + addToCart: 'wc-ajax=add_to_cart', + applyCoupon: 'wc-ajax=apply_coupon', + removeCoupon: 'wc-ajax=remove_coupon', + refreshedFragment: 'wc-ajax=get_refreshed_fragments', placeOrder: '?wc-ajax=checkout', billingAddress: 'my-account/edit-address/billing', shippingAddress: 'my-account/edit-address/shipping', @@ -1028,6 +1030,7 @@ export const data = { quoteDetails: (quotId: string) => `my-account/request-a-quote/${quotId}`, supportTicketDetails: (ticketId: string) => `my-account/support-tickets/${ticketId}`, productSubscriptionDetails: (subscriptionId: string) => `my-account/view-subscription/${subscriptionId}`, + talkjs: 'app.talkjs.com/api', productReview: 'wp-comments-post.php', submitSupport: 'wp-comments-post.php', @@ -1071,6 +1074,7 @@ export const data = { csvExport: 'dashboard/tools/csv-export', auction: 'dashboard/auction', auctionActivity: 'dashboard/auction-activity', + inbox: 'dashboard/inbox', storeSupport: 'dashboard/support', // sub menus @@ -1078,6 +1082,7 @@ export const data = { settingsAddon: 'dashboard/settings/product-addon', settingsAddonEdit: (addonId: string) => `dashboard/settings/product-addon/?edit=${addonId}`, settingsPayment: 'dashboard/settings/payment', + // payment settings paypal: 'dashboard/settings/payment-manage-paypal', bankTransfer: 'dashboard/settings/payment-manage-bank', @@ -1293,6 +1298,10 @@ export const data = { discountPercentage: '10', }, + liveChat: { + pageId: '', + }, + minMax: { minimumProductQuantity: '1', maximumProductQuantity: '20', @@ -2337,6 +2346,16 @@ export const data = { saveSuccessMessage: 'Setting has been saved successfully.', }, + // live chat + liveChat: { + settingTitle: 'Live Chat Settings', + chatProvider: 'talkjs', // messenger, talkjs, tawkto, whatsapp + talkJsAppId: TALKJS_APP_ID, + talkJsAppSecret: TALKJS_APP_SECRET, + chatButtonPosition: 'above_tab', // above_tab, inside_tab, dont_show + saveSuccessMessage: 'Setting has been saved successfully.', + }, + // Rma Settings rma: { settingTitle: 'RMA Settings', @@ -2481,6 +2500,7 @@ export const data = { uniqueId: { uuid: faker.string.uuid(), nanoId: faker.string.nanoid(10), + nanoIdRandom: () => faker.string.nanoid(10), }, // predefined test data