Comments (26)
https://github.com/terkelg/prompts#injectvalues
from prompts.
How about you only wipe the matched key/answer on completion? That way you could write this before testing myUI
:
prompts.inject({ q1: 'a1', q2: 'a1' })
And then when q1
resolves, it wipes q1
. When q2
resolves, it wipes q2
.
Also note from my example that I personally would want to just inject 1 object per inject
call. Passing multiple objects seems arbitrary and cumbersome when the answer keys are matched to the question names and not the prompt index anyway.
from prompts.
I guess we can do this in prompt.js
without any modifications to the actual prompt classes. That would be ideal
from prompts.
That would be kinda pointless, no? Names have to be unique otherwise prompts overwrite the values. We'd just need to test a 1:1 mapping so that we get expected output.
from prompts.
Thanks a lot @simonepri. I agree and prompts
itself need better tests for sure. Let me have a look at this
from prompts.
The idea is to add an API that enables to prepare
the answers for the following prompts
.
If I prepare 2 prompts then the next 2 prompts will not show the UI and they simply resolves with the answers given before.
Some more examples:
const prompts = require('prompts');
prompt.prepare({
meaning: '42'
});
prompts.prepare({
text: 'Some text'
});
let response1 = await prompts({
type: 'text',
name: 'meaning',
message: 'What is the meaning of life?'
});
let response2 = await prompts({
type: 'text',
name: 'text',
message: 'Insert some text?'
});
let response3 = await prompts({
type: 'text',
name: 'color',
message: 'What is your favourite color?'
});
console.log(response1); // => '42'
console.log(response2); // => 'Some text'
console.log(response3); // => This should be answered manually
This is just an idea, let me know if you have better way to achieve this.
from prompts.
Right, so they shouldn't render at all and immediately resolve when there's a prepare
method defined?
from prompts.
I'd personally prefer it be called inject
-- not that it really matters.
Since it's defined first, could save to an internal map if answers. Each prompt will look for its answer by name
from the map. If not found it proceeds with the UX/prompt.
from prompts.
The naming suggestion alludes more strongly to the fact that you're taking over/hijacking the responses, rather than preparing a set of defaults.
from prompts.
Yeah it makes sense, no preference over the name. inject
sound cool.
Each prompt will look for its answer by name from the map.
We actually need to store an array of maps. Then each prompts pop from that array.
Example scenario where a single map wouldn't be enough.
const prompts = require('prompts');
prompt.inject({
meaning: '42'
});
prompts.inject({
meaning: '24'
});
let response1 = await prompts({
type: 'text',
name: 'meaning',
message: 'What is the answer to life the universe and everything?'
});
let response2 = await prompts({
type: 'text',
name: 'meaning',
message: 'What is the meaning of life?'
});
console.log(response1); // => '42'
console.log(response2); // => '24'
from prompts.
This is an example of implementation:
function inject(answers) {
injections.concat(answers);
}
function prompt(questions) {
if (injections.lenght > 0) {
const answers = injections.pop();
// Use the answers
// If there isn't a default and there isn't an answer for a particular question then throw an exception
} else {
// Use the UI
}
}
from prompts.
That would be kinda pointless, no?
No, because maybe you have a block of code that you want to test, that internally creates 2+ prompts chains with some common names.
Example:
async function toTest() {
let questions = [{
type: 'text',
name: 'username',
message: 'What is your GitHub username?'
}, {
type: 'age',
name: 'age',
message: 'How old are you?'
}, {
type: 'text',
name: 'about',
message: 'Tell somethign about yourself',
initial: 'Why should I?'
}];
let answers1 = await prompts(questions);
let answers2 = await prompts(questions);
return [answers1, answers2];
}
Then you want to be able to do this:
prompts.inject({username: 'simonepri', age: -1, about: 'Something'});
prompts.inject({username: 'lukeed', age: -1});
[answers1, answers2] = await toTest();
// Check if the answer are the one expected
from prompts.
What do you think @lukeed?
from prompts.
I'm used to testing individual instances since it's more fine-grained control. Also synchronous code is easier to debug, especially in tests. Also, internally, it becomes simpler to look up in a single map/object, rather than traversing the list & making sure that everything is flushed at the correct times.
Here's my ideal usage, wherein calling prompts
force-wipes the internal mapping on completion (hence the re-definitions).
const prompts = require('prompts');
let dynamics = [
{
name: 'like',
type: 'boolean',
message: 'Do you like pizza?'
}, {
name: 'topping',
type: bool => bool && 'text',
message: 'Name a topping'
}
];
prompts.inject({ like:false, topping:'none' });
let foo = await prompts(dynamics);
//=> { like:false }
prompts.inject({ like:true, topping:'pineapple' });
let bar = await prompts(dynamics);
//=> { like:true, topping:'pineapple' }
let chained = [
{
type: 'text',
name: 'username',
message: 'What is your GitHub username?'
}, {
type: 'age',
name: 'age',
message: 'How old are you?'
}, {
type: 'text',
name: 'about',
message: 'Tell somethign about yourself',
initial: 'Why should I?'
}
];
prompts.inject({ username:'lukeed', age:100, about:'Something' });
let foo = await prompts(chained);
//=> { username:'lukeed', age:100, about:'Something' }
// with `onSubmit` callback
prompts.inject({ username:'lukeed', age:120, about:'Something' });
let bar = await prompts(chained, {
// stop if age > 100
onSubmit: (obj, val) => obj.name==='age' && val > 100
});
//=> { username:'lukeed', age:120 }
from prompts.
How do you test the example I've provided where you "can't" modify toTest
but you want to inject both?
The approach of having an array of maps is just more flexible and with it your ideal usage just works.
from prompts.
I'm not sure that I understand why toTest
has to be like that? I mean, among other things, that function is kinda point as is. It feels very much like an edge case & probably shouldn't be the example on which to build out a testing solution.
It requires changes, but something like this is far more useful:
function toTest(extra=[]) {
let questions = [{ type:'text', ... }, {...}].concat(extra);
return prompts(questions);
}
prompts.inject({ answers:123 });
let answers1 = await toTest();
prompts.inject({ foo:123, bar:456, baz:'hello' });
let answers2 = await toTest([
{
type: 'text',
name: 'username',
message: 'What is your GitHub username?'
}, {
type: 'age',
name: 'age',
message: 'How old are you?'
}
]);
Again, it's just my opinion & isn't up to me. I just feel that one-off injections are easier to reason about, implement, and (therefore) test.
from prompts.
I learn more towards @lukeed. What about adding a third param or option could that fix both cases?
from prompts.
Yes it is an edge case for sure.
I think that was come to my mind because we have two different ways to view this API
Your:
prompts.inject({q1: 'a1', q2: 'a2', q3: 'a3'}); // one single object for all prompts
let q1 = await prompts({
type: 'text',
name: 'q1',
message: 'Question 1'
});
let q2 = await prompts({
type: 'text',
name: 'q2',
message: 'Question 2'
}, {
type: 'text',
name: 'q3',
message: 'Question 3'
});
Mine:
prompts.inject({q1: 'a1'}, {q2: 'a2', q3: 'a3'}); // one object per prompt
let q1 = await prompts({
type: 'text',
name: 'q1',
message: 'Question 1'
});
let q2 = await prompts({
type: 'text',
name: 'q2',
message: 'Question 2'
}, {
type: 'text',
name: 'q3',
message: 'Question 3'
});
That said, I have no specific needs or preferences, is just another point of view.
But I agree that your approach seems easier
from prompts.
Yeah, for sure!
Quick clarification, mine is actually one inject
per prompts()
, as prompts()
would wipe the internal map on completion. So mine would look like this:
prompts.inject({q1: 'a1' });
let q1 = await prompts({
type: 'text',
name: 'q1',
message: 'Question 1'
});
prompts.inject({ q2: 'a2', q3: 'a3'});
let q2 = await prompts({
type: 'text',
name: 'q2',
message: 'Question 2'
}, {
type: 'text',
name: 'q3',
message: 'Question 3'
});
from prompts.
Yes but there are a lot of cases where you can't wipe on completion:
Imagine the following situation:
// q1.js
async function q1() {
return prompts({
type: 'text',
name: 'q1',
message: 'Question 1'
});
}
// q2.js
async function q2() {
return prompts({
type: 'text',
name: 'q2',
message: 'Question 2'
});
}
// ui.js
const q1 = require('q1.js');
const q2 = require('q2.js');
function myUI() {
return 'The answers are: (' + await q1 + ', ' + await q2 + ')';
}
Now you can test q1.js
and q2.js
but you can't test ui.js
if you wipe on completion.
Then with the array approach a simple:
prompts.inject({q1: 'a1'}, {q2: 'a2'});
lets you test also ui.js
.
Obviously you can re-code the example to use one single prompt, but as said I'm just imagining all the scenarios.
from prompts.
That'd be a good balance, and I don't think it'd be easy to leak accidentally.
from prompts.
Right! I might implement this tonight. Just to be sure I get it right:
- In the prompt loop we look up the internal "inject object".
- If a matching value is found resolve with that value immediately and delete the property from the inject object. Otherwise continue and leave the rest of the values alone for future prompts?
- Every time you call
prompts.inject
it adds to the same internal inject object
from prompts.
Yep! Something like
inject(obj) {
this._map = this._map || {};
for (let k in obj) {
this._map[k] = obj[k];
}
}
// ...
let answer, quit, name;
let map = this._map || {};
for (const prompt of prompts) {
name = prompt.name;
if (map[name] !== void 0) {
answers[name] = map[name];
delete map[name];
continue;
}
// if property is a function, invoke it unless it's ignored
// ...
}
return answers;
from prompts.
Shouldn't be for (let k of obj)
?
from prompts.
No, single object input. Still sticking to my preference 😄
from prompts.
Was looking for how to test prompts
and found this issue,
it seems that this functionality is not documented as far as I see, but I think it deserve to be on readme and have dedicated example for simple test, WDYT?
If yes, I will be happy to contribute.
from prompts.
Related Issues (20)
- How to test prompts in CircleCI?
- Select crashing in VsCode + Git Bash: Cannot read properties of undefined (reading 'split') HOT 2
- Multi-option toggle. Worth it?
- Ensure types are exported HOT 3
- How to cancel these unnecessary logs HOT 5
- logic diagram
- Ast prompts
- Roadmap for a 3.0 HOT 5
- prompts captures Ctrl-W "cut word" shortcut as control character
- How to make autocomplete required or select searchable?
- Add mask option to Text Type
- Somewhat different published module than the one in the repo HOT 2
- Keypress events may not be triggered on Windows if validate callback contains async actions HOT 2
- Bun support HOT 11
- confirm element: pressing a function key throws an error
- correctly type return/resolved values instead of `any`
- Initial value not passed to validate function for `"number"` types
- When the type is multiSelect, options cannot be switched through the arrows on the keyboard HOT 1
- Better index selection when providing initial for autocomplete
- Ability to prefill input on autocomplete HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from prompts.