`Type '{}' is not an array type. ` error throws when set the context - typescript-typings

status context:
import * as React from "react";
export const StatusContext = React.createContext({});
export function StatusProvider({ children }:React.PropsWithChildren) {
const value = React.useState("set a status");
return (
<StatusContext.Provider value={value}>
{children}
</StatusContext.Provider>
); }
when assign the value:
function SetStatus() {
const [status, setStatus ] = React.useContext(StatusContext);
return (
<input value={status} onChange={(e) => setStatus(e.target.value)} />
)
}
getting an error as :
TS2461: Type '{}' is not an array type.
4 |
5 | function SetStatus() {
> 6 | const [status, setStatus ] = React.useContext(StatusContext);
| ^^^^^^^^^^^^^^^^^^^^
7 | return (
8 | <input value={status} onChange={(e) => setStatus(e.target.value)} />
9 | )
Not able to get the fix. any one help me please?

When you use the useState hook, you get back an array containing the value and a function to set the value. You currently pass this array in as the value in your context. Try modifying your code like the snippet below, and see if the error goes away.
export function StatusProvider({ children }:React.PropsWithChildren) {
const [value, setValue] = React.useState("set a status");
return (
<StatusContext.Provider value={{status: value, setStatus: setValue}}>
{children}
</StatusContext.Provider>
);
}
Edit: I changed the way you supply the value to the context provider here, so that now the context will be an object with status and setStatus as keys. Now you can read this in the consuming component, like this:
import { StatusContext } from '..path/to/file';
function SetStatus() { // assuming SetStatus is a component
const { status, setStatus } = React.useContext(StatusContext);
return (
<input value={status} onChange={(e) => setStatus(e.target.value)} />
)
}

Related

Jest/React Testing Library test failing - react router link click not working as expected

I have a failing test but can't work out why. I have react-router links which link to the URL structure: /classes/${weekday}.
Classes component then sets the activeWeekday in context by React Router location which is displayed by the Classes as {activeWeekday} Classes
Functionality works i nthe browser, but for some reason in my tests it's not updating the header so the test is failing.
TestingLibraryElementError: Unable to find an element with the text: /friday classes/i
Can anyone see why? I can't figure it out.
Thks so much in advance.
Update - Here is a codepen replicating the issue.
// Snapshot of the state passed to Classes via context
export const ClassesProvider = ({ children }: ClassesProviderProps) => {
const [activeWeekdayNumber, setActiveWeekdayNumber] = useState<number>(
new Date().getDay()
);
// Classes component
const Classes = () => {
const { activeWeekdayNumber, setActiveWeekdayNumber } = useContext(ClassesContext);
const location = useLocation();
useEffect(() => {
const day = location.pathname.replace("/classes/", "");
const dayIndex = daysOfWeekArray.indexOf(capitaliseFirstLetter(day));
if (dayIndex !== -1) {
setActiveWeekdayNumber(
daysOfWeekArray.indexOf(capitaliseFirstLetter(day))
);
}
}, [location, setActiveWeekdayNumber]);
return (
<>
<h2>{daysOfWeekArray[activeWeekdayNumber]} Classes</h2>
</>
);
};
// failing test - TestingLibraryElementError: Unable to find an element with the text: /friday classes/i
const setup = (value: ClassesContextType) =>
render(
<ClassesContext.Provider value={value}>
<MemoryRouter>
<Classes />
</MemoryRouter>
</ClassesContext.Provider>
);
test("displays the relevant heading when a day of the week link is clicked", () => {
const value = {
activeWeekdayNumber: 3, // wednesday
};
setup(value);
const link = screen.getByRole("link", { name: "Friday" });
fireEvent.click(link);
expect(screen.getByText(/friday classes/i)).toBeInTheDocument();
});
});
The menu list is a styled link:
<li>
<HorizontalMenuLink $active={weekdayNumber === 1} to="/classes/monday">
Monday
</HorizontalMenuLink>
</li>

wrapper.setValue() cannot be called on EL-INPUT

