-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This PR aims to add tests and linting for #3 as well as GitHub CI. To summarize, the commits add: - Mocha tests, similar to the "integration" tests at n_. One test is skipped because it fails on a possible bug. I'm happy to delete that test, or to try to find a fix for it on this or another PR. - a GitHub workflow CI similar to the one from shelljs-plugin-inspect. I used this to help me see where tests were passing/failing on Windows and Mac since I use Linux, and to check that applying linting didn't break stuff. Experiments with this CI workflow showed me that the tests work on NodeJS 10 through 14 but fail on NodeJS versions >=15 for Mac, Windows, and Linux with an error message related to `repl.history` in #6. I'm happy to delete/modify this commit though if you don't want it. - linting styles (copied over from the test folder at ShellJS). - The new linting applied to index.js. As always, I'm happy to make any changes. It's been fun learning about REPLs. Thank you for the opportunity to learn more about a really cool project!
- Loading branch information
1 parent
0f2ad2b
commit 24adc87
Showing
6 changed files
with
250 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node_modules/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
{ | ||
"env": { | ||
"node": true | ||
}, | ||
"extends": "airbnb-base", | ||
"rules": { | ||
"arrow-parens": "off", | ||
"comma-dangle": "off", | ||
"curly": "off", | ||
"global-require": "off", | ||
"import/no-dynamic-require": "off", | ||
"import/no-mutable-exports": "off", | ||
"indent": "off", | ||
"max-len": "off", | ||
"no-bitwise": "off", | ||
"no-console": "off", | ||
"no-param-reassign": "off", | ||
"no-plusplus": "off", | ||
"no-underscore-dangle": "off", | ||
"no-var": "error", | ||
"operator-linebreak": "off", | ||
"prefer-arrow-callback": "off", | ||
"prefer-const": "error", | ||
"prefer-destructuring": "off", | ||
"prefer-numeric-literals": "off", | ||
"prefer-template": "off", | ||
"spaced-comment": ["error", "always", { "markers": ["@", "@include"], "exceptions": ["@"] }], | ||
"vars-on-top": "off", | ||
"new-cap": ["error", { | ||
"capIsNewExceptions": [ | ||
"ShellString" | ||
]} | ||
] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
name: CI | ||
on: | ||
- push | ||
- pull_request | ||
jobs: | ||
test: | ||
name: Node.js ${{ matrix.node-version }} on ${{ matrix.os }} | ||
runs-on: ${{ matrix.os }} | ||
strategy: | ||
fail-fast: false | ||
matrix: | ||
node-version: | ||
- 10 | ||
- 12 | ||
- 14 | ||
os: | ||
- ubuntu-latest | ||
- macos-latest | ||
- windows-latest | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- uses: actions/setup-node@v2 | ||
with: | ||
node-version: ${{ matrix.node-version }} | ||
- run: npm install | ||
- run: npm run test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
/* eslint-env mocha */ | ||
const fs = require('fs'); | ||
const { spawn } = require('child_process'); | ||
const assert = require('assert'); | ||
|
||
// Set up variables for testing. | ||
const workDir = process.cwd(); | ||
const nodeEntry = `${workDir}/index.js`; | ||
const temporaryFile = 'test/tempFile.txt'; | ||
const testString = 'First line^^^^hip\nSecond line>>>>hip\nthird~~~hurray!\nLine number four.'; | ||
|
||
const runREPL = (child, commands) => new Promise((resolve) => { | ||
// Set up output and errors from stdin and stdout. | ||
const output = []; | ||
const err = []; | ||
child.stdout.on('data', (data) => output.push(data.toString())); | ||
child.stderr.on('data', (data) => err.push(data.toString())); | ||
|
||
// Run input commands and end. | ||
child.stdin.setEncoding('utf-8'); | ||
commands.forEach(c => child.stdin.write(`${c}\n`)); | ||
child.stdin.end(); | ||
|
||
// Exit. | ||
child.on('exit', (code) => resolve({ code, err, output })); | ||
}); | ||
|
||
before(() => { | ||
try { | ||
fs.writeFileSync(temporaryFile, testString); | ||
} catch (error) { | ||
throw new Error(`Unable to write temporary file ${temporaryFile} for tests.`); | ||
} | ||
}); | ||
|
||
after(() => { | ||
try { | ||
fs.unlinkSync(temporaryFile); | ||
} catch (error) { | ||
throw new Error(`Unable to delete file ${temporaryFile} after tests.`); | ||
} | ||
}); | ||
|
||
describe('running commands inside REPL', () => { | ||
it('executes non-ShellJS commands', async () => { | ||
const inputCommands = [ | ||
'function add(a, b) {', | ||
'return a + b;', | ||
'}', | ||
'add(2179242.724, 3198234.878)' | ||
]; | ||
|
||
const nShell = spawn('node', [nodeEntry]); | ||
const { output, code } = await runREPL(nShell, inputCommands); | ||
assert.equal(code, 0); | ||
assert.equal(output.join().includes('5377477.602'), true); | ||
}); | ||
|
||
it('executes ShellJS commands', async () => { | ||
const inputCommands = [ | ||
'pwd()', | ||
`cat('${temporaryFile}')` | ||
]; | ||
|
||
const nShell = spawn('node', [nodeEntry]); | ||
const { code, output } = await runREPL(nShell, inputCommands); | ||
const result = output.join(); | ||
assert.equal(code, 0); | ||
assert.equal(result.includes(workDir), true); | ||
assert.equal(result.includes(testString), true); | ||
}); | ||
|
||
it('lets the user pick a prompt to run in the REPL', async () => { | ||
const myPrompt = 'a-w-e-s-o-m-e-s-h-e-l-l-->'; | ||
const nShell = spawn('node', [nodeEntry, `--prompt=${myPrompt}`]); | ||
const { code, output } = await runREPL(nShell, ['\n']); | ||
const result = output.join(); | ||
assert.equal(code, 0); | ||
assert.equal(result.includes(myPrompt), true); | ||
}); | ||
}); | ||
|
||
describe('running REPL commands in strict mode', () => { | ||
const inputCommands = ['var undefined = 3;']; | ||
const strictModeErrMsg = 'Cannot assign to read only property \'undefined\''; | ||
|
||
it('does not enforce strict mode by default', async () => { | ||
const nShell = spawn('node', [nodeEntry]); | ||
const { code, output } = await runREPL(nShell, inputCommands); | ||
const result = output.join(); | ||
assert.equal(code, 0); | ||
assert.equal(result.includes(strictModeErrMsg), false); | ||
}); | ||
|
||
it('allows strict mode as an option', async () => { | ||
const nShell = spawn('node', [nodeEntry, '--use_strict']); | ||
const { code, output } = await runREPL(nShell, inputCommands); | ||
const result = output.join(); | ||
assert.equal(code, 0); | ||
assert.equal(result.includes(strictModeErrMsg), true); | ||
}); | ||
}); | ||
|
||
describe('respecting namespaces', () => { | ||
it('says global commands are undefined in local namespace', async () => { | ||
const nShell = spawn('node', [nodeEntry, '--no_global']); | ||
const { code, output } = await runREPL(nShell, ['ls()', 'pwd()']); | ||
assert.equal(code, 0); | ||
const result = output.join(); | ||
assert.equal(result.includes('ls is not defined'), true); | ||
assert.equal(result.includes('pwd is not defined'), true); | ||
}); | ||
|
||
it('runs a command in local shell namespace', async () => { | ||
const inputCommands = [`shell.grep('hurray', '${temporaryFile}')`]; | ||
const nShell = spawn('node', [nodeEntry, '--no_global']); | ||
const { code, output } = await runREPL(nShell, inputCommands); | ||
assert.equal(code, 0); | ||
const result = output.join(); | ||
assert.equal(result.includes('third~~~hurray'), true); | ||
}); | ||
|
||
it('runs a command in local user-defined namespace', async () => { | ||
const inputCommands = [`$.grep('hurray', '${temporaryFile}')`]; | ||
const nShell = spawn('node', [nodeEntry, '--no_global=$']); | ||
const { code, output } = await runREPL(nShell, inputCommands); | ||
assert.equal(code, 0); | ||
const result = output.join(); | ||
assert.equal(result.includes('third~~~hurray'), true); | ||
}); | ||
|
||
it.skip('does not allow overwriting namespace', async () => { | ||
const inputCommands = [ | ||
'shell = "fish"', | ||
`shell.grep('hurray', '${temporaryFile}')` | ||
]; | ||
|
||
const nShell = spawn('node', [nodeEntry, '--no_global']); | ||
const { code, output } = await runREPL(nShell, inputCommands); | ||
assert.equal(code, 0); | ||
const result = output.join(); | ||
assert.equal(result.includes('third~~~hurray'), true); | ||
}); | ||
}); |