Skip to content

Commit

Permalink
[E2E] Backporting e2e auth fixes to 3.20 (#5078)
Browse files Browse the repository at this point in the history
* [E2E] Fix auth file playwright and small refactor (#5065)

* fix for auth and save state function

* small refactor

* adding conditional assertion for TC 137

* e2e auth backport with a fix for  attr  test
  • Loading branch information
yellowee authored Jul 30, 2024
1 parent 4a59399 commit e14df76
Show file tree
Hide file tree
Showing 10 changed files with 89 additions and 49 deletions.
5 changes: 5 additions & 0 deletions .changeset/pretty-masks-lay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"saleor-dashboard": patch
---

You can now run E2E tests locally with no issues
2 changes: 1 addition & 1 deletion playwright/api/basics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,6 @@ export class BasicApiService {
});
const loginResponseJson = await loginResponse.json();

return loginResponseJson as ApiResponse<TokenCreateResponse>;
return loginResponseJson;
}
}
1 change: 1 addition & 0 deletions playwright/pages/appPageThirdparty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export class AppPage extends BasePage {
const appUrl = URL_LIST.apps + appId;

await this.page.goto(appUrl);
await this.pageHeader.waitFor({ state: "visible", timeout: 10000 });
}

async clickAppSettingsButton() {
Expand Down
1 change: 1 addition & 0 deletions playwright/pages/appsPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export class AppsPage extends BasePage {

async gotoAppsList() {
await this.page.goto(URL_LIST.apps);
await this.waitForDOMToFullyLoad();
}

async typeManifestUrl(manifestUrl: string) {
Expand Down
4 changes: 1 addition & 3 deletions playwright/pages/shippingRatesPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,7 @@ export class ShippingRatesPage extends BasePage {
await this.assignDialogProductRow.filter({ hasText: name }).waitFor({ state: "visible" });
await this.assignProductsDialog.selectProduct(name);
await expect(this.assignProductsDialog.assignAndSaveButton).toBeEnabled();
await this.waitForNetworkIdleAfterAction(() =>
this.assignProductsDialog.assignAndSaveButton.click(),
);
await this.assignProductsDialog.assignAndSaveButton.click();
await this.assignProductsDialog.assignAndSaveButton.waitFor({
state: "hidden",
timeout: 5000,
Expand Down
6 changes: 1 addition & 5 deletions playwright/tests/apps.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ test.skip("TC: SALEOR_119 User should be able to install and configure app from
page,
}) => {
await appsPage.gotoAppsList();
await appsPage.waitForDOMToFullyLoad();
await expect(appsPage.installExternalAppButton).toBeVisible();
await appsPage.installExternalAppButton.click();
await appsPage.typeManifestUrl("https://klaviyo.saleor.app/api/manifest");
Expand Down Expand Up @@ -50,10 +49,7 @@ test.skip("TC: SALEOR_119 User should be able to install and configure app from
await appsPage.expectSuccessBanner();
});
test("TC: SALEOR_120 User should be able to delete thirdparty app @e2e", async () => {
await appPage.waitForNetworkIdleAfterAction(() =>
appPage.goToExistingAppPage(APPS.appToBeDeleted.id),
);
await appPage.pageHeader.waitFor({ state: "visible", timeout: 10000 });
await appPage.goToExistingAppPage(APPS.appToBeDeleted.id);
await expect(appPage.pageHeader).toContainText("Saleor QA App");
await appPage.deleteButton.click();
await appPage.deleteAppDialog.clickDeleteButton();
Expand Down
10 changes: 6 additions & 4 deletions playwright/tests/attributes.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const attributeClasses = ["PRODUCT_TYPE", "PAGE_TYPE"];

for (const attr of attributeClasses) {
for (const type of ATTRIBUTES.attributeTypesWithAbilityToAddValues.names) {
const uniqueSlug = `${attr}-${type.replace(" ", "-")}-${SALEOR_124_uuid}`;
const uniqueSlug = `${attr}-${type}-${SALEOR_124_uuid}`.replace(/\s+/g, "-");

test(`TC: SALEOR_124 User should be able to create ${attr} ${type} attribute with ability to add values, required, public @e2e @attributes`, async ({
page,
Expand Down Expand Up @@ -53,7 +53,7 @@ const SALEOR_125_uuid = faker.datatype.uuid();

for (const attr of attributeClasses) {
for (const type of ATTRIBUTES.attributeTypesWithoutAbilityToAddValues.names) {
const uniqueSlug = `${attr}-${type.replace(" ", "-")}-${SALEOR_125_uuid}`;
const uniqueSlug = `${attr}-${type}-${SALEOR_125_uuid}`.replace(/\s+/g, "-");

test(`TC: SALEOR_125 User should be able to create ${attr} ${type} attribute without ability to add values, NOT required, private @e2e @attributes`, async ({
page,
Expand Down Expand Up @@ -88,7 +88,7 @@ const SALEOR_126_uuid = faker.datatype.uuid();

for (const attr of attributeClasses) {
for (const entity of ATTRIBUTES.attributeReferencesEntities.names) {
const uniqueSlug = `${attr}-${entity.replaceAll(" ", "-")}-${SALEOR_126_uuid}`;
const uniqueSlug = `${attr}-${entity}-${SALEOR_126_uuid}`.replace(/\s+/g, "-");

test(`TC: SALEOR_126 User should be able to create ${attr} References attribute for ${entity}, NOT required, public @e2e @attributes`, async ({
page,
Expand All @@ -101,7 +101,7 @@ for (const attr of attributeClasses) {
await attributesPage.selectAttributeType(attr);
await attributesPage.typeAttributeDefaultLabel(`${attr} - REFERENCES for ${entity}`);
await attributesPage.fillAttributeSlug(uniqueSlug);
await attributesPage.selectAttributeInputType("Reference");
await attributesPage.selectAttributeInputType("REFERENCE");
await attributesPage.selectAttributeEntityType(entity);
await attributesPage.clickValueRequiredCheckbox();
await attributesPage.waitForNetworkIdleAfterAction(() => attributesPage.clickSaveButton());
Expand Down Expand Up @@ -172,6 +172,8 @@ for (const attr of ATTRIBUTES.attributesToBeUpdated) {
await attributesPage.fillMetadataFields("new key", "new value");
await attributesPage.waitForNetworkIdleAfterAction(() => attributesPage.clickSaveButton());
await attributesPage.expectSuccessBanner();
await attributesPage.expectElementIsHidden(attributesPage.successBanner);
await attributesPage.attributeSelect.waitFor({ state: "visible" });
await expect(attributesPage.attributeSelect).toHaveAttribute("aria-disabled", "true");
await expect(attributesPage.metadataKeyInput).toHaveValue("new key");
await expect(attributesPage.metadataValueInput).toHaveValue("new value");
Expand Down
65 changes: 46 additions & 19 deletions playwright/tests/auth.setup.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
import { BasicApiService } from "@api/basics";
import { permissions, USER_PERMISSION, UserPermissionType } from "@data/userPermissions";
import { APIRequestContext, test as setup } from "@playwright/test";
import { permissions, USER_PERMISSION } from "@data/userPermissions";
import { APIRequestContext, expect, test as setup } from "@playwright/test";
import fs from "fs";
import path from "path";

setup.describe.configure({ mode: "serial" });

const removeAuthFolder = () => {
const authDir = path.join(__dirname, "../.auth");

if (fs.existsSync(authDir)) {
fs.rmSync(authDir, { recursive: true });
console.log(".auth folder removed");
}
};

setup.beforeAll(() => {
removeAuthFolder();
});

const authenticateAndSaveState = async (
request: APIRequestContext,
email: string,
Expand All @@ -14,19 +27,32 @@ const authenticateAndSaveState = async (
) => {
const basicApiService = new BasicApiService(request);

await basicApiService.logInUserViaApi({ email, password });
const loginResponse = await basicApiService.logInUserViaApi({ email, password });
const errors = loginResponse.data.tokenCreate.errors;

if (
setup.info().title ===
"TC: SALEOR_137 Admin User should be able to deactivate other user @e2e @staff-members"
) {
await expect(errors[0].code).toEqual("INACTIVE");
} else {
await expect(errors).toEqual([]);
}

const loginJsonInfo = await request.storageState();

loginJsonInfo.origins.push({
origin: process.env.BASE_URL!,
localStorage: [
{
name: "_saleorRefreshToken",
value: loginJsonInfo.cookies[0].value,
},
],
});
loginJsonInfo.origins = [
{
origin: process.env.BASE_URL!,
localStorage: [
{
name: "_saleorRefreshToken",
value: loginResponse.data.tokenCreate.refreshToken,
},
],
},
];

fs.writeFileSync(filePath, JSON.stringify(loginJsonInfo, null, 2));
};
const authSetup = async (
Expand Down Expand Up @@ -57,11 +83,12 @@ setup("Authenticate as admin via API", async ({ request }) => {
);
});

const user: UserPermissionType = USER_PERMISSION;
const password: string = process.env.E2E_PERMISSIONS_USERS_PASSWORD!;
setup("Authenticate permission users via API", async ({ request }) => {
for (const permission of permissions) {
const email = USER_PERMISSION[permission];
const password = process.env.E2E_PERMISSIONS_USERS_PASSWORD!;
const fileName = `${permission}.json`;

for (const permission of permissions) {
setup(`Authenticate as ${permission} user via API`, async ({ request }) => {
await authSetup(request, user[permission], password, `${permission}.json`);
});
}
await authSetup(request, email, password, fileName);
}
});
28 changes: 18 additions & 10 deletions playwright/tests/singlePermissions/product.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,50 @@ import { CollectionsPage } from "@pages/collectionsPage";
import { HomePage } from "@pages/homePage";
import { MainMenuPage } from "@pages/mainMenuPage";
import { ProductPage } from "@pages/productPage";
import { expect, test } from "@playwright/test";

test.use({ storageState: "playwright/.auth/product.json" });
import { BrowserContext, expect, test } from "@playwright/test";

let context: BrowserContext;
let home: HomePage;
let mainMenuPage: MainMenuPage;
let productPage: ProductPage;
let categoriesPage: CategoriesPage;
let collectionsPage: CollectionsPage;

test.beforeEach(({ page }) => {
test.beforeEach(async ({ browser }) => {
context = await browser.newContext({
storageState: "playwright/.auth/product.json",
});

const page = await context.newPage();

productPage = new ProductPage(page);
home = new HomePage(page);
mainMenuPage = new MainMenuPage(page);
categoriesPage = new CategoriesPage(page);
collectionsPage = new CollectionsPage(page);
});
test("TC: SALEOR_23 User should be able to navigate to product list as a staff member using PRODUCT permission @e2e", async () => {

await home.goto();
await home.welcomeMessage.waitFor({ state: "visible", timeout: 30000 });
});

test.afterEach(async () => {
await context.close();
});

test("TC: SALEOR_23 User should be able to navigate to product list as a staff member using PRODUCT permission @e2e", async () => {
await mainMenuPage.openProducts();
await expect(productPage.addProductButton).toBeVisible();
await mainMenuPage.expectMenuItemsCount(6);
await productPage.expectGridToBeAttached();
});

test("TC: SALEOR_24 User should be able to navigate to collections list as a staff member using PRODUCT permission @e2e", async () => {
await home.goto();
await home.welcomeMessage.waitFor({ state: "visible", timeout: 30000 });
await mainMenuPage.openCollections();
await expect(collectionsPage.createCollectionButton).toBeVisible();
await mainMenuPage.expectMenuItemsCount(6);
await collectionsPage.expectGridToBeAttached();
});
test("TC: SALEOR_25 User should be able to navigate to categories list as a staff member using PRODUCT permission @e2e", async () => {
await home.goto();
await home.welcomeMessage.waitFor({ state: "visible", timeout: 30000 });
await mainMenuPage.openCategories();
await expect(categoriesPage.createCategoryButton).toBeVisible();
await mainMenuPage.expectMenuItemsCount(6);
Expand Down
16 changes: 9 additions & 7 deletions playwright/tests/singlePermissions/readonlyAppAccess.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { URL_LIST } from "@data/url";
import { permissions } from "@data/userPermissions";
import { AppDetailsPage } from "@pages/appDetailsPage";
import { AppPage } from "@pages/appPageThirdparty";
import { AppsPage } from "@pages/appsPage";
import { HomePage } from "@pages/homePage";
import { MainMenuPage } from "@pages/mainMenuPage";
import { expect, test } from "@playwright/test";

Expand All @@ -11,17 +11,19 @@ const permissionList = permissions.filter(item => item !== permissionToExclude);

for (const permission of permissionList) {
test.use({ storageState: `playwright/.auth/${permission}.json` });
test(`TC: SALEOR_131 User with ${permission} permissions should have readonly access to Apps @e2e @appp`, async ({
test(`TC: SALEOR_131 User with ${permission} permissions should have readonly access to Apps @e2e @app`, async ({
page,
}) => {
const home = new HomePage(page);
const mainMenuPage = new MainMenuPage(page);
const appsPage = new AppsPage(page);
const appPage = new AppPage(page);
const appDetailsPage = new AppDetailsPage(page);

await page.goto(URL_LIST.homePage);
await mainMenuPage.waitForNetworkIdleAfterAction(() => mainMenuPage.openApps());
await mainMenuPage.waitForDOMToFullyLoad();
await home.goto();
await home.welcomeMessage.waitFor({ state: "visible", timeout: 30000 });
await mainMenuPage.openApps();

await expect(appsPage.installExternalAppButton).not.toBeVisible();

const appLists = [
Expand All @@ -34,9 +36,9 @@ for (const permission of permissionList) {
await appsPage.waitForDOMToFullyLoad();
await expect(appList).toBeVisible();
}
await appsPage.waitForNetworkIdleAfterAction(() => appsPage.installedAppRow.first().click());
await appsPage.installedAppRow.first().click();
await expect(appPage.appSettingsButton).toBeVisible();
await appsPage.waitForNetworkIdleAfterAction(() => appPage.appSettingsButton.click());
await appPage.appSettingsButton.click();
await expect(appDetailsPage.appDetailsSection).toBeVisible();

const buttons = [
Expand Down

0 comments on commit e14df76

Please sign in to comment.