TypeError: Cannot read property 'AccountToken' of undefined - jestjs

Trying to run the following test for a select component that is being import 'react-select'
I have the click events running fine, but onChange event is displaying an error:
TypeError: Cannot read property 'Accounts' of undefined
Here is where the error is located, line :
setReport = () => {
let data = this.state.Account.accountBody;
this.setState({
AccountToken: data.AccountToken,
Render();
<Select
className={'field-input-select margin-right'}
id='accounts-id-test'
value={this.state.Account}
onChange={(e) => { this.setState({Account: e}, ()=>{this.setReport()}) }}
Using mount :
it("should check button click event - Select ", () => {
baseProps.onClick.mockClear();
wrapper.find('CLASS YOUR TESTING').setState({
contactOptions:[],
Account:[[""]],
accountOptions: [{ value: 'test', label: 'label test', accountBody: "test account" }],
showRequired: false,
loading:false
});
wrapper.update()
// wrapper.update()
wrapper.find('CLASS YOUR TESTING').find('Select').at(0).props().onChange({
contactBody:{
Accounts:[]
}})
onChange works at(0) and not at (1) . Why ?

The error means that:
let contactBody = contact.contactBody;
is undefined so now you should try to debug with console.log or other ways and see why it is undefined and find a Solution

Able to figure out
wrapper.find('CLASS YOUR TESTING').find('Select').at(1).props().onChange({
accountBody:{
LOA:{
Documents:{
Signers:[],
}
}
}
})

Related

Angular: TypeError: Cannot read properties of undefined (reading 'forEach') with Treeview

I try execute on my view-post.component.ts
with treeview
Here is my code
constructor(private postService: PostService, private activateRoute: ActivatedRoute,
private commentService: CommentService, private router: Router) {
this.postId = this.activateRoute.snapshot.params.id;
this.commentForm = new FormGroup({
text: new FormControl('', Validators.required)
});
this.commentPayload = {
text: '',
postId: this.postId
};
this.dataSource.data = this.comments;
}
private _transformer = (node: CommentPayload, level: number) => {
return {
expandable: !!node.dtoList && node.dtoList.length > 0,
username: node.username,
text: node.text,
level: level,
};
};
treeControl = new FlatTreeControl<ExampleFlatNode>(
(node) => node.level,
(node) => node.expandable
);
treeFlattener = new MatTreeFlattener(
this._transformer,
(node) => node.level,
(node) => node.expandable,
(node) => node.dtoList
);
dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener);
hasChild = (_: number, node: ExampleFlatNode) => node.expandable;
}
I only want show something in console for every item is on "treeview" but show me this error
My code base on this project Stackblitz
*https://stackblitz.com/edit/angular-rtzh5a?file=src%2Fapp%2Ftree-flat-overview-example.html
Cannot read properties of undefined (reading "forEach")
Meaning that there is a place in your code, where you are using foreach on some array, which is null or undefined. Provided code sample doesn't contain this part, but if you will run app with 'ng serve' (on localhost), this console error will provide you also a component name and on which line problem occoured. For now it's saying main.js:1, because it's built version. You can easily secure it like this:
if (something) {
something.forEach(s => {
// ...
});
}
or use forof loops (like the example above, it just won't run when something is null/undefined)
for (let s of something) {
// ...
}

Jimp: How to fix 'TypeError: Cannot read property of 'lineHeight' of undefined

I'm trying to use jimp to add text to an image. Where am I going wrong in the print function to receive this error.
let fileName = 'botImageTemplate.png';
let fontPerson = Jimp.loadFont(Jimp.FONT_SANS_128_BLACK).then(font => font);
Jimp.read(fileName)
.then(image => {
return image
.print(fontPerson, 50, 50, {
text: "This is my text",
alignmentX: Jimp.HORIZONTAL_ALIGN_CENTER,
alignmentY: Jimp.VERTICAL_ALIGN_MIDDLE
}, 40, 40)
.write('botTesting.png')
})
.catch(err => {
console.error(err);
});
The error message I keep getting is "TypeError: Cannot read property of 'lineHeight' of undefined"
What do I have to change to get this to work?
i dont know jimp, but can you try to add arguments: maxWidth and maxHeight.
For me it seems there are missing some properies.
https://www.npmjs.com/package/jimp

Including dialogs or reusing dialogs from different file

I am trying to do begindialog from another another dialog js file. I am getting error.
<b>[onTurnError]: Error: DialogContext.beginDialog(): A dialog with an id of 'FollowUpDialog' wasn't found. </b>
this is dialog structure-
dialogs
orderstatus
orderstatus.js
index.js
FollowUp
followUp.js
index.js
i am trying to include FollowUp dialog in OrderStatus Dialog, similary i have other dialogs where i want to begin followup or orderstatus dialog. trying to reuse the dialogs.
One way to do use how we include the file in botjs amd to do adddialog same way i can include in otherfile. But it is redundant work. I am trying to avoid that. Can some one tell me better approach to include the dialog in different dialogs.
code:
Below code is from greeting.js
If you see line where i am doing begindialog.
return await step.beginDialog(ORDER_STATUS_DIALOG);
return await step.beginDialog(ENTITLEMENT_CHECK_DIALOG);
It is error. I am trying to include the dialog which is part of different JS files.
async step => {
if (step.context.activity.channelId == 'directline') {
const buttons = [{
type: ActionTypes.ImBack,
title: 'Repair Order Status',
value: symbolicString.ZEB_GR_STR_013
}, {
type: ActionTypes.ImBack,
title: 'Entitlement Check',
value: symbolicString.ZEB_GR_STR_014
}];
const card = CardFactory.heroCard('', undefined, buttons, {
text: symbolicString.ZEB_GR_STR_015
});
const reply = {type: ActivityTypes.Message};
reply.attachments = [card];
return await step.context.sendActivity(reply);
} else {
return await step.prompt(MENU_PROMPT, symbolicString.ZEB_GR_STR_028);
}
},
async step => {
if (step.context.activity.channelId != 'directline'){
console.log("step greeting dialog next step");
console.log(step);
console.log(step.context.activity);
if (step.context.activity.text == '1'){
return await step.beginDialog(ORDER_STATUS_DIALOG);
}else if (step.context.activity.text == '2'){
return await step.beginDialog(ENTITLEMENT_CHECK_DIALOG);
}
}
return await step.endDialog();
}
]));

Bot framework (v4) Prompt choice in carousel using HeroCards not going to next step

I’m trying to use HeroCards along with a prompt choice in a carousel. So the options to be selected by the user are displayed as HeroCards. As soon as the user clicks in the button of a card it should goes to the next waterfall function.
Here is a working example in bot framework v3. It does work as expected.
const cards = (data || []).map(i => {
return new builder.HeroCard(session)
.title(`${i.productName} ${i.brandName}`)
.subtitle(‘product details’)
.text(‘Choose a product’)
.images([builder.CardImage.create(session, i.image)])
.buttons([builder.CardAction.postBack(session, `${i.id.toString()}`, ‘buy’)]);
});
const msg = new builder.Message(session);
msg.attachmentLayout(builder.AttachmentLayout.carousel);
msg.attachments(cards);
builder.Prompts.choice(session, msg, data.map(i => `${i.id.toString()}`), {
retryPrompt: msg,
});
Below I’m trying to do the same with bot framework v4 but it does not work. It never goes to the next function in my waterfall.
How can I do the same with v4?
…
this.addDialog(new ChoicePrompt(PRODUCTS_CAROUSEL));
…
const productOptions: Partial<Activity> = MessageFactory.carousel(
item.map((p: Product) =>
CardFactory.heroCard(
p.productName,
‘product details’,
[p.image || ''],
[
{
type: ActionTypes.PostBack,
title: ‘buy’,
value: p.id,
},
],
),
),
‘Choose a product’,
);
return await step.prompt(PRODUCTS_CAROUSEL, productOptions);
…
UPDATE:
Follow full code with the suggestion from #Drew Marsh
export class ProductSelectionDialog extends ComponentDialog {
private selectedProducts: Product[] = [];
private productResult: Product[][];
private stateAccessor: StatePropertyAccessor<State>;
static get Name() {
return PRODUCT_SELECTION_DIALOG;
}
constructor(stateAccessor: StatePropertyAccessor<State>) {
super(PRODUCT_SELECTION_DIALOG);
if (!stateAccessor) {
throw Error('Missing parameter. stateAccessor is required');
}
this.stateAccessor = stateAccessor;
const choicePrompt = new ChoicePrompt(PRODUCTS_CAROUSEL);
choicePrompt.style = ListStyle.none;
this.addDialog(
new WaterfallDialog<State>(REVIEW_PRODUCT_OPTIONS_LOOP, [
this.init.bind(this),
this.selectionStep.bind(this),
this.loopStep.bind(this),
]),
);
this.addDialog(choicePrompt);
}
private init = async (step: WaterfallStepContext<State>) => {
const state = await this.stateAccessor.get(step.context);
if (!this.productResult) this.productResult = state.search.productResult;
return await step.next();
};
private selectionStep = async (step: WaterfallStepContext<State>) => {
const item = this.productResult.shift();
const productOptions: Partial<Activity> = MessageFactory.carousel(
item.map((p: Product) =>
CardFactory.heroCard(
p.productName,
'some text',
[p.image || ''],
[
{
type: ActionTypes.ImBack,
title: 'buy',
value: p.id,
},
],
),
),
'Choose a product',
);
return await step.prompt(PRODUCTS_CAROUSEL, {
prompt: productOptions,
choices: item.map((p: Product) => p.id),
});
};
private loopStep = async (step: WaterfallStepContext<State>) => {
console.log('step.result: ', step.result);
};
}
PARENT DIALOG BELOW:
...
this.addDialog(new ProductSelectionDialog(stateAccessor));
...
if (search.hasIncompletedProducts) await step.beginDialog(ProductSelectionDialog.Name);
...
return await step.next();
...
MY BOT DIALOG STRUCTURE
onTurn()
>>> await this.dialogContext.beginDialog(MainSearchDialog.Name) (LUIS)
>>>>>> await step.beginDialog(QuoteDialog.Name)
>>>>>>>>> await step.beginDialog(ProductSelectionDialog.Name)
UPDATE
Replacing the ChoicePrompt with TextPromt (as suggested by Kyle Delaney) seems to have the same result (do not go to the next step) but I realised that if remove return from the prompt like this:
return await step.prompt(PRODUCTS_CAROUSEL, `What is your name, human?`); TO await step.prompt(PRODUCTS_CAROUSEL, `What is your name, human?`);
it does work but when I'm returning the original code with ChoicePrompt without return like this:
await step.prompt(PRODUCTS_CAROUSEL, {
prompt: productOptions,
choices: item.map((p: Product) => p.id),
});
I'm getting another error in the framework:
error: TypeError: Cannot read property 'length' of undefined
at values.sort (/xxx/Workspace/temp/13.basic-bot/node_modules/botbuilder-dialogs/lib/choices/findValues.js:84:48)
at Array.sort (native)
at Object.findValues (/xxx/Workspace/temp/13.basic-bot/node_modules/botbuilder-dialogs/lib/choices/findValues.js:84:25)
at Object.findChoices (/xxx/Workspace/temp/13.basic-bot/node_modules/botbuilder-dialogs/lib/choices/findChoices.js:58:25)
at Object.recognizeChoices (/xxx/Workspace/temp/13.basic-bot/node_modules/botbuilder-dialogs/lib/choices/recognizeChoices.js:75:33)
at ChoicePrompt.<anonymous> (/xxx/Workspace/temp/13.basic-bot/node_modules/botbuilder-dialogs/lib/prompts/choicePrompt.js:62:39)
at Generator.next (<anonymous>)
at /xxx/Workspace/temp/13.basic-bot/node_modules/botbuilder-dialogs/lib/prompts/choicePrompt.js:7:71
at new Promise (<anonymous>)
at __awaiter (/xxx/Workspace/temp/13.basic-bot/node_modules/botbuilder-dialogs/lib/prompts/choicePrompt.js:3:12)
this is the line:
// Sort values in descending order by length so that the longest value is searched over first.
const list = values.sort((a, b) => b.value.length - a.value.length);
I can see the data from my state is coming properly
prompt: <-- the data is ok
choices: <-- the data is ok too
Sometimes I'm getting this error too:
error: TypeError: Cannot read property 'status' of undefined
at ProductSelectionDialog.<anonymous> (/xxxx/Workspace/temp/13.basic-bot/node_modules/botbuilder-dialogs/lib/componentDialog.js:92:28)
at Generator.next (<anonymous>)
at fulfilled (/xxxx/Workspace/temp/13.basic-bot/node_modules/botbuilder-dialogs/lib/componentDialog.js:4:58)
at <anonymous>
at process._tickDomainCallback (internal/process/next_tick.js:228:7)
this line
// Check for end of inner dialog
if (turnResult.status !== dialog_1.DialogTurnStatus.waiting) {
You're using a ChoicePrompt, but when you call prompt you're only passing through an activity (the carousel). ChoicePrompt is going to try to validate the input against a set of choices that you should be passing in when you call prompt. Because you're not doing this, the prompt is not recognizing the post back value as valid and technically should be reprompting you with the carousel again to make a valid choice.
The fix here should be to call prompt with PromptOptions instead of just a raw Activity and set the choices of the PromptOptions to an array that contains all the values you expect back (e.g. the same value you set for the value of the post back button).
This should end up looking a little something like this:
Since you're providing the choices UX with your cards, you want to set the ListStyle on the ChoicePrompt to none
const productsPrompt = new ChoicePrompt(PRODUCTS_CAROUSEL);
productsPrompt.style = ListStyle.none;
this.addDialog(productsPrompt);
Then, set the available choices for the specific prompt:
return await step.prompt(PRODUCTS_CAROUSEL, {
prompt: productOptions,
choices: items.map((p: Product) => p.id),
});
Basically Drew Marsh was right.
I just would like to add some other details that I had to tweak to make it work. In case someone else is going crazy like I was. It could give some insights. It's all about how you handle the returns of nested dialogs.
First change. I had to transform the identifier of the Choice prompt into string:
{
type: ActionTypes.PostBack,
title: 'buy',
value: p.id.toString(),
},
and
return await step.prompt(PRODUCTS_CAROUSEL, {
prompt: productOptions,
choices: item.map((p: Product) => p.id.toString()),
});
Another problem that I found was in the parent dialog:
I was basically trying to do this:
if (search.hasIncompletedProducts) await step.beginDialog(ProductSelectionDialog.Name);
return await step.next();
Which makes no sense, then I changed it to:
if (search.hasIncompletedProducts) {
return await step.beginDialog(ProductSelectionDialog.Name);
} else {
return await step.next();
}
And then the final change in the parent of the parent dialog:
Before was like this:
switch (step.result) {
case ESearchOptions.OPT1:
await step.beginDialog(OPT1Dialog.Name);
break;
default:
break;
}
await step.endDialog();
Which again does not make sense since I should return the beginDialog or endDialog. It was changed to:
switch (step.result) {
case ESearchOptions.OPT1:
return await step.beginDialog(OPT1Dialog.Name);
default:
break;
}

Trying to encapsulate TextInput, getting the addField error

I'm trying to encapsulate a TextInput such that when the value changes it does a serverside lookup and based on the result shows a notification to the user: "That group name already exists". I've been using this as my example to start from: https://marmelab.com/admin-on-rest/Actions.html#the-simple-way
My current error is
Error: The TextInput component wasn't called within a redux-form . Did you decorate it and forget to add the addField prop to your component? See https://marmelab.com/admin-on-rest/Inputs.html#writing-your-own-input-component for details.
but even if I add in
NameLookupTextInput.defaultProps = {
addField: true, // require a <Field> decoration
}
I still get the error. Heres my code
class NameLookupTextInput extends TextInput {
handleChange = eventOrValue => {
console.log("handleChange",eventOrValue);
this.props.onChange(eventOrValue);
this.props.input.onChange(eventOrValue);
if(this.timeoutHandle){
clearTimeout(this.timeoutHandle);
}
console.log(fetch);
this.timeoutHandle = setTimeout(function(){
let value = this.props.input.value;
fetchUtils.fetchJson(API_ENDPOINT+'/groupNameCheck/'+value, { method: 'GET'})
.then((data) => {
console.log(data);
let exists = data.json.exists;
let name = data.json.name;
if(exists){
console.log(this.props.showNotification('The group name "'+name+'" already exists.'));
}else{
console.log(this.props.showNotification('The group name "'+name+'" does not exist.'));
}
})
.catch((e) => {
console.error(e);
//showNotification('Error: comment not approved', 'warning')
});
}.bind(this),500);
};
}
export default connect(null, {
showNotification: showNotificationAction
})(NameLookupTextInput);

Resources