getByText doesn't find element with the text - jestjs

I am starting using jest to test simple component SysError.js in my React Native 0.68 app. SysError displays some message on screen when it is called (routed by react-navigation 6.x) and the jest test is to check if the page view does contain the message. The #testing-library/react-native used is v11.0.0
Here is the SysError.js:
import React, {useState, useContext, Component} from 'react';
import {Platform, Button, Text, TouchableOpacity, View } from 'react-native';
export default function SysError({route}) { //<<== routed by react-navigation
const message = route.params.message ? JSON.stringify(route.params.message) : "";
return (
<View styles={{marginTop: 32, paddingHorizontal: 24, alignItems:"center", alignContent:"center"}}>
<Text>{route.params.message} System NOT available right now. Try again later</Text>
</View>
)
};
Here is the jest test:
import React from 'react';
import { render, cleanup } from "#testing-library/react-native";
import SysError from './SysError';
afterEach(cleanup);
it ('describe SysError page view with a message', () => {
const route = {params: {message:"nnmm"}};
const {toJSON, getByText} = render(<SysError route={route} />);
const foundmsg = getByText("System NOT available right now"); //<<==this throws error
expect(toJSON()).toMatchSnapshot();
expect(foundmsg.props.children).toEqual("System NOT available right now");
})
To my surprise, there is an error:
FAIL src/components/app/SysError.test.js
● describe SysError page view with a message
Unable to find an element with text: System NOT available right now
9 | const route = {params: {message:"nnmm"}};
10 | const {toJSON, getByText} = render(<SysError route={route} />);
> 11 | const foundmsg = getByText("System NOT available right now");
| ^
12 | expect(toJSON()).toMatchSnapshot();
13 | expect(foundmsg.props.children).toEqual("System NOT available right now");
14 |
at Object.getByText (src/components/app/SysError.test.js:11:22)
However if the test code is changed to reg expression:
const foundmsg = getByText(/System NOT available right now/i);
Then the error becomes:
expect(received).toEqual(expected) // deep equality
Expected: "System NOT available right now"
Received: ["nnmm", " System NOT available right now. Try again later"]
11 | const foundmsg = getByText(/System NOT available right now/i);
12 | expect(toJSON()).toMatchSnapshot();
> 13 | expect(foundmsg.props.children).toEqual("System NOT available right now");
Is there way re-code expect(foundmsg.props.children).toEqual("System NOT available right now"); and make it pass? I tried toEqual(/System NOT available right now/i) and it didn't work.

As the react-native testing library shows in the documentation examples the getByText query, if provided a string, will look for the exact match.
That's the reason why on your first attempt the query is unable to find the element. As you found out, you can also provide a regex to look for partial match so on your second attempt the query is capable of finding the element.
Now that you have the element:
<Text>{route.params.message} System NOT available right now. Try again later</Text>
You can see that it actually has two children: One for the dynamic part that prints the route.params.message and the other one for the static part.
You can check both values in your test with:
expect(foundmsg.props.children).toEqual(["nnmm", "System NOT available right now"]);
If you only want to check that the static part is present you could also do:
expect(foundmsg.props.children).toContain("System NOT available right now");

Related

Remix.run blog tutorial - optimistic UI

