Skip to content

Commit

Permalink
Add shipstation tests (#2444)
Browse files Browse the repository at this point in the history
* Add shipstation tests & update previous tests

* Add shipstation api tests

* update command

* Fix case mismatch

* Update feature map

* Fix a method
  • Loading branch information
shashwatahalder01 authored Nov 26, 2024
1 parent 3aa625c commit 6ffe461
Show file tree
Hide file tree
Showing 16 changed files with 406 additions and 79 deletions.
199 changes: 149 additions & 50 deletions tests/pw/feature-map/feature-map.yml

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions tests/pw/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"site:reset": "NO_SETUP=false npm run site:setup && npm run env:setup",
"site:setup": "npx playwright test --project=local_site_setup --config=e2e.config.ts",
"env:setup": "npx playwright test --project=e2e_setup --config=e2e.config.ts",
"auth:setup": "NO_SETUP=true npx playwright test --project=auth_setup --config=e2e.config.ts",
"test:api": "npx playwright test --project=api_tests --config=api.config.ts",
"test:e2e": "npx playwright test --project=e2e_tests --config=e2e.config.ts",
"test:api:pro": "DOKAN_PRO=true npx playwright test --project=api_tests --config=api.config.ts",
Expand Down
16 changes: 13 additions & 3 deletions tests/pw/pages/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6545,16 +6545,26 @@ export const selector = {
shipStationText: '.dokan-settings-content h1',
visitStore: '//a[normalize-space()="Visit Store"]',

authenticationKey: '//label[normalize-space()="Authentication Key"]/..//code',
generateCredentials: 'button#dokan-shipstation-generate-credentials-btn',
generateSuccessMessage: '//div[@id="swal2-html-container" and normalize-space()="API credentials generated successfully."]',
revokeCredentials: 'button#dokan-shipstation-revoke-credentials-btn',
confirmRevoke: 'button.swal2-confirm',
revokeSuccessMessage: '//div[@id="swal2-html-container" and normalize-space()="API credentials revoked successfully."]',

credentials: {
authenticationKey: '//label[normalize-space()="Authentication Key"]/..//code',
consumerKey: '//label[normalize-space()="Consumer Key"]/..//code',
consumerSecret: '//label[normalize-space()="Consumer Secret"]/..//code',
},

selectedStatus: '//label[@for="dokan-shipstation-export-statuses"]/..//li[@class="select2-selection__choice"]',
exportOrderStatusesInput: '//label[normalize-space()="Export Order Statuses"]/..//span[@class="select2-selection select2-selection--multiple"]//input[@class="select2-search__field"]',
shippedOrderStatusDropdown: '.select2-selection__arrow',
shippedOrderStatusInput: '(//input[@class="select2-search__field"])[2]',
result: '.select2-results__option.select2-results__option--highlighted',

saveChanges: '#dokan-store-shipstation-form-submit',
saveSuccessMessage: '#swal2-html-container',
successOk: '.swal2-confirm',
saveSuccessMessage: '//div[@id="swal2-html-container" and normalize-space()="Settings saved successfully."]',
},

// social profile settings
Expand Down
35 changes: 35 additions & 0 deletions tests/pw/pages/shipstationPage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Page } from '@playwright/test';
import { VendorPage } from '@pages/vendorPage';
import { selector } from '@pages/selectors';
import { data } from '@utils/testData';

// selectors
const settingsShipStation = selector.vendor.vShipStationSettings;

export class ShipStationPage extends VendorPage {
constructor(page: Page) {
super(page);
}

// generate shipStation credentials
async generateShipStationCredentials() {
await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsShipStation);
await this.clickAndAcceptAndWaitForResponse(data.subUrls.api.dokan.shipStation, settingsShipStation.generateCredentials, 201);
await this.toBeVisible(settingsShipStation.generateSuccessMessage);

await this.toBeVisible(settingsShipStation.revokeCredentials);
await this.multipleElementVisible(settingsShipStation.credentials);
}

// revoke shipStation credentials
async revokeShipStationCredentials() {
await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsShipStation);

