Vue test utils how to change select value with v-model - javascript

Hello I would like to check what happens after changing the value of select inside of the test.I'm using vue-test-utils.
Currently I'm unable to check if the select emitted the input event. I'm using Buefy select component if that matters.
The html part of component
<b-select
v-model="workHoursType"
>
<option :value="WORKING_HOURS_PERIOD.daily">{{daily}}</option>
<option :value="WORKING_HOURS_PERIOD.weekly">{{weekly}}</option>
</b-select>
Test, which is failing due to undefined is emitted
it("once working hours type is set to daily, the hours per week should have no value", async () => {
const wrapper = createWrapper();
const options = wrapper.find("select").findAll("option");
await options.at(1).setSelected();
await flushPromises();
expect(wrapper.emitted().input).toBeDefined();
});
I've seen also different approach for v-model based components however it still doesnt work for me.
it("with v-model", async () => {
const wrapper = createWrapper();
const select = wrapper.find("select");
const option = wrapper.findAll("option").at(0);
option.element.selected = true;
select.trigger("change");
await flushPromises();
expect(wrapper.emitted().input).toBeDefined();
});

Related

Getting results of a MongoDB query to use in a select menu

I'm working on a website that allows you to search for people in a database based on location. Initially, the dropdown menu (select) is populated with provinces that available people are in. I'm trying to use a mongo query to populate that select menu. But when I try to get the values outside the function, it does not work and the select menu turns up empty.
import * as React from "react";
import axios from "axios";
const Locations = () => {
let options = null;
function axiosTest() {
// This is a server link i created that runs a query that returns distinct provinces from the database
const promise = axios.get("/api/v2/people/provinces");
const dataPromise = promise.then(result => result.data).then(data => {console.log(data);return data;});
// The console.log() above displays all the objects that are in the query given by the server link in an array
// e.g. ['British Columbia', 'Alberta', 'Saskatchewan', etc.]
}
var type = axiosTest();
console.log(type); // now it displays it as "undefined"
if (type) {
options = type.map((el) => <option key={el}>{el}</option>);
}
return (
<div
style={{
padding: "16px",
margin: "16px",
}}
>
<form>
<div>
<select>
{
/** This is where we have used our options variable */
options
// and the select menu is shown as blank, because it doesn't have any options to fill it with
}
</select>
</div>
</form>
</div>
);
};
export default Locations;
Can someone please help me get this to work? Is it something to do with Threads and Concurrency? I'm unfortunately rusty at that.
Function axiosTest() does not return anything. You should specify change your code so the function would return the result of DB query. You can also change .then() syntax with async/await so your code would become more readable.
const Locations = async () => {
let options = null;
function axiosTest() {
return axios.get("/api/v2/people/provinces");
}
var type = await axiosTest();
console.log(type);
...
};

Testing form reset on Vue with Jest

Testing a form built with Vue using Jest for unit tests. Among the elements I have a reset button (type=reset), which works fine and once clicked it removes all the values already introduced.
However, when unit testing, the button click doesn't seem to clear the values. I don't have a handler for the click, just using the default reset function of the form.
I've also tried using wrapper.emmited('reset'); to no avail, and wrapper.emmitedByOrder(); returns an empty array.
How do I test that the reset button is generated correctly and works as expected?
test('Assert Form Components', async () => {
const wrapper = mount(FormElement, {
propsData: {
message: sampleJSON.formJSON
}
})
let resetBtn = wrapper.find('.form-reset');
let requiredInput = wrapper.find('.required-input');
....
requiredInput.setValue('test');
expect(requiredInput.element).toHaveValue('test'); //This passes
await resetBtn.trigger('click');
expect(requiredInput.element).not.toHaveValue('test') //This fails
....
Apparently there were two things missing. First, as #AlexMA suggested, allowing for another tick to let the DOM settle. Second, I needed to attach the wrapper to the DOM. The final code look something like this:
test('Assert Form Components', async () => {
const wrapper = mount(FormElement, {
propsData: {
message: sampleJSON.formJSON
},
attachTo: document.body
})
let resetBtn = wrapper.find('.form-reset');
let requiredInput = wrapper.find('.required-input');
....
requiredInput.setValue('test');
expect(requiredInput.element).toHaveValue('test'); //This passes
await resetBtn.trigger('click');
await wrapper.vm.$nextTick()
expect(requiredInput.element).not.toHaveValue('test') //This works now!
....

React Button Reset Filters method to clear out info

I have a todo list fetching this endpoint
I have implemented some filters
Search for title
Toggling the todos completed and not
Multiple select filters for id
I am now implementing the reset filters, which is refetching the todos list, this the method resetFilters
const resetFilters = () => {
const fetchPosts = async () => {
setLoading(true);
const res = await axios.get(
"https://jsonplaceholder.typicode.com/todos/"
);
setIsCompleted(null);
setSearchValue("");
setTasks(res.data);
setFilteredData(res.data);
setLoading(false);
};
fetchPosts();
};
The reset filter method works fine except from not cancelling the text that i have for example put in the search input, switched the toggle back or removing the id number from the Multiple select in the filters column
How can i clear all these infos out in my method resetFilters ?
I have reproduced the demo here
Your input field is uncontrolled. I have edited your demo check it out here.
https://codesandbox.io/s/so-68247206-forked-vffwt?file=/src/App.js
I have added value prop to your SearchInput component so input will be controlled. Let me know if this helps

Async issue with State in React Native

I'm trying to build a simple app that lets the user type a name of a movie in a search bar, and get a list of all the movies related to that name (from an external public API).
I have a problem with the actual state updating.
If a user will type "Star", the list will show just movies with "Sta". So if the user would like to see the actual list of "Star" movies, he'd need to type "Star " (with an extra char to update the previous state).
In other words, the search query is one char behind the State.
How should it be written in React Native?
state = {
query: "",
data: []
};
searchUpdate = e => {
let query = this.state.query;
this.setState({ query: e }, () => {
if (query.length > 2) {
this.searchQuery(query.toLowerCase());
}
});
};
searchQuery = async query => {
try {
const get = await fetch(`${API.URL}/?s=${query}&${API.KEY}`);
const get2 = await get.json();
const data = get2.Search; // .Search is to get the actual array from the json
this.setState({ data });
} catch (err) {
console.log(err);
}
};
You don't have to rely on state for the query, just get the value from the event in the change handler
searchUpdate = e => {
if(e.target.value.length > 2) {
this.searchQuery(e.target.value)
}
};
You could keep state updated as well if you need to in order to maintain the value of the input correctly, but you don't need it for the search.
However, to answer what you're problem is, you are getting the value of state.query from the previous state. The first line of your searchUpdate function is getting the value of your query from the current state, which doesn't yet contain the updated value that triggered the searchUpdate function.
I don't prefer to send api call every change of letters. You should send API just when user stop typing and this can achieved by debounce function from lodash
debounce-lodash
this is the best practise and best for user and server instead of sending 10 requests in long phases
the next thing You get the value from previous state you should do API call after changing state as
const changeStateQuery = query => {
this.setState({query}, () => {
//call api call after already changing state
})
}

How do I place a placeholder inside a select type input?

I'm having a rather weird issue and I just can't seem to figure it out. So I have a form where the user selects which country they're from and I'd like to code in a placeholder to make it look better. I've connected a REST api to fetch all the countries in the world and display them as options.
I've tried the html <option value="" disabled selected>Choose Country...</option> and few other similar ones. I believe it has something to do with the way I coded the javascript to fetch the API but since I'm a novice I'm not too sure.
// set up global variables
const countriesList = document.getElementById("country");
let countries; //contains fetched data list
//establish connection with API
fetch("https://restcountries.eu/rest/v2/all")
.then(res => res.json())
.then(data => initialize(data))
.catch(err => console.log("Error: " + err));
function initialize(countriesData) {
countries = countriesData;
let options = ""; //assign option vriable empty string
// loop each country and assign it to options variable
for(let i=0; i<countries.length; i++){
options += `<option value= "${countries[i].name}"> ${countries[i].name} </option>`;
}
countriesList.innerHTML = options;
}
Above is the javascript I used in order to fetch the api and display it in the drop down select menu, and the issue is that the api replaces every option tag I manually input in the html code. Any suggestions? Cheers!
Just have one option in the select, acting as the placeholder:
<select id=country>
<option value=''>Select...</option>
</select>
Then have the JavaScript append the generated HTML, rather than replace the current HTML.
countriesList.innerHTML += options;
I refactored a smaller setup that may help, too:
const createElements = async () => {
const response = await fetch("https://restcountries.eu/rest/v2/all");
const countries = await response.json();
return countries.map(({ name }) => `<option value=${name}>${name}</option>`);
};
(async () => {
document.getElementById("app").innerHTML = `
<select>
<option>select</option>
${await createElements()}
</select>
`;
})();
<div id="app"/>

Categories