From 55fa8bd7433213adfe0d749b9000aff922162dd4 Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 10 Mar 2021 13:15:45 +0200 Subject: [PATCH] reverting integration tests refactoring / fixing tests to current branch Signed-off-by: Roman --- integration/__tests__/app.tests.ts | 79 ++- integration/__tests__/cluster-common.tests.ts | 64 -- integration/__tests__/cluster-pages.tests.ts | 615 ++++++++++++------ .../__tests__/command-palette.tests.ts | 21 +- integration/__tests__/logs.tests.ts | 56 -- integration/__tests__/workspace.tests.ts | 74 ++- integration/helpers/index.ts | 7 - integration/helpers/minikube.ts | 7 - integration/helpers/selectors.ts | 13 - integration/helpers/utils.ts | 23 +- 10 files changed, 526 insertions(+), 433 deletions(-) delete mode 100644 integration/__tests__/cluster-common.tests.ts delete mode 100644 integration/__tests__/logs.tests.ts delete mode 100644 integration/helpers/index.ts delete mode 100644 integration/helpers/selectors.ts diff --git a/integration/__tests__/app.tests.ts b/integration/__tests__/app.tests.ts index 716082d12f..af029a23e9 100644 --- a/integration/__tests__/app.tests.ts +++ b/integration/__tests__/app.tests.ts @@ -1,42 +1,57 @@ -import { clickWhatsNew, listHelmRepositories, setupAppLifecycle } from "../helpers"; +import { Application } from "spectron"; +import * as utils from "../helpers/utils"; +import { listHelmRepositories } from "../helpers/utils"; +import { fail } from "assert"; + jest.setTimeout(60000); -describe("App start", () => { - const runtime = setupAppLifecycle(); +// FIXME (!): improve / simplify all css-selectors + use [data-test-id="some-id"] (already used in some tests below) +describe("Lens integration tests", () => { + let app: Application; - it('shows "whats new"', async () => { - await clickWhatsNew(runtime.app); - }); + describe("app start", () => { + beforeAll(async () => app = await utils.appStart(), 20000); - it('shows "add cluster"', async () => { - await runtime.app.electron.ipcRenderer.send("test-menu-item-click", "File", "Add Cluster"); - await runtime.app.client.waitUntilTextExists("h2", "Add Cluster"); - }); - - describe("preferences page", () => { - it('shows "preferences"', async () => { - const appName: string = process.platform === "darwin" ? "Lens" : "File"; - - await runtime.app.electron.ipcRenderer.send("test-menu-item-click", appName, "Preferences"); - await runtime.app.client.waitUntilTextExists("h2", "Preferences"); - }); - - it("ensures helm repos", async () => { - const repos = await listHelmRepositories(); - - if (!repos[0]) { - fail("Lens failed to add Bitnami repository"); + afterAll(async () => { + if (app?.isRunning()) { + await utils.tearDown(app); } - - await runtime.app.client.waitUntilTextExists("div.repos #message-bitnami", repos[0].name); // wait for the helm-cli to fetch the repo(s) - await runtime.app.client.click("#HelmRepoSelect"); // click the repo select to activate the drop-down - await runtime.app.client.waitUntilTextExists("div.Select__option", ""); // wait for at least one option to appear (any text) }); - }); - it.skip('quits Lens"', async () => { - await runtime.app.client.keys(["Meta", "Q"]); - await runtime.app.client.keys("Meta"); + it('shows "whats new"', async () => { + await utils.clickWhatsNew(app); + }); + + it('shows "add cluster"', async () => { + await app.electron.ipcRenderer.send("test-menu-item-click", "File", "Add Cluster"); + await app.client.waitUntilTextExists("h2", "Add Cluster"); + }); + + describe("preferences page", () => { + it('shows "preferences"', async () => { + const appName: string = process.platform === "darwin" ? "Lens" : "File"; + + await app.electron.ipcRenderer.send("test-menu-item-click", appName, "Preferences"); + await app.client.waitUntilTextExists("h2", "Preferences"); + }); + + it("ensures helm repos", async () => { + const repos = await listHelmRepositories(); + + if (!repos[0]) { + fail("Lens failed to add Bitnami repository"); + } + + await app.client.waitUntilTextExists("div.repos #message-bitnami", repos[0].name); // wait for the helm-cli to fetch the repo(s) + await app.client.click("#HelmRepoSelect"); // click the repo select to activate the drop-down + await app.client.waitUntilTextExists("div.Select__option", ""); // wait for at least one option to appear (any text) + }); + }); + + it.skip('quits Lens"', async () => { + await app.client.keys(["Meta", "Q"]); + await app.client.keys("Meta"); + }); }); }); diff --git a/integration/__tests__/cluster-common.tests.ts b/integration/__tests__/cluster-common.tests.ts deleted file mode 100644 index 1d65c5b4f2..0000000000 --- a/integration/__tests__/cluster-common.tests.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { addClusterAndOpen, BACKSPACE, describeIf, getMainMenuSelectors, minikubeReady, setupAppLifecycle } from "../helpers"; - -jest.setTimeout(60000); - -describe("Lens cluster common tests", () => { - const TEST_NAMESPACE = "cluster-common-int-tests"; - const ready = minikubeReady(TEST_NAMESPACE); - - describeIf(ready)("cluster operations", () => { - const runtime = setupAppLifecycle(); - - beforeAll(async () => { - await addClusterAndOpen(runtime.app); - }); - - it("shows default namespace", async () => { - await runtime.app.client.click('a[href="/namespaces"]'); - await runtime.app.client.waitUntilTextExists("div.TableCell", "default"); - await runtime.app.client.waitUntilTextExists("div.TableCell", "kube-system"); - }); - - it(`creates ${TEST_NAMESPACE} namespace`, async () => { - await runtime.app.client.click('a[href="/namespaces"]'); - await runtime.app.client.waitUntilTextExists("div.TableCell", "default"); - await runtime.app.client.waitUntilTextExists("div.TableCell", "kube-system"); - await runtime.app.client.click("button.add-button"); - await runtime.app.client.waitUntilTextExists("div.AddNamespaceDialog", "Create Namespace"); - await runtime.app.client.keys(`${TEST_NAMESPACE}\n`); - await runtime.app.client.waitForExist(`.name=${TEST_NAMESPACE}`); - }); - - it(`creates a pod in ${TEST_NAMESPACE} namespace`, async () => { - await runtime.app.client.click(getMainMenuSelectors("workloads").expandIcon); - await runtime.app.client.waitUntilTextExists('a[href^="/pods"]', "Pods"); - await runtime.app.client.click('a[href^="/pods"]'); - - await runtime.app.client.click(".NamespaceSelect"); - await runtime.app.client.keys(TEST_NAMESPACE); - await runtime.app.client.keys("Enter");// "\uE007" - await runtime.app.client.click(".Icon.new-dock-tab"); - await runtime.app.client.waitUntilTextExists("li.MenuItem.create-resource-tab", "Create resource"); - await runtime.app.client.click("li.MenuItem.create-resource-tab"); - await runtime.app.client.waitForVisible(".CreateResource div.ace_content"); - // Write pod manifest to editor - await runtime.app.client.keys("apiVersion: v1\n"); - await runtime.app.client.keys("kind: Pod\n"); - await runtime.app.client.keys("metadata:\n"); - await runtime.app.client.keys(" name: nginx-create-pod-test\n"); - await runtime.app.client.keys(`namespace: ${TEST_NAMESPACE}\n`); - await runtime.app.client.keys(`${BACKSPACE}spec:\n`); - await runtime.app.client.keys(" containers:\n"); - await runtime.app.client.keys("- name: nginx-create-pod-test\n"); - await runtime.app.client.keys(" image: nginx:alpine\n"); - // Create deployment - await runtime.app.client.waitForEnabled("button.Button=Create & Close"); - await runtime.app.client.click("button.Button=Create & Close"); - // Wait until first bits of pod appears on dashboard - await runtime.app.client.waitForExist(".name=nginx-create-pod-test"); - // Open pod details - await runtime.app.client.click(".name=nginx-create-pod-test"); - await runtime.app.client.waitUntilTextExists("div.drawer-title-text", "Pod: nginx-create-pod-test"); - }); - }); -}); diff --git a/integration/__tests__/cluster-pages.tests.ts b/integration/__tests__/cluster-pages.tests.ts index 0ce4cd3417..8d2ac63e91 100644 --- a/integration/__tests__/cluster-pages.tests.ts +++ b/integration/__tests__/cluster-pages.tests.ts @@ -4,242 +4,461 @@ TEST_NAMESPACE namespace. This is done to minimize destructive impact of the cluster tests on an existing minikube cluster and vice versa. */ -import { addClusterAndOpen, describeIf, getMainMenuSelectors, minikubeReady, setupAppLifecycle } from "../helpers"; +import { Application } from "spectron"; +import * as utils from "../helpers/utils"; +import { addMinikubeCluster, minikubeReady, waitForMinikubeDashboard } from "../helpers/minikube"; +import { exec } from "child_process"; +import * as util from "util"; -jest.setTimeout(5000); +export const promiseExec = util.promisify(exec); -type SidebarItem = { - testId: string; - expectedSelector?: string; - expectedText?: string; - subMenu?: { - href: string; - expectedSelector: string; - expectedText: string; - }[]; -}; +jest.setTimeout(60000); +// FIXME (!): improve / simplify all css-selectors + use [data-test-id="some-id"] (already used in some tests below) describe("Lens cluster pages", () => { - const TEST_NAMESPACE = "cluster-pages-int-tests"; + const TEST_NAMESPACE = "integration-tests"; + const BACKSPACE = "\uE003"; + let app: Application; const ready = minikubeReady(TEST_NAMESPACE); - describeIf(ready)("cluster pages", () => { - const runtime = setupAppLifecycle(); + utils.describeIf(ready)("test common pages", () => { + let clusterAdded = false; + const addCluster = async () => { + await utils.clickWhatsNew(app); + await addMinikubeCluster(app); + await waitForMinikubeDashboard(app); + await app.client.click('a[href="/nodes"]'); + await app.client.waitUntilTextExists("div.TableCell", "Ready"); + }; - beforeAll(async () => { - await addClusterAndOpen(runtime.app); + describe("cluster add", () => { + beforeAll(async () => app = await utils.appStart(), 20000); + + afterAll(async () => { + if (app && app.isRunning()) { + return utils.tearDown(app); + } + }); + + it("allows to add a cluster", async () => { + await addCluster(); + clusterAdded = true; + }); }); - const items: SidebarItem[] = [ - { - testId: "cluster", - expectedSelector: "div.ClusterOverview div.label", - expectedText: "Master", + const appStartAddCluster = async () => { + if (clusterAdded) { + app = await utils.appStart(); + await addCluster(); + } + }; + + function getSidebarItemSelectors(itemId: string) { + const baseSelector = `.Sidebar [data-test-id="${itemId}"]`; + + return { + sidebarItemRoot: baseSelector, + expandSubMenu: `${baseSelector} .expand-icon`, + pageLink(href: string) { + return `${baseSelector} a[href^="/${href}"]`; + } + }; + } + + describe("cluster pages", () => { + + beforeAll(appStartAddCluster, 40000); + + afterAll(async () => { + if (app && app.isRunning()) { + return utils.tearDown(app); + } + }); + + const tests: { + drawer?: string + drawerId?: string + pages: { + name: string, + href: string, + expectedSelector: string, + expectedText: string + }[] + }[] = [{ + drawer: "", + drawerId: "", + pages: [{ + name: "Cluster", + href: "cluster", + expectedSelector: "div.ClusterOverview div.label", + expectedText: "Master" + }] }, { - testId: "nodes", - expectedSelector: "h5.title", - expectedText: "Nodes" + drawer: "", + drawerId: "", + pages: [{ + name: "Nodes", + href: "nodes", + expectedSelector: "h5.title", + expectedText: "Nodes" + }] }, { - testId: "workloads", - subMenu: [ - { - href: "workloads", - expectedSelector: "h5", - expectedText: "Overview", - }, - { - href: "pods", - expectedSelector: "h5.title", - expectedText: "Pods" - }, - { - href: "deployments", - expectedSelector: "h5.title", - expectedText: "Deployments" - }, - { - href: "daemonsets", - expectedSelector: "h5.title", - expectedText: "Daemon Sets" - }, - { - href: "statefulsets", - expectedSelector: "h5.title", - expectedText: "Stateful Sets" - }, - { - href: "replicasets", - expectedSelector: "h5.title", - expectedText: "Replica Sets" - }, - { - href: "jobs", - expectedSelector: "h5.title", - expectedText: "Jobs" - }, - { - href: "cronjobs", - expectedSelector: "h5.title", - expectedText: "Cron Jobs" - }] + drawer: "Workloads", + drawerId: "workloads", + pages: [{ + name: "Overview", + href: "workloads", + expectedSelector: "h5.box", + expectedText: "Overview" + }, + { + name: "Pods", + href: "pods", + expectedSelector: "h5.title", + expectedText: "Pods" + }, + { + name: "Deployments", + href: "deployments", + expectedSelector: "h5.title", + expectedText: "Deployments" + }, + { + name: "DaemonSets", + href: "daemonsets", + expectedSelector: "h5.title", + expectedText: "Daemon Sets" + }, + { + name: "StatefulSets", + href: "statefulsets", + expectedSelector: "h5.title", + expectedText: "Stateful Sets" + }, + { + name: "ReplicaSets", + href: "replicasets", + expectedSelector: "h5.title", + expectedText: "Replica Sets" + }, + { + name: "Jobs", + href: "jobs", + expectedSelector: "h5.title", + expectedText: "Jobs" + }, + { + name: "CronJobs", + href: "cronjobs", + expectedSelector: "h5.title", + expectedText: "Cron Jobs" + }] }, { - testId: "config", - subMenu: [ - { - href: "configmaps", - expectedSelector: "h5.title", - expectedText: "Config Maps" - }, - { - href: "secrets", - expectedSelector: "h5.title", - expectedText: "Secrets" - }, - { - href: "resourcequotas", - expectedSelector: "h5.title", - expectedText: "Resource Quotas" - }, - { - href: "limitranges", - expectedSelector: "h5.title", - expectedText: "Limit Ranges" - }, - { - href: "hpa", - expectedSelector: "h5.title", - expectedText: "Horizontal Pod Autoscalers" - }, - { - href: "poddisruptionbudgets", - expectedSelector: "h5.title", - expectedText: "Pod Disruption Budgets" - }] + drawer: "Configuration", + drawerId: "config", + pages: [{ + name: "ConfigMaps", + href: "configmaps", + expectedSelector: "h5.title", + expectedText: "Config Maps" + }, + { + name: "Secrets", + href: "secrets", + expectedSelector: "h5.title", + expectedText: "Secrets" + }, + { + name: "Resource Quotas", + href: "resourcequotas", + expectedSelector: "h5.title", + expectedText: "Resource Quotas" + }, + { + name: "Limit Ranges", + href: "limitranges", + expectedSelector: "h5.title", + expectedText: "Limit Ranges" + }, + { + name: "HPA", + href: "hpa", + expectedSelector: "h5.title", + expectedText: "Horizontal Pod Autoscalers" + }, + { + name: "Pod Disruption Budgets", + href: "poddisruptionbudgets", + expectedSelector: "h5.title", + expectedText: "Pod Disruption Budgets" + }] }, { - testId: "networks", - subMenu: [ - { - href: "services", - expectedSelector: "h5.title", - expectedText: "Services" - }, - { - href: "endpoints", - expectedSelector: "h5.title", - expectedText: "Endpoints" - }, - { - href: "ingresses", - expectedSelector: "h5.title", - expectedText: "Ingresses" - }, - { - href: "network-policies", - expectedSelector: "h5.title", - expectedText: "Network Policies" - }] + drawer: "Network", + drawerId: "networks", + pages: [{ + name: "Services", + href: "services", + expectedSelector: "h5.title", + expectedText: "Services" + }, + { + name: "Endpoints", + href: "endpoints", + expectedSelector: "h5.title", + expectedText: "Endpoints" + }, + { + name: "Ingresses", + href: "ingresses", + expectedSelector: "h5.title", + expectedText: "Ingresses" + }, + { + name: "Network Policies", + href: "network-policies", + expectedSelector: "h5.title", + expectedText: "Network Policies" + }] }, { - testId: "storage", - subMenu: [ - { - href: "persistent-volume-claims", - expectedSelector: "h5.title", - expectedText: "Persistent Volume Claims" - }, - { - href: "persistent-volumes", - expectedSelector: "h5.title", - expectedText: "Persistent Volumes" - }, - { - href: "storage-classes", - expectedSelector: "h5.title", - expectedText: "Storage Classes" - }] + drawer: "Storage", + drawerId: "storage", + pages: [{ + name: "Persistent Volume Claims", + href: "persistent-volume-claims", + expectedSelector: "h5.title", + expectedText: "Persistent Volume Claims" + }, + { + name: "Persistent Volumes", + href: "persistent-volumes", + expectedSelector: "h5.title", + expectedText: "Persistent Volumes" + }, + { + name: "Storage Classes", + href: "storage-classes", + expectedSelector: "h5.title", + expectedText: "Storage Classes" + }] }, { - testId: "namespaces", - expectedSelector: "h5.title", - expectedText: "Namespaces", + drawer: "", + drawerId: "", + pages: [{ + name: "Namespaces", + href: "namespaces", + expectedSelector: "h5.title", + expectedText: "Namespaces" + }] }, { - testId: "events", - expectedSelector: "h5.title", - expectedText: "Events", + drawer: "", + drawerId: "", + pages: [{ + name: "Events", + href: "events", + expectedSelector: "h5.title", + expectedText: "Events" + }] }, { - testId: "apps", - subMenu: [ - { - href: "apps/charts", - expectedSelector: "div.HelmCharts input", - expectedText: "" - }, - { - href: "apps/releases", - expectedSelector: "h5.title", - expectedText: "Releases" - }] + drawer: "Apps", + drawerId: "apps", + pages: [{ + name: "Charts", + href: "apps/charts", + expectedSelector: "div.HelmCharts input", + expectedText: "" + }, + { + name: "Releases", + href: "apps/releases", + expectedSelector: "h5.title", + expectedText: "Releases" + }] }, { - testId: "users", - subMenu: [ - { - href: "service-accounts", - expectedSelector: "h5.title", - expectedText: "Service Accounts" - }, - { - href: "role-bindings", - expectedSelector: "h5.title", - expectedText: "Role Bindings" - }, - { - href: "roles", - expectedSelector: "h5.title", - expectedText: "Roles" - }, - { - href: "pod-security-policies", - expectedSelector: "h5.title", - expectedText: "Pod Security Policies" - }] + drawer: "Access Control", + drawerId: "users", + pages: [{ + name: "Service Accounts", + href: "service-accounts", + expectedSelector: "h5.title", + expectedText: "Service Accounts" + }, + { + name: "Role Bindings", + href: "role-bindings", + expectedSelector: "h5.title", + expectedText: "Role Bindings" + }, + { + name: "Roles", + href: "roles", + expectedSelector: "h5.title", + expectedText: "Roles" + }, + { + name: "Pod Security Policies", + href: "pod-security-policies", + expectedSelector: "h5.title", + expectedText: "Pod Security Policies" + }] }, { - testId: "custom-resources", - subMenu: [{ + drawer: "Custom Resources", + drawerId: "custom-resources", + pages: [{ + name: "Definitions", href: "crd/definitions", expectedSelector: "h5.title", expectedText: "Custom Resources" }] }]; - items.forEach(({ testId, expectedSelector, expectedText, subMenu }) => { - const { sidebarItemRoot, expandIcon, pageLink } = getMainMenuSelectors(testId); + tests.forEach(({ drawer = "", drawerId = "", pages }) => { + const selectors = getSidebarItemSelectors(drawerId); - if (subMenu) { - it(`expands submenu for pages in "${testId}"`, async () => { - await runtime.app.client.click(expandIcon); - await runtime.app.client.waitForExist(pageLink(subMenu[0].href)); - }); - subMenu.forEach(({ href, expectedText, expectedSelector }) => { - it(`opens page "${expectedText.toLowerCase() || href}"`, async () => { - await runtime.app.client.click(pageLink(href)); - await runtime.app.client.waitUntilTextExists(expectedSelector, expectedText); + if (drawer !== "") { + it(`shows ${drawer} drawer`, async () => { + expect(clusterAdded).toBe(true); + await app.client.click(selectors.expandSubMenu); + await app.client.waitUntilTextExists(`a[href^="/${pages[0].href}"]`, pages[0].name); + }); + } + pages.forEach(({ name, href, expectedSelector, expectedText }) => { + it(`shows ${drawer}->${name} page`, async () => { + expect(clusterAdded).toBe(true); + await app.client.click(selectors.pageLink(href)); + await app.client.waitUntilTextExists(expectedSelector, expectedText); }); }); - } else { - it(`opens page "${testId}"`, async () => { - await runtime.app.client.click(sidebarItemRoot); - await runtime.app.client.waitUntilTextExists(expectedSelector, expectedText); - }); - } + + if (drawer !== "") { + // hide the drawer + it(`hides ${drawer} drawer`, async () => { + expect(clusterAdded).toBe(true); + await app.client.click(selectors.expandSubMenu); + await expect(app.client.waitUntilTextExists(selectors.pageLink(pages[0].href), pages[0].name, 100)).rejects.toThrow(); + }); + } + }); + }); + + describe("viewing pod logs", () => { + beforeEach(appStartAddCluster, 40000); + + afterEach(async () => { + if (app && app.isRunning()) { + return utils.tearDown(app); + } + }); + + it(`shows a logs for a pod`, async () => { + expect(clusterAdded).toBe(true); + // Go to Pods page + await app.client.click(getSidebarItemSelectors("workloads").expandSubMenu); + await app.client.waitUntilTextExists('a[href^="/pods"]', "Pods"); + await app.client.click('a[href^="/pods"]'); + await app.client.click(".NamespaceSelect"); + await app.client.keys("kube-system"); + await app.client.keys("Enter");// "\uE007" + await app.client.waitUntilTextExists("div.TableCell", "kube-apiserver"); + let podMenuItemEnabled = false; + + // Wait until extensions are enabled on renderer + while (!podMenuItemEnabled) { + const logs = await app.client.getRenderProcessLogs(); + + podMenuItemEnabled = !!logs.find(entry => entry.message.includes("[EXTENSION]: enabled lens-pod-menu@")); + + if (!podMenuItemEnabled) { + await new Promise(r => setTimeout(r, 1000)); + } + } + await new Promise(r => setTimeout(r, 500)); // Give some extra time to prepare extensions + // Open logs tab in dock + await app.client.click(".list .TableRow:first-child"); + await app.client.waitForVisible(".Drawer"); + await app.client.click(".drawer-title .Menu li:nth-child(2)"); + // Check if controls are available + await app.client.waitForVisible(".LogList .VirtualList"); + await app.client.waitForVisible(".LogResourceSelector"); + //await app.client.waitForVisible(".LogSearch .SearchInput"); + await app.client.waitForVisible(".LogSearch .SearchInput input"); + // Search for semicolon + await app.client.keys(":"); + await app.client.waitForVisible(".LogList .list span.active"); + // Click through controls + await app.client.click(".LogControls .show-timestamps"); + await app.client.click(".LogControls .show-previous"); + }); + }); + + describe("cluster operations", () => { + beforeEach(appStartAddCluster, 40000); + + afterEach(async () => { + if (app && app.isRunning()) { + return utils.tearDown(app); + } + }); + + it("shows default namespace", async () => { + expect(clusterAdded).toBe(true); + await app.client.click('a[href="/namespaces"]'); + await app.client.waitUntilTextExists("div.TableCell", "default"); + await app.client.waitUntilTextExists("div.TableCell", "kube-system"); + }); + + it(`creates ${TEST_NAMESPACE} namespace`, async () => { + expect(clusterAdded).toBe(true); + await app.client.click('a[href="/namespaces"]'); + await app.client.waitUntilTextExists("div.TableCell", "default"); + await app.client.waitUntilTextExists("div.TableCell", "kube-system"); + await app.client.click("button.add-button"); + await app.client.waitUntilTextExists("div.AddNamespaceDialog", "Create Namespace"); + await app.client.keys(`${TEST_NAMESPACE}\n`); + await app.client.waitForExist(`.name=${TEST_NAMESPACE}`); + }); + + it(`creates a pod in ${TEST_NAMESPACE} namespace`, async () => { + expect(clusterAdded).toBe(true); + await app.client.click(getSidebarItemSelectors("workloads").expandSubMenu); + await app.client.waitUntilTextExists('a[href^="/pods"]', "Pods"); + await app.client.click('a[href^="/pods"]'); + + await app.client.click(".NamespaceSelect"); + await app.client.keys(TEST_NAMESPACE); + await app.client.keys("Enter");// "\uE007" + await app.client.click(".Icon.new-dock-tab"); + await app.client.waitUntilTextExists("li.MenuItem.create-resource-tab", "Create resource"); + await app.client.click("li.MenuItem.create-resource-tab"); + await app.client.waitForVisible(".CreateResource div.ace_content"); + // Write pod manifest to editor + await app.client.keys("apiVersion: v1\n"); + await app.client.keys("kind: Pod\n"); + await app.client.keys("metadata:\n"); + await app.client.keys(" name: nginx-create-pod-test\n"); + await app.client.keys(`namespace: ${TEST_NAMESPACE}\n`); + await app.client.keys(`${BACKSPACE}spec:\n`); + await app.client.keys(" containers:\n"); + await app.client.keys("- name: nginx-create-pod-test\n"); + await app.client.keys(" image: nginx:alpine\n"); + // Create deployment + await app.client.waitForEnabled("button.Button=Create & Close"); + await app.client.click("button.Button=Create & Close"); + // Wait until first bits of pod appears on dashboard + await app.client.waitForExist(".name=nginx-create-pod-test"); + // Open pod details + await app.client.click(".name=nginx-create-pod-test"); + await app.client.waitUntilTextExists("div.drawer-title-text", "Pod: nginx-create-pod-test"); + }); }); }); - }); diff --git a/integration/__tests__/command-palette.tests.ts b/integration/__tests__/command-palette.tests.ts index 135c5af2cc..789806c445 100644 --- a/integration/__tests__/command-palette.tests.ts +++ b/integration/__tests__/command-palette.tests.ts @@ -1,16 +1,25 @@ -import { setupAppLifecycle, clickWhatsNew } from "../helpers/utils"; +import { Application } from "spectron"; +import * as utils from "../helpers/utils"; jest.setTimeout(60000); describe("Lens command palette", () => { - const runtime = setupAppLifecycle(); + let app: Application; describe("menu", () => { + beforeAll(async () => app = await utils.appStart(), 20000); + + afterAll(async () => { + if (app?.isRunning()) { + await utils.tearDown(app); + } + }); + it("opens command dialog from menu", async () => { - await clickWhatsNew(runtime.app); - await runtime.app.electron.ipcRenderer.send("test-menu-item-click", "View", "Command Palette..."); - await runtime.app.client.waitUntilTextExists(".Select__option", "Preferences: Open"); - await runtime.app.client.keys("Escape"); + await utils.clickWhatsNew(app); + await app.electron.ipcRenderer.send("test-menu-item-click", "View", "Command Palette..."); + await app.client.waitUntilTextExists(".Select__option", "Preferences: Open"); + await app.client.keys("Escape"); }); }); }); diff --git a/integration/__tests__/logs.tests.ts b/integration/__tests__/logs.tests.ts deleted file mode 100644 index 1a73198c1d..0000000000 --- a/integration/__tests__/logs.tests.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { addClusterAndOpen, describeIf, getMainMenuSelectors, minikubeReady, setupAppLifecycle } from "../helpers"; -import { delay } from "../../src/common/utils"; - -jest.setTimeout(60000); - -describe("Lens logs tests", () => { - const ready = minikubeReady("logs-int-tests"); - - describeIf(ready)("Pod logs", () => { - const runtime = setupAppLifecycle(); - - beforeAll(async () => { - await addClusterAndOpen(runtime.app); - }); - - it(`shows a logs for a pod`, async () => { - // Go to Pods page - await runtime.app.client.click(getMainMenuSelectors("workloads").expandIcon); - await runtime.app.client.waitUntilTextExists('a[href^="/pods"]', "Pods"); - await runtime.app.client.click('a[href^="/pods"]'); - await runtime.app.client.click(".NamespaceSelect"); - await runtime.app.client.keys("kube-system"); - await runtime.app.client.keys("Enter");// "\uE007" - await runtime.app.client.waitUntilTextExists("div.TableCell", "kube-apiserver"); - let podMenuItemEnabled = false; - - // Wait until extensions are enabled on renderer - while (!podMenuItemEnabled) { - const logs = await runtime.app.client.getRenderProcessLogs(); - - podMenuItemEnabled = !!logs.find(entry => entry.message.includes("[EXTENSION]: enabled lens-pod-menu@")); - - if (!podMenuItemEnabled) { - await delay(1000); - } - } - await delay(500); // Give some extra time to prepare extensions - // Open logs tab in dock - await runtime.app.client.click(".list .TableRow:first-child"); - await runtime.app.client.waitForVisible(".Drawer"); - await runtime.app.client.click(".drawer-title .Menu li:nth-child(2)"); - // Check if controls are available - await runtime.app.client.waitForVisible(".LogList .VirtualList"); - await runtime.app.client.waitForVisible(".LogResourceSelector"); - //await runtime.app.client.waitForVisible(".LogSearch .SearchInput"); - await runtime.app.client.waitForVisible(".LogSearch .SearchInput input"); - // Search for semicolon - await runtime.app.client.keys(":"); - await runtime.app.client.waitForVisible(".LogList .list span.active"); - // Click through controls - await runtime.app.client.click(".LogControls .show-timestamps"); - await runtime.app.client.click(".LogControls .show-previous"); - }); - }); - -}); diff --git a/integration/__tests__/workspace.tests.ts b/integration/__tests__/workspace.tests.ts index f8a2bd1958..4164151b0f 100644 --- a/integration/__tests__/workspace.tests.ts +++ b/integration/__tests__/workspace.tests.ts @@ -1,59 +1,75 @@ -import { addMinikubeCluster, clickWhatsNew, describeIf, minikubeReady, setupAppLifecycle } from "../helpers"; +import { Application } from "spectron"; +import * as utils from "../helpers/utils"; +import { addMinikubeCluster, minikubeReady } from "../helpers/minikube"; +import { exec } from "child_process"; +import * as util from "util"; + +export const promiseExec = util.promisify(exec); jest.setTimeout(60000); -describe("Lens workspace tests", () => { - const ready = minikubeReady("workspaces-int-tests"); +describe("Lens integration tests", () => { + let app: Application; + const ready = minikubeReady("workspace-int-tests"); - describeIf(ready)("workspaces", () => { - const runtime = setupAppLifecycle(clickWhatsNew); + utils.describeIf(ready)("workspaces", () => { + beforeAll(async () => { + app = await utils.appStart(); + await utils.clickWhatsNew(app); + }, 20000); + + afterAll(async () => { + if (app && app.isRunning()) { + return utils.tearDown(app); + } + }); const switchToWorkspace = async (name: string) => { - await runtime.app.client.click("[data-test-id=current-workspace]"); - await runtime.app.client.keys(name); - await runtime.app.client.keys("Enter"); - await runtime.app.client.waitUntilTextExists("[data-test-id=current-workspace-name]", name); + await app.client.click("[data-test-id=current-workspace]"); + await app.client.keys(name); + await app.client.keys("Enter"); + await app.client.waitUntilTextExists("[data-test-id=current-workspace-name]", name); }; const createWorkspace = async (name: string) => { - await runtime.app.client.click("[data-test-id=current-workspace]"); - await runtime.app.client.keys("add workspace"); - await runtime.app.client.keys("Enter"); - await runtime.app.client.keys(name); - await runtime.app.client.keys("Enter"); - await runtime.app.client.waitUntilTextExists("[data-test-id=current-workspace-name]", name); + await app.client.click("[data-test-id=current-workspace]"); + await app.client.keys("add workspace"); + await app.client.keys("Enter"); + await app.client.keys(name); + await app.client.keys("Enter"); + await app.client.waitUntilTextExists("[data-test-id=current-workspace-name]", name); }; it("creates new workspace", async () => { const name = "test-workspace"; await createWorkspace(name); - await runtime.app.client.waitUntilTextExists("[data-test-id=current-workspace-name]", name); + await app.client.waitUntilTextExists("[data-test-id=current-workspace-name]", name); }); it("edits current workspaces", async () => { await createWorkspace("to-be-edited"); - await runtime.app.client.click("[data-test-id=current-workspace]"); - await runtime.app.client.keys("edit current workspace"); - await runtime.app.client.keys("Enter"); - await runtime.app.client.keys("edited-workspace"); - await runtime.app.client.keys("Enter"); - await runtime.app.client.waitUntilTextExists("[data-test-id=current-workspace-name]", "edited-workspace"); + await app.client.click("[data-test-id=current-workspace]"); + await app.client.keys("edit current workspace"); + await app.client.keys("Enter"); + await app.client.keys("edited-workspace"); + await app.client.keys("Enter"); + await app.client.waitUntilTextExists("[data-test-id=current-workspace-name]", "edited-workspace"); }); it("adds cluster in default workspace", async () => { await switchToWorkspace("default"); - await addMinikubeCluster(runtime.app); - await runtime.app.client.waitUntilTextExists("pre.kube-auth-out", "Authentication proxy started"); - await runtime.app.client.waitForExist(`iframe[name="minikube"]`); - await runtime.app.client.waitForVisible(".ClustersMenu .ClusterIcon.active"); + await addMinikubeCluster(app); + await app.client.waitUntilTextExists("pre.kube-auth-out", "Authentication proxy started"); + await app.client.waitForExist(`iframe[name="minikube"]`); + await app.client.waitForVisible(".ClustersMenu .ClusterIcon.active"); }); it("adds cluster in test-workspace", async () => { await switchToWorkspace("test-workspace"); - await addMinikubeCluster(runtime.app); - await runtime.app.client.waitUntilTextExists("pre.kube-auth-out", "Authentication proxy started"); - await runtime.app.client.waitForExist(`iframe[name="minikube"]`); + await addMinikubeCluster(app); + await app.client.waitUntilTextExists("pre.kube-auth-out", "Authentication proxy started"); + await app.client.waitForExist(`iframe[name="minikube"]`); }); }); }); diff --git a/integration/helpers/index.ts b/integration/helpers/index.ts deleted file mode 100644 index 4d73650078..0000000000 --- a/integration/helpers/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -// Common utils for integration tests - -export const BACKSPACE = "\uE003"; - -export * from "./utils"; -export * from "./minikube"; -export * from "./selectors"; diff --git a/integration/helpers/minikube.ts b/integration/helpers/minikube.ts index 42f2646699..67ef0145d5 100644 --- a/integration/helpers/minikube.ts +++ b/integration/helpers/minikube.ts @@ -1,6 +1,5 @@ import { spawnSync } from "child_process"; import { Application } from "spectron"; -import { clickWhatsNew } from "./utils"; export function minikubeReady(testNamespace: string): boolean { // determine if minikube is running @@ -58,9 +57,3 @@ export async function waitForMinikubeDashboard(app: Application) { await app.client.frame("minikube"); await app.client.waitUntilTextExists("span.link-text", "Cluster"); } - -export async function addClusterAndOpen(app: Application) { - await clickWhatsNew(app); - await addMinikubeCluster(app); - await waitForMinikubeDashboard(app); -} diff --git a/integration/helpers/selectors.ts b/integration/helpers/selectors.ts deleted file mode 100644 index 5228632b4a..0000000000 --- a/integration/helpers/selectors.ts +++ /dev/null @@ -1,13 +0,0 @@ -// CSS-selectors for searching elements to interact in tests - -export function getMainMenuSelectors(itemId: string) { - const baseSelector = `.Sidebar [data-test-id="${itemId}"]`; - - return { - sidebarItemRoot: baseSelector, - expandIcon: `${baseSelector} .expand-icon`, - pageLink(href: string) { - return `${baseSelector} a[href^="/${href}"]`; - } - }; -} diff --git a/integration/helpers/utils.ts b/integration/helpers/utils.ts index 17d628d7df..f96c9124e2 100644 --- a/integration/helpers/utils.ts +++ b/integration/helpers/utils.ts @@ -37,7 +37,7 @@ export async function appStart() { await app.start(); // Wait for splash screen to be closed - while (await app.client.getWindowCount() > 1) ; + while (await app.client.getWindowCount() > 1); await app.client.windowByIndex(0); await app.client.waitUntilWindowLoaded(); @@ -71,7 +71,7 @@ type HelmRepository = { url: string; }; -export async function listHelmRepositories(retries = 0): Promise { +export async function listHelmRepositories(retries = 0): Promise{ if (retries < 5) { try { const { stdout: reposJson } = await promiseExec("helm repo list -o json"); @@ -86,22 +86,3 @@ export async function listHelmRepositories(retries = 0): Promise void, timeoutMs?: number) { - const runtime = { - app: null as Application, - }; - - beforeAll(async () => { - runtime.app = await appStart(); - await onStart?.(runtime.app); - }, timeoutMs); - - afterAll(async () => { - if (runtime.app?.isRunning()) { - await tearDown(runtime.app); - } - }); - - return runtime; -}