vue-cli-plugin-electron-builder
vue-cli-plugin-electron-builder copied to clipboard
Windows: testWithSpectron didn't kill the electron:serve process
Describe the bug
We are testing our Electron with { testWithSpectron } from 'vue-cli-plugin-electron-builder'
.
The stopServe
and done
are called, Jest
says the test ends, but
Jest did not exit one second after the test run has completed. This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with
--detectOpenHandles
to troubleshoot this issue.
I can see the serve
process in the TaskManager, and it not ended:
Screenshots
Environment (please complete the following information):
- OS and version:
- node version:
v12.13.1
- npm version:
6.13.4
- yarn version (if used):
1.21.1
- vue-cli-plugin-electron-builder version :
1.4.4
- electron version:
^5.0.0
- other vue plugins used:
"@vue/cli-plugin-babel": "^4.1.0",
"@vue/cli-plugin-eslint": "^4.1.0",
"@vue/cli-plugin-router": "^4.1.0",
"@vue/cli-plugin-unit-jest": "^4.1.2",
"@vue/cli-plugin-vuex": "^4.1.0",
"vue-cli-plugin-element": "^1.0.1"
- custom config for vcp-electron-builder:
- (if possible) link to your repo: https://github.com/baruchiro/israeli-bank-scrapers-desktop/tree/UpdateVersions (Note to the branch)
Additional context
Command: jest test/e2e --config='test/e2e/jest.e2e.config.js'
Config:
module.exports = {
preset: '@vue/cli-plugin-unit-jest',
testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'],
};
Test:
import { testWithSpectron } from 'vue-cli-plugin-electron-builder';
jest.setTimeout(100000);
describe('Launch', () => {
let app;
let stopServe;
let win;
let client;
beforeEach(async () => {
// Wait for dev server to start
({ app, stopServe } = await testWithSpectron());
win = app.browserWindow;
({ client } = app);
});
test('shows the proper application title', async () => {
// Window was created
expect(await client.getWindowCount()).toBe(1);
// It is not minimized
expect(win.isMinimized()).toBe(false);
// Window is visible
expect(win.isVisible()).toBe(true);
// Size is correct
const { width, height } = win.getBounds();
expect(width).toBeGreaterThan(0);
expect(height).toBeGreaterThan(0);
// App is loaded properly
expect(
/israeli-bank-scrapers-desktop/.test(
await client.getHTML('#app'),
),
).toBe(true);
});
afterEach(async (done) => {
await stopServe();
done();
console.log('done');
});
});
one more strange thing that I've found is that if there is more than a one test file the test will be resolved successfully.
but for some reason, this trick won't work on Github Workflow
one more strange thing that I've found is that if there is more than a one test file the test will be resolved successfully.
but for some reason, this trick won't work on Github Workflow
See this action as example.
Try upgrading to the v2.0 beta. It uses a newer version of execa (used to spawn the dev server), and may fix your problem.
Try upgrading to the v2.0 beta. It uses a newer version of execa (used to spawn the dev server), and may fix your problem.
I've tried with v2.0 beta but still having the same issue however the open handle is different this time. With v1.4.4 the open handle was PIPEWRAP but now its PROCESSWRAP. Not sure if that is significant.
What happens if you run the testWithSpectron
function in a node script (without jest)? Does it exit properly? Also, try waiting 6 seconds after calling stopServe
, as execa should force kill the process after 5 seconds if it doesn't exit initially (https://github.com/sindresorhus/execa#killsignal-options).
This issue has been automatically closed because there has been no response to our request for more information from the original author. With only the information that is currently in the issue, we don't have enough information to take action. Please reach out if you have or find the answers we need so that we can investigate further.
OK, it reproduced with ^2.0.0-rc.6
, see the branch test
.
I have a node script and Jest. In node script, it works as expected, but with Jest, Github Actions, and Windows, it still gives me the "test didn't finish" message, and after this message it is waiting forever.
It is not reproduced locally.
CI: https://github.com/brafdlog/budget-tracking/runs/2038188083?check_suite_focus=true
Also, note. When I'm running it locally in Windows, in Jest there are "Electron Terminal" windows (you know, when you open a CLI process in a new window) that opened and closed immediately during the test.
package.json
https://github.com/brafdlog/budget-tracking/blob/341cb6ed8ecaf999187067ea3f0e1eba13a6147f/package.json
{
"name": "hiuvi",
"version": "0.1.3-beta",
"author": "Jonathan Goldfarb <[email protected]>",
"description": "An electron app for automating expense tracking",
"license": "MIT",
"main": "background.js",
"private": true,
"repository": "https://github.com/brafdlog/budget-tracking",
"homepage": "https://github.com/brafdlog/budget-tracking#README.md",
"scripts": {
"serve": "vue-cli-service electron:serve",
"serve:docker": "yarn serve --no-sandbox",
"build": "vue-cli-service electron:build",
"postinstall": "electron-builder install-app-deps",
"postuninstall": "electron-builder install-app-deps",
"prepare": "node scripts/copyCategoryCalculationScript.js",
"lint": "eslint --ext .js,.vue,.ts -f ./node_modules/eslint-friendly-formatter src test",
"lint:fix": "yarn lint --fix",
"typeCheck": "tsc --noEmit",
"unit": "vue-cli-service test:unit",
"e2e": "vue-cli-service test:unit --config='test/e2e/jest.e2e.config.js'",
"test": "yarn unit && yarn e2e"
},
"husky": {
"hooks": {
"pre-push": "yarn lint && yarn typeCheck"
}
},
"dependencies": {
"@getstation/electron-google-oauth2": "2.1.0",
"@sentry/electron": "^1.3.0",
"@vue/composition-api": "^1.0.0-beta.14",
"analytics-node": "^3.4.0-beta.3",
"core-js": "^3.4.4",
"csv-parse": "^4.14.1",
"csv-stringify": "^5.5.3",
"direct-vuex": "^0.12.0",
"electron-devtools-installer": "^3.1.1",
"electron-log": "^4.1.1",
"emittery": "^0.7.1",
"googleapis": "^59.0.0",
"israeli-bank-scrapers-core": "^1.0.1",
"keytar": "^5.2.0",
"lodash": "^4.17.15",
"moment": "^2.24.0",
"node-machine-id": "^1.1.12",
"puppeteer-core": "^5.5.0",
"vue": "^2.6.10",
"vue-router": "^3.1.6",
"vuetify": "^2.2.22",
"vuex": "^3.1.3",
"vuex-persist": "^2.2.0",
"ynab": "^1.19.0"
},
"devDependencies": {
"@babel/core": "^7.9.0",
"@babel/plugin-proposal-class-properties": "^7.10.4",
"@babel/preset-env": "^7.9.5",
"@babel/preset-typescript": "^7.10.1",
"@babel/register": "^7.9.0",
"@types/analytics-node": "^3.1.4",
"@types/jest": "^26.0.10",
"@types/lodash": "^4.14.158",
"@types/node": "12",
"@types/puppeteer-core": "^5.4.0",
"@types/webdriverio": "^4.0.0",
"@typescript-eslint/eslint-plugin": "^3.7.0",
"@typescript-eslint/parser": "^3.2.0",
"@vue/cli-plugin-babel": "^4.3.1",
"@vue/cli-plugin-eslint": "^4.3.1",
"@vue/cli-plugin-router": "^4.3.1",
"@vue/cli-plugin-typescript": "^4.4.4",
"@vue/cli-plugin-unit-jest": "^4.5.4",
"@vue/cli-plugin-vuex": "^4.3.1",
"@vue/cli-service": "^4.3.1",
"@vue/eslint-config-prettier": "^6.0.0",
"@vue/eslint-config-typescript": "^5.0.2",
"@vue/test-utils": "^1.0.3",
"babel-core": "^7.0.0-bridge.0",
"babel-eslint": "^10.1.0",
"babel-jest": "^26.3.0",
"babel-plugin-component": "^1.1.1",
"electron": "^9.0.0",
"eslint": "^7.1.0",
"eslint-config-airbnb-base": "^14.1.0",
"eslint-config-prettier": "^6.11.0",
"eslint-friendly-formatter": "^4.0.1",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-loader": "^4.0.2",
"eslint-plugin-html": "^6.0.2",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-jest": "^23.20.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.1.3",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.1",
"eslint-plugin-vue": "^6.2.2",
"husky": "^4.2.5",
"identity-obj-proxy": "^3.0.0",
"jest": "^26.4.2",
"jest-circus": "^26.4.2",
"jest-config": "^26.4.2",
"jest-each": "^26.4.2",
"jest-environment-node": "^26.6.2",
"ncp": "^2.0.0",
"node-loader": "^1.0.2",
"prettier": "^2.0.5",
"replace-in-file": "5.0.2",
"sass": "^1.26.3",
"sass-loader": "^8.0.0",
"spectron": "^11.0.0",
"ts-jest": "^26.3.0",
"typescript": "^3.9.7",
"vue-cli-plugin-electron-builder": "^2.0.0-rc.6",
"vue-cli-plugin-vuetify": "~2.0.5",
"vue-jest": "4.0.0-beta.5",
"vue-template-compiler": "^2.6.11",
"vuetify-loader": "^1.4.4"
}
}
script.js
https://github.com/brafdlog/budget-tracking/blob/341cb6ed8ecaf999187067ea3f0e1eba13a6147f/script.js
const { testWithSpectron } = require('vue-cli-plugin-electron-builder');
const spectron = require('spectron');
(async function start() {
console.log('serve')
console.time('serve')
const { app, stopServe, stdout } = await testWithSpectron(spectron)
console.timeEnd('serve')
console.log('served')
console.log(stdout)
const { client } = app;
console.log('waitUntilWindowLoaded')
await client.waitUntilWindowLoaded();
console.log('finish waitUntilWindowLoaded')
console.log(await client.getWindowCount())
const appElement = await client.$('#app');
console.log(/Hiuvi/.test(await appElement.getHTML()))
console.log('stopServe')
await stopServe()
console.log('finish stopServe')
})()
launch.spec.ts
https://github.com/brafdlog/budget-tracking/blob/341cb6ed8ecaf999187067ea3f0e1eba13a6147f/test/e2e/specs/launch.spec.tsimport fs from 'fs';
import path from 'path';
import { testWithSpectron } from 'vue-cli-plugin-electron-builder';
import spectron from 'spectron';
import {
Application, SpectronClient, SpectronWindow, StopServe
} from '../type';
// import Interactions from '../utils/interactions';
const screenshotsDir = './screenshots';
jest.setTimeout(1000000);
describe('Launch', () => {
let app: Application;
let stopServe: StopServe;
let browserWindow: SpectronWindow;
let client: SpectronClient;
// let interactions: Interactions;
beforeAll(async () => {
let stdout: string;
({ app, stopServe, stdout } = await testWithSpectron(spectron));
// eslint-disable-next-line no-console
console.log(stdout);
});
beforeEach(async () => {
app = await app.restart();
({ client, browserWindow } = app);
await client.waitUntilWindowLoaded();
// interactions = new Interactions(client);
});
test('shows the proper application title', async () => {
// Window was created
expect(await client.getWindowCount()).toBe(1);
// It is not minimized
expect(await browserWindow.isMinimized()).toBe(false);
// Window is visible
expect(await browserWindow.isVisible()).toBe(true);
// Size is correct
const { width, height } = await browserWindow.getBounds();
expect(width).toBeGreaterThan(0);
expect(height).toBeGreaterThan(0);
// App is loaded properly
const appElement = await client.$('#app');
expect(await appElement.getHTML()).toMatch('Hiuvi');
});
// test.skip('Hide AddScraper components by default', async () => {
// const addScrapers = await interactions.getAddScrapers();
// // @ts-expect-error
// const visiblities = await Promise.all(addScrapers.map((scraper) => scraper.isVisible()));
// expect(visiblities).not.toContain(true);
// expect(visiblities).toContain(false);
// });
// test.skip('Show AddScraper components when clicking on AddScraper', async () => {
// await interactions.toggleLeftDrawer();
// await interactions.clickCollapseAddImporter();
// const addScrapers = await interactions.getAddScrapers();
// // @ts-expect-error
// const visiblities = await Promise.all(addScrapers.map((scraper) => scraper.isVisible()));
// expect(visiblities).not.toContain(false);
// });
afterEach(async () => {
if (global.lastTest.failed) {
if (!fs.existsSync(screenshotsDir)) {
fs.mkdirSync(screenshotsDir);
}
const screenshotFile = path.join(screenshotsDir, `${global.lastTest.test.name.replace(/\s/g, '')}.png`);
const imgBuffer = await browserWindow.capturePage();
fs.writeFileSync(screenshotFile, imgBuffer.toBitmap());
}
});
afterAll(async () => stopServe());
});
declare global {
namespace NodeJS {
interface Global {
lastTest: any;
}
}
}
Update:
I tried to wait for 10 seconds after the stopServe
.
https://github.com/brafdlog/budget-tracking/blob/7d49a2874f6d8dafa09fa2e4dc8b18f0a05fa254/test/e2e/specs/launch.spec.ts#L85-L90
Note that the CI is still running. It means that Jest reported about the "did not exit", and still waiting.
Seems like it may be related to this: https://github.com/sindresorhus/execa/issues/96. I'm not sure what else it could be, as stopServe kills it pretty clearly. I'll see if I can find a way to make sure it kills child processes as well.
Okay I changed the command to use SIGKILL
to kill the dev server, which might fix it. Can you update your app to use the git repo as the version for this plugin and then let me know if it works now?
Still not working.
https://github.com/brafdlog/budget-tracking/pull/203/checks?check_run_id=2115697081
Do I need to wait 5 seconds?