can't access value from inside then to outside then Promise - angular6

I'm trying to get value from inside to outside then using promise.
In my controller I have:
async Sample(userId: number)
{
let data = this.userService.getAffectedExpertisesPromise(userId);
await data.then((uri) =>
{
uri.forEach((exp: Expertise) =>
{
this.empList.push(exp.name);
});
})
return this.empList;
}
On ngOnInit, I call this function:
this.Sample(25).then(item =>
{
item.forEach((expLibelle: String) =>
{
listExp.push(expLibelle);
});
console.log("------------------------ List Size Inside: " + listExp.length);
});
console.log("------------------------ List Size Outside : " + listExp.length);
In service user file, I have:
getAffectedExpertisesPromise(id: number): Promise<any>
{
return this.http.get(`${this.baseUrl}/users/expertisesObj/${id}`).toPromise();
}
It produces:
------------------------ List Size Outside : 0
------------------------ List Size Inside: 3
As you saw:
the size inside then is 3 --> Correct answer
the size inside then is 0 --> Wrong answer
Could you please help me solving that issue ?.
Big thanks.

Why not trying using XMLHttpRequest.
var request = new XMLHttpRequest();
request.open('GET', 'http://localhost:6227/api/auth/users', false);
request.send(null);
HTH.

Related

How to make sure document is ready before calling getElementById() in Typescript

I have a component that loads some HTML (converted from MD via marked library) and diplays it to the page and if a row is clicked, the document will scroll to the appropriate HTML element with the matching headerID on the page.
import { marked } from 'marked';
const [content, setContent] = React.useState('');
React.useEffect(() => {
if (!source) {
return;
}
getRequest(source)
.then(response => {
if (!response.ok) {
return Promise.reject(response);
}
return response.text().then(faq => {
// sets page to html
setContent(marked(faq));
const nearestHeader = document.getElementById(headerID);
if (nearestHeader) {
// if search result is clicked, jump to result's nearest header
nearestHeader.scrollIntoView(true);
setRowClicked(false);
}
});
})
.catch(e => Dialog.error('Failed to load page.', e));
}, [source, rowClicked]);
However, when I go to test this code the 'nearestHeader' object is always null even after I verified that the headerID matches up with the existing HTML element's ID I want to navigate to. How can I make sure document is ready/loaded before attemping the getElementById call without using extra libraries?
Solved by adding another useEffect call which waits on content of page to be set first. Removed nearestHeader code from the initial useEffect() call that sets content
React.useEffect(() => {
const nearestHeader = document.getElementById(headerID);
if (nearestHeader) {
nearestHeader.scrollIntoView(true);
setRowClicked(false);
}
}, [content]);

Retrieve a request using the requestId after the response is received in Firefox extension

I am writing a Firefox extension using the WebRequest. I am in a situation that when I receive the response, I want to look back and find the request associated with this response to retrieve a custom request header. My current code is like this:
browser.webRequest.onBeforeSendHeaders.addListener(
addCustomHeader, // here I add custom_header:value
{urls: ["<all_urls>"]},
["blocking", "requestHeaders"]
);
...
browser.webRequest.onHeadersReceived.addListener(
process_response, // here I want to get back to the request and retrieve the custom header value
{urls: ["<all_urls>"]},
["blocking", "responseHeaders"]
);
The value of custom_header is set as a global variable, which changes per each request. And when I receive the response of, say, request_1, I want to retrieve the header value from request_1 in the process_response() function. However, if I directly use the value, I found it may have been changed by subsequent requests, say request_2 or request_3.
I noticed the response has a requestId property, and I guess I can use it to find the corresponding request. However, I am not able to find any document or example that tells me how. I'd appreciate for any hint!
Use a global map variable:
const reqMap = (() => {
const data = new Map();
const MAX_AGE = 10 * 60e3; // 10 minutes
const cleanup = () => {
const cutOff = performance.now() - MAX_AGE;
data.forEach(({ time }, id) => time < cutOff && data.delete(id));
};
return {
set(id, value) {
cleanup();
data.set(id, {value, time: performance.now()});
},
pop(id) {
const {value} = data.get(id) || {};
data.delete(id);
return value;
},
};
})();
function onBeforeSendHeaders(details) {
reqMap.set(details.requestId, {any: 'data'});
}
function onHeadersReceived(details) {
const data = reqMap.pop(details.requestId);
if (data) {
// ............
}
}

Display one value pair from JSON object

