Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add timeout option to prompt (Close #37) #38

Merged
merged 7 commits into from
Oct 7, 2020
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ Available options:
| replace | Replace each character with the specified string when `silent` is true | string | '' |
| input | Input stream to read from | [Stream](https://nodejs.org/api/process.html#process_process_stdin) | process.stdin |
| output | Output stream to write to | [Stream](https://nodejs.org/api/process.html#process_process_stdout) | process.stdout |
| timeout | Timeout in ms | number | 0 |
| useDefaultOnTimeout | Return default value if timed out | boolean | false |

The same **options** are available to **all functions** but with different default values.

Expand Down Expand Up @@ -103,6 +105,19 @@ The same **options** are available to **all functions** but with different defau
})();
```

- Ask for a name with timeout:

```js
const promptly = require('promptly');

(async () => {
const name = await promptly.prompt('Name: ', { timeout: 3000 });
console.log(name);
})();
```

It throws an `Error("timed out")` if timeout is reached and no default value is provided

#### Validators

The validators have two purposes: to check and transform input.
Expand Down
2 changes: 2 additions & 0 deletions lib/getOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ function getOptions(options) {
retry: true,
trim: true,
default: undefined,
useDefaultOnTimeout: false,

// `read` package options
silent: false,
replace: '',
input: process.stdin,
output: process.stdout,
timeout: 0,

...options,
};
Expand Down
25 changes: 18 additions & 7 deletions lib/prompt.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,25 @@ const { promisify } = require('util');
const read = promisify(require('read'));

async function prompt(message, options) {
let value;

// Read input
let value = await read({
prompt: message,
silent: options.silent,
replace: options.replace,
input: options.input,
output: options.output,
});
// Manage timeout
try {
value = await read({
prompt: message,
silent: options.silent,
replace: options.replace,
input: options.input,
output: options.output,
timeout: options.timeout,
});
} catch (err) {
if (err.message !== 'timed out' || !options.default || !options.useDefaultOnTimeout) {
satazor marked this conversation as resolved.
Show resolved Hide resolved
throw Object.assign(new Error(err.message), { code: 'TIMEDOUT' });
}
value = options.default;
loopingz marked this conversation as resolved.
Show resolved Hide resolved
}

// Trim?
if (options.trim) {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
],
"scripts": {
"lint": "eslint .",
"test": "jest --env node --coverage",
"test": "jest --env node --coverage --runInBand",
"prerelease": "npm t && npm run lint",
"release": "standard-version",
"postrelease": "git push --follow-tags origin HEAD && npm publish"
Expand Down
17 changes: 17 additions & 0 deletions test/prompt.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,20 @@ it('should write input using options.replace to stdout if silent is enabled', as
expect(process.stdout.write).toHaveBeenCalledWith('a');
expect(process.stdout.write).not.toHaveBeenCalledWith('z');
});

it('should timeout if user is not fast enough', async () => {
await expect(promptly.prompt('prompt: ', { timeout: 10 })).rejects.toEqual(new Error('timed out'));
});

it('should take default value if timed out with timeoutToDefault', async () => {
expect(await promptly.prompt('prompt: ', { timeout: 10, default: 'plop', useDefaultOnTimeout: true })).toEqual('plop');
});

it('should take default value if timed out', async () => {
await expect(promptly.prompt('prompt: ', { timeout: 10, default: 'plop' })).rejects.toEqual(new Error('timed out'));
});

it('should take input value if not timed out', async () => {
sendLine('plop2', 10);
expect(await promptly.prompt('prompt: ', { timeout: 20, default: 'plop' })).toEqual('plop2');
});