Skip to content

Commit 0a81df7

Browse files
authored
tests/end-to-end-test-for-report-submission-using-playwright-in-ci (Netflix#2936)
* initial work to create a e2e test for report submission on playwright * add gh action CI job and make login util more robust for CI * update playwright github actions workflow * make envs global * invalid credentials when connecting to database * still having issues with cross-env dep, debug, and try to force install * debug node:events:491 error, known previous issue, attempt mentioned solution * debug node:events:491 error, known previous issue, attempt mentioned solution * run commands as root * more node_modules debugging * remove potentially redundant actions * revert to hacky workflow, that worked 🐶 * add artifact upload * update report-submission test and add more inc types to sample data * don't need to checkout repo twice * move node setup to beginning * attempt to resolve flaky chromium with reuseExistingServer arg * merge root package.json into static dir * clean up npm install * try removing the node_modules hack now that things are cleaned up * forgot to add package.json * drop global cross-envs install * add debugging ls commands * add -D flag to npm ci install * do what npm wants, install with npm install :( * debug flaky chrome test and remove npm ls debug line
1 parent 7e24e0d commit 0a81df7

File tree

8 files changed

+330
-6
lines changed

8 files changed

+330
-6
lines changed

.github/workflows/playwright.yml

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
name: "playwright"
2+
on: # rebuild any PRs and main branch changes
3+
pull_request:
4+
push:
5+
branches:
6+
- main
7+
8+
env:
9+
LOG_LEVEL: ERROR
10+
STATIC_DIR:
11+
DATABASE_HOSTNAME: localhost
12+
DATABASE_CREDENTIALS: dispatch:dispatch
13+
DISPATCH_ENCRYPTION_KEY: NJHDWDJ3PbHT8h
14+
DISPATCH_JWT_SECRET: foo
15+
16+
jobs:
17+
end-to-end:
18+
runs-on: ubuntu-20.04
19+
services:
20+
postgres:
21+
image: postgres
22+
env:
23+
POSTGRES_USER: dispatch
24+
POSTGRES_PASSWORD: dispatch
25+
POSTGRES_DB: dispatch
26+
ports:
27+
- 5432:5432
28+
# needed because the postgres container does not provide a healthcheck
29+
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
30+
steps:
31+
- name: Check out Git repository
32+
uses: actions/checkout@v3
33+
- name: Set up Python 3.9
34+
uses: actions/setup-python@v2
35+
with:
36+
python-version: 3.9
37+
- uses: actions/setup-node@v3
38+
with:
39+
node-version: 16
40+
- uses: actions/cache@v3
41+
with:
42+
path: ~/.cache/pip
43+
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
44+
restore-keys: |
45+
${{ runner.os }}-pip-
46+
- name: Install python dependencies
47+
run: |
48+
export DISPATCH_LIGHT_BUILD=1
49+
python -m pip install --upgrade pip
50+
pip install psycopg[binary]
51+
pip install -e ".[dev]"
52+
- name: Install npm dependencies
53+
run: |
54+
npm ci -D --prefix src/dispatch/static/dispatch
55+
npm install -D @playwright/test
56+
- name: Install playwright browsers
57+
run: npx playwright install --with-deps
58+
- name: Setup sample database
59+
run: dispatch database restore --dump-file data/dispatch-sample-data.dump && dispatch database upgrade
60+
- name: Run tests
61+
run: npx playwright test
62+
- uses: actions/upload-artifact@v3
63+
if: always()
64+
with:
65+
name: playwright-report
66+
path: playwright-report/
67+
retention-days: 30

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -207,3 +207,7 @@ docker/.env
207207
*.dump
208208

209209
.gitconfig
210+
/test-results/
211+
/playwright-report/
212+
/playwright/.cache/
213+
/tests/e2e/artifacts/*

data/dispatch-sample-data.dump

+4-2
Original file line numberDiff line numberDiff line change
@@ -6665,8 +6665,11 @@ COPY dispatch_organization_default.incident_role_tag (incident_role_id, tag_id)
66656665
--
66666666

66676667
COPY dispatch_organization_default.incident_type (id, name, slug, description, exclude_from_metrics, enabled, "default", visibility, plugin_metadata, incident_template_document_id, executive_template_document_id, review_template_document_id, tracking_template_document_id, commander_service_id, liaison_service_id, search_vector, project_id) FROM stdin;
6668-
2 Employee Investigation \N This is an employee investigation. f t f Restricted [] 1 2 3 \N \N \N 'employe':1,6 'investig':2,7 1
6668+
6 Other \N This is a miscellaneous incident. f t f Open [] 1 2 3 \N \N \N 'oth':1,8 'misc':2,9 'incid':6 'involv':7 1
6669+
5 Denial of Service \N This is an incident involving a Denial of Service attack on a compute resource or service. f t f Open [] 1 2 3 \N \N \N 'ddos':1,8 'den':2,9 'incid':6 'involv':7 1
6670+
4 Malware \N This is an incident involving malware on a host. f t f Open [] 1 2 3 \N \N \N 'mal':1,8 'incid':6 'involv':7 1
66696671
3 Customer Data \N This is an incident involving customer data. f t f Open [] 1 2 3 \N \N \N 'custom':1,8 'data':2,9 'incid':6 'involv':7 1
6672+
2 Employee Investigation \N This is an employee investigation. f t f Restricted [] 1 2 3 \N \N \N 'employe':1,6 'investig':2,7 1
66706673
1 Vulnerability \N This is an incident involving a misconfiguration or vulnerability. f t t Open [] 1 2 3 \N \N \N 'incid':5 'involv':6 'misconfigur':8 'vulner':1,10 1
66716674
\.
66726675

@@ -12042,4 +12045,3 @@ ALTER TABLE ONLY public.workflow_term
1204212045
--
1204312046
-- PostgreSQL database dump complete
1204412047
--
12045-

playwright.config.ts

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import type { PlaywrightTestConfig } from "@playwright/test"
2+
import { devices } from "@playwright/test"
3+
4+
/**
5+
* See https://playwright.dev/docs/test-configuration.
6+
*/
7+
const config: PlaywrightTestConfig = {
8+
testDir: "./tests/e2e",
9+
outputDir: "./tests/e2e/artifacts/test-failures",
10+
/* Maximum time one test can run for. */
11+
timeout: 100 * 1000,
12+
expect: {
13+
/**
14+
* Maximum time expect() should wait for the condition to be met.
15+
* For example in `await expect(locator).toHaveText();`
16+
*/
17+
timeout: 10000,
18+
},
19+
/* Run tests in files in parallel */
20+
fullyParallel: true,
21+
/* Fail the build on CI if you accidentally left test.only in the source code. */
22+
forbidOnly: !!process.env.CI,
23+
/* Retry on CI only */
24+
retries: process.env.CI ? 2 : 0,
25+
/* Opt out of parallel tests on CI. */
26+
workers: process.env.CI ? 1 : undefined,
27+
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
28+
reporter: "html",
29+
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
30+
use: {
31+
/* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */
32+
actionTimeout: 0,
33+
/* Base URL to use in actions like `await page.goto('/')`. */
34+
baseURL: "http://localhost:8080/",
35+
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
36+
trace: "on",
37+
video: "on",
38+
screenshot: "on",
39+
},
40+
41+
/* Configure projects for major browsers */
42+
projects: [
43+
{
44+
name: "chromium",
45+
use: {
46+
...devices["Desktop Chrome"],
47+
},
48+
},
49+
50+
{
51+
name: "firefox",
52+
use: {
53+
...devices["Desktop Firefox"],
54+
},
55+
},
56+
57+
{
58+
name: "webkit",
59+
use: {
60+
...devices["Desktop Safari"],
61+
},
62+
},
63+
],
64+
/* Folder for test artifacts such as screenshots, videos, traces, etc. */
65+
// outputDir: 'test-results/',
66+
67+
/* Run your local dev server before starting the tests */
68+
webServer: {
69+
command: "dispatch server develop",
70+
url: "http://localhost:8080/",
71+
reuseExistingServer: !process.env.CI,
72+
},
73+
}
74+
75+
export default config

src/dispatch/static/dispatch/package-lock.json

+47-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/dispatch/static/dispatch/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
},
4242
"devDependencies": {
4343
"@mdi/font": "^5.9.55",
44+
"@playwright/test": "^1.30.0",
4445
"@vitejs/plugin-vue2": "^2.0.0",
4546
"@vue/compiler-sfc": "^3.0.11",
4647
"babel-runtime": "^6.26.0",

tests/e2e/report-submission.spec.ts

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import { test, expect, chromium } from "@playwright/test"
2+
import login from "./utils/login"
3+
4+
test.describe("Authenticated Dispatch App", () => {
5+
test.beforeEach(async ({ page }) => {
6+
await login(page)
7+
})
8+
test("Should allow me to report an incident", async ({ page }) => {
9+
/* The ability to report an incident is one of the most critical
10+
user stories in the Dispatch application. */
11+
12+
const project = "default"
13+
const type = "Denial of Service"
14+
const priority = "Low"
15+
16+
await page.goto("./default/incidents/report")
17+
18+
// Title
19+
await page.getByLabel("Title").click()
20+
await page.getByLabel("Title").fill("Incident Test Created by Playwright")
21+
22+
// Description
23+
await page.getByLabel("Description").click()
24+
await page.getByLabel("Description").fill("test")
25+
26+
// Project
27+
await page.getByRole("combobox").filter({ hasText: "Project" }).locator("i").click()
28+
await page.getByText(project, { exact: true }).click()
29+
30+
// Type
31+
await page.getByRole("button", { name: "Type" }).click()
32+
33+
// Soft check that the 'Load More' selector is available upon opening the Project dropdown
34+
await expect
35+
.soft(
36+
page.getByText("Load More"),
37+
"The 'Load More' selector should be visible when there are more than 5 options in the Tags combobox."
38+
)
39+
.toBeVisible()
40+
41+
// Click load more
42+
await page.getByText("Load More").click()
43+
44+
/* Project Options:
45+
46+
Other
47+
Denial of Service
48+
Malware
49+
Customer Data
50+
Employee Investigation
51+
Vulnerability
52+
*/
53+
54+
// Click a type to select it
55+
await page.getByText(type, { exact: true }).click()
56+
57+
// Priority
58+
await page.getByRole("button", { name: "Priority" }).click()
59+
await page.getByText("Low").click()
60+
61+
// Open the dropdown selection for the Tags field
62+
await page.getByRole("combobox").filter({ hasText: "Tags" }).locator("i").click()
63+
await page.getByText("default/ExampleTag").click()
64+
65+
// Click out the dialog
66+
await page
67+
.locator("span")
68+
.filter({
69+
hasText: "Report Incident If you suspect an incident and need help, please fill out this f",
70+
})
71+
.click()
72+
73+
// Submit the form
74+
await page.getByRole("button", { name: "Submit" }).click()
75+
76+
// Wait for the incident to be created
77+
await page.waitForLoadState("networkidle")
78+
79+
// Soft validate that we get redirected to the incident submission form
80+
await expect
81+
.soft(page)
82+
.toHaveURL(
83+
encodeURI(
84+
`./default/incidents/report?project=${project}&incident_priority=${priority}&incident_type=${type}`
85+
)
86+
)
87+
88+
// Soft validate that we recieve the report form.
89+
await expect
90+
.soft(
91+
page.getByText("Incident Report"),
92+
"'Incident Report' text not visible on page after submission of incident report."
93+
)
94+
.toBeVisible()
95+
96+
// Soft validate that we recieve the report form.
97+
await expect
98+
.soft(
99+
page.getByText(
100+
"This page will be populated with incident resources as they are created (if available). If you have any questions, please feel free to review the Frequently Asked Questions (FAQ) document linked below, and/or reach out to the listed Incident Commander."
101+
),
102+
"'Incident Report: Description' not visible on page after submission of incident report."
103+
)
104+
.toBeVisible()
105+
})
106+
})

0 commit comments

Comments
 (0)