I'll preface this saying I'm a UX Designer that's new to React.
I'm using Expo/React-Native and using the "Location" feature to get the device's location information. I'm able to get the information back in a JSON object by using:
const { height, width } = Dimensions.get("window");
class Explore extends Component {
static navigationOptions = {
header: null
};
state = {
locationResult: ""
};
componentDidMount() {
this._getLocationAsync();
}
_getLocationAsync = async () => {
let { status } = await Permissions.askAsync(Permissions.LOCATION);
if (status !== "granted") {
this.setState({
locationResult: "Permission to access location was denied"
});
}
let location = await Location.getCurrentPositionAsync({});
let geocode = await Location.reverseGeocodeAsync(location.coords);
this.setState({ locationResult: JSON.stringify(geocode) });
};
And in my render I'm calling the value using:
<WelcomeText>
Discover {this.state.locationResult}
</WelcomeText>
Which returns the object:
[{"street":"Stockton St","city":"San Francisco","region":"CA","country":"United States","postalCode":"94108","isoCountryCode":"US","name":"1 Stockton St"}]
But how do I go about just displaying the value of "City" that's in the object?
Try this:
<WelcomeText>
Discover {this.state.locationResult[0].city}
</WelcomeText>
Explanation:
Your this.state.locationResult is an array of objects. With this.state.locationResult[0] we are accessing the first object. Then we can use the . operator to access the property we want. In your case .city
Edit:
You need to pass in geocode without stringifying it, otherwise you cannot access it like i described it above. reverseGeocodeAsync is already returning an array of objects, no need to transform it to a string.
Replace:
this.setState({ locationResult: JSON.stringify(geocode) });
with:
this.setState({ locationResult: geocode });
Edit2:
Here is a working example: https://snack.expo.io/B1SqSd3iN

How to get element text/value/innertext using Nightwatch?

I have 10 elements with the same class ('botaoParametroAc') and I would like to check one by one and use a click on element that contains "id" as text. This is my code right now:
browser
.waitForElementVisible('#txtBusca', 4000)
.elements('class name', 'botaoParametroAc', function(res) {
for(var item in res.value){
console.log(item.text)
}
});
It is returning "undefined" for each item.
When I try to print res.value, it is the result:
{"ELEMENT":"0.06577812833436414-2"}
{"ELEMENT":"0.06577812833436414-3"}
{"ELEMENT":"0.06577812833436414-4"}
{"ELEMENT":"0.06577812833436414-5"}
{"ELEMENT":"0.06577812833436414-6"}
{"ELEMENT":"0.06577812833436414-7"}
{"ELEMENT":"0.06577812833436414-8"}
{"ELEMENT":"0.06577812833436414-9"}
{"ELEMENT":"0.06577812833436414-10"}
How can I get the text or attributes of each element?!
Just to update, it is working right now. I needed to get the elementIdAttribute for each element getting innerText to discover it and click on it when condition matches.
browser
.waitForElementVisible('#txtBusca', 4000)
.elements('class name', 'botaoParametroAc', function(result) {
result.value.map(function(element, err) {
browser.elementIdAttribute(element.ELEMENT, 'innerText', function(res) {
if (res.value == 'id') {
browser.elementIdClick(element.ELEMENT);
}
})
})
})
For me, using elements + elementIdAttribute wasn't working well.
What I did instead was use execute():
'Verify table summary': function (browser) {
browser.execute(function (data) {
var innerTotal = 0;
document.querySelectorAll('.cell-with-number')
.forEach(a => innerTotal += Number(a.innerText));
return innerTotal;
}, [], function(res) {
total = res.value;
});
The var total will have the value returned from the script run in the contex of the browser.
As of the current nightwatch version (1.7.6) it seems like the simplest way to do this in a way that is compatible with both Chromedriver and Geckodriver is with getElementProperty:
browser.getElementProperty('#thisElementId .some-class-name', 'innerText',
function(result) {
console.log('result', result);
}
);

Asynchronously working of for loop in protractor

when i execute the following code using protractor it works. I am passing nested json to for loop. Because of asynchronously working of for loop it print all values of variable i and reaches to last value because of this it always access last pair of username and password. How can i solve this issue?
var data = require('.../testdata.json');
describe('homepage Test', function() {
it('candidate login', function() {
browser.driver.get('https://abcxyz.com');
for (i in data.testdata) {
element(by.id('tool_btn3')).click();
console.log(i);
browser.getTitle().then(function(title) {
console.log("Title: " + title)
if (title === "<page title>") {
browser.driver.sleep(3000);
element(by.id('email_input')).sendKeys(data.testdata[i].username);
element(by.id('pwd_input')).sendKeys(data.testdata[i].password);
element(by.xpath('//*[#id="signIn_btn"]/div[2]')).click();
browser.sleep(3000);
element(by.id('setting_img')).click();
browser.sleep(2000);
element(by.id('logout_div')).click().then(function() {
console.log('success');
});
} else {
console.log("problem");
}
});
}
});
});
You need to keep in mind that you can't use a for-loop with promises. All is async so in the end it will bite you in the ass, meaning that the it is ready but the test isn't.
Based on you example it would suggest to make a method called for example logon (place it in a Page Object or something). It will do the logon and stuff for you. Add an empty promise-container (array) and push the promises in there.
When the for-loop is done you can resolve the complete promise-container at once and it will execute all the promises 1 after each other. It will look something like this.
var data = require('.../testdata.json');
describe('homepage Test', function() {
it('candidate login', function() {
var promises = [];
browser.driver.get('https://abcxyz.com');
for (i in data.testdata) {
promises.push(expect(logon(data.testdata[i].username, data.testdata[i].password)).to.equal(true));
promises.push(console.log(i));
}
Promise.all(promises);
});
});
/**
* Logon
* #params {string} username
* #params {string} password
* #return {boolean}
*/
function logon(username, password) {
element(by.id('tool_btn3')).click();\
return browser.getTitle().then(function(title) {
console.log("Title: " + title)
if (title === "<page title>") {
browser.driver.sleep(3000);
element(by.id('email_input')).sendKeys(username);
element(by.id('pwd_input')).sendKeys(password);
element(by.xpath('//*[#id="signIn_btn"]/div[2]')).click();
browser.sleep(3000);
element(by.id('setting_img')).click();
browser.sleep(2000);
return element(by.id('logout_div')).click()
.then(function() {
return Promise.resolve(true);
});
} else {
return Promise.resolve(false);
}
});
}
If you are using for example Node 7 you can use async/await, or use Babel to transpile the code. If you can write TypeScript you also get the async/await