1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

revert integration test code

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2021-02-18 10:04:55 -05:00
parent 65274f0d5f
commit c80965e512
5 changed files with 310 additions and 629 deletions

View File

@ -2,28 +2,16 @@ import { Application } from "spectron";
import * as utils from "../helpers/utils"; import * as utils from "../helpers/utils";
import { listHelmRepositories } from "../helpers/utils"; import { listHelmRepositories } from "../helpers/utils";
import { fail } from "assert"; import { fail } from "assert";
import open from "open";
import { AbortController } from "abort-controller";
jest.setTimeout(60000); jest.setTimeout(60000);
// FIXME (!): improve / simplify all css-selectors + use [data-test-id="some-id"] (already used in some tests below) // FIXME (!): improve / simplify all css-selectors + use [data-test-id="some-id"] (already used in some tests below)
describe("Lens integration tests", () => { describe("Lens integration tests", () => {
let app: Application; let app: Application;
let abortContoller: AbortController;
describe("app start", () => { describe("app start", () => {
beforeAll(async () => { beforeAll(async () => app = await utils.appStart(), 20000);
try {
app = await utils.appStart();
} catch (error) {
fail(error);
}
});
beforeEach(() => {
abortContoller = new AbortController();
});
afterAll(async () => { afterAll(async () => {
if (app?.isRunning()) { if (app?.isRunning()) {
@ -31,10 +19,6 @@ describe("Lens integration tests", () => {
} }
}); });
afterEach(() => {
abortContoller.abort();
});
it('shows "whats new"', async () => { it('shows "whats new"', async () => {
await utils.clickWhatsNew(app); await utils.clickWhatsNew(app);
}); });
@ -44,26 +28,6 @@ describe("Lens integration tests", () => {
await app.client.waitUntilTextExists("h2", "Add Cluster"); await app.client.waitUntilTextExists("h2", "Add Cluster");
}); });
/**
* skipping this for the time being until we can figure out why they are opening a second instace
* and seemingly bypassing the single instance lock
*/
describe.skip("protocol app start", () => {
it("should handle opening lens:// links", async () => {
await open("lens://app/foobar");
await utils.waitForLogsToContain(app, abortContoller, {
main: ["No handler", "lens://app/foobar"],
renderer: ["No handler", "lens://app/foobar"],
});
});
it("should opening lens://app/preferences", async () => {
await open("lens://app/preferences");
await app.client.waitUntilTextExists("h2", "Preferences");
});
});
describe("preferences page", () => { describe("preferences page", () => {
it('shows "preferences"', async () => { it('shows "preferences"', async () => {
const appName: string = process.platform === "darwin" ? "Lens" : "File"; const appName: string = process.platform === "darwin" ? "Lens" : "File";

View File

@ -9,8 +9,6 @@ import * as utils from "../helpers/utils";
import { addMinikubeCluster, minikubeReady, waitForMinikubeDashboard } from "../helpers/minikube"; import { addMinikubeCluster, minikubeReady, waitForMinikubeDashboard } from "../helpers/minikube";
import { exec } from "child_process"; import { exec } from "child_process";
import * as util from "util"; import * as util from "util";
import { delay } from "../../src/common/utils";
import { AbortController } from "abort-controller";
export const promiseExec = util.promisify(exec); export const promiseExec = util.promisify(exec);
@ -34,21 +32,11 @@ describe("Lens cluster pages", () => {
}; };
describe("cluster add", () => { describe("cluster add", () => {
beforeAll(async () => { beforeAll(async () => app = await utils.appStart(), 20000);
try {
app = await utils.appStart();
} catch (error) {
fail(error);
}
});
afterAll(async () => { afterAll(async () => {
try { if (app && app.isRunning()) {
if (app?.isRunning()) { return utils.tearDown(app);
await utils.tearDown(app);
}
} catch (error) {
fail(error);
} }
}); });
@ -65,420 +53,299 @@ describe("Lens cluster pages", () => {
} }
}; };
describe("cluster menu pages", () => { describe("cluster pages", () => {
beforeAll(async () => {
try { beforeAll(appStartAddCluster, 40000);
await appStartAddCluster();
} catch (error) {
fail(error);
}
});
afterAll(async () => { afterAll(async () => {
try { if (app && app.isRunning()) {
if (app?.isRunning()) { return utils.tearDown(app);
await utils.tearDown(app);
}
} catch (error) {
fail(error);
} }
}); });
type Page = [ const tests: {
string, // name drawer?: string
{ drawerId?: string
pages: {
name: string,
href: string, href: string,
expectedSelector: string, expectedSelector: string,
expectedText: string, expectedText: string
} }[]
]; }[] = [{
drawer: "",
type PageTestCase = [ drawerId: "",
string, // drawer pages: [{
name: "Cluster",
href: "cluster",
expectedSelector: "div.ClusterOverview div.label",
expectedText: "Master"
}]
},
{
drawer: "",
drawerId: "",
pages: [{
name: "Nodes",
href: "nodes",
expectedSelector: "h5.title",
expectedText: "Nodes"
}]
},
{
drawer: "Workloads",
drawerId: "workloads",
pages: [{
name: "Overview",
href: "workloads",
expectedSelector: "h5.box",
expectedText: "Overview"
},
{ {
drawerId: string, name: "Pods",
pages: Page[], 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"
}]
},
{
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"
}]
},
{
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"
}]
},
{
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"
}]
},
{
drawer: "",
drawerId: "",
pages: [{
name: "Namespaces",
href: "namespaces",
expectedSelector: "h5.title",
expectedText: "Namespaces"
}]
},
{
drawer: "",
drawerId: "",
pages: [{
name: "Events",
href: "events",
expectedSelector: "h5.title",
expectedText: "Events"
}]
},
{
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"
}]
},
{
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"
}]
},
{
drawer: "Custom Resources",
drawerId: "custom-resources",
pages: [{
name: "Definitions",
href: "crd/definitions",
expectedSelector: "h5.title",
expectedText: "Custom Resources"
}]
}];
tests.forEach(({ drawer = "", drawerId = "", pages }) => {
if (drawer !== "") {
it(`shows ${drawer} drawer`, async () => {
expect(clusterAdded).toBe(true);
await app.client.click(`.sidebar-nav [data-test-id="${drawerId}"] span.link-text`);
await app.client.waitUntilTextExists(`a[href^="/${pages[0].href}"]`, pages[0].name);
});
} }
]; pages.forEach(({ name, href, expectedSelector, expectedText }) => {
it(`shows ${drawer}->${name} page`, async () => {
const noSubMenuTests: Page[] = [ expect(clusterAdded).toBe(true);
[ await app.client.click(`a[href^="/${href}"]`);
"Cluster", await app.client.waitUntilTextExists(expectedSelector, expectedText);
{ });
href: "cluster",
expectedSelector: "div.ClusterOverview div.label",
expectedText: "Master",
}
],
[
"Nodes",
{
href: "nodes",
expectedSelector: "h5.title",
expectedText: "Nodes"
}
],
[
"Namespaces",
{
href: "namespaces",
expectedSelector: "h5.title",
expectedText: "Namespaces"
}
],
[
"Events",
{
href: "events",
expectedSelector: "h5.title",
expectedText: "Events"
}
],
];
const subMenuTests: PageTestCase[] = [
[
"Workloads",
{
drawerId: "workloads",
pages: [
[
"Overview",
{
href: "workloads",
expectedSelector: "h5.box",
expectedText: "Overview"
}
],
[
"Pods",
{
href: "pods",
expectedSelector: "h5.title",
expectedText: "Pods"
}
],
[
"Deployments",
{
href: "deployments",
expectedSelector: "h5.title",
expectedText: "Deployments"
}
],
[
"DaemonSets",
{
href: "daemonsets",
expectedSelector: "h5.title",
expectedText: "Daemon Sets"
}
],
[
"StatefulSets",
{
href: "statefulsets",
expectedSelector: "h5.title",
expectedText: "Stateful Sets"
}
],
[
"ReplicaSets",
{
href: "replicasets",
expectedSelector: "h5.title",
expectedText: "Replica Sets"
}
],
[
"Jobs",
{
href: "jobs",
expectedSelector: "h5.title",
expectedText: "Jobs"
}
],
[
"CronJobs",
{
href: "cronjobs",
expectedSelector: "h5.title",
expectedText: "Cron Jobs"
}
]
]
}
],
[
"Configuration",
{
drawerId: "config",
pages: [
[
"ConfigMaps",
{
href: "configmaps",
expectedSelector: "h5.title",
expectedText: "Config Maps"
}
],
[
"Secrets",
{
href: "secrets",
expectedSelector: "h5.title",
expectedText: "Secrets"
}
],
[
"Resource Quotas",
{
href: "resourcequotas",
expectedSelector: "h5.title",
expectedText: "Resource Quotas"
}
],
[
"Limit Ranges",
{
href: "limitranges",
expectedSelector: "h5.title",
expectedText: "Limit Ranges"
}
],
[
"HPA",
{
href: "hpa",
expectedSelector: "h5.title",
expectedText: "Horizontal Pod Autoscalers"
}
],
[
"Pod Disruption Budgets",
{
href: "poddisruptionbudgets",
expectedSelector: "h5.title",
expectedText: "Pod Disruption Budgets"
}
]
]
}
],
[
"Network",
{
drawerId: "networks",
pages: [
[
"Services",
{
href: "services",
expectedSelector: "h5.title",
expectedText: "Services"
}
],
[
"Endpoints",
{
href: "endpoints",
expectedSelector: "h5.title",
expectedText: "Endpoints"
}
],
[
"Ingresses",
{
href: "ingresses",
expectedSelector: "h5.title",
expectedText: "Ingresses"
}
],
[
"Network Policies",
{
href: "network-policies",
expectedSelector: "h5.title",
expectedText: "Network Policies"
}
]
]
}
],
[
"Storage",
{
drawerId: "storage",
pages: [
[
"Persistent Volume Claims",
{
href: "persistent-volume-claims",
expectedSelector: "h5.title",
expectedText: "Persistent Volume Claims"
}
],
[
"Persistent Volumes",
{
href: "persistent-volumes",
expectedSelector: "h5.title",
expectedText: "Persistent Volumes"
}
],
[
"Storage Classes",
{
href: "storage-classes",
expectedSelector: "h5.title",
expectedText: "Storage Classes"
}
]
]
}
],
[
"Apps",
{
drawerId: "apps",
pages: [
[
"Charts",
{
href: "apps/charts",
expectedSelector: "div.HelmCharts input",
expectedText: ""
}
],
[
"Releases",
{
href: "apps/releases",
expectedSelector: "h5.title",
expectedText: "Releases"
}
]
]
}
],
[
"Access Control",
{
drawerId: "users",
pages: [
[
"Service Accounts",
{
href: "service-accounts",
expectedSelector: "h5.title",
expectedText: "Service Accounts"
}
],
[
"Role Bindings",
{
href: "role-bindings",
expectedSelector: "h5.title",
expectedText: "Role Bindings"
}
],
[
"Roles",
{
href: "roles",
expectedSelector: "h5.title",
expectedText: "Roles"
}
],
[
"Pod Security Policies",
{
href: "pod-security-policies",
expectedSelector: "h5.title",
expectedText: "Pod Security Policies"
}
]
]
}
],
[
"Custom Resources",
{
drawerId: "custom-resources",
pages: [
[
"Definitions",
{
href: "crd/definitions",
expectedSelector: "h5.title",
expectedText: "Custom Resources"
}
]
]
}
]
];
describe.each(noSubMenuTests)("%s", (name, { href, expectedSelector, expectedText }) => {
it("shows page", async () => {
expect(clusterAdded).toBe(true);
await app.client.click(`a[href^="/${href}"]`);
await app.client.waitUntilTextExists(expectedSelector, expectedText);
});
});
describe.each(subMenuTests)("%s Drawer", (drawer, { drawerId, pages }) => {
it("does open", async () => {
expect(clusterAdded).toBe(true);
await app.client.click(`.sidebar-nav [data-test-id="${drawerId}"] span.link-text`);
await app.client.waitUntilTextExists(`a[href^="/${pages[0][1].href}"]`, pages[0][0]);
}); });
it.each(pages)("shows %s page", async (name, { href, expectedSelector, expectedText }) => { if (drawer !== "") {
expect(clusterAdded).toBe(true); // hide the drawer
await app.client.click(`a[href^="/${href}"]`); it(`hides ${drawer} drawer`, async () => {
await app.client.waitUntilTextExists(expectedSelector, expectedText); expect(clusterAdded).toBe(true);
}); await app.client.click(`.sidebar-nav [data-test-id="${drawerId}"] span.link-text`);
await expect(app.client.waitUntilTextExists(`a[href^="/${pages[0].href}"]`, pages[0].name, 100)).rejects.toThrow();
it("does close", async () => { });
expect(clusterAdded).toBe(true); }
await app.client.click(`.sidebar-nav [data-test-id="${drawerId}"] span.link-text`);
try {
expect(await app.client.waitUntilTextExists(`a[href^="/${pages[0][1].href}"]`, pages[0][0], 100)).toBeUndefined();
} catch (error) {
expect(error).not.toBeUndefined();
}
});
}); });
}); });
describe("viewing pod logs", () => { describe("viewing pod logs", () => {
let abortContoller: AbortController; beforeEach(appStartAddCluster, 40000);
beforeEach(async () => {
abortContoller = new AbortController();
try {
await appStartAddCluster();
} catch (error) {
fail(error);
}
});
afterEach(async () => { afterEach(async () => {
abortContoller.abort(); if (app && app.isRunning()) {
return utils.tearDown(app);
try {
if (app?.isRunning()) {
await utils.tearDown(app);
}
} catch (error) {
fail(error);
} }
}); });
it("shows a logs for a pod", async () => { it(`shows a logs for a pod`, async () => {
expect(clusterAdded).toBe(true); expect(clusterAdded).toBe(true);
// Go to Pods page // Go to Pods page
await app.client.click(".sidebar-nav [data-test-id='workloads'] span.link-text"); await app.client.click(".sidebar-nav [data-test-id='workloads'] span.link-text");
@ -488,13 +355,19 @@ describe("Lens cluster pages", () => {
await app.client.keys("kube-system"); await app.client.keys("kube-system");
await app.client.keys("Enter");// "\uE007" await app.client.keys("Enter");// "\uE007"
await app.client.waitUntilTextExists("div.TableCell", "kube-apiserver"); await app.client.waitUntilTextExists("div.TableCell", "kube-apiserver");
let podMenuItemEnabled = false;
await utils.waitForLogsToContain(app, abortContoller, { // Wait until extensions are enabled on renderer
renderer: ["[EXTENSION]: enabled lens-pod-menu@"], while (!podMenuItemEnabled) {
}); const logs = await app.client.getRenderProcessLogs();
await delay(2000); // Give some extra time to prepare extensions 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 // Open logs tab in dock
await app.client.click(".list .TableRow:first-child"); await app.client.click(".list .TableRow:first-child");
await app.client.waitForVisible(".Drawer"); await app.client.waitForVisible(".Drawer");
@ -514,21 +387,11 @@ describe("Lens cluster pages", () => {
}); });
describe("cluster operations", () => { describe("cluster operations", () => {
beforeEach(async () => { beforeEach(appStartAddCluster, 40000);
try {
await appStartAddCluster();
} catch (error) {
fail(error);
}
});
afterEach(async () => { afterEach(async () => {
try { if (app && app.isRunning()) {
if (app?.isRunning()) { return utils.tearDown(app);
await utils.tearDown(app);
}
} catch (error) {
fail(error);
} }
}); });

View File

@ -7,21 +7,11 @@ describe("Lens command palette", () => {
let app: Application; let app: Application;
describe("menu", () => { describe("menu", () => {
beforeAll(async () => { beforeAll(async () => app = await utils.appStart(), 20000);
try {
app = await utils.appStart();
} catch (error) {
fail(error);
}
});
afterAll(async () => { afterAll(async () => {
try { if (app?.isRunning()) {
if (app?.isRunning()) { await utils.tearDown(app);
await utils.tearDown(app);
}
} catch (error) {
fail(error);
} }
}); });

View File

@ -14,21 +14,13 @@ describe("Lens integration tests", () => {
utils.describeIf(ready)("workspaces", () => { utils.describeIf(ready)("workspaces", () => {
beforeAll(async () => { beforeAll(async () => {
try { app = await utils.appStart();
app = await utils.appStart(); await utils.clickWhatsNew(app);
await utils.clickWhatsNew(app); }, 20000);
} catch (error) {
fail(error);
}
});
afterAll(async () => { afterAll(async () => {
try { if (app && app.isRunning()) {
if (app?.isRunning()) { return utils.tearDown(app);
await utils.tearDown(app);
}
} catch (error) {
fail(error);
} }
}); });

View File

@ -1,31 +1,12 @@
import { AppConstructorOptions, Application } from "spectron"; import { Application } from "spectron";
import * as util from "util"; import * as util from "util";
import { exec } from "child_process"; import { exec } from "child_process";
import { delay } from "../../src/common/utils";
import { AbortController } from "abort-controller";
interface AppTestingPaths { const AppPaths: Partial<Record<NodeJS.Platform, string>> = {
testingPath: string, "win32": "./dist/win-unpacked/Lens.exe",
} "linux": "./dist/linux-unpacked/kontena-lens",
"darwin": "./dist/mac/Lens.app/Contents/MacOS/Lens",
function getAppTestingPaths(): AppTestingPaths { };
switch (process.platform) {
case "win32":
return {
testingPath: "./dist/win-unpacked/Lens.exe",
};
case "linux":
return {
testingPath: "./dist/linux-unpacked/kontena-lens",
};
case "darwin":
return {
testingPath: "./dist/mac/Lens.app/Contents/MacOS/Lens",
};
default:
throw new TypeError(`platform ${process.platform} is not supported`);
}
}
export function itIf(condition: boolean) { export function itIf(condition: boolean) {
return condition ? it : it.skip; return condition ? it : it.skip;
@ -35,18 +16,16 @@ export function describeIf(condition: boolean) {
return condition ? describe : describe.skip; return condition ? describe : describe.skip;
} }
export function setup(): AppConstructorOptions { export function setup(): Application {
const appPath = getAppTestingPaths(); return new Application({
path: AppPaths[process.platform], // path to electron app
return {
path: appPath.testingPath,
args: [], args: [],
startTimeout: 30000, startTimeout: 30000,
waitTimeout: 60000, waitTimeout: 60000,
env: { env: {
CICD: "true" CICD: "true"
} }
}; });
} }
export const keys = { export const keys = {
@ -54,7 +33,7 @@ export const keys = {
}; };
export async function appStart() { export async function appStart() {
const app = new Application(setup()); const app = setup();
await app.start(); await app.start();
// Wait for splash screen to be closed // Wait for splash screen to be closed
@ -62,31 +41,6 @@ export async function appStart() {
await app.client.windowByIndex(0); await app.client.windowByIndex(0);
await app.client.waitUntilWindowLoaded(); await app.client.waitUntilWindowLoaded();
/**
* This is commented out to pass CI, need to do some more investiagation into why this isn't working
*/
// if (process.platform === "linux") {
// const testingDesktop = [
// "[Desktop Entry]",
// "Name=Lens",
// `Exec=${path.resolve(getAppTestingPaths().testingPath)} %U`,
// "Terminal=false",
// "Type=Application",
// "Icon=lens",
// "StartupWMClass=Lens",
// "Comment=Lens - The Kubernetes IDE",
// "MimeType=x-scheme-handler/lens;",
// "Categories=Network;"
// ].join("\n");
// await mkdirp(path.join(os.homedir(), ".local/share/applications/"));
// await writeFile(path.join(os.homedir(), ".local/share/applications/lens-testing.desktop"), testingDesktop);
// const { status } = spawnSync("xdg-settings set default-url-scheme-handler lens lens-testing.desktop", { shell: true });
// expect(status).toBe(0);
// }
return app; return app;
} }
@ -132,85 +86,3 @@ export async function listHelmRepositories(retries = 0): Promise<HelmRepository
return []; return [];
} }
const rendererLogPrefixMatcher = /^\[[0-9]{5}:[0-9]{4}\/[0-9]{6}\.[0-9]{6}:[A-Z]+:CONSOLE\([0-9)]+\)\]\s"(?<message>.*)", source: http:\/\//;
export interface LogMatches {
renderer?: string[];
main?: string[];
}
interface LogLines {
renderer: string[];
main: string[];
}
async function* splitLogs(app: Application, signal: AbortController): AsyncGenerator<LogLines, void, void> {
let lastLogLineCount = 0;
while (!signal.signal.aborted) { // infinite loop
const curLogs: string[] = (app as any).chromeDriver.getLogs();
const newLogs = curLogs.slice(lastLogLineCount);
lastLogLineCount = curLogs.length;
const item: LogLines = {
renderer: [],
main: [],
};
for (const logLine of newLogs) {
const logParts = logLine.match(rendererLogPrefixMatcher);
if (logParts === null) {
item.main.push(logLine);
} else {
item.renderer.push(logParts.groups.message);
}
}
yield item;
await delay(500, signal); // only delay after the first attempt and fail fast if the signal has occured
}
}
/**
* Wait for all of `values` to be part of the logs. Does not clear logs. Does
* not work well with `app.client.get(Main|Renderer)ProcessLogs()`
*
* Note: this is a "best attempt" since spectron's `getMainProcessLogs` sometimes
* contains `renderer` logs.
* @param app The spectron app that we are testing against
* @param source Whether to wait for renderer or main logs
* @param values The list of strings that should all be contained in the logs
*/
export async function waitForLogsToContain(app: Application, signal: AbortController, matches: LogMatches): Promise<void> {
const notYetFound = {
main: new Set(matches.main ?? []),
renderer: new Set(matches.renderer ?? []),
};
for await (const logs of splitLogs(app, signal)) {
mainMatch: for (const logPart of notYetFound.main) {
for (const logLine of logs.main) {
if (logLine.includes(logPart)) {
notYetFound.main.delete(logPart);
continue mainMatch; // we have found this log part, try the next part
}
}
}
rendererMatch: for (const logPart of notYetFound.renderer) {
for (const logLine of logs.renderer) {
if (logLine.includes(logPart)) {
notYetFound.renderer.delete(logPart);
continue rendererMatch; // we have found this log part, try the next part
}
}
}
if (notYetFound.main.size === 0 && notYetFound.renderer.size === 0) {
return; // we are done, have found all log parts
}
}
}