I'm following the blog tutorial on the remix.run example page and I'm struggling with the Optimistic UI aspect of it and failing to find any examples online
As you can see in my github repo I am trying to render the <PostAdmin /> route, but it's not loading for some reason.
import PostAdmin from "~/routes/posts/admin";
export default function NewPost() {
const errors = useActionData();
const transition = useTransition();
const isCreating = Boolean(transition.submission);
const title = transition?.submission?.formData?.get("title");
return isCreating ? (
<>
<PostAdmin />
</>
) : (
....
My original plan was to pass some additional items in here so I can render to the sidebar optimistically like the following. However I can't get the PostAdmin route to load at all, with the error Cannot destructure property 'posts' of 'useLoaderData(...)' as it is undefined.
export default function PostAdmin({
newPost,
}: {
newPost?: { title: string; slug: string };
}) {
As a side note, it's rendering the nested AdminIndex ok when I try that, but this would not achieve the homework example in the remix tasks as I need to pass it to the sidebar.
Hard one to explain and I imagine someone who's done the tasks before or has a solid example of Remix will understand. It may be that I am approaching this incorrectly. I have struggled to find complete examples anywhere.

How to unit test permissions in a React Admin controller?

I'm using react-admin and I have a list component that has some conditional display behavior based on permissions.
I'd like to write a simple Jest test that asserts the correct behavior (display the Edit button if admin, hide the Edit button if not admin), but I need to feed some mock records into my list component. How do I pass mock data to my list component?
There is (now) a dedicated paragraph on the documentation about testing permissions-based view: https://marmelab.com/react-admin/UnitTesting.html#testing-permissions
I also wrote an example of unit test available on the code base: UnitShow.spec.js
it('should show the user role in the second tab', () => {
const wrapper = shallow(<UserShow permissions="admin" />);
const tabs = wrapper.find(Tab);
const fields = tabs.at(1).find(TextField);
expect(fields.at(0).prop('source')).toBe('role');
});

prop not displayed in react custom dropdown component

I'm facing a silly issue of the default value not being rendered in the form.
In my app, when the user is logged in, a form will be auto-filled with some of the details as it will fetch the data from the stored user information passed to my component through props.
In that case, my already selected 'Gender' i.e. the default value is not getting displayed when the component is rendered.
At the same time, when I passing the same value as hard-coded, it works perfectly fine.
I'm receiving the 'defaultValue' in 'renderGenderDropDown' as 'Male'(same as I stored in myValue const).
But, myValue const works, defaultValue doesn't.
And yes, my component is used in multiple other components and works perfectly fine. It basically, renders '' from 'React'.
What do I need to fix this?
Code:
renderGender() {
const { options, data } = this.props;
const gender = get(data, 'gender');
const defaultValue = gender ? capitalize(gender) : gender;
const fieldName = 'gender';
return this.renderGenderDropDown(fieldName, defaultValue, prefixOptions);
}
renderGenderDropDown(fieldName, defaultValue, options) {
const { configuration, id, validations } = this.props;
const myValue = 'Male';
return <AppDropDown
label={getLabel(fieldName, configuration, validations, 'gender')}
options={dropdownOptions}
defaultValue={myValue}
//defaultValue={defaultValue}
key={fieldName}
className={fieldName}
disabled={false}
id={id}
onChange={this.onGenderChange(this[fieldName])}
/>
}
In Javascript, there isnt a native capitalize() . This is probably returning back undefined instead of a string. Try this to capitalize the first letter in the string.
gender.charAt(0).toUpperCase() + gender.substr(1)

MEAN SATCK angular2:get data from multiple api in typescript

Working with angular2,nodejs,expressjs,mongodb.
i want all api to return data and show over html page.
here is my code for .ts file.
enter image description here
all apis tested working fine returns data form mongodb.
but very first api return data and shows over the html page.
in this case countphones api retuns data and other two not .
but when first is commented second starts showing data over the html
page.
the case is like first come only shows.
export class AppComponent {
phone$ = http.get("...").map(r => r.json())
laptop$ = http.get("...").map(r => r.json())
television$ = http.get("...").map(r => r.json())
ngOnInit(){
Observable
.forkJoin(this.phone$, this.laptop$, this.television$)
.subscribe(([phones, laptops, televisions])=>{
this.phones = phones;
this.laptios = laptops;
this.televisions = televisions;
});
}
}

How to do proper Column Filtering with React-Virtualized - Advice needed?

I have a react-virtualized table where column sorting is enabled. My plan is to add a filter icon next to column headers and do a Material-UI popover when someone clicks on it.
So here is what I did:
I enabled headerRenderer
headerRenderer= {this.renderHeader}
My headerRenderer returns a component
renderHeader = (value) => {
// console.log(value)
return <ColumnFilterContainer label= {value.label} />
}
ColumnFilterContainer is as follows.
import React from 'react'
import ContentClear from 'material-ui/svg-icons/content/clear'
import FilterList from 'material-ui/svg-icons/content/filter-list'
const ColumnFilterContainer = (props) => {
const {label} = props
return <span>{label} <a onClick={console.log('TEST')} ><FilterList /></a></span>
}
export default ColumnFilterContainer
But when I click on the svg-icon it consoles out the 'TEST' but also resorts the table. How can I achieve what I would like to do. Is it doable?
Thanks
Table listens for clicks on sortable headers. (That is, columns that aren't tagged as disableSort that belong to a Table with a sort callback.)
In your case, if you have something within your sortable header that shouldn't trigger sorting- just prevent the event from bubbling and you should be fine. :)
Alternately you could also just ignore the next call to your sort function but I think that would be a hackish solution.

Resources