Merge branch 'main' into envs
This commit is contained in:
commit
e7a3df4777
39 changed files with 940 additions and 194 deletions
14
.changeset/chilled-kiwis-type.md
Normal file
14
.changeset/chilled-kiwis-type.md
Normal file
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
"saleor-app-emails-and-messages": minor
|
||||
"saleor-app-data-importer": minor
|
||||
"saleor-app-products-feed": minor
|
||||
"saleor-app-invoices": minor
|
||||
"saleor-app-klaviyo": minor
|
||||
"saleor-app-search": minor
|
||||
"saleor-app-slack": minor
|
||||
"saleor-app-taxes": minor
|
||||
"saleor-app-cms": minor
|
||||
"saleor-app-crm": minor
|
||||
---
|
||||
|
||||
Filled "about" field in App Manifest. Dashboard will display it in app details page now.
|
17
.changeset/three-timers-glow.md
Normal file
17
.changeset/three-timers-glow.md
Normal file
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
"saleor-app-emails-and-messages": patch
|
||||
"saleor-app-data-importer": patch
|
||||
"saleor-app-products-feed": patch
|
||||
"saleor-app-monitoring": patch
|
||||
"@saleor/apps-shared": patch
|
||||
"saleor-app-invoices": patch
|
||||
"saleor-app-klaviyo": patch
|
||||
"saleor-app-search": patch
|
||||
"@saleor/apps-ui": patch
|
||||
"saleor-app-slack": patch
|
||||
"saleor-app-taxes": patch
|
||||
"saleor-app-cms": patch
|
||||
"saleor-app-crm": patch
|
||||
---
|
||||
|
||||
Update @saleor/app-sdk to 0.41.0
|
|
@ -13,6 +13,8 @@ export default createManifestHandler({
|
|||
const apiBaseURL = process.env.APP_API_BASE_URL ?? appBaseUrl;
|
||||
|
||||
const manifest: AppManifest = {
|
||||
about:
|
||||
"CMS App is a multi-integration app that connects Saleor with popular Content Management Systems.",
|
||||
appUrl: iframeBaseUrl,
|
||||
author: "Saleor Commerce",
|
||||
brand: {
|
||||
|
|
|
@ -11,6 +11,7 @@ export default createManifestHandler({
|
|||
const apiBaseURL = process.env.APP_API_BASE_URL ?? appBaseUrl;
|
||||
|
||||
const manifest: AppManifest = {
|
||||
about: "CRM App allows synchronization of customers from Saleor to other platforms",
|
||||
appUrl: iframeBaseUrl,
|
||||
author: "Saleor Commerce",
|
||||
brand: {
|
||||
|
|
|
@ -9,6 +9,8 @@ export default createManifestHandler({
|
|||
const apiBaseURL = process.env.APP_API_BASE_URL ?? appBaseUrl;
|
||||
|
||||
const manifest: AppManifest = {
|
||||
about:
|
||||
"Data Importer allows batch import of shop data to Saleor from sources like CSV or Excel",
|
||||
appUrl: iframeBaseUrl,
|
||||
author: "Saleor Commerce",
|
||||
brand: {
|
||||
|
|
|
@ -9,6 +9,8 @@ export default createManifestHandler({
|
|||
const apiBaseURL = process.env.APP_API_BASE_URL ?? appBaseUrl;
|
||||
|
||||
const manifest: AppManifest = {
|
||||
about:
|
||||
"Emails & Messages App is a multi-vendor Saleor app that integrates with notification services.",
|
||||
appUrl: iframeBaseUrl,
|
||||
author: "Saleor Commerce",
|
||||
brand: {
|
||||
|
|
|
@ -11,6 +11,8 @@ export default createManifestHandler({
|
|||
const apiBaseURL = process.env.APP_API_BASE_URL ?? appBaseUrl;
|
||||
|
||||
const manifest: AppManifest = {
|
||||
about:
|
||||
"An app that generates PDF invoices for Orders and stores them in Saleor file storage.",
|
||||
appUrl: iframeBaseUrl,
|
||||
author: "Saleor Commerce",
|
||||
brand: {
|
||||
|
|
|
@ -15,6 +15,7 @@ const handler = createManifestHandler({
|
|||
const apiBaseURL = process.env.APP_API_BASE_URL ?? appBaseUrl;
|
||||
|
||||
return {
|
||||
about: "Klaviyo integration allows sending Klaviyo notifications on Saleor events.",
|
||||
appUrl: iframeBaseUrl,
|
||||
author: "Saleor Commerce",
|
||||
brand: {
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
"@material-ui/core": "^4.12.4",
|
||||
"@material-ui/icons": "^4.11.3",
|
||||
"@material-ui/lab": "4.0.0-alpha.61",
|
||||
"@saleor/app-sdk": "0.40.1",
|
||||
"@saleor/app-sdk": "0.41.0",
|
||||
"@saleor/apps-shared": "workspace:*",
|
||||
"@saleor/apps-ui": "workspace:*",
|
||||
"@saleor/macaw-ui": "0.8.0-pre.95",
|
||||
|
|
|
@ -14,6 +14,7 @@ export default createManifestHandler({
|
|||
const apiBaseURL = process.env.APP_API_BASE_URL ?? appBaseUrl;
|
||||
|
||||
const manifest: AppManifest = {
|
||||
about: "Generate feeds consumed by Merchant Platforms",
|
||||
appUrl: iframeBaseUrl,
|
||||
author: "Saleor Commerce",
|
||||
brand: {
|
||||
|
|
|
@ -15,7 +15,10 @@ export default createManifestHandler({
|
|||
const apiBaseURL = process.env.APP_API_BASE_URL ?? appBaseUrl;
|
||||
|
||||
const manifest: AppManifest = {
|
||||
about:
|
||||
"Search App is a multi-integration app that connects your Saleor store with search engines.",
|
||||
appUrl: iframeBaseUrl,
|
||||
author: "Saleor Commerce",
|
||||
brand: {
|
||||
logo: {
|
||||
default: `${apiBaseURL}/logo.png`,
|
||||
|
|
|
@ -10,6 +10,8 @@ const handler = createManifestHandler({
|
|||
const apiBaseURL = process.env.APP_API_BASE_URL ?? appBaseUrl;
|
||||
|
||||
const manifest: AppManifest = {
|
||||
about:
|
||||
"Saleor Slack integration allows you to get notifications on Slack channel from Saleor events.",
|
||||
appUrl: iframeBaseUrl,
|
||||
author: "Saleor Commerce",
|
||||
brand: {
|
||||
|
|
|
@ -14,6 +14,7 @@ export default createManifestHandler({
|
|||
const apiBaseURL = process.env.APP_API_BASE_URL ?? appBaseUrl;
|
||||
|
||||
const manifest: AppManifest = {
|
||||
about: "Taxes App allows dynamic taxes calculations for orders",
|
||||
appUrl: iframeBaseUrl,
|
||||
author: "Saleor Commerce",
|
||||
brand: {
|
||||
|
|
3
packages/e2e/.env.example
Normal file
3
packages/e2e/.env.example
Normal file
|
@ -0,0 +1,3 @@
|
|||
INSTANCE_URL=
|
||||
DASHBOARD_USER_EMAIL=
|
||||
DASHBOARD_USER_PASSWORD=
|
4
packages/e2e/.eslintrc
Normal file
4
packages/e2e/.eslintrc
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"root": true,
|
||||
"extends": ["saleor"]
|
||||
}
|
3
packages/e2e/.gitignore
vendored
Normal file
3
packages/e2e/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
/test-results/
|
||||
/playwright-report/
|
||||
/playwright/.cache/
|
20
packages/e2e/package.json
Normal file
20
packages/e2e/package.json
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"name": "@saleor/e2e",
|
||||
"description": "",
|
||||
"version": "1.0.0",
|
||||
"author": "",
|
||||
"scripts": {
|
||||
"e2e": "playwright test",
|
||||
"e2e:ui": "playwright test --ui"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.35.1",
|
||||
"@saleor/app-sdk": "0.40.1",
|
||||
"dotenv": "^16.3.1",
|
||||
"eslint-config-saleor": "workspace:*",
|
||||
"zod": "3.20.2"
|
||||
},
|
||||
"keywords": [],
|
||||
"license": "ISC",
|
||||
"main": "index.js"
|
||||
}
|
62
packages/e2e/playwright.config.ts
Normal file
62
packages/e2e/playwright.config.ts
Normal file
|
@ -0,0 +1,62 @@
|
|||
import { defineConfig, devices } from "@playwright/test";
|
||||
|
||||
/**
|
||||
* Read environment variables from file.
|
||||
* Check setup/configuration
|
||||
*/
|
||||
require("dotenv").config();
|
||||
|
||||
/**
|
||||
* See https://playwright.dev/docs/test-configuration.
|
||||
*/
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default defineConfig({
|
||||
testDir: "./tests",
|
||||
/* Run tests in files in parallel */
|
||||
fullyParallel: false,
|
||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||
forbidOnly: !!process.env.CI,
|
||||
/* Retry on CI only */
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
/* Opt out of parallel tests on CI. */
|
||||
workers: process.env.CI ? 1 : undefined,
|
||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||
// reporter: "html",
|
||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||
use: {
|
||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||
// baseURL: 'http://127.0.0.1:3000',
|
||||
|
||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||
trace: "on-first-retry",
|
||||
},
|
||||
|
||||
/* Configure projects for major browsers */
|
||||
projects: [
|
||||
{
|
||||
name: "chromium",
|
||||
use: { ...devices["Desktop Chrome"] },
|
||||
},
|
||||
/*
|
||||
*
|
||||
* {
|
||||
* name: 'firefox',
|
||||
* use: { ...devices['Desktop Firefox'] },
|
||||
* },
|
||||
*
|
||||
* {
|
||||
* name: 'webkit',
|
||||
* use: { ...devices['Desktop Safari'] },
|
||||
* },
|
||||
*/
|
||||
],
|
||||
|
||||
/* Run your local dev server before starting the tests */
|
||||
/*
|
||||
* webServer: {
|
||||
* command: 'npm run start',
|
||||
* url: 'http://127.0.0.1:3000',
|
||||
* reuseExistingServer: !process.env.CI,
|
||||
* },
|
||||
*/
|
||||
});
|
17
packages/e2e/setup/configuration.ts
Normal file
17
packages/e2e/setup/configuration.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import { z } from "zod";
|
||||
|
||||
const instanceUrl = process.env.INSTANCE_URL;
|
||||
const dashboardUserEmail = process.env.DASHBOARD_USER_EMAIL;
|
||||
const dashboardUserPassword = process.env.DASHBOARD_USER_PASSWORD;
|
||||
|
||||
export const configuration = z
|
||||
.object({
|
||||
instanceUrl: z.string().nonempty().url(),
|
||||
dashboardUserEmail: z.string().nonempty(),
|
||||
dashboardUserPassword: z.string().nonempty(),
|
||||
})
|
||||
.parse({
|
||||
instanceUrl,
|
||||
dashboardUserEmail,
|
||||
dashboardUserPassword,
|
||||
});
|
20
packages/e2e/setup/routing.ts
Normal file
20
packages/e2e/setup/routing.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { configuration } from "./configuration";
|
||||
|
||||
export const appUrls = (appUrl: string) => ({
|
||||
manifest: new URL("/api/manifest", appUrl).href,
|
||||
register: new URL("/api/register", appUrl).href,
|
||||
});
|
||||
|
||||
const saleorUrls = (dashboardUrl: string) => ({
|
||||
dashboard: {
|
||||
homepage: new URL("/dashboard", dashboardUrl).href,
|
||||
apps: new URL("/dashboard/apps", dashboardUrl).href,
|
||||
appInstallPage: (appManifest: string) =>
|
||||
new URL(`/dashboard/apps/install?manifestUrl=${appManifest}`, dashboardUrl).href,
|
||||
},
|
||||
api: new URL("/graphql/", dashboardUrl).href,
|
||||
});
|
||||
|
||||
export const routing = {
|
||||
saleor: saleorUrls(configuration.instanceUrl),
|
||||
};
|
66
packages/e2e/tests/apps-installation.spec.ts
Normal file
66
packages/e2e/tests/apps-installation.spec.ts
Normal file
|
@ -0,0 +1,66 @@
|
|||
import { test, expect, Page } from "@playwright/test";
|
||||
import { logInIntoDashboard } from "./operations/log-in-to-dashboard";
|
||||
import { installTheApp } from "./operations/install-app";
|
||||
import { appUrls, routing } from "../setup/routing";
|
||||
import { AppManifest } from "@saleor/app-sdk/types";
|
||||
import { assertAppAvailable } from "./assertions/assert-app-available";
|
||||
|
||||
/**
|
||||
* Hardcoded list of every app deployed on staging and production.
|
||||
* TODO: Eventually this should be the entry point and the list should be provided via env
|
||||
*/
|
||||
const apps: string[] = [
|
||||
"taxes",
|
||||
"crm",
|
||||
"cms",
|
||||
"emails-and-messages",
|
||||
"product-feed",
|
||||
"search",
|
||||
"klaviyo",
|
||||
"slack",
|
||||
"invoices",
|
||||
"data-importer",
|
||||
].reduce((urls, appSegment) => {
|
||||
urls.push(`https://${appSegment}.saleor.app`);
|
||||
urls.push(`https://${appSegment}.staging.saleor.app`);
|
||||
|
||||
return urls;
|
||||
}, []);
|
||||
/*
|
||||
*
|
||||
* test.describe.configure({
|
||||
* mode: "parallel",
|
||||
* });
|
||||
*/
|
||||
|
||||
/**
|
||||
* TODO Enable parallel mode. It cant work with beforeAll.
|
||||
*/
|
||||
test.describe("Apps Installation", () => {
|
||||
let page: Page;
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
if (page) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("beforeAll run");
|
||||
|
||||
page = await browser.newPage();
|
||||
|
||||
await logInIntoDashboard({ page });
|
||||
});
|
||||
|
||||
for (const appUrl of apps) {
|
||||
test(`App: "${appUrl}" can be installed in the dashboard`, async () => {
|
||||
const appManifestUrl = appUrl + "/api/manifest";
|
||||
|
||||
await installTheApp({ page, appManifest: appManifestUrl }); // todo extract to helper
|
||||
|
||||
const appManifest = (await fetch(appManifestUrl).then((r) => r.json())) as AppManifest;
|
||||
const appName = appManifest.name;
|
||||
|
||||
await assertAppAvailable({ page, appName });
|
||||
});
|
||||
}
|
||||
});
|
|
@ -0,0 +1,33 @@
|
|||
import { Page, test, expect } from "@playwright/test";
|
||||
import { logInIntoDashboard } from "../../operations/log-in-to-dashboard";
|
||||
import { openTheApp } from "../../operations/open-app";
|
||||
|
||||
test.describe("Klaviyo Configuration", () => {
|
||||
let page: Page;
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
if (page) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("beforeAll run");
|
||||
|
||||
page = await browser.newPage();
|
||||
|
||||
await logInIntoDashboard({ page });
|
||||
});
|
||||
|
||||
// Test assumes app is installed
|
||||
test("App can be configured @stable @critical", async () => {
|
||||
await openTheApp({ page, appName: "Klaviyo" });
|
||||
|
||||
// todo make more strict selector
|
||||
const iframeLocator = page.frameLocator("iframe");
|
||||
|
||||
await expect(iframeLocator.getByLabel("CUSTOMER_CREATED_METRIC")).toBeVisible();
|
||||
await expect(iframeLocator.getByLabel("FULFILLMENT_CREATED_METRIC")).toBeVisible();
|
||||
await expect(iframeLocator.getByLabel("ORDER_CREATED_METRIC")).toBeVisible();
|
||||
await expect(iframeLocator.getByLabel("ORDER_FULLY_PAID_METRIC")).toBeVisible();
|
||||
await expect(iframeLocator.getByLabel("PUBLIC_TOKEN")).toBeVisible();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,8 @@
|
|||
import { expect, FrameLocator } from "@playwright/test";
|
||||
|
||||
export const assertAppRender = async (iframeLocator: FrameLocator) => {
|
||||
await expect(iframeLocator.getByTestId("root-heading")).toBeVisible();
|
||||
await expect(iframeLocator.getByTestId("s3-configuration-section")).toBeVisible();
|
||||
await expect(iframeLocator.getByTestId("channels-configuration-section")).toBeVisible();
|
||||
await expect(iframeLocator.getByTestId("categories-mapping-section")).toBeVisible();
|
||||
};
|
|
@ -0,0 +1,10 @@
|
|||
import { FrameLocator, Locator } from "@playwright/test";
|
||||
|
||||
export const fillAwsS3Form = async (iframeLocator: FrameLocator) => {
|
||||
await iframeLocator.getByLabel("Amazon access key ID").fill("test-id");
|
||||
await iframeLocator.getByLabel("Amazon secret access key").fill("test-secret");
|
||||
await iframeLocator.getByLabel("Bucket name").fill("test-bucket");
|
||||
await iframeLocator.getByLabel("Bucket region").fill("eu-west-1");
|
||||
|
||||
await iframeLocator.getByText("Save bucket configuration").click();
|
||||
};
|
|
@ -0,0 +1,16 @@
|
|||
import { FrameLocator } from "@playwright/test";
|
||||
|
||||
export const fillChannelConfig = async (iframeLocator: FrameLocator) => {
|
||||
const sectionsSelector = await iframeLocator.getByTestId("channels-configuration-section");
|
||||
|
||||
const channelRow = sectionsSelector.getByText("Default channel"); // todo add test-id
|
||||
|
||||
channelRow.click();
|
||||
|
||||
await sectionsSelector.getByLabel("Storefront URL").fill("https://www.example.com");
|
||||
await sectionsSelector
|
||||
.getByLabel("Storefront product URL")
|
||||
.fill("https://www.example.com/{productId}");
|
||||
|
||||
await sectionsSelector.getByText("Save channel settings").click();
|
||||
};
|
|
@ -0,0 +1,12 @@
|
|||
import { FrameLocator, expect } from "@playwright/test";
|
||||
|
||||
export const navigateToCategoryMapping = async (iframeLocator: FrameLocator) => {
|
||||
await iframeLocator.getByText("Map categories").click({ force: true });
|
||||
|
||||
await expect(iframeLocator.getByTestId("categories-mapping-container")).toBeVisible();
|
||||
|
||||
// todo doesnt load, probably app must be optimized
|
||||
await expect(iframeLocator.getByText("Accessories")).toBeVisible({
|
||||
timeout: 120000,
|
||||
});
|
||||
};
|
|
@ -0,0 +1,7 @@
|
|||
import { FrameLocator } from "@playwright/test";
|
||||
|
||||
export const setCategoryMapping = async (iframeLocator: FrameLocator) => {
|
||||
await iframeLocator.locator("select").first().selectOption({ index: 0 });
|
||||
|
||||
await iframeLocator.getByText("Save").first().click();
|
||||
};
|
|
@ -0,0 +1,63 @@
|
|||
import { Page, test, expect } from "@playwright/test";
|
||||
import { logInIntoDashboard } from "../../operations/log-in-to-dashboard";
|
||||
import { openTheApp } from "../../operations/open-app";
|
||||
import { fillAwsS3Form } from "./operations/fill-aws-s3-form";
|
||||
import { assertAppRender } from "./assertions/assert-app-render";
|
||||
import { fillChannelConfig } from "./operations/fill-channel-config";
|
||||
import { setCategoryMapping } from "./operations/set-category-mapping";
|
||||
import { navigateToCategoryMapping } from "./operations/navigate-to-category-mapping";
|
||||
|
||||
test.describe("Product Feed Configuration", () => {
|
||||
let page: Page;
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
if (page) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("beforeAll run");
|
||||
|
||||
page = await browser.newPage();
|
||||
|
||||
await logInIntoDashboard({ page });
|
||||
});
|
||||
|
||||
// Test assumes app is installed
|
||||
test("App can be configured @stable @critical", async () => {
|
||||
await openTheApp({ page, appName: "Product Feed" });
|
||||
|
||||
// todo make more strict selector
|
||||
const iframeLocator = page.frameLocator("iframe");
|
||||
|
||||
await assertAppRender(iframeLocator);
|
||||
|
||||
await fillAwsS3Form(iframeLocator);
|
||||
|
||||
await expect(page.getByText("Updated S3 configuration")).toBeVisible({ timeout: 10000 });
|
||||
|
||||
await fillChannelConfig(iframeLocator);
|
||||
|
||||
await expect(page.getByText("Success")).toBeVisible({
|
||||
timeout: 10000,
|
||||
}); // todo add more meaningul message, only "success" is set
|
||||
});
|
||||
|
||||
/**
|
||||
* Test fails. Probably because of a very big list of Google categories that are fetched.
|
||||
* TODO: Fix this in the app
|
||||
*/
|
||||
test.skip("App can be configured with categories mapping", async () => {
|
||||
await openTheApp({ page, appName: "Product Feed" });
|
||||
|
||||
// todo make more strict selector
|
||||
const iframeLocator = page.frameLocator("iframe");
|
||||
|
||||
await navigateToCategoryMapping(iframeLocator);
|
||||
|
||||
await setCategoryMapping(iframeLocator);
|
||||
|
||||
await expect(page.getByText("Success")).toBeVisible({ timeout: 10000 }); // todo add more meaningul message, only "success" is set
|
||||
|
||||
await iframeLocator.getByText("Configuration").click();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,21 @@
|
|||
import { expect, FrameLocator } from "@playwright/test";
|
||||
|
||||
export const assertAppRender = async (iframeLocator: FrameLocator) => {
|
||||
/*
|
||||
* TODO Add test-ids assertions after added to app
|
||||
* todo assert empty state, but these tests must ensure app has fresh install
|
||||
*/
|
||||
await expect(
|
||||
iframeLocator.getByRole("heading", {
|
||||
name: "Tax providers",
|
||||
})
|
||||
).toBeVisible();
|
||||
await expect(iframeLocator.getByRole("heading", { name: "Available channels" })).toBeVisible();
|
||||
// await expect(iframeLocator.getByRole("heading", { name: "Tax code matcher" })).toBeVisible(); // todo enable when app enables
|
||||
|
||||
const addProviderButton = await iframeLocator.getByRole("button", {
|
||||
name: new RegExp(/Add new|Add first provider/),
|
||||
});
|
||||
|
||||
await expect(addProviderButton).toBeVisible();
|
||||
};
|
57
packages/e2e/tests/apps/taxes/taxes-configuration.spec.ts
Normal file
57
packages/e2e/tests/apps/taxes/taxes-configuration.spec.ts
Normal file
|
@ -0,0 +1,57 @@
|
|||
import { Page, test, expect } from "@playwright/test";
|
||||
import { logInIntoDashboard } from "../../operations/log-in-to-dashboard";
|
||||
import { openTheApp } from "../../operations/open-app";
|
||||
import { assertAppRender } from "./assertions/assert-app-render";
|
||||
|
||||
// Test assumes app is installed
|
||||
test.describe("Taxes Configuration", () => {
|
||||
let page: Page;
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
if (page) {
|
||||
return;
|
||||
}
|
||||
|
||||
page = await browser.newPage();
|
||||
|
||||
await logInIntoDashboard({ page });
|
||||
});
|
||||
|
||||
test("App renders config screen @stable @critical", async () => {
|
||||
await openTheApp({ page, appName: "Taxes" });
|
||||
|
||||
// todo make more strict selector
|
||||
const iframeLocator = page.frameLocator("iframe");
|
||||
|
||||
await assertAppRender(iframeLocator);
|
||||
});
|
||||
|
||||
test("App can configure new Taxjar provider @taxjar", async () => {
|
||||
await openTheApp({ page, appName: "Taxes" });
|
||||
|
||||
// todo make more strict selector
|
||||
const iframeLocator = page.frameLocator("iframe");
|
||||
|
||||
await iframeLocator
|
||||
.getByRole("button", {
|
||||
name: new RegExp(/Add new|Add first provider/),
|
||||
})
|
||||
.click();
|
||||
|
||||
await iframeLocator.getByRole("button", { name: "Choose" }).first().click(); // todo - test id
|
||||
|
||||
await iframeLocator.getByLabel("Configuration name").fill("Test Taxjar provider");
|
||||
await iframeLocator.getByLabel("API key").fill("TEST");
|
||||
await iframeLocator.getByLabel("Street").fill("Street");
|
||||
await iframeLocator.getByLabel("City").fill("City");
|
||||
await iframeLocator.getByLabel("State").fill("State");
|
||||
await iframeLocator.getByRole("combobox", { name: "Country *" }).click();
|
||||
await iframeLocator.getByText("Albania").click();
|
||||
await iframeLocator.getByLabel("Zip").fill("Zip");
|
||||
|
||||
await iframeLocator.getByRole("button", { name: "Save" }).first().click(); // todo - test id
|
||||
});
|
||||
|
||||
// todo
|
||||
test.skip("App can configure new Avalara provider @avalara", async () => {});
|
||||
});
|
19
packages/e2e/tests/assertions/assert-app-available.ts
Normal file
19
packages/e2e/tests/assertions/assert-app-available.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { expect, Page } from "@playwright/test";
|
||||
import { routing } from "../../setup/routing";
|
||||
import { configuration } from "../../setup/configuration";
|
||||
|
||||
interface checkIfAppIsAvailableArgs {
|
||||
page: Page;
|
||||
appName: string;
|
||||
}
|
||||
|
||||
export const assertAppAvailable = async ({ page, appName }: checkIfAppIsAvailableArgs) => {
|
||||
await page.goto(routing.saleor.dashboard.apps, { timeout: 20000, waitUntil: "load" });
|
||||
|
||||
// todo need data-testid. this element is not unique
|
||||
const appEntry = await page.getByText(appName).first();
|
||||
|
||||
await expect(appEntry).toBeVisible();
|
||||
|
||||
await expect(await page.getByText("Problem occured during installation.")).toBeHidden();
|
||||
};
|
22
packages/e2e/tests/operations/install-app.ts
Normal file
22
packages/e2e/tests/operations/install-app.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { Page } from "@playwright/test";
|
||||
import { routing } from "../../setup/routing";
|
||||
|
||||
interface InstallTheAppArgs {
|
||||
page: Page;
|
||||
appManifest: string;
|
||||
}
|
||||
|
||||
export const installTheApp = async ({ page, appManifest }: InstallTheAppArgs) => {
|
||||
// got to Apps page, assuming user is logged in
|
||||
await page.goto(routing.saleor.dashboard.appInstallPage(appManifest), {
|
||||
timeout: 20000,
|
||||
waitUntil: "load",
|
||||
});
|
||||
|
||||
console.log("Navigated to", page.url());
|
||||
|
||||
await page.getByRole("button", { name: "Install App" }).click();
|
||||
|
||||
// wait for the toast
|
||||
await page.getByText("App installed").isVisible();
|
||||
};
|
25
packages/e2e/tests/operations/log-in-to-dashboard.ts
Normal file
25
packages/e2e/tests/operations/log-in-to-dashboard.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import { Page, expect } from "@playwright/test";
|
||||
import { configuration } from "../../setup/configuration";
|
||||
import { routing } from "../../setup/routing";
|
||||
|
||||
interface LogInIntoDashboardArgs {
|
||||
page: Page;
|
||||
}
|
||||
|
||||
export const logInIntoDashboard = async ({ page }: LogInIntoDashboardArgs) => {
|
||||
console.log("Will redirect to", routing.saleor.dashboard.homepage);
|
||||
|
||||
await page.goto(routing.saleor.dashboard.homepage, { timeout: 20000, waitUntil: "load" });
|
||||
|
||||
const url = page.url();
|
||||
|
||||
await page.locator('[data-test-id="email"]').click();
|
||||
await page.locator('[data-test-id="email"]').fill(configuration.dashboardUserEmail);
|
||||
await page.locator('[data-test-id="email"]').press("Tab");
|
||||
await page.locator('[data-test-id="password"]').fill(configuration.dashboardUserPassword);
|
||||
await page.locator('[data-test-id="submit"]').click();
|
||||
|
||||
await expect(page.locator('[data-test-id="welcome-header"]')).toBeVisible();
|
||||
|
||||
console.log("Logged in");
|
||||
};
|
21
packages/e2e/tests/operations/open-app.ts
Normal file
21
packages/e2e/tests/operations/open-app.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { Page, expect } from "@playwright/test";
|
||||
import { routing } from "../../setup/routing";
|
||||
|
||||
interface InstallTheAppArgs {
|
||||
page: Page;
|
||||
appName: string;
|
||||
}
|
||||
|
||||
export const openTheApp = async ({ page, appName }: InstallTheAppArgs) => {
|
||||
// got to Apps page, assuming user is logged in
|
||||
await page.goto(routing.saleor.dashboard.apps, {
|
||||
waitUntil: "load",
|
||||
});
|
||||
|
||||
console.log("Navigated to", page.url());
|
||||
|
||||
// todo it must be test-id because we also have same name in appstore list
|
||||
await page.getByText(appName).first().click();
|
||||
|
||||
await expect(page.url()).toMatch(new RegExp("https:\\/\\/.*\\/dashboard\\/apps\\/.*\\/app"));
|
||||
};
|
12
packages/e2e/turbo.json
Normal file
12
packages/e2e/turbo.json
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"$schema": "https://turbo.build/schema.json",
|
||||
"extends": ["//"],
|
||||
"pipeline": {
|
||||
"e2e": {
|
||||
"env": ["INSTANCE_URL", "DASHBOARD_USER_PASSWORD", "DASHBOARD_USER_EMAIL"]
|
||||
},
|
||||
"e2e:ui": {
|
||||
"env": ["INSTANCE_URL", "DASHBOARD_USER_PASSWORD", "DASHBOARD_USER_EMAIL"]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,7 +17,7 @@
|
|||
"@material-ui/core": "^4.12.4",
|
||||
"@material-ui/icons": "^4.11.3",
|
||||
"@material-ui/lab": "4.0.0-alpha.61",
|
||||
"@saleor/app-sdk": "0.40.1",
|
||||
"@saleor/app-sdk": "0.41.0",
|
||||
"@saleor/macaw-ui": "^0.7.2",
|
||||
"@types/react": "18.2.5",
|
||||
"@types/react-dom": "18.2.5",
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
"typescript": "5.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@saleor/app-sdk": "0.40.1",
|
||||
"@saleor/app-sdk": "0.41.0",
|
||||
"@saleor/macaw-ui": "0.8.0-pre.95",
|
||||
"@types/react": "18.2.5",
|
||||
"@types/react-dom": "18.2.5",
|
||||
|
|
557
pnpm-lock.yaml
557
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"$schema": "https://turbo.build/schema.json",
|
||||
"globalDependencies": ["**/.env.*local"],
|
||||
"globalEnv": ["VERCEL_ENV", "APP_LOG_LEVEL", "NODE_ENV"],
|
||||
"globalEnv": ["VERCEL_ENV", "APP_LOG_LEVEL", "NODE_ENV", "CI"],
|
||||
"pipeline": {
|
||||
"build": {
|
||||
"env": ["NEXT_PUBLIC_VERCEL_ENV"],
|
||||
|
|
Loading…
Reference in a new issue