Skip to content

Commit

Permalink
tweak e2e tests
Browse files Browse the repository at this point in the history
* don't fail on Object has been destroyed: "sender" electron-rpc-api module error
* take more screenshots
  • Loading branch information
vladimiry committed Dec 25, 2018
1 parent 357210e commit 4d66a74
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 29 deletions.
87 changes: 59 additions & 28 deletions src/e2e/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// TODO track this issue https://github.com/DefinitelyTyped/DefinitelyTyped/issues/25186
// tslint:disable:await-promise

import byline from "byline";
import fs from "fs";
import path from "path";
import psNode from "ps-node"; // see also https://www.npmjs.com/package/find-process
Expand All @@ -10,7 +11,7 @@ import {platform} from "os";
import {promisify} from "util";

import {ACCOUNTS_CONFIG_ENTRY_URL_LOCAL_PREFIX} from "src/shared/constants";
import {APP_NAME, CI, ENV, initApp, test} from "./workflow";
import {APP_NAME, CI, ENV, initApp, saveScreenshot, test} from "./workflow";

test.serial("general actions: app start, master password setup, add accounts, logout, auto login", async (t) => {
// setup and login
Expand Down Expand Up @@ -65,42 +66,72 @@ test.serial("general actions: app start, master password setup, add accounts, lo
await workflow.destroyApp();
})();

// making sure log file has not been created (no errors happened)
t.false(fs.existsSync(t.context.logFilePath), `"${t.context.logFilePath}" file should not exist`);
if (fs.existsSync(t.context.logFilePath)) {
await new Promise((resolve, reject) => {
const stream = byline.createStream(
fs.createReadStream(t.context.logFilePath),
);
stream.on("data", (_, line = String(_)) => {
if (
line.includes("[electron-rpc-api]") &&
line.includes(`Object has been destroyed: "sender"`)
) {
return;
}
line = null; // WARN: don't print log line
t.fail(`App log file error line`);
});
stream.on("error", reject);
stream.on("end", resolve);
});
}

// additionally making sure that settings file is actually encrypted by simply scanning it for the raw "login" value
const rawSettings = promisify(fs.readFile)(path.join(t.context.userDataDirPath, "settings.bin"));
t.true(rawSettings.toString().indexOf(ENV.loginPrefix) === -1);
});

if (CI) {
test.beforeEach(async (t) => {
t.context.testStatus = "initial";
});

test.afterEach(async (t) => {
t.context.testStatus = "success";
});

test.afterEach.always(async (t) => {
if (t.context.testStatus !== "success") {
await saveScreenshot(t);
}

if (!CI) {
return;
}

// kill processes to avoid appveyor error during preparing logs for uploading:
// The process cannot access the file because it is being used by another process: output\e2e\1545563294836\chrome-driver.log
await (async () => {
// HINT: add "- ps: Get-Process" line to appveyor.yml to list the processes
const processes: Array<{ pid: number }> = await Promise.all(
[
{command: APP_NAME}, {arguments: APP_NAME},
{command: "electron"}, {arguments: "electron"},
{command: "chrome"}, {arguments: "chrome"},
{command: "webdriver"}, {arguments: "webdriver"},
{command: "chrome-driver"}, {arguments: "chrome-driver"},
{arguments: "log"},
{arguments: "e2e"},
].map((criteria) => promisify(psNode.lookup)(criteria)),
);

test.afterEach(async () => {
await (async () => {
// HINT: add "- ps: Get-Process" line to appveyor.yml to list the processes
const processes: Array<{ pid: number }> = await Promise.all(
[
{command: APP_NAME}, {arguments: APP_NAME},
{command: "electron"}, {arguments: "electron"},
{command: "chrome"}, {arguments: "chrome"},
{command: "webdriver"}, {arguments: "webdriver"},
{command: "chrome-driver"}, {arguments: "chrome-driver"},
{arguments: "log"},
{arguments: "e2e"},
].map((criteria) => promisify(psNode.lookup)(criteria)),
);

for (const {pid} of processes) {
try {
await killSelfAndChildrenProcesses(pid);
} catch {
// NOOP
}
for (const {pid} of processes) {
try {
await killSelfAndChildrenProcesses(pid);
} catch {
// NOOP
}
})();
});
}
})();

async function killSelfAndChildrenProcesses(pid: number) {
const processesToKill = [
Expand All @@ -116,4 +147,4 @@ if (CI) {
}
}
}
}
});
10 changes: 9 additions & 1 deletion src/e2e/workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {AccountType} from "src/shared/model/account";
import {CI_ENV_LOGOUT_ACTION_TIMEOUT_MS} from "./shared-constants";

export interface TestContext {
testStatus: "initial" | "success" | "fail";
app: Application;
outputDirPath: string;
userDataDirPath: string;
Expand Down Expand Up @@ -57,7 +58,6 @@ const GLOBAL_STATE = {

export async function initApp(t: ExecutionContext<TestContext>, options: { initial: boolean }): Promise<TestContext["workflow"]> {
t.context.workflow = buildWorkflow(t);

t.context.sinon = {
addAccountSpy: sinon.spy(t.context.workflow, "addAccount"),
};
Expand Down Expand Up @@ -165,13 +165,17 @@ export async function initApp(t: ExecutionContext<TestContext>, options: { initi
function buildWorkflow(t: ExecutionContext<TestContext>) {
const workflow = {
async destroyApp() {
await saveScreenshot(t);

// TODO update to electron 2: app.isRunning() returns undefined, uncomment as soon as it's fixed
if (!t.context.app || !t.context.app.isRunning()) {
t.pass("app is not running");
return;
}

await t.context.app.stop();
t.is(t.context.app.isRunning(), false);

delete t.context.app;
},

Expand Down Expand Up @@ -422,6 +426,10 @@ export async function catchError(t: ExecutionContext<TestContext>, error?: Error
}

export async function saveScreenshot(t: ExecutionContext<TestContext>) {
if (!t.context.app || !t.context.app.browserWindow) {
return;
}

const file = path.join(
t.context.outputDirPath,
`sreenshot-${t.title}-${new Date().toISOString()}.png`.replace(/[^A-Za-z0-9\.]/g, "_"),
Expand Down

0 comments on commit 4d66a74

Please sign in to comment.