Initial attempt for e2e tests
- Add node code for e2e tests. This is a first take to try running these tests via actions. - Relates to #401
This commit is contained in:
2
e2e/spring-shell-e2e/.gitignore
vendored
Normal file
2
e2e/spring-shell-e2e/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
lib
|
||||
11
e2e/spring-shell-e2e/.prettierrc.json
Normal file
11
e2e/spring-shell-e2e/.prettierrc.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"printWidth": 120,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"bracketSpacing": true,
|
||||
"arrowParens": "avoid",
|
||||
"parser": "typescript"
|
||||
}
|
||||
38
e2e/spring-shell-e2e/package-lock.json
generated
Normal file
38
e2e/spring-shell-e2e/package-lock.json
generated
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "spring-shell-e2e",
|
||||
"version": "2.1.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"nan": {
|
||||
"version": "2.15.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz",
|
||||
"integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ=="
|
||||
},
|
||||
"node-pty": {
|
||||
"version": "0.10.1",
|
||||
"resolved": "https://registry.npmjs.org/node-pty/-/node-pty-0.10.1.tgz",
|
||||
"integrity": "sha512-JTdtUS0Im/yRsWJSx7yiW9rtpfmxqxolrtnyKwPLI+6XqTAPW/O2MjS8FYL4I5TsMbH2lVgDb2VMjp+9LoQGNg==",
|
||||
"requires": {
|
||||
"nan": "^2.14.0"
|
||||
}
|
||||
},
|
||||
"prettier": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz",
|
||||
"integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==",
|
||||
"dev": true
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.6.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz",
|
||||
"integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==",
|
||||
"dev": true
|
||||
},
|
||||
"xterm-headless": {
|
||||
"version": "4.18.0",
|
||||
"resolved": "https://registry.npmjs.org/xterm-headless/-/xterm-headless-4.18.0.tgz",
|
||||
"integrity": "sha512-VwSPG2cyVOwesVVLBVrybYNY6cUMiVkD2fLnIXcBs/1iJ3M7bhD3lP9HdQOHGtOkbxV2Duf7MZNmEfngBXL/iQ=="
|
||||
}
|
||||
}
|
||||
}
|
||||
41
e2e/spring-shell-e2e/package.json
Normal file
41
e2e/spring-shell-e2e/package.json
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "spring-shell-e2e",
|
||||
"version": "2.1.0",
|
||||
"description": "spring-shell e2e test framework",
|
||||
"main": "./lib/cli.js",
|
||||
"exports": {
|
||||
".": "./lib/cli.js"
|
||||
},
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"cli.d.ts": [
|
||||
"lib/cli.d.ts"
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "jest",
|
||||
"format": "prettier --write **/*.ts",
|
||||
"format-check": "prettier --check **/*.ts"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/spring-projects/spring-shell.git"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/spring-projects/spring-shell/issues"
|
||||
},
|
||||
"homepage": "https://github.com/spring-projects/spring-shell#readme",
|
||||
"devDependencies": {
|
||||
"prettier": "^2.6.2",
|
||||
"typescript": "^4.6.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"node-pty": "^0.10.1",
|
||||
"xterm-headless": "^4.18.0"
|
||||
}
|
||||
}
|
||||
128
e2e/spring-shell-e2e/src/cli.ts
Normal file
128
e2e/spring-shell-e2e/src/cli.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
import * as pty from 'node-pty';
|
||||
import { Terminal } from 'xterm-headless';
|
||||
|
||||
export interface CliOptions {
|
||||
command: string;
|
||||
options?: string[];
|
||||
keyWait?: number;
|
||||
cols?: number;
|
||||
rows?: number;
|
||||
}
|
||||
|
||||
export class Cli {
|
||||
private isDisposed: boolean = false;
|
||||
private pty: pty.IPty | undefined;
|
||||
private term: Terminal | undefined;
|
||||
private keyWait: number = 500;
|
||||
private cols: number = 80;
|
||||
private rows: number = 20;
|
||||
private exit: Promise<number> | undefined;
|
||||
|
||||
constructor(private options: CliOptions) {
|
||||
if (options.keyWait) {
|
||||
this.keyWait = options.keyWait;
|
||||
}
|
||||
if (options.cols) {
|
||||
this.cols = options.cols;
|
||||
}
|
||||
if (options.rows) {
|
||||
this.rows = options.rows;
|
||||
}
|
||||
}
|
||||
|
||||
public run(): void {
|
||||
this.pty = pty.spawn(this.options.command, this.options.options || [], {
|
||||
name: 'xterm-256color',
|
||||
cols: this.cols,
|
||||
rows: this.rows
|
||||
});
|
||||
this.term = new Terminal({
|
||||
cols: this.cols,
|
||||
rows: this.rows
|
||||
});
|
||||
this.pty.onData(data => {
|
||||
this.term?.write(data);
|
||||
});
|
||||
this.exit = new Promise(resolve => {
|
||||
this.pty?.onExit(data => {
|
||||
resolve(data.exitCode);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public exitCode(): Promise<number> {
|
||||
if (!this.exit) {
|
||||
return Promise.reject('cli has not been started');
|
||||
}
|
||||
return this.exit;
|
||||
}
|
||||
|
||||
public screen(): string[] {
|
||||
const l = this.term?.buffer.active.length || 0;
|
||||
const ret: string[] = [];
|
||||
for (let index = 0; index < l; index++) {
|
||||
const line = this.term?.buffer.active.getLine(index)?.translateToString();
|
||||
if (line) {
|
||||
ret.push(line);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public async keyText(data: string, wait: number): Promise<Cli> {
|
||||
if (!this.pty) {
|
||||
return Promise.reject('cli has not been started');
|
||||
}
|
||||
this.pty.write(data);
|
||||
await this.doWait(wait);
|
||||
return this;
|
||||
}
|
||||
|
||||
public async keyUp(wait?: number): Promise<Cli> {
|
||||
if (!this.pty) {
|
||||
return Promise.reject('cli has not been started');
|
||||
}
|
||||
this.pty.write('\x1BOA');
|
||||
await this.doWait(wait);
|
||||
return this;
|
||||
}
|
||||
|
||||
public async keyDown(wait?: number): Promise<Cli> {
|
||||
if (!this.pty) {
|
||||
return Promise.reject('cli has not been started');
|
||||
}
|
||||
this.pty.write('\x1BOB');
|
||||
await this.doWait(wait);
|
||||
return this;
|
||||
}
|
||||
|
||||
public async keyEnter(wait?: number): Promise<Cli> {
|
||||
if (!this.pty) {
|
||||
return Promise.reject('cli has not been started');
|
||||
}
|
||||
this.pty.write('\x0D');
|
||||
await this.doWait(wait);
|
||||
return this;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
if (this.isDisposed) {
|
||||
return;
|
||||
}
|
||||
if (this.pty) {
|
||||
this.pty.kill();
|
||||
}
|
||||
if (this.term) {
|
||||
this.term.dispose();
|
||||
}
|
||||
this.isDisposed = true;
|
||||
}
|
||||
|
||||
private async doWait(wait?: number): Promise<void> {
|
||||
await this.sleep(wait || this.keyWait);
|
||||
}
|
||||
|
||||
private async sleep(ms: number): Promise<void> {
|
||||
return new Promise(r => setTimeout(r, ms));
|
||||
}
|
||||
}
|
||||
13
e2e/spring-shell-e2e/tsconfig.json
Normal file
13
e2e/spring-shell-e2e/tsconfig.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
||||
"module": "commonjs", /* Specify what module code is generated. */
|
||||
"moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||
"declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
||||
"outDir": "./lib", /* Specify an output folder for all emitted files. */
|
||||
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
|
||||
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user