Enzyme+React expect component string - failed to parse selector - reactjs

So I have this test case which I need to solve. Background is updating dev environment to newer version and after that a lot of our tests broke.
Here I have a weird case which results in:
"Failed to parse selector: Label price detail 1"
This is how the test snippet looks like, I hope I've added all that is necessary.
it('Should render with price and one addon', () => {
data.addonHeaderName = 'addonHeaderName';
data.addons.push(
{
price: {
label: 'Addon text 1',
value: 50.33,
unit: 'dollars',
vat: 'excl'
},
discount: {
label: 'Addon text 2',
value: 11.43,
unit: 'dollars',
vat: 'excl'
},
future: false,
addonIcon: 'icon',
ecoText: 'Addon eco text',
linkUrl: 'http://testaddonlink.com'
}
);
data.contract.prices.push(
{
id: 'price',
label: 'Label price detail 1',
unit: 'dollars',
value: 4.03
},
{
id: 'Label price detail 2',
label: 'Discount',
unit: 'dollars',
value: -3.00
}
);
const component = shallow(
<MyContract
data={data}
andSomeOtherStuff={otherStuff}
/>
);
expect(component).toMatchSnapshot();
expect(component.find('Label price detail 1')).toBeTruthy();
expect(component.find('Label price detail 2')).toBeTruthy();
expect(component.find('Addon text 1')).toBeTruthy();
expect(component.find('Addon text 2')).toBeTruthy();
expect(component.find('Addon eco text')).toBeTruthy();
If I comment out the first expectation, it hits the next one, and then the other one etc etc.
Earlier we ran Enzyme 2.9.1 together with enzyme-adapter-react-15 (and of course React 15) but since we've upgraded to React 16 we also need to update a few other dependencies such as this one. And then shit hit the fan.
Now we're on Enzyme 3.8.0, enzyme-adapter-react-16.3 and React 16.3.x.
I've been fiddling around with trying to get it as a string instead but no bueno. Any ideas on what I'm missing here?

Enzyme find works with css selectors so if you would like to search on the label there you should probably use something like:
component.find('[label="Label price detail 1"]')
Additionally I believe this will always be truthy no matter if it's found or not. (Not sure on that one though).
I usually use .toHaveLength(1) to check if it gets rendered!

I had this before, this looks like a typing error. Confirm the strings.

Related

Dynamically use React Component based on data in an object

I'm creating this menu as a fun project in React, and I've finished the code to display/style the components, so now I'm setting it up to be dynamic and generate the menu based on a passed set of data. My React project routes like this:App /→Tab /→Various components based on data.
The plan is to have a menu (App/) contain potentially multiple Tab / of various inputs, such as date, text, number, range, etc. Let's say I use this dataset as an example:
elements: [
{
type: 'number',
text: 'Some Text Label',
fields: [
{
text: 'Some Text',
min: 0,
max: 50,
value: 25,
},
{
text: 'Some Text',
min: 25,
max: 75,
value: 50,
},
],
},
{
type: 'text',
text: 'Some Text Label',
fields: [
{
text: 'Some Text',
value: 'Some Text Placeholder',
},
],
},
{
type: 'number',
text: 'Some Text Label',
fields: [
{
text: 'Some Text',
min: 0,
max: 100,
value: 50,
},
],
},
]
Within the Tab / component, I'd want to look through the elements to find the type of one element, then use the component that is ready for that element (for example, type:number, I would use Number / and then pass the fields as a prop to that component.
Something like this:Number fields={insertdatahere}/>
I'm a total beginner when it comes to react, but I've tried a few ways myself and I feel like I'm just missing something because nothing is working. I was considering just having all the Components manually placed inside the tab component and having them set as Display: None unless an element is present for that type. Thanks for any advice.
Here's a Code sandbox which illustrates one way you could get started.
The basic idea is to define a component for each type of field (text, number, ...) and make a lookup. A function component is like any other value in Javascript - you can store it in an array or an object.
In this case I've defined TextDisplay and NumberDisplay:
const TextDisplay = ({ text, value }) => (
<li>
<h4>{text}</h4>
<input value={value} />
</li>
);
const NumberDisplay = ({ text, min, max, value }) => (
<div>
<h4>{text}</h4>
<input type="number" min={min} max={max} value={value} />
</div>
);
const ComponentForType = {
text: TextDisplay,
number: NumberDisplay
};
Then there's a bit of machinery for displaying the lists of elements in the definition, and the list of fields in each element.
Hopefully that can give you something to play around with. There's a bit of weird syntax in there like the spread operator, and everything gets complicated once you want to make the values editable, but this could be a starting point.

Get a list of components and their props from MDX string - by regex?

My problem - Get components & props from MDX/JSX string
I have an MDX string with Front-matter meta data in YAML, some regular text, some markdown and some React components.
I need to get the list of all React (non-HTML) components from it with their parameters.
So given this example:
---
title: Title of documents
tags: one, two, three
---
# My heading H1
Some text in paragraph. Than the list:
- First item
- Second item
More text with [a link](https://example.com).
<Articles category="theatre" count={3} />
Further text with more information.
<Newsletter categories={['theatre', 'design']} />
<MultilineComponent
paramA="A"
paramB="B"
/>
<ComponentWithChildren param="value">
Some children
</ComponentWithChildren>
... I would need this output:
[
{
component: 'Articles',
props: {
category: 'theatre',
count: 3,
},
},
{
component: 'Newsletter',
props: {
categories: ['theatre', 'design'],
}
},
{
component: 'MultilineComponent',
props: {
paramA: 'A',
paramB: 'B',
}
},
{
component: 'ComponentWithChildren',
props: {
param: 'value',
}
}
]
Also I need to do this on the server, so I don't have access to browser functionality (window, document, etc.).
What I've tried
Some basic Regex, but as I'm far from being professional in regexing, now I have two problems. :)
Is there some built in way how to parse JSX string to get a list of components & props in the way that I've described above? Or is there some maybe some other parser that I can use to solve this? If not, is there some Regex pattern I can use to get this?
Quick summary on "Why"
During the build of my Next.js project I need to determine which data is actually needed for each MDX page in the bundle. So if I see this in the Mdx file:
...other text
<Articles category="theatre" count={3} />
...other text
... which I'm somehow able to parse to this:
component: "Articles"
category: "theatre"
count: 3
that's enough info for me to know that I need to send those data to the page:
[
{
title: 'Romeo and Juliet',
category: 'theatre',
},
{
title: 'The Cherry Orchard',
category: 'theatre',
},
{
title: 'Death of a Salesman',
category: 'theatre',
}
]
Would you be able to help me with this? Thank you in advance! 💪
Edit
#Rango's answer pointed me to the right direction! One caveat: jsx-parser can not handle multiline components to which Rango's proposed the following solution:
if (rsp.test(c)) continue; // add before /index.js:374
This however removes all whitespace from string attributes. So I've replaced it with this:
if (/[\n\r]/.test(c)) continue; // this should remove lines only
So far this solution works. I would be more comfortable to use more stable libraries, but unfortunately none of the proposed solution worked for me (acorn-jsx, react-jsx-parser, babel/parser).
Not sure that parsing JSX with regular expressions is efficient because curly brackets {...} can contain any JS expression, so if you choose this way then prepare to parse Javascript as well.
Fortunately, there are a bunch of JSX parsers that can do it for you. E.g. the first one I picked was jsx-parser and this small beast can parse your example (with a simple trick). The shape of the result is quite different but you can transform it to match your needs.
var test = `
---
title: Title of documents
tags: one, two, three
---
# My heading H1
Some text in paragraph. Than the list:
- First item
- Second item
More text with [a link](https://example.com).
<Articles category="theatre" count={3} />
Further text with more information.
<Newsletter categories={['theatre', 'design']} />
<MultilineComponent
paramA="A"
paramB="B"
/>
<ComponentWithChildren param="value">
Some children
</ComponentWithChildren>
`
const components = [...test.matchAll(/<[A-Z]/g)]
.map(match => JSXParser(test.slice(match.index)))
document.getElementById('result').textContent = JSON.stringify(components, null, 2)
<script src="https://unpkg.com/jsx-parser#1.0.8/index.umd.js"></script>
<pre id="result">Hello</pre>
In my snippet I used UMD version of the package, but for node.js consider choosing ES module ofc.

Yup dynamic object validation

I am sending a value to yupa via formik. As a result of this value, what can I do to make the necessary checks and return an error message in this style? Since the object has unlimited length, I decided to keep it validated as an object in order not to cause any slowness. I'm solving it with array but the yup part is getting slow.
The body I send:
{
user_id_1: {
name: 'test name', // required
surname: 'test surname', // required
age: 10, // optional
},
user_id_2: {
name: 'test name 2',
surname: 'test surname 2',
},
user_id_3: {
name: 'test name 2',
surname: '',
},
}
The expected error result:
user_id_3: {
surname: 'surname is required',
},
I wrote and tested a code suitable for my question. I want to share the solution with you. The critical point here was that I produced my own method and a custom error message with addMethod. You can check how I did it in the related code example. The inside of the test could be solved with the yup scheme, but I solved it at a simple level with if else. The else part in the test is also important, if I do not delete the object value, it remains in the cache.
code example: codesandbox

Is there a way to have a select and creatable hybrid?

I have been using the select from react-select for some time. So far, only with predefined options, without any functionality for adding any other option/s.
As far as I could read up and figure out, there is also something called creatable, which is exactly doing that. But it doesn’t allow my to predefined/static lists, as far as I could see.
I assume both have to be implemented to get either functionality, or is there a way or prop to just stick one of them?
Edit:
Maybe I didn’t emphasis to enough on the static part. Basically, I would like to have one component that has a prop like: “canAddOptions: bool”. To either allows to add values or not. As far as I can understand, I have to implement both to get this..?
I'm also using similar approach in my application, where I'm rendering static list as options and it should work as a creatable select.
As per the problem statement, you can use isValidNewOption={() => false} to make creatable as normal select.
Try something like below:
import CreatableSelect from 'react-select/creatable';
<CreatableSelect
isMulti
isValidNewOption={() => false} // You can apply condition here as per the prop you will get.
options={[
{ value: 'one', label: 'One' },
{ value: 'two', label: 'Two' },
{ value: 'three', label: 'Three' },
]}
/>

react-beautiful-dnd throws error when ordering the second time

I have bean following the official tutorial for react-beautiful-dnd from egghead.io. On lesson 5 persisting the reordering my implementation throws all the time an error but only the second time when I try to reorder the top item. It works fine when I reorder the first time.
This is my branch specific to this question: https://github.com/bogdan-marian/my-react-beautiful-dnd/tree/002-property-id-question
The error that I get when I order the second time is:
TypeError: Cannot read property 'id' of undefined
src/Column.js:31
# and row 31 shows
<Task key={task.id} task={task} index={index} />)}
I'm not able to spot what is wrong with my implementation.
I found the problem. There was a typo bug in my initialData.js
My second task had the id taks-2 instead of task-2. The columns on the other hand was set to point to the task-2. This is how initial data looked before the fix
const initialData = {
tasks: {
'task-1': {id: 'task-1', content: 'Take out the garbage'},
'task-2': {id: 'taks-2', content: 'Watch my favorite show'},
'task-3': {id: 'task-3', content: 'Charge my phone'},
'task-4': {id: 'task-4', content: 'Cook dinner'},
},
columns: {
'column-1':{
id:'column-1',
title:'To do',
taskIds:['task-1','task-2', 'task-3', 'task-4']
}
},
// Facilitate reordering of the columns
columnOrder:['column-1']
}
All I had to do was to updated my second task id to task-2.

Resources