await this.click(settingsShipStation.revokeCredentials);
await this.clickAndAcceptAndWaitForResponse(data.subUrls.api.dokan.shipStation, settingsShipStation.confirmRevoke);
await this.toBeVisible(settingsShipStation.revokeSuccessMessage);

await this.toBeVisible(settingsShipStation.generateCredentials);
await this.multipleElementNotVisible(settingsShipStation.credentials);
}
}
16 changes: 12 additions & 4 deletions tests/pw/pages/vendorAuctionsPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,10 +235,6 @@ export class AuctionsPage extends VendorPage {
await this.removeAttribute(auctionProductsVendor.auction.auctionEndDate, 'readonly');
await this.clearAndType(auctionProductsVendor.auction.auctionStartDate, generalOption.startDate);
await this.clearAndType(auctionProductsVendor.auction.auctionEndDate, generalOption.endDate);
await this.check(auctionProductsVendor.auction.enableAutomaticRelisting);
await this.clearAndType(auctionProductsVendor.auction.relistIfFailAfterNHours, generalOption.relistIfFailAfterNHours);
await this.clearAndType(auctionProductsVendor.auction.relistIfNotPaidAfterNHours, generalOption.relistIfNotPaidAfterNHours);
await this.clearAndType(auctionProductsVendor.auction.relistAuctionDurationInH, generalOption.relistAuctionDurationInH);

await this.saveProduct();

Expand All @@ -251,6 +247,18 @@ export class AuctionsPage extends VendorPage {
await this.toHaveValue(auctionProductsVendor.auction.buyItNowPrice, buyItNowPrice);
await this.toHaveValue(auctionProductsVendor.auction.auctionStartDate, generalOption.startDate);
await this.toHaveValue(auctionProductsVendor.auction.auctionEndDate, generalOption.endDate);
}

// add product Relist option
async addProductRelistingOption(productName: string, generalOption: product['auction']) {
await this.goToAuctionProductEditById(productName);
await this.check(auctionProductsVendor.auction.enableAutomaticRelisting);
await this.clearAndType(auctionProductsVendor.auction.relistIfFailAfterNHours, generalOption.relistIfFailAfterNHours);
await this.clearAndType(auctionProductsVendor.auction.relistIfNotPaidAfterNHours, generalOption.relistIfNotPaidAfterNHours);
await this.clearAndType(auctionProductsVendor.auction.relistAuctionDurationInH, generalOption.relistAuctionDurationInH);

await this.saveProduct();

await this.toBeChecked(auctionProductsVendor.auction.enableAutomaticRelisting);
await this.toHaveValue(auctionProductsVendor.auction.relistIfFailAfterNHours, generalOption.relistIfFailAfterNHours);
await this.toHaveValue(auctionProductsVendor.auction.relistIfNotPaidAfterNHours, generalOption.relistIfNotPaidAfterNHours);
Expand Down
36 changes: 21 additions & 15 deletions tests/pw/pages/vendorSettingsPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,18 +70,23 @@ export class VendorSettingsPage extends VendorPage {
await this.toBeVisible(settingsVendor.updateSettings);
}

// vendor shipstation render properly
async vendorShipstationSettingsRenderProperly() {
await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsShipstation);
// vendor ShipStation render properly
async vendorShipStationSettingsRenderProperly() {
await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsShipStation);

// shipStation text is visible
await this.toBeVisible(settingsShipStation.shipStationText);

// visit store link is visible
await this.toBeVisible(settingsShipStation.visitStore);

// authentication key is visible
await this.toBeVisible(settingsShipStation.authenticationKey);
const isCredentialsGenerated = await this.isVisible(settingsShipStation.revokeCredentials);

if (isCredentialsGenerated) {
await this.multipleElementVisible(settingsShipStation.credentials);
} else {
await this.toBeVisible(settingsShipStation.generateCredentials);
}

// export order statuses is visible
await this.toBeVisible(settingsShipStation.exportOrderStatusesInput);
Expand Down Expand Up @@ -438,26 +443,27 @@ export class VendorSettingsPage extends VendorPage {
await this.clearAndType(settingsVendor.minMax.maximumAmountToPlaceAnOrder, minMax.maximumAmount);
}

// vendor set Shipstation settings
// vendor set ShipStation settings
async setShipStation(shipStation: vendor['shipStation']): Promise<void> {
await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsShipstation);
await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsShipStation);

// export order statuses
const allStatus = await this.getMultipleElementTexts(settingsShipStation.selectedStatus);
const statusIsSelected = allStatus.includes('×' + shipStation.status);
const statusIsSelected = allStatus.includes(${shipStation.status}`);
if (!statusIsSelected) {
await this.clearAndType(settingsShipStation.exportOrderStatusesInput, shipStation.status);
await this.toContainText(settingsShipStation.result, shipStation.status);
await this.press(data.key.enter);
}

// await this.click(settingsShipStation.shippedOrderStatusDropdown);
// await this.clearAndType(settingsShipStation.shippedOrderStatusInput, shipStation.status);// todo: need to fix -> locator issue
// await this.toContainText(settingsShipStation.result, shipStation.status);
// await this.press(data.key.enter);
// shipped order status
await this.click(settingsShipStation.shippedOrderStatusDropdown);
await this.clearAndType(settingsShipStation.shippedOrderStatusInput, shipStation.status);
await this.toContainText(settingsShipStation.result, shipStation.status);
await this.press(data.key.enter);

await this.clickAndAcceptAndWaitForResponse(data.subUrls.ajax, settingsShipStation.saveChanges);
await this.toContainText(settingsShipStation.saveSuccessMessage, 'Your changes has been updated!');
await this.click(settingsShipStation.successOk);
await this.clickAndAcceptAndWaitForResponse(data.subUrls.api.dokan.shipStation, settingsShipStation.saveChanges, 201);
await this.toBeVisible(settingsShipStation.saveSuccessMessage);
}

// vendor set social profile settings
Expand Down
2 changes: 1 addition & 1 deletion tests/pw/pages/vendorShippingPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export class VendorShippingPage extends VendorPage {
async vendorShippingSettingsRenderProperly() {
await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsShipping);

// shipstation text is visible
// ShipStation text is visible
await this.toBeVisible(vendorShipping.shippingSettingsText);

// visit store link is visible
Expand Down
69 changes: 69 additions & 0 deletions tests/pw/tests/api/shipstation.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//COVERAGE_TAG: GET /dokan/v1/shipstation/credentials/(?P<id>[\d]+)
//COVERAGE_TAG: POST /dokan/v1/shipstation/credentials/create
//COVERAGE_TAG: DELETE /dokan/v1/shipstation/credentials/(?P<id>[\d]+)
//COVERAGE_TAG: GET /dokan/v1/shipstation/order-statuses
//COVERAGE_TAG: POST /dokan/v1/shipstation/order-statuses/(?P<id>[\d]+)
//COVERAGE_TAG: DELETE /dokan/v1/shipstation/order-statuses/(?P<id>[\d]+)

import { test, expect, request } from '@playwright/test';
import { ApiUtils } from '@utils/apiUtils';
import { endPoints } from '@utils/apiEndPoints';
import { payloads } from '@utils/payloads';
import { schemas } from '@utils/schemas';

const { VENDOR_ID } = process.env;

test.describe('ShipStation api test', () => {
test.skip(true, 'remove after pr is merged');
let apiUtils: ApiUtils;

test.beforeAll(async () => {
apiUtils = new ApiUtils(await request.newContext());
});

test.afterAll(async () => {
await apiUtils.dispose();
});

test('create ShipStation credential', { tag: ['@pro'] }, async () => {
const [response, responseBody] = await apiUtils.post(endPoints.createShipStationCredential, { data: { vendor_id: VENDOR_ID } });
expect(response.ok()).toBeTruthy();
expect(responseBody).toBeTruthy();
expect(responseBody).toMatchSchema(schemas.shipStationSchema.shipStationCredentialSchema);
});

test('get ShipStation credential', { tag: ['@pro'] }, async () => {
const [response, responseBody] = await apiUtils.get(endPoints.getShipStationCredential(VENDOR_ID));
expect(response.ok()).toBeTruthy();
expect(responseBody).toBeTruthy();
expect(responseBody).toMatchSchema(schemas.shipStationSchema.shipStationCredentialSchema);
});

test('delete ShipStation credential', { tag: ['@pro'] }, async () => {
const [response, responseBody] = await apiUtils.delete(endPoints.deleteShipStationCredential(VENDOR_ID));
expect(response.ok()).toBeTruthy();
expect(responseBody).toBeTruthy();
expect(responseBody).toMatchSchema(schemas.shipStationSchema.shipStationCredentialSchema);
});

test('create ShipStation order status settings', { tag: ['@pro'] }, async () => {
const [response, responseBody] = await apiUtils.post(endPoints.createShipStationOrderStatusSettings, { data: { ...payloads.shipStationOrderStatusSettings, vendor_id: VENDOR_ID } });
expect(response.ok()).toBeTruthy();
expect(responseBody).toBeTruthy();
expect(responseBody).toMatchSchema(schemas.shipStationSchema.shipStationOrderStatusSettingSchema);
});

test('get ShipStation order status settings', { tag: ['@pro'] }, async () => {
const [response, responseBody] = await apiUtils.get(endPoints.getShipStationOrderStatusSettings(VENDOR_ID));
expect(response.ok()).toBeTruthy();
expect(responseBody).toBeTruthy();
expect(responseBody).toMatchSchema(schemas.shipStationSchema.shipStationOrderStatusSettingSchema);
});

test('delete ShipStation order status settings', { tag: ['@pro'] }, async () => {
const [response, responseBody] = await apiUtils.delete(endPoints.deleteShipStationOrderStatusSettings(VENDOR_ID));
expect(response.ok()).toBeTruthy();
expect(responseBody).toBeTruthy();
expect(responseBody).toMatchSchema(schemas.shipStationSchema.shipStationOrderStatusSettingSchema);
});
});
9 changes: 9 additions & 0 deletions tests/pw/tests/e2e/productsDetailsAuction.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,15 @@ test.describe('Auction Product details functionality test', () => {
await vendor.addProductGeneralOption(productIdBasic, { ...data.product.auction, itemCondition: 'used', auctionType: 'reverse' });
});

test('vendor can enable product relist options', { tag: ['@pro', '@vendor'] }, async () => {
await vendor.addProductRelistingOption(productIdBasic, data.product.auction);
});

test('vendor can update product relist options', { tag: ['@pro', '@vendor'] }, async () => {
test.skip(true, 'not implemented yet');
await vendor.addProductRelistingOption(productIdFull, { ...data.product.auction, relistIfFailAfterNHours: '5', relistIfNotPaidAfterNHours: '6', relistAuctionDurationInH: '7' });
});

// product inventory options

test('vendor can add auction product inventory options (SKU)', { tag: ['@pro', '@vendor'] }, async () => {
Expand Down
29 changes: 29 additions & 0 deletions tests/pw/tests/e2e/shipstation.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { test, Page } from '@playwright/test';
import { ShipStationPage } from '@pages/shipStationPage';
import { data } from '@utils/testData';

test.describe('ShipStation test', () => {
test.skip(true, 'remove after pr is merged');
let vendor: ShipStationPage;
let vPage: Page;

test.beforeAll(async ({ browser }) => {
const vendorContext = await browser.newContext(data.auth.vendorAuth);
vPage = await vendorContext.newPage();
vendor = new ShipStationPage(vPage);
});

test.afterAll(async () => {
await vPage.close();
});

// vendor

test('vendor can generate ShipStation credentials', { tag: ['@pro', '@exploratory', '@vendor'] }, async () => {
await vendor.generateShipStationCredentials();
});

test('vendor can revoke ShipStation credentials', { tag: ['@pro', '@exploratory', '@vendor'] }, async () => {
await vendor.revokeShipStationCredentials();
});
});
7 changes: 4 additions & 3 deletions tests/pw/tests/e2e/vendorSettings.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ test.describe('Vendor settings test', () => {
await vendor.vendorStoreSettingsRenderProperly();
});

test('vendor can view Shipstation settings menu page', { tag: ['@pro', '@exploratory', '@vendor'] }, async () => {
await vendor.vendorShipstationSettingsRenderProperly();
test('vendor can view ShipStation settings menu page', { tag: ['@pro', '@exploratory', '@vendor'] }, async () => {
await vendor.vendorShipStationSettingsRenderProperly();
});

test('vendor can view social profile settings menu page', { tag: ['@pro', '@exploratory', '@vendor'] }, async () => {
Expand Down Expand Up @@ -113,11 +113,12 @@ test.describe('Vendor settings test', () => {

test('vendor can set min-max settings', { tag: ['@pro', '@vendor'] }, async () => {
await vendor.setStoreSettings(data.vendor.vendorInfo, 'min-max');

// disable min-max
await dbUtils.updateOptionValue(dbData.dokan.optionName.selling, { enable_min_max_quantity: 'off', enable_min_max_amount: 'off' });
});

test('vendor can set shipStation settings', { tag: ['@pro', '@vendor'] }, async () => {
test('vendor can set ShipStation settings', { tag: ['@pro', '@vendor'] }, async () => {
await vendor.setShipStation(data.vendor.shipStation);
});

Expand Down
10 changes: 9 additions & 1 deletion tests/pw/utils/apiEndPoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ export const endPoints = {
updateVerificationRequest: (requestId: string) => `${SERVER_URL}/dokan/v1/verification-requests/${requestId}`,
deleteVerificationRequest: (requestId: string) => `${SERVER_URL}/dokan/v1/verification-requests/${requestId}`,

//commission
// commission
getCommission: `${SERVER_URL}/dokan/v1/commission`,

// shipping status
Expand All @@ -375,6 +375,14 @@ export const endPoints = {
getSingleShipment: (orderId: string, shipmentId: string) => `${SERVER_URL}/dokan/v1/shipping-status/orders/${orderId}/shipment/${shipmentId}`,
updateShipment: (orderId: string, shipmentId: string) => `${SERVER_URL}/dokan/v1/shipping-status/orders/${orderId}/shipment/${shipmentId}`,

// ShipStation
getShipStationCredential: (vendorId: string) => `${SERVER_URL}/dokan/v1/shipstation/credentials/${vendorId}`,
createShipStationCredential: `${SERVER_URL}/dokan/v1/shipstation/credentials/create`,
deleteShipStationCredential: (vendorId: string) => `${SERVER_URL}/dokan/v1/shipstation/credentials/${vendorId}`,
getShipStationOrderStatusSettings: (vendorId: string) => `${SERVER_URL}/dokan/v1/shipstation/order-statuses/${vendorId}`,
createShipStationOrderStatusSettings: `${SERVER_URL}/dokan/v1/shipstation/order-statuses`,
deleteShipStationOrderStatusSettings: (vendorId: string) => `${SERVER_URL}/dokan/v1/shipstation/order-statuses/${vendorId}`,

wc: {
// coupons
getAllCoupons: `${SERVER_URL}/wc/v3/coupons`,
Expand Down
24 changes: 24 additions & 0 deletions tests/pw/utils/apiUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1533,6 +1533,30 @@ export class ApiUtils {
return [responseBody, orderId, shipmentId];
}

/**
* ShipStation api methods
*/

async createShipStationCredential(vendorId: string, auth?: auth): Promise<responseBody> {
const [, responseBody] = await this.post(endPoints.createShipStationCredential, { data: { vendor_id: vendorId }, headers: auth });
return responseBody;
}

async deleteShipStationCredential(vendorId: string, auth?: auth): Promise<responseBody> {
const [, responseBody] = await this.delete(endPoints.deleteShipStationCredential(vendorId), { headers: auth });
return responseBody;
}

async createShipStationOrderStatusSettings(payload: object, auth?: auth): Promise<responseBody> {
const [, responseBody] = await this.post(endPoints.createShipStationOrderStatusSettings, { data: payload, headers: auth });
return responseBody;
}

async deleteShipStationOrderStatusSettings(vendorId: string, auth?: auth): Promise<responseBody> {
const [, responseBody] = await this.delete(endPoints.deleteShipStationOrderStatusSettings(vendorId), { headers: auth });
return responseBody;
}

/**
* wp api methods
*/
Expand Down
Loading

0 comments on commit 6ffe461

Please sign in to comment.