I want to interact with multiple elements like multiple checkboxes radio buttons, buttons etc. I want to store the label/name of the elements into the json file. How can I interact with multiple elements using the name from Json file in testcafe
Take a look at the data-driven test example. It shows how to load data from a JSON file. You can use the loaded data in Selector expressions like Selector('button').withText(data.buttons[0]) to reference elements.
I don't know your particular use case, but speaking purely technically, you can easily do what you're asking:
Resources/names.json:
{
"buttons": [
"First Click",
"Second Click"
],
"checkboxes": [
"Choice1",
"Choice2"
]
}
then I can lod the file in a test file and work with the values:
import { getBaseUrl } from '../Helpers/baseUrl';
import { getEnv } from '../Helpers/env';
import Webelements from '../Objects/webelements'
const baseUrl = getBaseUrl();
const env = getEnv();
const webelements = require('../Resources/names.json');
fixture `Webelements`
.page(baseUrl);
test
('Access Webelements From Json', async t => {
webelements.buttons.forEach((button) => {
console.log(button);
});
webelements.checkboxes.forEach((checkbox) => {
console.log(checkbox)
});
});
this will print the following into the console:
First Click
Second Click
Choice1
Choice2
Another solution could be using classes:
Objects/webelements.js:
class Checkboxes {
constructor () {
this.choices = {
1: "Choice1",
2: "Choice2"
}
}
}
class Buttons {
constructor () {
this.names = ["First Click", "Second Click"]
}
}
class Webelements {
constructor () {
this.checkboxes = new Checkboxes();
this.buttons = new Buttons();
}
}
export default new Webelements();
and use it like this:
test
('Access Webelements From Classes', async t => {
Object.entries(Webelements.checkboxes.choices).forEach(([key, val]) => {
console.log(key + " - " + val);
})
Webelements.buttons.names.forEach((name) => {
console.log(name)
});
});
this will output:
1 - Choice1
2 - Choice2
First Click
Second Click
So, there're options, but the point is that some solutions are better for some situations. I have very little idea about your situation, so you have to make this decision for yourself.
Related
I am trying to use Country/City dropdowns in multiple places of my project, however I am getting stuck with an unusual behaviour - when I am changing the countries. How can I make one request to get the local JSON file and populate multiple dropdowns?
Here is my code:
$(document).ready(function() {
fetch('assets/test.json').then(response => {return response.json()}).then(selectData => {
console.log(selectData)
function updateSelectsBirth() {
let citiesBirth = selectData[this.value].map((key, val) => {
return $("<option />").text(key).val(key);
});
$("#cityBirth, #cityBirth1").empty().append(citiesBirth);
}
let stateBirth;
$countryBirth = $("#countryBirth, #countryBirth1").on("change", updateSelectsBirth);
for (stateBirth in selectData) {
$("<option />").text(stateBirth).val(stateBirth).appendTo($countryBirth);
}
$countryBirth.change();
})
});
And the HTML
<select id="countryBirth"></select>
<select id="cityBirth"></select>
<br/>
<select id="countryBirth1"></select>
<select id="cityBirth1"></select>
Here's also a link to the demo project: link to the demo
The unexpected behaviour comes from
$("#cityBirth, #cityBirth1").empty().append(citiesBirth);
Because, when it's updating the cities, it's updating all the dropdowns instead of just one.
So you can try:
$(document).ready(function() {
fetch('assets/test.json').then(response => {return response.json()}).then(selectData => {
// console.log(selectData)
function updateSelectsBirth(event) {
let citiesBirth = selectData[this.value].map((key, val) => {
return $("<option />").text(key).val(key);
});
// console.log(event.data.target)
$(event.data.target).empty().append(citiesBirth);
}
let stateBirth;
$countryBirth = $("#countryBirth").on("change", {target: "#cityBirth"}, updateSelectsBirth);
$countryBirth1 = $("#countryBirth1").on("change", {target: "#cityBirth1"}, updateSelectsBirth);
// $countryBirth1 = $("#countryBirth1").on("change", updateSelectsBirth("#cityBirth1"));
for (stateBirth in selectData) {
$("<option />").text(stateBirth).val(stateBirth).appendTo($countryBirth);
$("<option />").text(stateBirth).val(stateBirth).appendTo($countryBirth1);
}
$countryBirth.change();
$countryBirth1.change();
})
});
I apologize this is not a complete answer, as I'm not generalizing to multiple dropdowns, however I am not able to leave comments yet. I hope this can still be helpful.
I'm working in vue/quasar application.
I've my mixin like this in my view.cshtml
var mixin1 = {
data: function () {
return { data1:0,data2:'' }
}
,
beforeCreate: async function () {
...}
},
methods: {
addformulaire(url) {
},
Kilometrique() { }
}
}
And I want merge with my content in js file (it's to centralize same action an severals cshtml)
const nomeMixins = {
data: function () {
return { loadingcdt: false, lstclt: [], filterclient: [], loadingdoc: false, lstdoc: [], filterdoc: [] }
},
computed: {
libmntpiece(v) { return "toto"; }
},
methods: {
findinfcomplemtX3(cdecltx3, cdedocx3) {
},
preremplissagex3: async function (cdecltx3, cdedocx3) {
}
}
}
};
I want merge this 2 miwin in one. But when I try assign or var mixin = { ...mixin1, ...nomeMixins };
I've only mixin1 nothing about methods,data from my js file nomeMixins but merging failed cause I've same key in my json object. I'm trying to make a foreach but failed too
Someone try to merge to mixin / json object with same key in the case you've no double child property ?
You cant merge mixins in that way. the spread syntax will overwrite keys e.g data, computed, methods etc and final result will not be suitable for your purpose.
refer documentation for adding mixins in your component. Also note that You can easily add multiple mixins in any component, so I don't think combination of two mixins will be any useful.
UPDATE
reply to YannickIngenierie answer and pointing out mistakes in this article
Global Mixins are not declared like this
// not global mixin; on contrary MyMixin is local
// and only available in one component.
new Vue({
el: '#demo',
mixins: [MyMixin]
});
Local Mixins are not declared like this
// NOT local mixin; on contrary its global Mixin
// and available to all components
const DataLoader = Vue.mixin({....}}
Vue.component("article-card", {
mixins: [DataLoader], // no need of this
template: "#article-card-template",
created() {
this.load("https://jsonplaceholder.typicode.com/posts/1")
}
});
Point is refer documentation first before reading any article written by some random guy, including me. Do slight comparison what he is saying whats in documentation.
After working and searching... I find this one And understand that I can add directly mixin in my compoment (don't laught I'm begging with vue few months ago)
my custommiwin.js
const DataLoader = Vue.mixin({
data: function () {
return { loadingcdt: false, lstclt: [], filterclient: [], loadingdoc: false, lstdoc: [], filterdoc: [] }
},
methods: {
filterClt: async function (val, update, abort) {
if (val.length < 3) { abort(); return; }
else {//recherche
this.loadingcdt = true;
let res = await axios...
this.loadingcdt = false;
}
update(() => {
const needle = val.toLowerCase();
this.filterclient = this.lstclt.filter(v => v.libelle.toLowerCase().indexOf(needle) > -1 || v.id.toLowerCase().indexOf(needle) > -1);
})
},
filterDocument: async function (val, update, abort, cdecltx3) {
if (!cdecltx3 || val.length < 3) { abort(); return; }
else {//recherche
this.loadingdoc = true;
let res = await axios({ ...) }
this.loadingdoc = false;
}
update(() => {
const needle = val.toLowerCase();
this.filterdoc = this.lstdoc.filter(v => v.id.toLowerCase().indexOf(needle) > -1);
})
},
}
});
and in my compoment.js I add this
mixins: [DataLoader],
I include all my js file in my cshtml file
I'm working on a small project and I am trying to map data from a JSON file into my project.
In components with nested data, I keep getting an let data = props.data["runways"];.
data.json:
{
"runways":[
{
"slot":"Area 1",
"planes":[
{
"name":"PanAm",
"number":"12345",
"start":{
"time":1585129140
},
"end":{
"time":1585130100
}
},
{
"name":"PanAm 222 ",
"number":"12345",
"start":{
"time":1585129140
},
"end":{
"time":1585130100
}
}
]
}
]
}
App.js,
I pass the JSON data as props:
import planeData from './plane_info.json'
const Container = () => {
const [planeDataState, setPlaneDataState] = useState({})
const planeData = () => setPlaneDataState(planeData[0].runways)
return (
<>
<MyPlane planeInfo={planeDataState}/>
<button onClick={planeData} type="button">Get Data</button>
</>
)
}
and finally, I want to bring my data into my component:
MyPlane.jsx
const MyPlane = (props) => {
let data = props.data["runways"];
if(data)
console.log(data, 'aaa')
return (
<>
{
data ? (
<div>
<span>{props.planeInfo.name}</span>
<span>RAIL TYPE: {props.planeInfo.type}</span>
</div>
) : <h6>Empty</h6>
}
</>
);
}
According to the error message, the problem occurs at this line of code: let data = props.data["runways"]; However, I believe that I am passing the data for runways from the JSON file.
I've never worked with React Hooks to pass data, so I'm confused about why this error is occurring.
In order to map effectively over the JSON data it's necessary to understand how that data structure is composed.
If you're unsure, using JSON.stringify() is a great way to get the "bigger picture" and then decide what exactly is it that you want to display or pass down as props to other components.
It appears you wish to get the plane data (which is currently an array of 2 planes). If so, you could first get that array, set the state, then map over it to display relevant info. Perhaps like this:
const data = {
"runways":[
{
"slot":"Area 1",
"planes":[
{
"name":"PanAm",
"number":"12345",
"start":{
"time":1585129140
},
"end":{
"time":1585130100
}
},
{
"name":"PanAm 222 ",
"number":"12345",
"start":{
"time":1585129140
},
"end":{
"time":1585130100
}
}
]
}
]
}
function App() {
const [ planeData, setPlaneData ] = React.useState(null)
React.useEffect(() => {
setPlaneData(data.runways[0].planes)
}, [])
return (
<div className="App">
{/* {JSON.stringify(planeData)} */}
{planeData && planeData.map(p => (
<p key={p.name}>
{p.name} | {p.number} | {p.start.time} | {p.end.time}
</p>
))}
</div>
)
}
ReactDOM.render(<App />, document.getElementById('root'))
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root"></div>
Here const planeData = () => setPlaneDataState(planeData[0].runways)
In this line, planeData[0].runways will be undefined according to the json file which you have shared.
Instead try setting and passing entire json object, ie,
const planeData = () => setPlaneDataState(planeData)
Try this, And then inside MyPlane.jsx component, let data = props.data["runways"]; this won't be undefined. So , the error won't come.
At the beginning there is no data in props.data['runways'] (also you can use props.data.runways, I guess you come from another language like Python as of this syntax that you are using), because you sent the request at first, it takes time for request to be satisfied, so you need to check in your <MyPlane /> component to see if there is a runways key in data and then proceed to render the component, something like below:
const MyPlane = (props) => {
const data = props.data
return (
<>
{
data.runways
? <>
...your render able items that you wrote before
</>
: <p>There is no data yet!</p>
}
</>
)
}
Also please note that you might return something from component. At your case your render is inside the if(data){...} statement! what if the condition was not satisfied? which is your current error case !
NOTE: please check that you are passing your planeDataState as planeInfo prop to the child component, so you might have something like:
const data = props.planInfo
to be able to use the data variable that you've defined before the render part.
I'm trying to save an array to local-storage in my react app, so that if the user goes to another page in the app, or closes the app and reopens it, the value stays the same.
In my index.js (simplified code):
import ls from 'local-storage';
function HomeIndex() {
const [testString, setTestString] = useState(ls('localStorageText') || '');
if(condition){
const array = [1,2,3];
const saveArray = {key: array};
localStorage.setItem('key1', JSON.stringify(saveArray));
const restoreValue = localStorage.getItem('key1');
setTestString(JSON.parse(restoreValue).key);
}
return (
<div className="col-12">
{testString}
</div>
);
}
When I press the button, and the condition is met, the testString value displays 123 as it should. And it holds the value. However it does not work when I try and add my own array.
const array = reversedHistoryText;
const saveArray = {key: array};
localStorage.setItem('key1', JSON.stringify(saveArray));
const restoreValue = localStorage.getItem('key1');
setTestString(JSON.parse(restoreValue).key);
It doesn't display anything the first time the button is clicked, then gives error on the 2nd time:
Error: Minified React error #31;
When I do this test:
setTestString(JSON.stringify(reversedHistoryText));
The result is []
You need to set your testString to the localStorage value.
import ls from "local-storage";
import React, { useEffect, useState } from "react";
function MyComponent() {
const [testArray, setTestArray] = useState([]);
useEffect(() => {
setTestArray(ls("testArray") || []);
}, []);
function handleClick(e) {
ls("testArray", [
{ id: 1, name: "this" },
{ id: 2, name: "thing" },
{ id: 3, name: "is" },
{ id: 4, name: "cool" }
]);
setTestArray(ls("testArray"));
}
return (
<div className="col-12">
<ul>
{testArray.map(obj => (
<p key={obj.id}>{obj.name}</p>
))}
</ul>
<button onClick={handleClick}>Set The State</button>
</div>
);
}
export default MyComponent;
You don't need to use third party for localStorage.
Just use localStorage without importing anything.
To save,
localStorage.setItem('key', 'value');
To get value from localStorage,
localStorage.getItem('key') // value
To remove value,
localStorage.removeItem('key')
Use
if(condition) ls('localStorageText', "TEST");
setTestString(ls('localStorageText')|| ' '); }
Instead
if(condition){ ls('localStorageText', "TEST");
setTestString(ls('localStorageText')); }
Because when you go back to the index page a new instance of this component is rendered and i think the condition in the if statement is false, so the code don't change the setstate value...
To set use
localStorage.setItem('itemName', JSON.stringify(arrayName));
To get use
whatEver = jQuery.parseJSON(localStorage.getItem('itemName'));
Local storage stores strings
I've just started using feathers to build REST server. I need your help for querying tips. Document says
When used via REST URLs all query values are strings. Depending on the service the values in params.query might have to be converted to the right type in a before hook. (https://docs.feathersjs.com/api/databases/querying.html)
, which puzzles me. find({query: {value: 1} }) does mean value === "1" not value === 1 ? Here is example client side code which puzzles me:
const feathers = require('#feathersjs/feathers')
const fetch = require('node-fetch')
const restCli = require('#feathersjs/rest-client')
const rest = restCli('http://localhost:8888')
const app = feathers().configure(rest.fetch(fetch))
async function main () {
const Items = app.service('myitems')
await Items.create( {name:'one', value:1} )
//works fine. returns [ { name: 'one', value: 1, id: 0 } ]
console.log(await Items.find({query:{ name:"one" }}))
//wow! no data returned. []
console.log(await Items.find({query:{ value:1 }})) // []
}
main()
Server side code is here:
const express = require('#feathersjs/express')
const feathers = require('#feathersjs/feathers')
const memory = require('feathers-memory')
const app = express(feathers())
.configure(express.rest())
.use(express.json())
.use(express.errorHandler())
.use('myitems', memory())
app.listen(8888)
.on('listening',()=>console.log('listen on 8888'))
I've made hooks, which works all fine but it is too tidious and I think I missed something. Any ideas?
Hook code:
app.service('myitems').hooks({
before: { find: async (context) => {
const value = context.params.query.value
if (value) context.params.query.value = parseInt(value)
return context
}
}
})
This behaviour depends on the database and ORM you are using. Some that have a schema (like feathers-mongoose, feathers-sequelize and feathers-knex), will convert values like that automatically.
Feathers itself does not know about your data format and most adapters (like the feathers-memory you are using here) do a strict comparison so they will have to be converted. The usual way to deal with this is to create some reusable hooks (instead of one for each field) like this:
const queryToNumber = (...fields) => {
return context => {
const { params: { query = {} } } = context;
fields.forEach(field => {
const value = query[field];
if(value) {
query[field] = parseInt(value, 10)
}
});
}
}
app.service('myitems').hooks({
before: {
find: [
queryToNumber('age', 'value')
]
}
});
Or using something like JSON schema e.g. through the validateSchema common hook.