Upgrade to electron 12 and Node 14

- Compute cluster ID for tests
- Switch to temporary appData path while testing

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton committed 2021-08-23 15:55:05 -04:00
1 parent ac2ce1ba57
commit 2d75fd6717
11 files changed
+112 -97

No files matched your search

+3 -11
View File
@@ -27,8 +27,6 @@
*/
import * as utils from "../helpers/utils";
jest.setTimeout(20_000);
describe("preferences page tests", () => {
it('shows "preferences" and can navigate through the tabs', async () => {
const { window, cleanup } = await utils.start();
@@ -59,15 +57,9 @@ describe("preferences page tests", () => {
} finally {
await cleanup();
}
});
}, 10*60*1000);
it("ensures helm repos", async () => {
const repos = await utils.listHelmRepositories();
if (repos.length === 0) {
fail("Lens failed to add any repositories");
}
const { window, cleanup } = await utils.start();
try {
@@ -75,7 +67,7 @@ describe("preferences page tests", () => {
await window.keyboard.press("Meta+,");
await window.click("[data-testid=kubernetes-tab]");
await window.waitForSelector(`[data-testid=repository-name] >> text=${repos[0].name}`, {
await window.waitForSelector("[data-testid=repository-name]", {
timeout: 100_000,
});
await window.click("#HelmRepoSelect");
@@ -83,5 +75,5 @@ describe("preferences page tests", () => {
} finally {
await cleanup();
}
}, 120_000);
}, 10*60*1000);
});
+25 -17
View File
@@ -30,8 +30,6 @@ import { minikubeReady } from "../helpers/minikube";
const TEST_NAMESPACE = "integration-tests";
jest.setTimeout(30_000);
function getSidebarSelectors(itemId: string) {
const root = `.SidebarItem[data-test-id="${itemId}"]`;
@@ -252,7 +250,7 @@ const commonPageTests: CommonPageTest[] = [{
name: "Releases",
href: "apps/releases",
expectedSelector: "h5.title",
expectedText: "Helm Releases"
expectedText: "Releases"
}]
},
{
@@ -344,7 +342,7 @@ utils.describeIf(minikubeReady(TEST_NAMESPACE))("Minikube based tests", () => {
} finally {
await cleanup();
}
});
}, 10*60*1000);
it("show logs and highlight the log search entries", async () => {
const { window, cleanup } = await utils.start();
@@ -354,11 +352,11 @@ utils.describeIf(minikubeReady(TEST_NAMESPACE))("Minikube based tests", () => {
const frame = await utils.lauchMinikubeClusterFromCatalog(window);
if ((await frame.innerText(`a[href^="/workloads"] .Icon .icon`)) === "keyboard_arrow_down") {
await frame.click(`a[href^="/workloads"]`);
if ((await frame.innerText(`a[href="/workloads"] .expand-icon`)) === "keyboard_arrow_down") {
await frame.click(`a[href="/workloads"]`);
}
await frame.click(`a[href^="/pods"]`);
await frame.click(`a[href="/pods"]`);
const namespacesSelector = await frame.waitForSelector(".NamespaceSelect");
@@ -395,7 +393,7 @@ utils.describeIf(minikubeReady(TEST_NAMESPACE))("Minikube based tests", () => {
} finally {
await cleanup();
}
});
}, 10*60*1000);
it("should show the default namespaces", async () => {
const { window, cleanup } = await utils.start();
@@ -411,7 +409,7 @@ utils.describeIf(minikubeReady(TEST_NAMESPACE))("Minikube based tests", () => {
} finally {
await cleanup();
}
});
}, 10*60*1000);
it(`should create the ${TEST_NAMESPACE} and a pod in the namespace`, async () => {
const { window, cleanup } = await utils.start();
@@ -430,9 +428,9 @@ utils.describeIf(minikubeReady(TEST_NAMESPACE))("Minikube based tests", () => {
await namespaceNameInput.type(TEST_NAMESPACE);
await namespaceNameInput.press("Enter");
await frame.waitForSelector(`div.TableCell >> text='${TEST_NAMESPACE}'`);
await frame.waitForSelector(`div.TableCell >> text=${TEST_NAMESPACE}`);
if ((await frame.innerText(`a[href^="/workloads"] .Icon .icon`)) === "keyboard_arrow_down") {
if ((await frame.innerText(`a[href^="/workloads"] .expand-icon`)) === "keyboard_arrow_down") {
await frame.click(`a[href^="/workloads"]`);
}
@@ -446,14 +444,24 @@ utils.describeIf(minikubeReady(TEST_NAMESPACE))("Minikube based tests", () => {
await namespacesSelector.click();
await frame.click(".Icon.new-dock-tab");
await frame.waitForTimeout(500); // TODO: fix menus to be less flaky
const createResourceTabButtom = await frame.waitForSelector("li.MenuItem.create-resource-tab");
await frame.waitForTimeout(500); // TODO: fix menus to be less flaky
await createResourceTabButtom.click();
try {
await frame.click("li.MenuItem.create-resource-tab", {
// NOTE: the following shouldn't be required, but is because without it a TypeError is thrown
// see: https://github.com/microsoft/playwright/issues/8229
position: {
y: 0,
x: 0,
}
});
} catch (error) {
console.log(error);
await frame.waitForTimeout(100_000);
}
const inputField = await frame.waitForSelector(".CreateResource div.ace_content");
const inputField = await frame.waitForSelector(".CreateResource div.react-monaco-editor-container");
await inputField.click();
await inputField.type("apiVersion: v1", { delay: 10 });
await inputField.press("Enter", { delay: 10 });
await inputField.type("kind: Pod", { delay: 10 });
@@ -480,5 +488,5 @@ utils.describeIf(minikubeReady(TEST_NAMESPACE))("Minikube based tests", () => {
} finally {
await cleanup();
}
});
}, 10*60*1000);
});
@@ -21,8 +21,6 @@
import * as utils from "../helpers/utils";
jest.setTimeout(20_000);
describe("Lens command palette", () => {
describe("menu", () => {
it("opens command dialog from keyboard shortcut", async () => {
@@ -35,6 +33,6 @@ describe("Lens command palette", () => {
} finally {
await cleanup();
}
});
}, 10*60*1000);
});
});
+56 -31
View File
@@ -18,9 +18,12 @@
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
import * as util from "util";
import { exec } from "child_process";
import { Frame, Page, _electron as electron } from "playwright";
import { createHash } from "crypto";
import { mkdirp, remove } from "fs-extra";
import * as os from "os";
import * as path from "path";
import * as uuid from "uuid";
import { ElectronApplication, Frame, Page, _electron as electron } from "playwright";
export const AppPaths: Partial<Record<NodeJS.Platform, string>> = {
"win32": "./dist/win-unpacked/OpenLens.exe",
@@ -36,52 +39,74 @@ export function describeIf(condition: boolean) {
return condition ? describe : describe.skip;
}
export const promiseExec = util.promisify(exec);
async function getMainWindow(app: ElectronApplication, timeout = 50_000): Promise<Page> {
const deadline = Date.now() + timeout;
type HelmRepository = {
name: string;
url: string;
};
export async function listHelmRepositories(): Promise<HelmRepository[]>{
for (let i = 0; i < 10; i += 1) {
try {
const { stdout } = await promiseExec("helm repo list -o json");
return JSON.parse(stdout);
} catch {
await new Promise(r => setTimeout(r, 2000)); // if no repositories, wait for Lens adding bitnami repository
for (; Date.now() < deadline;) {
for (const page of app.windows()) {
if (page.url().startsWith("http://localhost")) {
return page;
}
}
await new Promise(resolve => setTimeout(resolve, 2_000));
}
return [];
throw new Error(`Lens did not open the main window within ${timeout}ms`);
}
async function closeApp(app: ElectronApplication, timeout = 30_000) {
// TODO: change once timeouts for the native function are available
await Promise.race([
app.evaluateHandle(({ app }) => app.quit()),
new Promise((r, reject) => setTimeout(() => reject(`Lens failed to quit within ${timeout}ms`), timeout)),
]);
}
export async function start() {
const CICD = path.join(os.tmpdir(), "lens-integration-testing", uuid.v4());
// Make sure that the directory is clear
await remove(CICD);
await mkdirp(CICD);
const app = await electron.launch({
args: ["--integration-testing"], // this argument turns off the blocking of quit
executablePath: AppPaths[process.platform],
bypassCSP: true,
});
env: { CICD },
timeout: 100_000,
} as Parameters<typeof electron["launch"]>[0]);
const window = await app.waitForEvent("window", {
predicate: async (page) => page.url().startsWith("http://localhost"),
});
try {
const window = await getMainWindow(app);
return {
app,
window,
cleanup: async () => {
await window.close();
await app.close();
},
};
return {
app,
window,
cleanup: async () => {
try {
await window.close();
} catch {}
await closeApp(app);
await remove(CICD);
},
};
} catch (error) {
await closeApp(app);
await remove(CICD);
throw error;
}
}
export async function clickWelcomeButton(window: Page) {
await window.click("#hotbarIcon-catalog-entity .Icon");
}
function minikubeEntityId() {
return createHash("md5").update(`${path.join(os.homedir(), ".kube", "config")}:minikube`).digest("hex");
}
/**
* From the catalog, click the minikube entity and wait for it to connect, returning its frame
*/
@@ -91,7 +116,7 @@ export async function lauchMinikubeClusterFromCatalog(window: Page): Promise<Fra
await window.waitForSelector("div.drawer-title-text >> text='KubernetesCluster: minikube'");
await window.click("div.EntityIcon div.HotbarIcon div div.MuiAvatar-root");
const minikubeFrame = await window.waitForSelector("#cluster-frame-484e864bad9b84ce5d6b4fff704cc0e4");
const minikubeFrame = await window.waitForSelector(`#cluster-frame-${minikubeEntityId()}`);
const frame = await minikubeFrame.contentFrame();