diff --git a/esp/src/eclwatch/ECLPlaygroundWidget.js b/esp/src/eclwatch/ECLPlaygroundWidget.js index 2b652d96a2d..e256a190a71 100644 --- a/esp/src/eclwatch/ECLPlaygroundWidget.js +++ b/esp/src/eclwatch/ECLPlaygroundWidget.js @@ -111,7 +111,7 @@ define([ var logicalCluster = context.targetSelectWidget.selectedTarget(); var submitBtn = registry.byId(context.id + "SubmitBtn"); var publishBtn = registry.byId(context.id + "PublishBtn"); - if (logicalCluster.QueriesOnly) { + if (logicalCluster.QueriesOnly || logicalCluster.Name === "roxie") { domStyle.set(submitBtn.domNode, "display", "none"); domStyle.set(publishBtn.domNode, "display", null); } else { diff --git a/esp/src/playwright.config.ts b/esp/src/playwright.config.ts index 00031962989..73c2a8bae9c 100644 --- a/esp/src/playwright.config.ts +++ b/esp/src/playwright.config.ts @@ -11,6 +11,10 @@ export default defineConfig({ forbidOnly: !!process.env.CI, retries: process.env.CI ? 2 : 0, workers: process.env.CI ? 4 : undefined, + timeout: 60_000, + expect: { + timeout: 30_000 + }, reporter: "html", use: { baseURL, @@ -19,20 +23,30 @@ export default defineConfig({ }, projects: [ + { + name: "setup", + testMatch: /global\.setup\.ts/, + teardown: "teardown" + }, { name: "chromium", - use: { ...devices["Desktop Chrome"] }, + use: devices["Desktop Chrome"], + dependencies: ["setup"] }, - { name: "firefox", - use: { ...devices["Desktop Firefox"] }, + use: devices["Desktop Firefox"], + dependencies: ["setup"] }, - { name: "webkit", - use: { ...devices["Desktop Safari"] }, + use: devices["Desktop Safari"], + dependencies: ["setup"] }, + { + name: "teardown", + testMatch: /global\.teardown\.ts/ + } ], diff --git a/esp/src/src-react/components/ECLPlayground.tsx b/esp/src/src-react/components/ECLPlayground.tsx index ceca0b9eed9..d96f415fa2f 100644 --- a/esp/src/src-react/components/ECLPlayground.tsx +++ b/esp/src/src-react/components/ECLPlayground.tsx @@ -346,7 +346,7 @@ const ECLEditorToolbar: React.FunctionComponent = ({ className={playgroundStyles.inlineDropdown} onChange={React.useCallback((evt, option: TargetClusterOption) => { const selectedCluster = option.key.toString(); - if (option?.queriesOnly) { + if (option?.queriesOnly || selectedCluster === "roxie") { setShowSubmitBtn(false); } else { setShowSubmitBtn(true); diff --git a/esp/src/tests/eclwatch-v9.spec.ts b/esp/src/tests/eclwatch-v9.spec.ts index 745a274254d..1becb25883d 100644 --- a/esp/src/tests/eclwatch-v9.spec.ts +++ b/esp/src/tests/eclwatch-v9.spec.ts @@ -1,9 +1,12 @@ import { test, expect } from "@playwright/test"; -test.describe("ECLWatch V9", () => { +test.describe("Basic ECLWatch V9 UI", () => { - test("Basic Frame", async ({ page }) => { + test.beforeEach(async ({ page }) => { await page.goto("/esp/files/index.html#/activities"); + }) + + test("Frame Loaded", async ({ page }) => { await expect(page.getByRole("link", { name: "ECL Watch" })).toBeVisible(); await expect(page.locator("button").filter({ hasText: "" })).toBeVisible(); await expect(page.getByRole("button", { name: "Advanced" })).toBeVisible(); @@ -17,9 +20,7 @@ test.describe("ECLWatch V9", () => { await expect(page.getByRole("link", { name: "Event Scheduler" })).toBeVisible(); }); - test("Activities", async ({ page }) => { - await page.goto("/esp/files/index.html#/activities"); - await page.getByTitle("Disk Usage").locator("i").click(); + test("Activities page", async ({ page }) => { await expect(page.locator("svg").filter({ hasText: "%hthor" })).toBeVisible(); await expect(page.locator(".reflex-splitter")).toBeVisible(); await expect(page.getByRole("menubar")).toBeVisible(); @@ -32,11 +33,135 @@ test.describe("ECLWatch V9", () => { await expect(page.getByText("State")).toBeVisible(); await expect(page.getByText("Owner")).toBeVisible(); await expect(page.getByText("Job Name")).toBeVisible(); - await expect(page.getByRole("gridcell", { name: "HThorServer - hthor" })).toBeVisible(); - await expect(page.getByRole("gridcell", { name: "ThorMaster - thor", exact: true })).toBeVisible(); - await expect(page.getByRole("gridcell", { name: "ThorMaster - thor_roxie" })).toBeVisible(); - await expect(page.getByRole("gridcell", { name: "RoxieServer - roxie" })).toBeVisible(); - await expect(page.getByRole("gridcell", { name: "myeclccserver - hthor." })).toBeVisible(); - await expect(page.getByRole("gridcell", { name: "mydfuserver - dfuserver_queue" })).toBeVisible(); + await expect(page.locator(".dgrid-row")).not.toHaveCount(0); + }); +}); + +test.describe("Workunit tests", () => { + + test.beforeEach(async ({ page }) => { + await page.goto("/esp/files/index.html#/workunits"); + }); + + test("View the Workunits list page", async ({ page }) => { + await expect(page.getByRole("menubar")).toBeVisible(); + await expect(page.getByRole("menuitem", { name: "Refresh" })).toBeVisible(); + await expect(page.getByText("WUID")).toBeVisible(); + await expect(page.getByText("Owner", { exact: true })).toBeVisible(); + await expect(page.getByText("Job Name")).toBeVisible(); + await expect(page.getByText("Cluster", { exact: true })).toBeVisible(); + await expect(page.locator(".ms-DetailsRow")).not.toHaveCount(0); + }); + + test("Filter the Workunits list page", async ({ page }) => { + const date = new Date(); + const month = date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1; + const day = date.getDate() < 10 ? "0" + date.getDate() : date.getDate(); + await expect(page.getByRole("menubar")).toBeVisible(); + await expect(page.getByRole("menuitem", { name: "Refresh" })).toBeVisible(); + await page.getByRole("menuitem", { name: "Filter" }).click(); + const wuidField = await page.getByPlaceholder("W20200824-060035"); + wuidField.fill(`W${date.getFullYear()}${month}${day}*`); + await page.getByRole("button", { name: "Apply" }).click(); + await expect(page.locator(".ms-DetailsRow")).not.toHaveCount(0); + await page.getByRole("menuitem", { name: "Filter" }).click(); + await page.getByPlaceholder("W20200824-060035").fill(`W2023*`); + await page.getByRole("button", { name: "Apply" }).click(); + await expect(page.locator(".ms-DetailsRow")).toHaveCount(0); + await page.getByRole("menuitem", { name: "Filter" }).click(); + await page.getByRole("button", { name: "Clear" }).click(); + await page.getByRole("button", { name: "Apply" }).click(); + await expect(page.locator(".ms-DetailsRow")).not.toHaveCount(0); + }); + + test("Protect / Unprotect a WU", async ({ page }) => { + await expect(page.locator(".ms-DetailsRow")).not.toHaveCount(0); + await page.locator(".ms-DetailsRow").first().locator(".ms-DetailsRow-check").click(); + await expect(page.locator(".ms-DetailsRow.is-selected")).toHaveCount(1); + await page.getByRole("menuitem", { name: "Protect", exact: true }).click(); + await expect(page.locator(".ms-DetailsRow").first().locator("[data-icon-name=\"LockSolid\"]")).toBeVisible(); + await page.getByRole("menuitem", { name: "Unprotect" }).click(); + await expect(page.locator(".ms-DetailsRow").first().locator("[data-icon-name=\"LockSolid\"]")).not.toBeVisible(); + }); + + test("Set a WU to failed", async ({ page }) => { + await expect(page.locator(".ms-DetailsRow")).not.toHaveCount(0); + await page.locator(".ms-DetailsRow").filter({ hasText: "completed" }).last().locator(".ms-DetailsRow-check").click(); + await expect(page.locator(".ms-DetailsRow.is-selected")).toHaveCount(1); + await page.getByRole("menuitem", { name: "Set To Failed", exact: true }).click(); + await expect(page.locator(".ms-DetailsRow.is-selected").filter({ hasText: "failed" })).toBeVisible(); }); + + // test("Delete a WU", async ({ page }) => { + // const wuCount = await page.locator(".ms-DetailsRow").count(); + // await expect(page.locator(".ms-DetailsRow")).not.toHaveCount(0); + // await page.locator(".ms-DetailsRow").filter({ hasText: "completed" }).first().locator(".ms-DetailsRow-check").click(); + // await expect(page.locator(".ms-DetailsRow.is-selected")).toHaveCount(1); + // await page.getByRole("menuitem", { name: "Delete", exact: true }).click(); + // await page.getByRole("button", { name: "OK" }).click(); + // await expect(page.locator(".ms-DetailsRow")).toHaveCount(wuCount - 1); + // }); + +}); + +test.describe("File tests", () => { + + test.beforeEach(async ({ page }) => { + await page.goto("/esp/files/index.html#/files"); + }); + + test("View the Files list page", async ({ page }) => { + await expect(page.getByRole("menubar")).toBeVisible(); + await expect(page.getByRole("menuitem", { name: "Refresh" })).toBeVisible(); + await expect(page.getByText("Logical Name")).toBeVisible(); + await expect(page.getByText("Owner", { exact: true })).toBeVisible(); + await expect(page.getByText("Cluster")).toBeVisible(); + await expect(page.getByText("Records")).toBeVisible(); + await expect(page.locator(".ms-DetailsRow")).not.toHaveCount(0); + }); + + test("Filter the Files list page", async ({ page }) => { + await expect(page.getByRole("menubar")).toBeVisible(); + await expect(page.getByRole("menuitem", { name: "Refresh" })).toBeVisible(); + await page.getByRole("menuitem", { name: "Filter" }).click(); + await page.getByPlaceholder("*::somefile*").fill("*allPeople*"); + await page.getByRole("button", { name: "Apply" }).click(); + await expect(page.locator(".ms-DetailsRow")).toHaveCount(1); + await page.getByRole("menuitem", { name: "Filter" }).click(); + await page.getByRole("button", { name: "Clear" }).click(); + await page.getByRole("button", { name: "Apply" }).click(); + await expect(page.locator(".ms-DetailsRow")).not.toHaveCount(1); + }); + +}); + +test.describe("Query tests", () => { + + test.beforeEach(async ({ page }) => { + await page.goto("/esp/files/index.html#/queries"); + }); + + test("View the Queries list page", async ({ page }) => { + await expect(page.getByRole("menubar")).toBeVisible(); + await expect(page.getByRole("menuitem", { name: "Refresh" })).toBeVisible(); + await expect(page.getByText("ID", { exact: true })).toBeVisible(); + await expect(page.getByText("Priority", { exact: true })).toBeVisible(); + await expect(page.getByText("Name")).toBeVisible(); + await expect(page.getByText("Target")).toBeVisible(); + await expect(page.locator(".ms-DetailsRow")).not.toHaveCount(0); + }); + + test("Filter the Queries list page", async ({ page }) => { + await expect(page.getByRole("menubar")).toBeVisible(); + await expect(page.getByRole("menuitem", { name: "Refresh" })).toBeVisible(); + await page.getByRole("menuitem", { name: "Filter" }).click(); + await page.getByPlaceholder("My?Su?erQ*ry").fill("asdf"); + await page.getByRole("button", { name: "Apply" }).click(); + await expect(page.locator(".ms-DetailsRow")).toHaveCount(0); + await page.getByRole("menuitem", { name: "Filter" }).click(); + await page.getByRole("button", { name: "Clear" }).click(); + await page.getByRole("button", { name: "Apply" }).click(); + await expect(page.locator(".ms-DetailsRow")).not.toHaveCount(0); + }); + }); diff --git a/esp/src/tests/global.setup.ts b/esp/src/tests/global.setup.ts new file mode 100644 index 00000000000..237f821ab8a --- /dev/null +++ b/esp/src/tests/global.setup.ts @@ -0,0 +1,102 @@ +import { test, expect } from "@playwright/test"; + +test.describe("Playground tests", () => { + + let editor; + + test.beforeEach(async ({ page }) => { + await page.goto("/esp/files/index.html#/play"); + editor = await page.locator(".CodeMirror"); + await editor?.click(); + await page.keyboard.press("Control+A"); + await page.keyboard.press("Backspace"); + }) + + test("Execute Simple Sort sample", async ({ page }) => { + await page.getByText("Simple Filter").click(); + await page.getByRole("option", { name: "Simple Sort" }).click(); + await page.getByRole("button", { name: "Submit" }).click(); + await expect(page.getByRole("link", { name: "completed" })).toBeVisible(); + await expect(page.getByRole("tab", { name: "Result" })).toBeVisible(); + await expect(page.locator("#dgrid_0-header")).toBeVisible(); + await expect(page.locator(".dgrid-row")).toHaveCount(3); + await expect(page.locator("svg > g > g > g")).toBeVisible(); + }); + + test("Create two simple files", async ({ page }) => { + await page.keyboard.type(` +Layout_Person := RECORD + UNSIGNED1 PersonID; + STRING15 FirstName; + STRING25 LastName; +END; + +allPeople := DATASET([ {1, 'Fred', 'Smith'}, + {2, 'Joe', 'Blow'}, + {3, 'Jane', 'Smith'}], Layout_Person); + +somePeople := allPeople(LastName = 'Smith'); + +// Outputs --- +OUTPUT(allPeople,,'~allPeople',OVERWRITE); +OUTPUT(somePeople,,'~somePeople',OVERWRITE); + `); + + await page.getByRole("button", { name: "Submit" }).click(); + await expect(page.getByRole("link", { name: "completed" })).toBeVisible(); + const result2 = await page.getByRole("tab", { name: "Result 2" }); + await expect(result2).toBeVisible(); + await result2.click(); + await expect(page.locator(".dgrid-header-row")).toBeVisible(); + await expect(page.locator(".dgrid-row")).toHaveCount(2); + }); + + test("Publish a roxie query", async ({ page }) => { + await page.keyboard.type(` +resistorCodes := dataset([{0, 'Black'}, + {1, 'Brown'}, + {2, 'Red'}, + {3, 'Orange'}, + {4, 'Yellow'}, + {5, 'Green'}, + {6, 'Blue'}, + {7, 'Violet'}, + {8, 'Grey'}, + {9, 'White'}], {unsigned1 value, string color}) : stored('colorMap'); + +color2code := DICTIONARY(resistorCodes, { color => value}); + +colourDictionary := dictionary(recordof(color2code)); + +bands := DATASET([{'Red'},{'Yellow'},{'Blue'}], {string band}) : STORED('bands'); + +valrec := RECORD +unsigned1 value; +END; + +valrec getValue(bands L, colourDictionary mapping) := TRANSFORM +SELF.value := mapping[L.band].value; +END; + +results := allnodes(PROJECT(bands, getValue(LEFT, THISNODE(color2code)))); + +ave(results, value);` + ); + await page.getByText("hthor", { exact: true }).click(); + await page.getByRole("option", { name: "roxie", exact: true }).click(); + await page.getByLabel("Name", { exact: true }).fill("dictallnodes2"); + await page.getByRole("button", { name: "Publish" }).click(); + await expect(page.getByRole("link", { name: "compiled" })).toBeVisible(); + }); + + test("Create a few WUs", async ({ page }) => { + await page.keyboard.type(`OUTPUT('Hello World')`); + await page.getByRole("button", { name: "Submit" }).click(); + await expect(page.getByRole("link", { name: "completed" })).toBeVisible(); + await page.getByRole("button", { name: "Submit" }).click(); + await expect(page.getByRole("link", { name: "completed" })).toBeVisible(); + await page.getByRole("button", { name: "Submit" }).click(); + await expect(page.getByRole("link", { name: "completed" })).toBeVisible(); + }); + +}); \ No newline at end of file diff --git a/esp/src/tests/global.teardown.ts b/esp/src/tests/global.teardown.ts new file mode 100644 index 00000000000..4025db2a1d2 --- /dev/null +++ b/esp/src/tests/global.teardown.ts @@ -0,0 +1,26 @@ +import { test, expect } from "@playwright/test"; + +test.describe("Teardown", () => { + + test("Delete all Queries", async ({ page }) => { + await page.goto("/esp/files/index.html#/queries"); + await page.locator(".ms-DetailsHeader .ms-DetailsRow-check").click(); + await page.getByRole("menuitem", { name: "Delete" }).click(); + await page.getByRole("button", { name: "OK" }).click(); + }); + + test("Delete all Files", async ({ page }) => { + await page.goto("/esp/files/index.html#/files"); + await page.locator(".ms-DetailsHeader .ms-DetailsRow-check").click(); + await page.getByRole("menuitem", { name: "Delete" }).click(); + await page.getByRole("button", { name: "OK" }).click(); + }); + + test("Delete all Workunits", async ({ page }) => { + await page.goto("/esp/files/index.html#/workunits"); + await page.locator(".ms-DetailsHeader .ms-DetailsRow-check").click(); + await page.getByRole("menuitem", { name: "Delete" }).click(); + await page.getByRole("button", { name: "OK" }).click(); + }); + +}); \ No newline at end of file