Add smoke test
This commit is contained in:
parent
54e77d495e
commit
fb68ded38f
15 changed files with 331 additions and 0 deletions
27
apps/e2e-tests/.github/workflows/playwright.yml
vendored
Normal file
27
apps/e2e-tests/.github/workflows/playwright.yml
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
name: Playwright Tests
|
||||
on:
|
||||
push:
|
||||
branches: [ main, master ]
|
||||
pull_request:
|
||||
branches: [ main, master ]
|
||||
jobs:
|
||||
test:
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
- name: Install Playwright Browsers
|
||||
run: pnpm dlx playwright install --with-deps
|
||||
- name: Run Playwright tests
|
||||
run: pnpm dlx playwright test
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: playwright-report
|
||||
path: playwright-report/
|
||||
retention-days: 30
|
4
apps/e2e-tests/.gitignore
vendored
Normal file
4
apps/e2e-tests/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
node_modules/
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
/playwright/.cache/
|
16
apps/e2e-tests/configuration.ts
Normal file
16
apps/e2e-tests/configuration.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import appUrls from "./urls/app-urls";
|
||||
import saleorUrls from "./urls/saleor-urls";
|
||||
|
||||
export const appName = process.env.APP_NAME; // TODO: name should be taken from the manifest to eliminate possible footguns
|
||||
export const appUrl = process.env.APP_URL;
|
||||
export const instanceUrl = process.env.INSTANCE_URL;
|
||||
export const dashboardUserEmail = process.env.DASHBOARD_USER_EMAIL;
|
||||
export const dashboardUserPassword = process.env.DASHBOARD_USER_PASSWORD;
|
||||
|
||||
export const urls = {
|
||||
app: {
|
||||
baseUrl: appUrl,
|
||||
...appUrls(appUrl)
|
||||
},
|
||||
saleor: saleorUrls(instanceUrl)
|
||||
}
|
13
apps/e2e-tests/package.json
Normal file
13
apps/e2e-tests/package.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "e2e-tests",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.29.2"
|
||||
}
|
||||
}
|
100
apps/e2e-tests/playwright.config.ts
Normal file
100
apps/e2e-tests/playwright.config.ts
Normal file
|
@ -0,0 +1,100 @@
|
|||
import type { PlaywrightTestConfig } from '@playwright/test';
|
||||
import { devices } from '@playwright/test';
|
||||
|
||||
/**
|
||||
* Read environment variables from file.
|
||||
* https://github.com/motdotla/dotenv
|
||||
*/
|
||||
// require('dotenv').config();
|
||||
|
||||
/**
|
||||
* See https://playwright.dev/docs/test-configuration.
|
||||
*/
|
||||
const config: PlaywrightTestConfig = {
|
||||
testDir: './tests',
|
||||
/* Maximum time one test can run for. */
|
||||
timeout: 30 * 1000,
|
||||
expect: {
|
||||
/**
|
||||
* Maximum time expect() should wait for the condition to be met.
|
||||
* For example in `await expect(locator).toHaveText();`
|
||||
*/
|
||||
timeout: 5000
|
||||
},
|
||||
/* Run tests in files in parallel */
|
||||
fullyParallel: true,
|
||||
/* 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: {
|
||||
/* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */
|
||||
actionTimeout: 0,
|
||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||
// baseURL: 'http://localhost: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'],
|
||||
// },
|
||||
// },
|
||||
|
||||
/* Test against mobile viewports. */
|
||||
// {
|
||||
// name: 'Mobile Chrome',
|
||||
// use: {
|
||||
// ...devices['Pixel 5'],
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// name: 'Mobile Safari',
|
||||
// use: {
|
||||
// ...devices['iPhone 12'],
|
||||
// },
|
||||
// },
|
||||
|
||||
/* Test against branded browsers. */
|
||||
// {
|
||||
// name: 'Microsoft Edge',
|
||||
// use: {
|
||||
// channel: 'msedge',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// name: 'Google Chrome',
|
||||
// use: {
|
||||
// channel: 'chrome',
|
||||
// },
|
||||
// },
|
||||
],
|
||||
|
||||
/* Folder for test artifacts such as screenshots, videos, traces, etc. */
|
||||
// outputDir: 'test-results/',
|
||||
|
||||
/* Run your local dev server before starting the tests */
|
||||
// webServer: {
|
||||
// command: 'npm run start',
|
||||
// port: 3000,
|
||||
// },
|
||||
};
|
||||
|
||||
export default config;
|
53
apps/e2e-tests/tests/example.spec.ts
Normal file
53
apps/e2e-tests/tests/example.spec.ts
Normal file
|
@ -0,0 +1,53 @@
|
|||
import { expect, test } from '@playwright/test';
|
||||
import { appName, urls } from '../configuration';
|
||||
import { checkIfAppIsAvailable } from '../utils/check-if-app-is-available';
|
||||
import { installTheApp } from '../utils/install-the-app';
|
||||
import { logInIntoDashboard } from '../utils/log-in-into-dashboard';
|
||||
import { randomString } from '../utils/random-string';
|
||||
|
||||
test("The app can be installed", async ({page}) => {
|
||||
// TODO: add function to completely remove all the installed apps in the test env
|
||||
// alternative: make locators tighter to restrict it only to the tested app
|
||||
await logInIntoDashboard({page})
|
||||
await installTheApp({page})
|
||||
await checkIfAppIsAvailable({page})
|
||||
})
|
||||
|
||||
test("Smoke test of the configuration", async ({page}) => {
|
||||
await logInIntoDashboard({page})
|
||||
|
||||
// open app configuration view
|
||||
await page.goto(urls.saleor.dashboard.apps, {timeout: 20000, waitUntil: "load"});
|
||||
await page.getByText(appName).first().click()
|
||||
|
||||
// generate unique marker to ensure values are updated during this test run
|
||||
const marker = randomString()
|
||||
|
||||
// fill the configuration fields
|
||||
await page.frameLocator('iframe').locator('input[name="secretKey"]').click();
|
||||
await page.frameLocator('iframe').locator('input[name="secretKey"]').fill('secret-key-'+marker);
|
||||
await page.frameLocator('iframe').locator('input[name="searchKey"]').click();
|
||||
await page.frameLocator('iframe').locator('input[name="searchKey"]').fill('search-key-'+marker);
|
||||
await page.frameLocator('iframe').locator('input[name="appId"]').click();
|
||||
await page.frameLocator('iframe').locator('input[name="appId"]').fill('app-id-'+marker);
|
||||
await page.frameLocator('iframe').locator('input[name="indexNamePrefix"]').click();
|
||||
await page.frameLocator('iframe').locator('input[name="indexNamePrefix"]').fill('prefix-'+marker);
|
||||
|
||||
// submit and wait for the confirmation toast
|
||||
await page.mouse.wheel(0, 20); // TODO: investigate how to automatically scroll
|
||||
await page.frameLocator('iframe').getByRole('button', { name: 'Save' }).click();
|
||||
await page.getByText('Configuration saved!').isVisible();
|
||||
|
||||
// check if the data persists
|
||||
await page.goto(urls.saleor.dashboard.apps, {timeout: 20000, waitUntil: "load"});
|
||||
await page.getByText(appName).first().click()
|
||||
|
||||
// check if the form data loaded
|
||||
await page.frameLocator('iframe').getByRole('button', { name: 'Save' }).isEnabled();
|
||||
|
||||
// check field values
|
||||
await expect(await page.frameLocator('iframe').locator('input[name="secretKey"]').inputValue()).toBe("secret-key-"+marker);
|
||||
await expect(await page.frameLocator('iframe').locator('input[name="searchKey"]').inputValue()).toBe("search-key-"+marker);
|
||||
await expect(await page.frameLocator('iframe').locator('input[name="appId"]').inputValue()).toBe("app-id-"+marker);
|
||||
await expect(await page.frameLocator('iframe').locator('input[name="indexNamePrefix"]').inputValue()).toBe("prefix-"+marker);
|
||||
})
|
17
apps/e2e-tests/types.ts
Normal file
17
apps/e2e-tests/types.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
export interface WebhookManifest {
|
||||
name: string;
|
||||
targetUrl: string;
|
||||
asyncEvents: string[];
|
||||
isActive: boolean;
|
||||
query: string;
|
||||
}
|
||||
|
||||
export interface Manifest {
|
||||
id: string;
|
||||
version: string;
|
||||
name: string;
|
||||
permissions: string[];
|
||||
appUrl: string;
|
||||
tokenTargetUrl: string;
|
||||
webhooks: WebhookManifest[];
|
||||
}
|
7
apps/e2e-tests/urls/app-urls.ts
Normal file
7
apps/e2e-tests/urls/app-urls.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
|
||||
export const appUrls = (appUrl: string) => ({
|
||||
manifest: new URL('/api/manifest', appUrl).href,
|
||||
register: new URL('/api/register', appUrl).href
|
||||
})
|
||||
|
||||
export default appUrls
|
9
apps/e2e-tests/urls/saleor-urls.ts
Normal file
9
apps/e2e-tests/urls/saleor-urls.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
export const saleorUrls = (url: string) => ({
|
||||
dashboard: {
|
||||
homepage: new URL('/dashboard', url).href,
|
||||
apps: new URL('/dashboard/apps', url).href
|
||||
},
|
||||
api: new URL('/graphql/', url).href
|
||||
})
|
||||
|
||||
export default saleorUrls
|
17
apps/e2e-tests/utils/check-if-app-is-available.ts
Normal file
17
apps/e2e-tests/utils/check-if-app-is-available.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import { expect, Page } from "@playwright/test";
|
||||
import { appName, urls } from "../configuration";
|
||||
|
||||
interface checkIfAppIsAvailableArgs {
|
||||
page: Page
|
||||
}
|
||||
|
||||
export const checkIfAppIsAvailable = async ({page}: checkIfAppIsAvailableArgs) => {
|
||||
// got to Apps page, assuming user is logged in
|
||||
await page.goto(urls.saleor.dashboard.apps, {timeout: 20000, waitUntil: "load"});
|
||||
|
||||
// look for a entry with name of our app
|
||||
await expect(await page.getByText(appName).first()).toBeVisible()
|
||||
|
||||
// and confirm its installed
|
||||
await expect(await page.getByText('Problem occured during installation.')).toBeHidden()
|
||||
}
|
5
apps/e2e-tests/utils/delay.ts
Normal file
5
apps/e2e-tests/utils/delay.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
export const delay = (time) => {
|
||||
return new Promise(function(resolve) {
|
||||
setTimeout(resolve, time)
|
||||
});
|
||||
}
|
22
apps/e2e-tests/utils/install-the-app.ts
Normal file
22
apps/e2e-tests/utils/install-the-app.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { Page } from "@playwright/test";
|
||||
import { urls } from "../configuration";
|
||||
|
||||
interface InstallTheAppArgs {
|
||||
page: Page
|
||||
}
|
||||
|
||||
export const installTheApp = async ({page}: InstallTheAppArgs) => {
|
||||
// got to Apps page, assuming user is logged in
|
||||
await page.goto(urls.saleor.dashboard.apps, {timeout: 20000, waitUntil: "load"});
|
||||
|
||||
// Install the app via the manifest URL
|
||||
await page.locator('[data-test-id="add-app-from-manifest"]').click();
|
||||
await page.getByRole('textbox').click();
|
||||
await page.getByRole('textbox').fill(urls.app.manifest);
|
||||
await page.locator('[data-test-id="install-app-from-manifest"]').click();
|
||||
await page.getByRole('button', { name: 'Install App' }).click();
|
||||
|
||||
// wait for the toast
|
||||
await page.getByText('App installed').isVisible();
|
||||
|
||||
}
|
19
apps/e2e-tests/utils/log-in-into-dashboard.ts
Normal file
19
apps/e2e-tests/utils/log-in-into-dashboard.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { Page, expect } from "@playwright/test";
|
||||
import { dashboardUserEmail, dashboardUserPassword, urls } from "../configuration";
|
||||
|
||||
interface LogInIntoDashboardArgs {
|
||||
page: Page
|
||||
}
|
||||
|
||||
export const logInIntoDashboard = async ({page}: LogInIntoDashboardArgs) => {
|
||||
await page.goto(urls.saleor.dashboard.homepage, {timeout: 20000, waitUntil: "load"});
|
||||
await page.locator('[data-test-id="email"]').click();
|
||||
await page.locator('[data-test-id="email"]').fill(dashboardUserEmail);
|
||||
await page.locator('[data-test-id="email"]').press('Tab');
|
||||
await page.locator('[data-test-id="password"]').fill(dashboardUserPassword);
|
||||
await page.locator('[data-test-id="submit"]').click();
|
||||
|
||||
await expect(page.locator('[data-test-id="welcome-header"]')).toBeVisible()
|
||||
}
|
||||
|
||||
export default logInIntoDashboard
|
1
apps/e2e-tests/utils/random-string.ts
Normal file
1
apps/e2e-tests/utils/random-string.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export const randomString = () => Math.random().toString(36).substr(2, 5)
|
|
@ -222,6 +222,12 @@ importers:
|
|||
pretty-quick: 3.1.3_prettier@2.8.3
|
||||
typescript: 4.8.3
|
||||
|
||||
apps/e2e-tests:
|
||||
specifiers:
|
||||
'@playwright/test': ^1.29.2
|
||||
devDependencies:
|
||||
'@playwright/test': 1.30.0
|
||||
|
||||
packages/eslint-config-custom:
|
||||
specifiers:
|
||||
eslint-config-next: ^13.1.3
|
||||
|
@ -2373,6 +2379,15 @@ packages:
|
|||
tiny-glob: 0.2.9
|
||||
tslib: 2.4.1
|
||||
|
||||
/@playwright/test/1.30.0:
|
||||
resolution: {integrity: sha512-SVxkQw1xvn/Wk/EvBnqWIq6NLo1AppwbYOjNLmyU0R1RoQ3rLEBtmjTnElcnz8VEtn11fptj1ECxK0tgURhajw==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
'@types/node': 18.11.18
|
||||
playwright-core: 1.30.0
|
||||
dev: true
|
||||
|
||||
/@repeaterjs/repeater/3.0.4:
|
||||
resolution: {integrity: sha512-AW8PKd6iX3vAZ0vA43nOUOnbq/X5ihgU+mSXXqunMkeQADGiqw/PY0JNeYtD5sr0PAy51YPgAPbDoeapv9r8WA==}
|
||||
dev: true
|
||||
|
@ -7689,6 +7704,12 @@ packages:
|
|||
thread-stream: 2.3.0
|
||||
dev: false
|
||||
|
||||
/playwright-core/1.30.0:
|
||||
resolution: {integrity: sha512-7AnRmTCf+GVYhHbLJsGUtskWTE33SwMZkybJ0v6rqR1boxq2x36U7p1vDRV7HO2IwTZgmycracLxPEJI49wu4g==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/png-js/1.0.0:
|
||||
resolution: {integrity: sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g==}
|
||||
dev: false
|
||||
|
|
Loading…
Reference in a new issue