replace Spectron by Playwright

This commit is contained in:
Maxime GRIS
2021-11-13 19:55:50 +01:00
parent 6463897e8f
commit 558c646e2f
15 changed files with 1479 additions and 1386 deletions

2
.gitignore vendored
View File

@@ -43,6 +43,8 @@ testem.log
/e2e/*.js
!/e2e/protractor.conf.js
/e2e/*.map
/e2e/tracing
/e2e/screenshots
# System Files
.DS_Store

View File

@@ -3,9 +3,6 @@ import * as path from 'path';
import * as fs from 'fs';
import * as url from 'url';
// Initialize remote module
require('@electron/remote/main').initialize();
let win: BrowserWindow = null;
const args = process.argv.slice(1),
serve = args.some(val => val === '--serve');
@@ -25,7 +22,6 @@ function createWindow(): BrowserWindow {
nodeIntegration: true,
allowRunningInsecureContent: (serve) ? true : false,
contextIsolation: false, // false if you want to run e2e test with Spectron
enableRemoteModule : true // true if you want to run e2e test with Spectron or use remote module in renderer context (ie. Angular)
},
});

10
app/package-lock.json generated
View File

@@ -1,13 +1,5 @@
{
"name": "angular-electron",
"version": "10.1.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@electron/remote": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@electron/remote/-/remote-1.2.0.tgz",
"integrity": "sha512-C774t2DFVJsa+dxU9Gc2nYzylRZoJ79I0Sxrh8T9cN69fBkntfGbyBEQiD9UfZopqL0CYLzk1anY2Ywhql6h1w=="
}
}
"lockfileVersion": 1
}

View File

@@ -3,7 +3,5 @@
"version": "10.1.0",
"main": "main.js",
"private": true,
"dependencies": {
"@electron/remote": "1.2.0"
}
"dependencies": {}
}

View File

@@ -1,26 +0,0 @@
const APPLICATION = require('spectron').Application;
const ELECTRON_PATH = require('electron'); // Require Electron from the binaries included in node_modules.
const PATH = require('path');
export default function setup(): void {
beforeEach(async function() {
this.app = new APPLICATION({
// Your electron path can be any binary
// i.e for OSX an example path could be '/Applications/MyApp.app/Contents/MacOS/MyApp'
// But for the sake of the example we fetch it from our node_modules.
path: ELECTRON_PATH,
// The following line tells spectron to look and use the main.js file
// and the package.json located in app folder.
args: [PATH.join(__dirname, '../app/main.js'), PATH.join(__dirname, '../app/package.json')],
webdriverOptions: {}
});
await this.app.start();
});
afterEach(async function() {
if (this.app && this.app.isRunning()) {
await this.app.stop();
}
});
}

View File

@@ -1,27 +0,0 @@
import { expect } from 'chai';
import { SpectronClient } from 'spectron';
import commonSetup from './common-setup';
describe('angular-electron App', function() {
commonSetup.apply(this);
let client: SpectronClient;
beforeEach(function() {
client = this.app.client;
});
it('creates initial windows', async function() {
const count = await client.getWindowCount();
expect(count).to.equal(1);
});
it('should display message saying App works !', async function() {
const elem = await client.$('app-home h1');
const text = await elem.getText();
expect(text).to.equal('App works !');
});
});

58
e2e/main.spec.ts Normal file
View File

@@ -0,0 +1,58 @@
import { BrowserContext, ElectronApplication, Page, _electron as electron } from 'playwright';
import { test, expect } from '@playwright/test';
const PATH = require('path');
test.describe('Check Home Page', async () => {
let app: ElectronApplication;
let firstWindow: Page;
let context: BrowserContext;
test.beforeAll( async () => {
app = await electron.launch({ args: [PATH.join(__dirname, '../app/main.js'), PATH.join(__dirname, '../app/package.json')] });
context = app.context();
await context.tracing.start({ screenshots: true, snapshots: true });
firstWindow = await app.firstWindow();
});
test('Launch electron app', async () => {
const windowState: { isVisible: boolean; isDevToolsOpened: boolean; isCrashed: boolean } = await app.evaluate(async (process) => {
const mainWindow = process.BrowserWindow.getAllWindows()[0];
const getState = () => ({
isVisible: mainWindow.isVisible(),
isDevToolsOpened: mainWindow.webContents.isDevToolsOpened(),
isCrashed: mainWindow.webContents.isCrashed(),
});
return new Promise((resolve) => {
if (mainWindow.isVisible()) {
resolve(getState());
} else {
mainWindow.once('ready-to-show', () => setTimeout(() => resolve(getState()), 0));
}
});
});
expect(windowState.isVisible).toBeTruthy();
expect(windowState.isDevToolsOpened).toBeFalsy();
expect(windowState.isCrashed).toBeFalsy();
});
test('Check Home Page design', async ({ browserName}) => {
// Uncomment if you change the design of Home Page in order to create a new screenshot
const screenshot = await firstWindow.screenshot({ path: '/tmp/home.png' });
expect(screenshot).toMatchSnapshot(`home-${browserName}.png`);
});
test('Check title', async () => {
const elem = await firstWindow.$('app-home h1');
const text = await elem.innerText();
expect(text).toBe('App works !');
});
test.afterAll( async () => {
await context.tracing.stop({ path: 'e2e/tracing/trace.zip' });
await app.close();
});
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 KiB

19
e2e/playwright.config.ts Normal file
View File

@@ -0,0 +1,19 @@
/** @type {import('@playwright/test').PlaywrightTestConfig} */
const config = {
testDir: '.',
timeout: 45000,
outputDir: './screenshots',
use: {
headless: false,
viewport: { width: 1280, height: 720 },
launchOptions: {
slowMo: 1000,
},
trace: 'on',
},
expect: {
toMatchSnapshot: { threshold: 0.2 },
},
};
module.exports = config;

