test: add electron test (#1840)

This commit is contained in:
Himself65
2023-04-24 18:53:36 -05:00
committed by GitHub
parent 9c94d05dd8
commit d3ce90e721
18 changed files with 212 additions and 33 deletions

View File

@@ -17,16 +17,6 @@ jobs:
uses: ./.github/actions/setup-node uses: ./.github/actions/setup-node
- run: yarn lint --max-warnings=0 - run: yarn lint --max-warnings=0
install-all:
name: Install All Dependencies
runs-on: ubuntu-latest
environment: development
steps:
- uses: actions/checkout@v3
- name: Install All Dependencies
uses: ./.github/actions/setup-node
build-storybook: build-storybook:
name: Build Storybook name: Build Storybook
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -44,6 +34,23 @@ jobs:
path: ./packages/component/storybook-static path: ./packages/component/storybook-static
if-no-files-found: error if-no-files-found: error
build-electron:
name: Build @affine/electron
runs-on: ubuntu-latest
environment: development
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: ./.github/actions/setup-node
- name: Build Electron
working-directory: apps/electron
run: yarn exec ts-node-esm ./scripts/build-ci.mts
- name: Upload Ubuntu desktop artifact
uses: actions/upload-artifact@v3
with:
name: affine-ubuntu
path: ./apps/electron/dist
build: build:
name: Build @affine/web name: Build @affine/web
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -230,6 +237,48 @@ jobs:
path: ./test-results path: ./test-results
if-no-files-found: ignore if-no-files-found: ignore
dekstop-test:
name: Desktop Test
runs-on: ubuntu-latest
environment: development
needs: [build, build-electron]
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: ./.github/actions/setup-node
with:
playwright-install: true
- name: Download Ubuntu desktop artifact
uses: actions/download-artifact@v3
with:
name: affine-ubuntu
path: ./apps/electron/dist
- name: Download artifact
uses: actions/download-artifact@v3
with:
name: next-js
path: ./apps/web/.next
- name: Generate static files
run: yarn export
working-directory: ./apps/web
- name: Move static files to electron
run: mv ./apps/web/out ./apps/electron/resources/web-static
- name: Run desktop tests
run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- yarn test
working-directory: apps/electron
- name: Upload test results
if: ${{ failure() }}
uses: actions/upload-artifact@v2
with:
name: test-results-e2e-${{ matrix.shard }}
path: ./test-results
if-no-files-found: ignore
unit-test: unit-test:
name: Unit Test name: Unit Test
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@@ -134,7 +134,6 @@ We would like to express our gratitude to all the individuals who have already c
<img src="https://user-images.githubusercontent.com/5910926/233382206-312428ca-094a-4579-ae06-213961ed7eab.svg" /> <img src="https://user-images.githubusercontent.com/5910926/233382206-312428ca-094a-4579-ae06-213961ed7eab.svg" />
</a> </a>
## Self-Host ## Self-Host
Get started with Docker and deploy your own feature-rich, restriction-free deployment of AFFiNE - check the [latest packages]. Get started with Docker and deploy your own feature-rich, restriction-free deployment of AFFiNE - check the [latest packages].

View File

@@ -5,7 +5,8 @@ import { join } from 'path';
import { logger } from '../../logger'; import { logger } from '../../logger';
import { isMacOS } from '../../utils'; import { isMacOS } from '../../utils';
const IS_DEV = process.env.NODE_ENV === 'development'; const IS_DEV: boolean =
process.env.NODE_ENV === 'development' && !process.env.CI;
async function createWindow() { async function createWindow() {
logger.info('create window'); logger.info('create window');

View File

@@ -16,7 +16,8 @@
"make-windows-x64": "electron-forge make --platform=win32 --arch=x64", "make-windows-x64": "electron-forge make --platform=win32 --arch=x64",
"make-linux-x64": "electron-forge make --platform=linux --arch=x64", "make-linux-x64": "electron-forge make --platform=linux --arch=x64",
"rebuild:for-test": "yarn rebuild better-sqlite3", "rebuild:for-test": "yarn rebuild better-sqlite3",
"rebuild:for-electron": "yarn electron-rebuild" "rebuild:for-electron": "yarn electron-rebuild",
"test": "playwright test"
}, },
"config": { "config": {
"forge": "./forge.config.js" "forge": "./forge.config.js"
@@ -42,6 +43,8 @@
"electron-window-state": "^5.0.3", "electron-window-state": "^5.0.3",
"esbuild": "^0.17.18", "esbuild": "^0.17.18",
"fs-extra": "^11.1.1", "fs-extra": "^11.1.1",
"playwright": "^1.32.3",
"ts-node": "^10.9.1",
"undici": "^5.22.0", "undici": "^5.22.0",
"zx": "^7.2.1" "zx": "^7.2.1"
}, },
@@ -62,5 +65,9 @@
"stableVersion": "0.5.3", "stableVersion": "0.5.3",
"installConfig": { "installConfig": {
"hoistingLimits": "workspaces" "hoistingLimits": "workspaces"
},
"peerDependencies": {
"playwright": "*",
"ts-node": "*"
} }
} }

