From 735b17c254e313e94f0a56a5aa92998d70c153f4 Mon Sep 17 00:00:00 2001 From: Michael Gao <16783916+mgaoVA@users.noreply.github.com> Date: Wed, 25 Sep 2024 16:15:01 -0400 Subject: [PATCH] Sync with main repo (#3) * copy/paste contents from the main repository * add codeowners file * update readme --- API-tests/database/portal_test_db.sql | 2 +- API-tests/employee_test.go | 118 ++++++++++ API-tests/formQuery.go | 8 + API-tests/formQuery_test.go | 43 ++-- CODEOWNERS | 1 + README.md | 7 + end2end/README.md | 5 + end2end/package-lock.json | 221 ++++++++++++++++++ end2end/playwright.config.ts | 4 +- end2end/tests/homepage.spec.ts | 2 +- .../lifecycleDeveloperConsoleApproval.spec.ts | 21 ++ end2end/tests/lifecycleSimpleTravel.spec.ts | 13 +- 12 files changed, 408 insertions(+), 37 deletions(-) create mode 100644 CODEOWNERS create mode 100644 end2end/package-lock.json create mode 100644 end2end/tests/lifecycleDeveloperConsoleApproval.spec.ts diff --git a/API-tests/database/portal_test_db.sql b/API-tests/database/portal_test_db.sql index 4b7f19ef2..9fc3118e4 100644 --- a/API-tests/database/portal_test_db.sql +++ b/API-tests/database/portal_test_db.sql @@ -6280,7 +6280,7 @@ INSERT INTO `records` (`recordID`, `date`, `serviceID`, `userID`, `title`, `prio (8, 1694021464, 0, 'tester', 'TestFormWorkflow_ApplyAction', 0, 'Approved', 1694021485, 0, 0, 1), (9, 1694021464, 0, 'tester', 'TestFormQuery_GroupClickedApprove', 0, 'Approved', 1694021485, 0, 0, 1), (10, 1694021465, 0, 'tester', 'TestFormWorkflow_ApplyAction', 0, 'Submitted', 1694021485, 0, 0, 1), -(11, 1694021465, 0, 'tester', 'Employee Metadata Posts Correctly', 0, 'Submitted', 1694021485, 0, 0, 1), +(11, 1694021465, 0, 'tester', 'TestFormQuery_Employee_Format__Orgchart_Has_Expected_Values', 0, 'Submitted', 1694021485, 0, 0, 1), (12, 1694021465, 0, 'tester', 'Available for test case', 0, 'Submitted', 1694021485, 0, 0, 1), (13, 1694021465, 0, 'tester', 'Available for test case', 0, 'Submitted', 1694021485, 0, 0, 1), (14, 1694021465, 0, 'tester', 'Available for test case', 0, 'Submitted', 1694021485, 0, 0, 1), diff --git a/API-tests/employee_test.go b/API-tests/employee_test.go index d647b0680..011c15f02 100644 --- a/API-tests/employee_test.go +++ b/API-tests/employee_test.go @@ -7,6 +7,7 @@ import ( "log" "net/http" "net/url" + "strconv" "strings" "testing" @@ -91,6 +92,123 @@ func disableEmployee(postUrl string) error { } +func TestEmployee_AvoidPhantomIncrements(t *testing.T) { + // as the test name suggests this test is to prevent the auto increment in + // the employees table from incrementing without an actual insert. This + // test will reveal when a condition exists where an insert causes the + // increment to increase but a unique key forces the ON DUPLICATE UPDATE + // to update an existing row. + + // This test needs to run before TestEmployee_CheckNationalEmployee as they + // both run the refreshOrgchartEmployees.php. This test expects there to be + // a difference between National and Local orgcharts and that may not be true + // once the refreshOrgchartEmployees.php runs. + + // add new employee getting the empUID + m := Employee{ + FirstName: "testing", + LastName: "users", + UserName: "testingusers", + } + + n := Employee{ + FirstName: "testing", + LastName: "users", + UserName: "TESTINGUSERS", + } + + employeeId, err := postEmployee(NationalOrgchartURL+`api/employee/new`, m) + + if err != nil { + t.Error(err) + } + + if employeeId == "" { + t.Error("no user id returned") + } + + var empUID1 string + + empUID1, err = postEmployee(RootOrgchartURL+`api/employee/new`, n) + + if err != nil { + t.Error(err) + } + + if empUID1 == "" { + t.Error("no user id returned") + } + + // ensure userNames are spelled the same but with different cases in + // national and local + var localEmployeeKey string + var natEmployeeKey string + + natEmpoyeeRes, err := getEmployee(NationalOrgchartURL + `api/employee/search?q=username:testingusers`) + + if err != nil { + t.Error(err) + } + + for key := range natEmpoyeeRes { + natEmployeeKey = key + break + } + + localEmployeeRes, _ := getEmployee(RootOrgchartURL + `api/employee/search?q=username:testingusers`) + for key := range localEmployeeRes { + localEmployeeKey = key + break + } + + local := localEmployeeRes[localEmployeeKey].UserName + nat := natEmpoyeeRes[natEmployeeKey].UserName + + if (!(nat != local && strings.ToLower(nat) == strings.ToLower(local))) { + t.Errorf("userNames should match except case - local = %v, national = %v", local, nat) + } + + // run refresh Orgchart + err = updateEmployees(RootOrgchartURL + `scripts/refreshOrgchartEmployees.php`) + + if err != nil { + t.Error(err) + } + + var empUID2 string + + // add new user getting empUID + o := Employee{ + FirstName: "testing", + LastName: "users", + UserName: "testingusers2", + } + + empUID2, err = postEmployee(RootOrgchartURL+`api/employee/new`, o) + + if err != nil { + t.Error(err) + } + + if empUID2 == "" { + t.Error("no user id returned") + } + + var id1 int + var id2 int + + id1, err1 := strconv.Atoi(empUID1) + id2, err2 := strconv.Atoi(empUID2) + + if err1 != nil || err2 != nil { + t.Error("empUID is not a number") + } + + if id2 != (id1 + 1) { + t.Error("unexpected auto increment value") + } +} + func TestEmployee_CheckNationalEmployee(t *testing.T) { // make sure the users are in place before we start. diff --git a/API-tests/formQuery.go b/API-tests/formQuery.go index 874188d48..7b89768d6 100644 --- a/API-tests/formQuery.go +++ b/API-tests/formQuery.go @@ -4,6 +4,14 @@ type FormQueryResponse map[int]FormQueryRecord type FormQueryData map[string]any +type FormQuery_Orgchart_Employee struct { + FirstName string `json:"firstName"` + LastName string `json:"lastName"` + MiddleName string `json:"middleName"` + Email string `json:"email"` + UserName string `json:"userName"` +} + type FormQueryRecord struct { RecordID int `json:"recordID"` ServiceID int `json:"serviceID"` diff --git a/API-tests/formQuery_test.go b/API-tests/formQuery_test.go index ab23dfd90..e34767386 100644 --- a/API-tests/formQuery_test.go +++ b/API-tests/formQuery_test.go @@ -208,23 +208,17 @@ func TestFormQuery_FindTwoSteps(t *testing.T) { } } -/* -* Reading of metadata values will be added in a future deployment -* The orgchart value is still from the orgchart lookup, not the metadata field - // "strconv" - // "github.com/google/go-cmp/cmp" - -func TestFormQuery_Employee_Metadata(t *testing.T) { - //values that should be assigned to S1 ind orchart value when form data are read - mock_orgchart_employee := Orgchart_employee_metadata{ + +/* post a new employee to an orgchart format question and then confirm expected values on orgchart property */ +func TestFormQuery_Employee_Format__Orgchart_Has_Expected_Values(t *testing.T) { + mock_orgchart_employee := FormQuery_Orgchart_Employee{ FirstName: "Ramon", LastName: "Watsica", MiddleName: "Yundt", Email: "Ramon.Watsica@fake-email.com", - UserName: "VTRYCXBETHANY", + UserName: "vtrycxbethany", } - //post and confirm post success postData := url.Values{} postData.Set("CSRFToken", CsrfToken) postData.Set("8", "201") @@ -242,52 +236,45 @@ func TestFormQuery_Employee_Metadata(t *testing.T) { } formRes, _ := getFormQuery(RootURL + `api/form/query/?q={"terms":[{"id":"categoryID","operator":"=","match":"form_5ea07","gate":"AND"},{"id":"deleted","operator":"=","match":0,"gate":"AND"}],"joins":[],"sort":{},"getData":["8"],"limit":10000,"limitOffset":0}&x-filterData=recordID,title`) - if _, exists := formRes[11]; !exists { t.Errorf("Record 11 should be readable") } recData := formRes[11].S1 - metadataInterface := recData["id8_orgchart"] - orgchart := metadataInterface.(map[string]interface {}) + dataInterface := recData["id8_orgchart"] + orgchart := dataInterface.(map[string]interface {}) b, _ := json.Marshal(orgchart) - var org_emp_md Orgchart_employee_metadata - err = json.Unmarshal(b, &org_emp_md) + var org_emp FormQuery_Orgchart_Employee + err = json.Unmarshal(b, &org_emp) if err != nil { - t.Error("Error on orgchart_employee_metadata unmarshal") + t.Error("Error on FormQuery_Orgchart_Employee unmarshal") } - got = org_emp_md.FirstName + got = org_emp.FirstName want = mock_orgchart_employee.FirstName if !cmp.Equal(got, want) { t.Errorf("firstName got = %v, want = %v", got, want) } - got = org_emp_md.LastName + got = org_emp.LastName want = mock_orgchart_employee.LastName if !cmp.Equal(got, want) { t.Errorf("lastName got = %v, want = %v", got, want) } - got = org_emp_md.MiddleName + got = org_emp.MiddleName want = mock_orgchart_employee.MiddleName if !cmp.Equal(got, want) { t.Errorf("middleName got = %v, want = %v", got, want) } - got = org_emp_md.Email + got = org_emp.Email want = mock_orgchart_employee.Email if !cmp.Equal(got, want) { t.Errorf("email got = %v, want = %v", got, want) } - got = org_emp_md.UserName + got = org_emp.UserName want = mock_orgchart_employee.UserName if !cmp.Equal(got, want) { t.Errorf("userName got = %v, want = %v", got, want) } - got = strconv.Itoa(org_emp_md.EmpUID) - want = "201" - if !cmp.Equal(got, want) { - t.Errorf("userName got = %v, want = %v", got, want) - } } -*/ diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 000000000..4434d87df --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1 @@ +* @mgaoVA @Pelentan @aerinkayne @pete-nerantzinis @shaneodd @jampaul3 @nk2136 @KCN8 diff --git a/README.md b/README.md index 73b2265c1..f7a90e7a1 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,9 @@ # LEAF Automated Tests +This repository contains automated tests for https://github.com/department-of-veterans-affairs/LEAF. + +## Running Tests + +1. Install and Run the LEAF Development Environment: + - https://github.com/department-of-veterans-affairs/LEAF/blob/master/docs/InstallationConfiguration.md +2. Navigate to https://host.docker.internal/ and follow prompts to run tests diff --git a/end2end/README.md b/end2end/README.md index d5543329a..fbebb22fa 100644 --- a/end2end/README.md +++ b/end2end/README.md @@ -13,3 +13,8 @@ Debug tests: ``` npx playwright test --ui ``` + +View trace: +``` +npx playwright show-trace [path to trace.zip] +``` diff --git a/end2end/package-lock.json b/end2end/package-lock.json new file mode 100644 index 000000000..0668ccfd2 --- /dev/null +++ b/end2end/package-lock.json @@ -0,0 +1,221 @@ +{ + "name": "app", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "app", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "mysql2": "^3.11.0" + }, + "devDependencies": { + "@playwright/test": "^1.46.0", + "@types/node": "^22.1.0" + } + }, + "node_modules/@playwright/test": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.46.0.tgz", + "integrity": "sha512-/QYft5VArOrGRP5pgkrfKksqsKA6CEFyGQ/gjNe6q0y4tZ1aaPfq4gIjudr1s3D+pXyrPRdsy4opKDrjBabE5w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.46.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.1.0.tgz", + "integrity": "sha512-AOmuRF0R2/5j1knA3c6G3HOk523Ga+l+ZXltX8SF1+5oqcXijjfTd8fY3XRZqSihEu9XhtQnKYLmkFaoxgsJHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.13.0" + } + }, + "node_modules/aws-ssl-profiles": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.1.tgz", + "integrity": "sha512-+H+kuK34PfMaI9PNU/NSjBKL5hh/KDM9J72kwYeYEm0A8B1AC4fuCy3qsjnA7lxklgyXsB68yn8Z2xoZEjgwCQ==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "license": "MIT", + "dependencies": { + "is-property": "^1.0.2" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", + "license": "MIT" + }, + "node_modules/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==", + "license": "Apache-2.0" + }, + "node_modules/lru-cache": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-8.0.5.tgz", + "integrity": "sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==", + "license": "ISC", + "engines": { + "node": ">=16.14" + } + }, + "node_modules/mysql2": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.11.0.tgz", + "integrity": "sha512-J9phbsXGvTOcRVPR95YedzVSxJecpW5A5+cQ57rhHIFXteTP10HCs+VBjS7DHIKfEaI1zQ5tlVrquCd64A6YvA==", + "license": "MIT", + "dependencies": { + "aws-ssl-profiles": "^1.1.1", + "denque": "^2.1.0", + "generate-function": "^2.3.1", + "iconv-lite": "^0.6.3", + "long": "^5.2.1", + "lru-cache": "^8.0.0", + "named-placeholders": "^1.1.3", + "seq-queue": "^0.0.5", + "sqlstring": "^2.3.2" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/named-placeholders": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz", + "integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==", + "license": "MIT", + "dependencies": { + "lru-cache": "^7.14.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/named-placeholders/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/playwright": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.46.0.tgz", + "integrity": "sha512-XYJ5WvfefWONh1uPAUAi0H2xXV5S3vrtcnXe6uAOgdGi3aSpqOSXX08IAjXW34xitfuOJsvXU5anXZxPSEQiJw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.46.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.46.0.tgz", + "integrity": "sha512-9Y/d5UIwuJk8t3+lhmMSAJyNP1BUC/DqP3cQJDQQL/oWqAiuPTLgy7Q5dzglmTLwcBRdetzgNM/gni7ckfTr6A==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/seq-queue": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", + "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" + }, + "node_modules/sqlstring": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", + "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/undici-types": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz", + "integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/end2end/playwright.config.ts b/end2end/playwright.config.ts index 0bbb764e3..93fdae311 100644 --- a/end2end/playwright.config.ts +++ b/end2end/playwright.config.ts @@ -16,8 +16,8 @@ export default defineConfig({ 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, + retries: 2, + // repeatEach: 3, // only temporarily enable to find flaky tests /* Opt out of parallel tests on CI. */ workers: process.env.CI ? 1 : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ diff --git a/end2end/tests/homepage.spec.ts b/end2end/tests/homepage.spec.ts index 3b9304b25..df7721d74 100644 --- a/end2end/tests/homepage.spec.ts +++ b/end2end/tests/homepage.spec.ts @@ -46,7 +46,7 @@ test('new record', async ({ page }, testInfo) => { await page.getByRole('button', { name: 'Click here to Proceed' }).click(); await page.getByLabel('single line text').click(); await page.getByLabel('single line text').fill('single line'); - await page.getByRole('button', { name: 'Next Question', exact: true }).click(); + await page.getByRole('button', { name: 'Next Question', exact: true }).first().click(); await expect(page.locator('#requestTitle')).toContainText(uniqueText); const screenshot = await page.screenshot(); diff --git a/end2end/tests/lifecycleDeveloperConsoleApproval.spec.ts b/end2end/tests/lifecycleDeveloperConsoleApproval.spec.ts new file mode 100644 index 000000000..ab3dd06a2 --- /dev/null +++ b/end2end/tests/lifecycleDeveloperConsoleApproval.spec.ts @@ -0,0 +1,21 @@ +import { test, expect } from '@playwright/test'; + +test('no javascript errors on supervisor selection page', async ({ page }, testInfo) => { + let errors = new Array; + page.on('pageerror', err => { + errors.push(err); + }); + + await page.goto('https://host.docker.internal/Test_Request_Portal/report.php?a=LEAF_start_leaf_dev_console_request'); + await page.getByRole('button', { name: 'I understand and accept' }).click(); + + // Wait for load + await expect(page.locator('#xhr')).toContainText('This is a request to access the LEAF Developer Console.'); + + await page.getByRole('button', { name: 'Next Question' }).last().click(); + + // wait for async request to complete + await expect(page.getByText('Approval Officials', { exact: true })).toContainText('Approval Officials'); + + expect(errors).toHaveLength(0); +}); diff --git a/end2end/tests/lifecycleSimpleTravel.spec.ts b/end2end/tests/lifecycleSimpleTravel.spec.ts index 4c6aec9f8..c4cf2a94a 100644 --- a/end2end/tests/lifecycleSimpleTravel.spec.ts +++ b/end2end/tests/lifecycleSimpleTravel.spec.ts @@ -12,19 +12,22 @@ test('navigate to Workflow Editor and create a travel workflow', async ({ page } await page.goto('https://host.docker.internal/Test_Request_Portal/admin/'); await page.getByRole('button', { name: ' Workflow Editor Edit' }).click(); + + // wait for async request to finish loading the first workflow + await expect(page.getByLabel('workflow step: Group')).toBeInViewport(); + await page.getByRole('button', { name: 'New Workflow' }).click(); await page.getByLabel('Workflow Title:').click(); await page.getByLabel('Workflow Title:').fill(uniqueText); await page.getByRole('button', { name: 'Save' }).click(); // wait for async request to finish saving - await expect(page.getByRole('button', { name: 'Save' })).not.toBeVisible(); - await expect(page.locator('a').filter({ hasText: uniqueText })).toBeVisible(); - // Workaround: Since the drag handles can overlap sometimes (maybe due to async rendering // in the jsPlumb library?), we'll move the requestor step out of the way first. // TODO: fix the workflow editor since end-users might have the same issue - await expect(page.getByLabel('workflow step: Step 1')).not.toBeInViewport(); + await expect(page.getByLabel('workflow step: Group')).not.toBeInViewport(); + await expect(page.locator('a').filter({ hasText: uniqueText })).toBeVisible(); + await expect(page.locator('rect').first()).toBeInViewport(); // Workaround: Set specific position because the workflow step's drag handle overlaps with the connector's handle await page.getByLabel('workflow step: Requestor', { exact: true }).hover({position: {x: 16, y: 16}}); await page.mouse.down(); @@ -134,7 +137,7 @@ test('navigate to Homepage, create and submit a travel request', async ({ page } // selecting a user triggers an async request, wait for loading to complete await expect(page.getByText('*** Loading... ***')).not.toBeVisible(); - await page.getByRole('button', { name: 'Next Question', exact: true }).click(); + await page.getByRole('button', { name: 'Next Question', exact: true }).first().click(); await expect(page.getByRole('button', { name: 'Submit Request' })).toBeInViewport(); await page.getByRole('button', { name: 'Submit Request' }).click();