Skip to content

Commit

Permalink
Merge pull request #20 from theethernaut/remove-pty
Browse files Browse the repository at this point in the history
Remove pty
  • Loading branch information
eternauta1337 authored Apr 3, 2024
2 parents be5b01f + 3c51725 commit 21ffd3a
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 46 deletions.
1 change: 1 addition & 0 deletions .mocharc.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"timeout": 60000,
"require": ["test/setup.js"],
"recursive": true,
"bail": false,
"ignore": ["../../fixture-projects/**/*"],
"spec": ["../../**/*.test.js"]
}
13 changes: 11 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/ethernaut-common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
"devDependencies": {
"fs-extra": "^11.2.0",
"mocha": "^10.4.0",
"node-pty": "^1.0.0",
"nyc": "^15.1.0",
"tree-kill": "^1.2.2",
"nyc-report-lcov-absolute": "^1.0.0"
},
"gitHead": "5ffea95c7b8186e6365da19d189a79f09a78d475"
Expand Down
77 changes: 40 additions & 37 deletions packages/ethernaut-common/src/test/terminal.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
const pty = require('node-pty')
const os = require('os')
const debug = require('ethernaut-common/src/ui/debug')
const assert = require('assert')
const chalk = require('chalk')
const wait = require('ethernaut-common/src/util/wait')
const { spawn } = require('child_process')
const kill = require('tree-kill')

// eslint-disable-next-line no-control-regex
const ansiEscapeCodesPattern = /\x1B\[[0-?]*[ -/]*[@-~]/g
Expand All @@ -21,44 +21,51 @@ class Terminal {
constructor() {
this.history = ''
this.output = ''
this.shell = os.platform() === 'win32' ? 'powershell.exe' : 'bash'
}

async run(command, delay = 10000) {
if (this.running) {
throw new Error('Terminal is already running a command')
}
async run(command, delay = 10000, killAfter = false) {
this.output = ''

this.process = pty.spawn(this.shell, [], {
name: 'xterm-color',
cols: 80,
rows: 30,
cwd: process.cwd(),
env: process.env,
})
const args = command.split(' ')
args.concat(['&&', 'sleep', '1', '&&', 'exit'])
const f = 'npx'
debug.log(`Running command: ${f} ${args.join(' ')}`, 'terminal')
this.process = spawn(f, args, { shell: true, stdio: 'pipe' })

if (this.listener) {
this.listener.dispose()
}

this.listener = this.process.onData((data) => {
const txt = this.stripAnsi(data.toString())
const onData = (data) => {
const txt = data.toString().replace(ansiEscapeCodesPattern, '')
this.history += txt
this.output += txt
debug.log(`Terminal output: ${txt}`, 'terminal')
})

this.running = true
debug.log(`Running command: ${command}`, 'terminal')
}

const c = command.replace('hardhat', 'nyc hardhat')
this._write(`${c} && sleep 1 && exit\r`)
const onError = (data) => {
throw new Error(`Terminal error, ${data}`)
}

const completion = this._waitForCompletion()
const waitPromise = wait(delay)
await Promise.race([completion, waitPromise])
this.process.stdout.on('data', onData)
this.process.stderr.on('data', onData)
this.process.stderr.on('error', onError)

const completion = this._waitForCompletion().then(() => ({
type: 'completion',
}))
const waitPromise = wait(delay).then(() => ({ type: 'wait' }))
const result = await Promise.race([completion, waitPromise])
debug.log(`Terminal process ended with type: ${result.type}`, 'terminal')
if (result.type === 'wait') {
if (killAfter) this.kill()
}
}

this.running = false
kill() {
this.process.stdout.removeAllListeners('data')
this.process.stderr.removeAllListeners('data')
this.process.stderr.removeAllListeners('error')
kill(this.process.pid, 'SIGKILL', (err) => {
if (err) debug.log(`Unable to kill process: ${err}`, 'terminal')
else debug.log('Killed process', 'terminal')
})
}

async input(command, delay = 200) {
Expand All @@ -68,20 +75,16 @@ class Terminal {

_waitForCompletion() {
return new Promise((resolve) => {
this.process.onExit(() => {
debug.log('Command completed', 'terminal')
this.process.once('close', (code) => {
debug.log(`Command completed with code ${code}`, 'terminal')
resolve()
})
})
}

_write(content) {
this.output = ''
this.process.write(content)
}

stripAnsi(inputString) {
return inputString.replace(ansiEscapeCodesPattern, '')
this.process.stdin.write(content)
}

has(output) {
Expand Down
7 changes: 4 additions & 3 deletions packages/ethernaut-common/test/test/terminal.test.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
const { Terminal } = require('../../src/test/terminal')
const hardhat = require('hardhat')

describe('terminal', function () {
describe('when running a simple command', function () {
let terminal = new Terminal()

before('run command', async function () {
await terminal.run('echo "Hello World"', 1000)
await terminal.run('hardhat --version', 1000)
})

it('prints hello world', async function () {
terminal.has('Hello World')
it('shows hardhat version', async function () {
terminal.has(hardhat.version)
})
})
})
7 changes: 6 additions & 1 deletion packages/ethernaut-network/test/tasks/node.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ describe('node', function () {
describe('when parameters are provided', function () {
describe('with none', function () {
before('run', async function () {
await terminal.run('hardhat network node --fork none --port 8547', 2000)
await terminal.run(
'hardhat network node --fork none --port 8547',
2000,
true,
)
})

it('starts a local chain', async function () {
Expand Down Expand Up @@ -47,6 +51,7 @@ describe('node', function () {
await terminal.run(
'hardhat network node --fork test__mainnet --port 8547',
5000,
true,
)
})

Expand Down
4 changes: 2 additions & 2 deletions packages/ethernaut-ui/test/tasks/help.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ describe('help', function () {

describe('when entering the cli with no arguments', function () {
before('run hardhat', async function () {
await terminal.run('hardhat', 2500)
await terminal.run('hardhat', 2500, true)
})

it('displays the main prompt', async function () {
Expand All @@ -23,7 +23,7 @@ describe('help', function () {

describe('when entering the cli with just a scope', function () {
before('run hardhat', async function () {
await terminal.run('hardhat util', 2500)
await terminal.run('hardhat util', 2500, true)
})

it('displays the main prompt', async function () {
Expand Down

0 comments on commit 21ffd3a

Please sign in to comment.