View File

@@ -0,0 +1,27 @@
import type { PlaywrightTestConfig } from '@playwright/test';
// import { devices } from '@playwright/test';
/**
* Read environment variables from file.
* https://github.com/motdotla/dotenv
*/
// require('dotenv').config();
/**
* See https://playwright.dev/docs/test-configuration.
*/
const config: PlaywrightTestConfig = {
testDir: './tests',
fullyParallel: true,
timeout: process.env.CI ? 50_000 : 30_000,
use: {
viewport: { width: 1440, height: 800 },
},
};
if (process.env.CI) {
config.retries = 3;
config.workers = '50%';
}
export default config;

View File

@@ -0,0 +1,17 @@
#!/usr/bin/env ts-node-esm
import * as esbuild from 'esbuild';
import { config } from './common.mjs';
const common = config();
await esbuild.build(common.preload);
await esbuild.build({
...common.main,
define: {
...common.main.define,
'process.env.NODE_ENV': `"production"`,
},
});
console.log('Compiled successfully.');

View File

@@ -1,4 +1,9 @@
const NODE_MAJOR_VERSION = 18; import { resolve } from 'node:path';
import { fileURLToPath } from 'url';
export const root = fileURLToPath(new URL('..', import.meta.url));
export const NODE_MAJOR_VERSION = 18;
const nativeNodeModulesPlugin = { const nativeNodeModulesPlugin = {
name: 'native-node-modules', name: 'native-node-modules',
@@ -14,7 +19,7 @@ const nativeNodeModulesPlugin = {
const ENV_MACROS = ['AFFINE_GOOGLE_CLIENT_ID', 'AFFINE_GOOGLE_CLIENT_SECRET']; const ENV_MACROS = ['AFFINE_GOOGLE_CLIENT_ID', 'AFFINE_GOOGLE_CLIENT_SECRET'];
/** @return {{main: import('esbuild').BuildOptions, preload: import('esbuild').BuildOptions}} */ /** @return {{main: import('esbuild').BuildOptions, preload: import('esbuild').BuildOptions}} */
export default () => { export const config = () => {
const define = Object.fromEntries( const define = Object.fromEntries(
ENV_MACROS.map(key => [ ENV_MACROS.map(key => [
'process.env.' + key, 'process.env.' + key,
@@ -23,8 +28,8 @@ export default () => {
); );
return { return {
main: { main: {
entryPoints: ['layers/main/src/index.ts'], entryPoints: [resolve(root, './layers/main/src/index.ts')],
outdir: 'dist/layers/main', outdir: resolve(root, './dist/layers/main'),
bundle: true, bundle: true,
target: `node${NODE_MAJOR_VERSION}`, target: `node${NODE_MAJOR_VERSION}`,
platform: 'node', platform: 'node',
@@ -33,8 +38,8 @@ export default () => {
define: define, define: define,
}, },
preload: { preload: {
entryPoints: ['layers/preload/src/index.ts'], entryPoints: [resolve(root, './layers/preload/src/index.ts')],
outdir: 'dist/layers/preload', outdir: resolve(root, './dist/layers/preload'),
bundle: true, bundle: true,
target: `node${NODE_MAJOR_VERSION}`, target: `node${NODE_MAJOR_VERSION}`,
platform: 'node', platform: 'node',

View File

@@ -1,15 +1,11 @@
import { spawn } from 'node:child_process'; import { spawn } from 'node:child_process';
import { readFileSync } from 'node:fs'; import { readFileSync } from 'node:fs';
import path from 'node:path'; import path from 'node:path';
import { fileURLToPath } from 'node:url';
import electronPath from 'electron'; import electronPath from 'electron';
import * as esbuild from 'esbuild'; import * as esbuild from 'esbuild';
import commonFn from './common.mjs'; import { config, root } from './common.mjs';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
/** @type 'production' | 'development'' */ /** @type 'production' | 'development'' */
const mode = (process.env.NODE_ENV = process.env.NODE_ENV || 'development'); const mode = (process.env.NODE_ENV = process.env.NODE_ENV || 'development');
@@ -22,9 +18,9 @@ const stderrFilterPatterns = [
/ExtensionLoadWarning/, /ExtensionLoadWarning/,
]; ];
// these are set before calling commonFn so we have a chance to override them // these are set before calling `config`, so we have a chance to override them
try { try {
const devJson = readFileSync(path.resolve(__dirname, '../dev.json'), 'utf-8'); const devJson = readFileSync(path.resolve(root, './dev.json'), 'utf-8');
const devEnv = JSON.parse(devJson); const devEnv = JSON.parse(devJson);
Object.assign(process.env, devEnv); Object.assign(process.env, devEnv);
} catch (err) { } catch (err) {
@@ -67,7 +63,7 @@ function spawnOrReloadElectron() {
spawnProcess.on('exit', process.exit); spawnProcess.on('exit', process.exit);
} }
const common = commonFn(); const common = config();
async function main() { async function main() {
async function watchPreload(onInitialBuild) { async function watchPreload(onInitialBuild) {

View File

@@ -5,7 +5,7 @@ import path from 'node:path';
import * as esbuild from 'esbuild'; import * as esbuild from 'esbuild';
import commonFn from './common.mjs'; import { config } from './common.mjs';
const repoRootDir = path.join(__dirname, '..', '..', '..'); const repoRootDir = path.join(__dirname, '..', '..', '..');
const electronRootDir = path.join(__dirname, '..'); const electronRootDir = path.join(__dirname, '..');
@@ -77,7 +77,7 @@ async function cleanup() {
} }
async function buildLayers() { async function buildLayers() {
const common = commonFn(); const common = config();
await esbuild.build(common.preload); await esbuild.build(common.preload);
await esbuild.build({ await esbuild.build({

View File

@@ -0,0 +1,22 @@
import { resolve } from 'node:path';
import { expect, test } from '@playwright/test';
import { _electron as electron } from 'playwright';
test('new page', async () => {
const electronApp = await electron.launch({
args: [resolve(__dirname, '..')],
executablePath: resolve(__dirname, '../node_modules/.bin/electron'),
});
const page = await electronApp.firstWindow();
await page.getByTestId('new-page-button').click({
delay: 100,
});
await page.waitForSelector('v-line');
const flavour = await page.evaluate(
// @ts-expect-error
() => globalThis.currentWorkspace.flavour
);
expect(flavour).toBe('local');
await electronApp.close();
});

View File

@@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"noEmit": true
},
"include": ["**.spec.ts", "**.test.ts"]
}

View File

@@ -0,0 +1,27 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"composite": true,
"target": "ESNext",
"module": "ESNext",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"moduleResolution": "bundler",
"isolatedModules": false,
"resolveJsonModule": true,
"types": ["node"],
"outDir": "dist",
"noEmit": false
},
"include": ["layers", "types", "package.json"],
"exclude": ["out", "dist", "node_modules"],
"references": [
{
"path": "./tsconfig.node.json"
}
],
"ts-node": {
"esm": true,
"experimentalSpecifierResolution": "node"
}
}

View File

@@ -0,0 +1,11 @@
{
"compilerOptions": {
"composite": true,
"target": "ESNext",
"module": "ESNext",
"resolveJsonModule": true,
"moduleResolution": "Node",
"allowSyntheticDefaultImports": true
},
"include": ["./scripts", "package.json"]
}

View File

@@ -37,7 +37,7 @@ export const ChangeLog = () => {
<StyledChangeLogWrapper isClose={isClose}> <StyledChangeLogWrapper isClose={isClose}>
<StyledChangeLog data-testid="change-log" isClose={isClose}> <StyledChangeLog data-testid="change-log" isClose={isClose}>
<StyledLink <StyledLink
href='https://github.com/toeverything/AFFiNE/releases' href="https://github.com/toeverything/AFFiNE/releases"
target="_blank" target="_blank"
> >
<NewIcon /> <NewIcon />

View File

@@ -1,4 +1,3 @@
import { config } from '@affine/env'; import { config } from '@affine/env';
import { useTranslation } from '@affine/i18n'; import { useTranslation } from '@affine/i18n';
import { WorkspaceFlavour } from '@affine/workspace/type'; import { WorkspaceFlavour } from '@affine/workspace/type';

View File

@@ -37,6 +37,9 @@
{ {
"path": "./tests" "path": "./tests"
}, },
{
"path": "./apps/electron/tests"
},
{ {
"path": "./apps/web" "path": "./apps/web"
}, },
@@ -66,6 +69,9 @@
}, },
{ {
"path": "./tsconfig.node.json" "path": "./tsconfig.node.json"
},
{
"path": "./apps/electron"
} }
], ],
"files": [], "files": [],

View File

@@ -27,10 +27,10 @@ export default defineConfig({
'packages/**/*.spec.tsx', 'packages/**/*.spec.tsx',
'apps/web/**/*.spec.ts', 'apps/web/**/*.spec.ts',
'apps/web/**/*.spec.tsx', 'apps/web/**/*.spec.tsx',
'apps/electron/**/*.spec.ts',
'tests/unit/**/*.spec.ts', 'tests/unit/**/*.spec.ts',
'tests/unit/**/*.spec.tsx', 'tests/unit/**/*.spec.tsx',
], ],
exclude: ['**/node_modules', '**/dist', '**/build', '**/out'],
testTimeout: 5000, testTimeout: 5000,
coverage: { coverage: {
provider: 'istanbul', // or 'c8' provider: 'istanbul', // or 'c8'

View File

@@ -132,9 +132,14 @@ __metadata:
electron-window-state: ^5.0.3 electron-window-state: ^5.0.3
esbuild: ^0.17.18 esbuild: ^0.17.18
fs-extra: ^11.1.1 fs-extra: ^11.1.1
playwright: ^1.32.3
ts-node: ^10.9.1
undici: ^5.22.0 undici: ^5.22.0
yjs: ^13.6.0 yjs: ^13.6.0
zx: ^7.2.1 zx: ^7.2.1
peerDependencies:
playwright: "*"
ts-node: "*"
languageName: unknown languageName: unknown
linkType: soft linkType: soft
@@ -18914,7 +18919,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"playwright@npm:^1.14.0": "playwright@npm:^1.14.0, playwright@npm:^1.32.3":
version: 1.32.3 version: 1.32.3
resolution: "playwright@npm:1.32.3" resolution: "playwright@npm:1.32.3"
dependencies: dependencies: