test: optimize command (#3030)
* test: optimize command * chore: add force options * chore: kill child process
This commit is contained in:
parent
4d4b73767f
commit
887ddf0ed1
@ -12,11 +12,13 @@ VERDACCIO_PORT=10104
|
|||||||
# !!! It is recommended to use nginx to proxy static files. For example https://github.com/nocobase/nocobase/blob/main/docker/nocobase/nocobase.conf
|
# !!! It is recommended to use nginx to proxy static files. For example https://github.com/nocobase/nocobase/blob/main/docker/nocobase/nocobase.conf
|
||||||
APP_ENV=development
|
APP_ENV=development
|
||||||
APP_PORT=20000
|
APP_PORT=20000
|
||||||
APP_BASE_URL=http://localhost:20000
|
|
||||||
APP_KEY=test-key-e2e
|
APP_KEY=test-key-e2e
|
||||||
SOCKET_PATH=storage/gateway-e2e.sock
|
SOCKET_PATH=storage/gateway-e2e.sock
|
||||||
__E2E__=true
|
__E2E__=true
|
||||||
|
|
||||||
|
# 指定运行测试的服务地址;当 APP_BASE_URL 不为空时,将不会在本地启动测试服务
|
||||||
|
# APP_BASE_URL=http://localhost:20000
|
||||||
|
|
||||||
# 启用 mock-collections 插件
|
# 启用 mock-collections 插件
|
||||||
APPEND_PRESET_BUILT_IN_PLUGINS=mock-collections
|
APPEND_PRESET_BUILT_IN_PLUGINS=mock-collections
|
||||||
|
|
||||||
|
@ -114,6 +114,9 @@ interface CreatePageOptions {
|
|||||||
pageSchema?: any;
|
pageSchema?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PORT = process.env.APP_PORT || 20000;
|
||||||
|
const APP_BASE_URL = process.env.APP_BASE_URL || `http://localhost:${PORT}`;
|
||||||
|
|
||||||
class NocoPage {
|
class NocoPage {
|
||||||
private url: string;
|
private url: string;
|
||||||
private uid: string;
|
private uid: string;
|
||||||
@ -213,7 +216,7 @@ export const test = Object.assign(_test, {
|
|||||||
|
|
||||||
const getStorageItem = (key: string, storageState: any) => {
|
const getStorageItem = (key: string, storageState: any) => {
|
||||||
return storageState.origins
|
return storageState.origins
|
||||||
.find((item) => item.origin === process.env.APP_BASE_URL)
|
.find((item) => item.origin === APP_BASE_URL)
|
||||||
?.localStorage.find((item) => item.name === key)?.value;
|
?.localStorage.find((item) => item.name === key)?.value;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -470,8 +473,8 @@ function getHeaders(storageState: any) {
|
|||||||
const headers: any = {};
|
const headers: any = {};
|
||||||
const token = getStorageItem('NOCOBASE_TOKEN', storageState);
|
const token = getStorageItem('NOCOBASE_TOKEN', storageState);
|
||||||
const auth = getStorageItem('NOCOBASE_AUTH', storageState);
|
const auth = getStorageItem('NOCOBASE_AUTH', storageState);
|
||||||
const subAppName = new URL(process.env.APP_BASE_URL).pathname.match(/^\/apps\/([^/]*)\/*/)?.[1];
|
const subAppName = new URL(APP_BASE_URL).pathname.match(/^\/apps\/([^/]*)\/*/)?.[1];
|
||||||
const hostName = new URL(process.env.APP_BASE_URL).host;
|
const hostName = new URL(APP_BASE_URL).host;
|
||||||
const locale = getStorageItem('NOCOBASE_LOCALE', storageState);
|
const locale = getStorageItem('NOCOBASE_LOCALE', storageState);
|
||||||
const timezone = '+08:00';
|
const timezone = '+08:00';
|
||||||
const withAclMeta = 'true';
|
const withAclMeta = 'true';
|
||||||
|
@ -28,7 +28,7 @@ export default defineConfig({
|
|||||||
|
|
||||||
use: {
|
use: {
|
||||||
// Base URL to use in actions like `await page.goto('/')`.
|
// Base URL to use in actions like `await page.goto('/')`.
|
||||||
baseURL: process.env.APP_BASE_URL,
|
baseURL: process.env.APP_BASE_URL || `http://localhost:${process.env.APP_PORT || 20000}`,
|
||||||
|
|
||||||
// Collect trace when retrying the failed test.
|
// Collect trace when retrying the failed test.
|
||||||
trace: 'on-first-retry',
|
trace: 'on-first-retry',
|
||||||
|
@ -5,9 +5,7 @@ import path from 'path';
|
|||||||
const adminFile = 'playwright/.auth/admin.json';
|
const adminFile = 'playwright/.auth/admin.json';
|
||||||
|
|
||||||
// 加载变量
|
// 加载变量
|
||||||
if (!process.env.APP_BASE_URL) {
|
dotenv.config({ path: path.resolve(process.cwd(), '.env.e2e') });
|
||||||
dotenv.config({ path: path.resolve(process.cwd(), '.env.e2e') });
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保存登录状态,避免每次都要登录
|
// 保存登录状态,避免每次都要登录
|
||||||
setup('admin', async ({ page }) => {
|
setup('admin', async ({ page }) => {
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
import { execSync } from 'node:child_process';
|
import { execSync } from 'node:child_process';
|
||||||
import { commonConfig, runNocoBase } from './utils';
|
import { APP_BASE_URL, commonConfig, runNocoBase } from './utils';
|
||||||
|
|
||||||
const runCodegenSync = () => {
|
const runCodegenSync = () => {
|
||||||
try {
|
try {
|
||||||
execSync(
|
execSync(
|
||||||
`npx playwright codegen --load-storage=playwright/.auth/codegen.auth.json ${process.env.APP_BASE_URL} --save-storage=playwright/.auth/codegen.auth.json`,
|
`npx playwright codegen --load-storage=playwright/.auth/codegen.auth.json ${APP_BASE_URL} --save-storage=playwright/.auth/codegen.auth.json`,
|
||||||
commonConfig,
|
commonConfig,
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.message.includes('auth.json')) {
|
if (err.message.includes('auth.json')) {
|
||||||
execSync(
|
execSync(
|
||||||
`npx playwright codegen ${process.env.APP_BASE_URL} --save-storage=playwright/.auth/codegen.auth.json`,
|
`npx playwright codegen ${APP_BASE_URL} --save-storage=playwright/.auth/codegen.auth.json`,
|
||||||
commonConfig,
|
commonConfig,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
import { runNocoBase } from './utils';
|
import { runNocoBase } from './utils';
|
||||||
|
|
||||||
runNocoBase();
|
runNocoBase({
|
||||||
|
force: true,
|
||||||
|
});
|
||||||
|
@ -1,15 +1,23 @@
|
|||||||
import { runCommand, runNocoBase } from './utils';
|
import { runCommand, runNocoBase } from './utils';
|
||||||
|
|
||||||
|
const abortController = new AbortController();
|
||||||
|
|
||||||
|
process.on('SIGINT', () => {
|
||||||
|
abortController.abort();
|
||||||
|
process.exit();
|
||||||
|
});
|
||||||
|
|
||||||
const run = async () => {
|
const run = async () => {
|
||||||
const { kill, awaitForNocoBase } = await runNocoBase({
|
const { awaitForNocoBase } = await runNocoBase({
|
||||||
stdio: 'ignore', // 不输出服务的日志,避免干扰测试的日志
|
stdio: 'ignore', // 不输出服务的日志,避免干扰测试的日志
|
||||||
|
signal: abortController.signal,
|
||||||
});
|
});
|
||||||
|
|
||||||
await awaitForNocoBase();
|
await awaitForNocoBase();
|
||||||
|
|
||||||
console.log('Start running tests...');
|
console.log('Start running tests...');
|
||||||
await runCommand('npx', ['playwright', 'test', ...process.argv.slice(2)]);
|
await runCommand('npx', ['playwright', 'test', ...process.argv.slice(2)]);
|
||||||
kill?.('SIGKILL');
|
abortController.abort();
|
||||||
};
|
};
|
||||||
|
|
||||||
run();
|
run();
|
||||||
|
@ -2,19 +2,23 @@ import axios from 'axios';
|
|||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
import type { CommonOptions } from 'execa';
|
import type { CommonOptions } from 'execa';
|
||||||
import execa from 'execa';
|
import execa from 'execa';
|
||||||
|
import _ from 'lodash';
|
||||||
import net from 'net';
|
import net from 'net';
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
|
const PORT = process.env.APP_PORT || 20000;
|
||||||
|
export const APP_BASE_URL = process.env.APP_BASE_URL || `http://localhost:${PORT}`;
|
||||||
|
|
||||||
export const commonConfig: any = {
|
export const commonConfig: any = {
|
||||||
stdio: 'inherit',
|
stdio: 'inherit',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const runCommand = (command, argv, options = {}) => {
|
export const runCommand = (command, argv, options: any = {}) => {
|
||||||
return execa(command, argv, {
|
return execa(command, argv, {
|
||||||
shell: true,
|
shell: true,
|
||||||
stdio: 'inherit',
|
stdio: 'inherit',
|
||||||
...options,
|
..._.omit(options, 'force'),
|
||||||
env: {
|
env: {
|
||||||
...process.env,
|
...process.env,
|
||||||
},
|
},
|
||||||
@ -53,12 +57,12 @@ const checkServer = async (duration = 1000, max = 60 * 10) => {
|
|||||||
return reject(new Error('Server start timeout.'));
|
return reject(new Error('Server start timeout.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(await checkPort(process.env.APP_PORT))) {
|
if (!(await checkPort(PORT))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
axios
|
axios
|
||||||
.get(`${process.env.APP_BASE_URL}/api/__health_check`)
|
.get(`${APP_BASE_URL}/api/__health_check`)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
clearInterval(timer);
|
clearInterval(timer);
|
||||||
@ -86,7 +90,7 @@ const checkUI = async (duration = 1000, max = 60 * 10) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
axios
|
axios
|
||||||
.get(`${process.env.APP_BASE_URL}/__umi/api/bundle-status`)
|
.get(`${APP_BASE_URL}/__umi/api/bundle-status`)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response.data.bundleStatus.done) {
|
if (response.data.bundleStatus.done) {
|
||||||
clearInterval(timer);
|
clearInterval(timer);
|
||||||
@ -100,7 +104,15 @@ const checkUI = async (duration = 1000, max = 60 * 10) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const runNocoBase = async (options?: CommonOptions<any>) => {
|
export const runNocoBase = async (
|
||||||
|
options?: CommonOptions<any> & {
|
||||||
|
/**
|
||||||
|
* 是否强制启动服务
|
||||||
|
*/
|
||||||
|
force?: boolean;
|
||||||
|
signal?: AbortSignal;
|
||||||
|
},
|
||||||
|
) => {
|
||||||
// 用于存放 playwright 自动生成的相关的文件
|
// 用于存放 playwright 自动生成的相关的文件
|
||||||
if (!fs.existsSync('playwright')) {
|
if (!fs.existsSync('playwright')) {
|
||||||
fs.mkdirSync('playwright');
|
fs.mkdirSync('playwright');
|
||||||
@ -117,6 +129,11 @@ export const runNocoBase = async (options?: CommonOptions<any>) => {
|
|||||||
|
|
||||||
dotenv.config({ path: path.resolve(process.cwd(), '.env.e2e') });
|
dotenv.config({ path: path.resolve(process.cwd(), '.env.e2e') });
|
||||||
|
|
||||||
|
if (process.env.APP_BASE_URL && !options?.force) {
|
||||||
|
console.log('APP_BASE_URL is setting, skip starting server.');
|
||||||
|
return { awaitForNocoBase: () => {} };
|
||||||
|
}
|
||||||
|
|
||||||
const awaitForNocoBase = async () => {
|
const awaitForNocoBase = async () => {
|
||||||
if (process.env.CI) {
|
if (process.env.CI) {
|
||||||
console.log('check server...');
|
console.log('check server...');
|
||||||
@ -133,28 +150,22 @@ export const runNocoBase = async (options?: CommonOptions<any>) => {
|
|||||||
if (process.env.CI) {
|
if (process.env.CI) {
|
||||||
console.log('yarn nocobase install');
|
console.log('yarn nocobase install');
|
||||||
await runCommand('yarn', ['nocobase', 'install'], options);
|
await runCommand('yarn', ['nocobase', 'install'], options);
|
||||||
console.log(`yarn start -d -p ${process.env.APP_PORT}`);
|
console.log(`yarn start -d -p ${PORT}`);
|
||||||
await runCommand('yarn', ['start', '-d', `-p ${process.env.APP_PORT}`], options);
|
await runCommand('yarn', ['start', '-d', `-p ${PORT}`], options);
|
||||||
return { awaitForNocoBase };
|
return { awaitForNocoBase };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!process.env.APP_BASE_URL.includes('localhost')) {
|
|
||||||
return {
|
|
||||||
awaitForNocoBase: async () => {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 加上 -f 会清空数据库
|
// 加上 -f 会清空数据库
|
||||||
console.log('yarn nocobase install -f');
|
console.log('yarn nocobase install -f');
|
||||||
await runCommand('yarn', ['nocobase', 'install', '-f'], options);
|
await runCommand('yarn', ['nocobase', 'install', '-f'], options);
|
||||||
|
|
||||||
if (await checkPort(process.env.APP_PORT)) {
|
if (await checkPort(PORT)) {
|
||||||
console.log('Server is running, skip starting server.');
|
console.log('Server is running, skip starting server.');
|
||||||
return { awaitForNocoBase };
|
return { awaitForNocoBase };
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('starting server...');
|
console.log('starting server...');
|
||||||
const { cancel, kill } = runCommand('yarn', ['dev', `-p ${process.env.APP_PORT}`, ...process.argv.slice(2)], options);
|
const { cancel, kill } = runCommand('yarn', ['dev', `-p ${PORT}`, ...process.argv.slice(2)], options);
|
||||||
|
|
||||||
return { cancel, kill, awaitForNocoBase };
|
return { cancel, kill, awaitForNocoBase };
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user