View File

@@ -4,11 +4,10 @@
"outDir": "../out-tsc/e2e",
"module": "commonjs",
"types": [
"mocha",
"node"
]
},
"include": [
"**.ts"
]
"**.spec.ts"
],
}

2560
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -13,7 +13,7 @@
"electron",
"nodejs",
"typescript",
"spectron",
"playwright",
"eslint",
"sass",
"windows",
@@ -36,7 +36,8 @@
"electron:build": "npm run build:prod && electron-builder build --publish=never",
"test": "ng test --watch=false",
"test:watch": "ng test",
"e2e": "npm run build:prod && cross-env TS_NODE_PROJECT='e2e/tsconfig.e2e.json' mocha --timeout 300000 --require ts-node/register e2e/**/*.e2e.ts",
"e2e": "npm run build:prod && playwright test -c e2e/playwright.config.ts e2e/",
"e2e:show-trace": "playwright show-trace e2e/tracing/trace.zip",
"version": "conventional-changelog -i CHANGELOG.md -s -r 0 && git add CHANGELOG.md",
"lint": "ng lint"
},
@@ -49,7 +50,6 @@
"@angular/platform-browser": "12.1.2",
"@angular/platform-browser-dynamic": "12.1.2",
"@angular/router": "12.1.2",
"@electron/remote": "1.2.0",
"rxjs": "~6.6.0",
"tslib": "^2.1.0",
"zone.js": "~0.11.4"
@@ -66,17 +66,15 @@
"@angular/compiler-cli": "12.1.2",
"@ngx-translate/core": "13.0.0",
"@ngx-translate/http-loader": "6.0.0",
"@playwright/test": "1.16.3",
"@types/jasmine": "3.8.1",
"@types/jasminewd2": "2.0.10",
"@types/mocha": "8.2.3",
"@types/node": "16.3.3",
"@typescript-eslint/eslint-plugin": "4.28.3",
"@typescript-eslint/parser": "4.28.3",
"chai": "4.3.4",
"conventional-changelog-cli": "2.1.1",
"cross-env": "7.0.3",
"electron": "13.3.0",
"electron-builder": "22.11.9",
"electron": "15.3.1",
"electron-builder": "22.13.1",
"electron-reload": "1.5.0",
"eslint": "7.30.0",
"eslint-plugin-import": "2.23.4",
@@ -89,10 +87,9 @@
"karma-electron": "7.0.0",
"karma-jasmine": "4.0.1",
"karma-jasmine-html-reporter": "1.7.0",
"mocha": "9.0.2",
"nan": "2.14.2",
"npm-run-all": "4.1.5",
"spectron": "15.0.0",
"playwright": "1.16.3",
"ts-node": "10.1.0",
"typescript": "~4.2.0",
"wait-on": "5.0.1",

View File

@@ -3,7 +3,6 @@ import { Injectable } from '@angular/core';
// If you import a module but never use any of the imported values other than as TypeScript types,
// the resulting javascript file will look as if you never imported the module at all.
import { ipcRenderer, webFrame } from 'electron';
import * as remote from '@electron/remote';
import * as childProcess from 'child_process';
import * as fs from 'fs';
@@ -13,7 +12,6 @@ import * as fs from 'fs';
export class ElectronService {
ipcRenderer: typeof ipcRenderer;
webFrame: typeof webFrame;
remote: typeof remote;
childProcess: typeof childProcess;
fs: typeof fs;
@@ -30,10 +28,9 @@ export class ElectronService {
this.childProcess = window.require('child_process');
this.fs = window.require('fs');
// If you want to use a NodeJS 3rd party deps in Renderer process (like @electron/remote),
// it must be declared in dependencies of both package.json (in root and app folders)
// If you want to use remote object in renderer process, please set enableRemoteModule to true in main.ts
this.remote = window.require('@electron/remote');
// If you want to use a NodeJS 3rd party deps in Renderer process,
// ipcRenderer.invoke can serve many common use cases.
// https://www.electronjs.org/docs/latest/api/ipc-renderer#ipcrendererinvokechannel-args
}
}
}

View File

@@ -36,7 +36,6 @@ module.exports = function (config) {
nodeIntegration: true,
nodeIntegrationInSubFrames: true,
allowRunningInsecureContent: true,
enableRemoteModule: true,
contextIsolation: false
}
}

View File

@@ -1,2 +1 @@
import 'core-js/es/reflect';
import 'zone.js';