I'm trying call a Vue component for unit test with Jest, I want do it set value a input text field. this is my "file.vue"
<el-form-item label="Nombre" data-test="id-form">
<el-input
v-model="data.nombre"
maxlength="45"
#blur="v$.data.nombre.$touch()"
data-test="nombre_caja"
></el-input>
<div v-if="v$.data.nombre.$error" class="text-danger text-xs">
<small
v-for="error in v$.data.nombre.$errors"
:key="error.index"
>{{ error.$message }}</small
>
</div>
</el-form-item>
My test code is
it('Set value',async()=> {
const wrapper = shallowMount(ModalNuevaCaja)
const input = wrapper.find('[data-test="nombre_caja"]')
await input.setValue({nombre:'New value'})
expect(input.element.value).toBe('New Value')
And the error message is:
wrapper.setValue() cannot be called on EL-INPUT
26 | const input = wrapper.find('[data-test="nombre_caja"]')
27 |
> 28 | await input.setValue({nombre:'New value'})
| ^
29 |
30 | expect(input.element.value).toBe('New value')
31 |
I'm new doing this and would appreciate any advice. Thank!!
wrapper.find() returns a DOMWrapper. The setValue() implementation on the DOMWrapper only allows you to use it on input, textarea, 'select`, etc.
You should use findComponent() in order to retrieve a VUEWrapper, on which you can call setValue().
it('Set value', async () => {
const wrapper = shallowMount(ModalNuevaCaja)
const input = wrapper.findComponent('[data-test="nombre_caja"]')
await input.setValue('New value')
expect(input.element.value).toBe('New Value')
})

How to print object value using key as another string

I'm trying to print an objects value by not its own key but a string similar to the key. I somehow got the key match using filter function from the useParams() string, just one more step remaining for my desired output.
import React from 'react';
import { useParams } from 'react-router-dom';
function MoreArticle() {
const feed = {
Fall : 'This is the Detailed description about season of Fall',
Summer : 'This is the Detailed description about season Summer',
Winter : 'This is the Detailed description about season Winter',
Monsoon : 'This is the Detailed description about season Monsoon',
Spring : 'This is the Detailed description about season Spring',
};
const { name } = useParams(); //Summer
const seasons = Object.keys(feed);
return (
<div>
<div>
{seasons.filter(season => {
console.log(feed.season);
return(
season == name && <div>{season}</div> //Returns Summer
//season == name && <div>{feed.season}</div>
//How to return object description 👆🏻
//by using something like this value |
);
})}
</div>
</div>
);
}
export default MoreArticle;
Instead of using feed.season, consider using the bracket notation to target a specific key value pair, like this: feed[name]
import React from 'react';
import { useParams } from 'react-router-dom';
function MoreArticle() {
const feed = {
Fall : 'This is the Detailed description about season of Fall',
Summer : 'This is the Detailed description about season Summer',
Winter : 'This is the Detailed description about season Winter',
Monsoon : 'This is the Detailed description about season Monsoon',
Spring : 'This is the Detailed description about season Spring',
};
const { name } = useParams(); //Summer
return (
<div>{feed[name]}</div>
);
}
export default MoreArticle;
See more here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors

Any workarounds for app.client.setValue in Spectron?

In my tests I fill the input fields (of Ant.Design https://ant.design/components/input/) with app.client.setValue( selector, value ) method. According to https://github.com/electron-userland/spectron it is supposed to be Selenium Webdriver's method. Ans it says here https://webdriver.io/docs/api/element/setValue.html the mehtod overrides the value in input. To me it always acts like addValue (meaning it sends the keys on top of the current value in the input) and I cannot find a workaround.
Resetting the input on the client just before setValue by some reason doesn't work...
async type( selector, value ) {
await this.app.client.execute( ( selector ) => {
const el = document.querySelector( selector );
// When it's INPUT_NUMBER reset is 0
el.setAttribute( "value", el.classList.contains( "ant-input-number-input" ) ? 0 : "" );
}, selector );
return await this.app.client.setValue( selector, value );
}

enzyme mocha AssertionError: expected 0 to equal 21

Writing some unit tests for an app and hitting a wall in the describe block.
/* eslint-env mocha */
const React = require('react')
const chai = require('chai')
const { expect } = chai
const Search = require('../js/Search')
const ShowCard = require('../js/ShowCard')
const enzyme = require('enzyme')
const { shallow } = enzyme
const data = require('../public/data')
describe('<Search />', () => {
it('should render as many shows as there are data for', () => {
const wrapper = shallow(<Search />)
expect(wrapper.find(ShowCard).length).to.equal(data.shows.length)
console.log(wrapper.debug())
})
})
The code in the Search component is rendering ShowCard like this:
<div className='shows'>
{data.shows
.filter((show) => `${show.title} ${show.description}`.toUpperCase().indexOf(this.state.searchTerm.toUpperCase()) >= 0)
.map((show, index) => (
<ShowCard {...show} key={index} id={index} />
))}
</div>
(wrapper.find(ShowCard).length) should equal (data.shows.length), but it's giving this error:
<Search /> should render as many shows as there are data for:
AssertionError: expected 0 to equal 21
+ expected - actual
-0
+21
at Context.<anonymous> (App.spec.js:19:45)
According to the above error, the problem starts at the expectation equal(data.shows.length) but I see nothing wrong with that. Can anyone point me in the right direction?
wow, how embarrassing. i had the state of the Search constructor's input value set to "default search term" - thus preventing any search results from appearing until that string was manually removed from the input.
replacing with an empty string solved the problem. all tests now pass.

Resources