I'm new to Flow and am having a bit of trouble assigning to DOM Element types properly.
Looking at the DOM declarations in the Flow repo, it feels like I'm missing something.
// Works
const otherMeta:?HTMLMetaElement = document.querySelector("meta");
//Doesn't work
const metaTag:?HTMLMetaElement = document.querySelector("meta[name='something']");
The second example results in the following error:
const metaTag:?HTMLMetaElement = document.querySelector("meta[name='something']");
^ HTMLElement. This type is incompatible with
const metaTag:?HTMLMetaElement = document.querySelector("meta[name='something']");
^ HTMLMetaElement
Have a look at the example in the Try Flow REPL tool.
Flow is not smart enough to know what the return type will be for an arbitrary querySelector query. The simple element-name queries have been hard-coded into the builtin type definitions. You can see them in Flow's Github repo.
For Flow to know that the result is an HTMLMetaElement, you'll need to explicitly verify that with code like
const metaTag: ?HTMLElement = document.querySelector("meta[name='something']");
if (metaTag && !(metaTag instanceof HTMLMetaElement)) throw new Error("Expected a 'meta' element.");
// use metaTag here
so by explicitly checking instanceof, Flow will recognize that metaTag must now be the type HTMLMetaElement. This type of behavior is very common in Flowtype and is referred to as refining the type.
Related
I'm trying to execute javascript on QQuickWebEngineView object in c++ and get returned value. In QML it's easy
view.runJavaScript("document.documentElement.outerHTML", function(result){//do smth})
in c++ method signature for executing js is this:
void runJavaScript(const QString&, const QJSValue & = QJSValue());
and I believe I could use QJSValue to get returned data, but I'm not finding anything on how to use it... maybe someone has an example of how to use QJSValue here. Thanks.
Why does calling fake.Provide<T>() wipe out fakes already configured with A.CallTo()? Is this a bug?
I'm trying to understand a problem I've run into with Autofac.Extras.FakeItEasy (aka AutoFake). I have a partial solution, but I don't understand why my original code doesn't work. The original code is complicated, so I've spent some time simplifying it for the purposes of this question.
Why does this test fail? (working DotNetFiddle)
public interface IStringService { string GetString(); }
public static void ACallTo_before_Provide()
{
using (var fake = new AutoFake())
{
A.CallTo(() => fake.Resolve<IStringService>().GetString())
.Returns("Test string");
fake.Provide(new StringBuilder());
var stringService = fake.Resolve<IStringService>();
string result = stringService.GetString();
// FAILS. The result should be "Test string",
// but instead it's an empty string.
Console.WriteLine($"ACallTo_before_Provide(): result = \"{result}\"");
}
}
If I swap the order of the calls to fake.Provide<T>() and A.CallTo(), it works:
public static void Provide_before_ACallTo()
{
// Same code as above, but with the calls to
// fake.Provide<T>() and A.CallTo() swapped
using (var fake = new AutoFake())
{
fake.Provide(new StringBuilder());
A.CallTo(() => fake.Resolve<IStringService>().GetString())
.Returns("Test string");
var stringService = fake.Resolve<IStringService>();
string result = stringService.GetString();
// SUCCESS. The result is "Test string" as expected
Console.WriteLine($"Provide_before_ACallTo(): result = \"{result}\"");
}
}
I know what is happening, sort of, but I'm not sure if it's intentional behavior or if it's a bug.
What is happening is, the call to fake.Provide<T>() is causing anything configured with A.CallTo() to be lost. As long as I always call A.CallTo() after fake.Provide<T>(), everything works fine.
But I don't understand why this should be.
I can't find anything in the documentation stating that A.CallTo() cannot be called before Provide<T>().
Likewise, I can't find anything suggesting Provide<T>() cannot be used with A.CallTo().
It seems the order in which you configure unrelated dependencies shouldn't matter.
Is this a bug? Or is this the expected behavior? If this is the expected behavior, can someone explain why it works like this?
It isn't that the Fake's configuration is being changed. In the first test, Resolve is returning different Fakes each time it's called. (Check them for reference equality; I did.)
Provide creates a new scope and pushes it on a stack. The topmost scope is used by Resolve when it finds an object to return. I think this is why you're getting different Fakes in ACallTo_before_Provide.
Is this a bug? Or is this the expected behavior? If this is the expected behavior, can someone explain why it works like this?
It's not clear to me. I'm not an Autofac user, and don't understand why an additional scope is introduced by Provide. The stacked scope behaviour was introduced in PR 18. Perhaps the author can explain why.
In the meantime, if possible, I'd Provide all you need to before Resolveing, if you can manage it.
I have added a custom locator in protractor, below is the code
const customLocaterFunc = function (locater: string, parentElement?: Element, rootSelector?: any) {
var using = parentElement || (rootSelector && document.querySelector(rootSelector)) || document;
return using.querySelector("[custom-locater='" + locater + "']");
}
by.addLocator('customLocater', customLocaterFunc);
And then, I have configured it inside protractor.conf.js file, in onPrepare method like this:
...
onPrepare() {
require('./path-to-above-file/');
...
}
...
When I run my tests on the localhost, using browser.get('http://localhost:4200/login'), the custom locator function works absolutely fine. But when I use browser.get('http://11.15.10.111/login'), the same code fails to locate the element.
Please note, that the test runs, the browser gets open, user input gets provided, the user gets logged-in successfully as well, but the element which is referred via this custom locator is not found.
FYI, 11.15.10.111 is the remote machine (a virtual machine) where the application is deployed. So, in short the custom locator works as expected on localhost, but fails on production.
Not an answer, but something you'll want to consider.
I remember adding this custom locator, and encounter some problems with it and realised it's just an attribute name... nothing fancy, so I thought it's actually much faster to write
let elem = $('[custom-locator="locator"]')
which is equivalent to
let elem = element(by.css('[custom-locator="locator"]'))
than
let elem = element(by.customLocator('locator'))
And I gave up on this idea. So maybe you'll want to go this way too
I was able to find a solution to this problem, I used data- prefix for the custom attribute in the HTML. Using which I can find that custom attribute on the production build as well.
This is an HTML5 principle to prepend data- for any custom attribute.
Apart from this, another mistake that I was doing, is with the selector's name. In my code, the selector name is in camelCase (loginBtn), but in the production build, it was replaced with loginbtn (all small case), that's why my custom locater was not able to find it on the production build.
I am new to Katalon Studio and I am facing an issue regarding selection of the drop down.
Please find below the details:
This is the HTML :
I have tried using selectByIndex with the object xpath as:
//div[#class='paCriteriaContainer']//select[#class = 'pa-criteria-select a-select initialized']
It does not select any option and fails with an error stating "Unable to select option by index '2' of object"
Note:
I tried clicking on the input and then selecting the option, but that doesn't seem to work either.
Selecting by label and value don't work either
Please help me here.
Thank you
Try to capture an object and then use following methods :
WebUI.click(findTestObject(Your captured object))
WebUI.selectOptionByValue(findTestObject(Your captured object), 'TEST (2020)', false)
Did you done as I've described and it does not work ?
I tried clicking on the input and then selecting the option, but that doesn't seem to work either.
Are you sure you are clicking the right element in this case?
Try the following instead: create programmatically the element and select by value (note, value isn't the text contained, it is the value html attribute):
TestObject to = new TestObject().addProperty("xpath", ConditionType.EQUALS, "//div[#class='paCriteriaContainer']//select[#class = 'pa-criteria-select a-select initialized']")
WebUI.selectOptionByValue(to, '40696', false)
You have some options to do that, I reggardly suggest you that use always the xpath to reach all the elements that you want to use. The reasson is because the object reports usually fail and, in my opinion, this way is so much more complicated.
But obviously, the xpath will change if the web do, so take care with it.
The imports you need:
import static org.junit.Assert.*
import org.openqa.selenium.By
import org.openqa.selenium.Keys
import com.kms.katalon.core.webui.driver.DriverFactory as DriverFactory
def driver = DriverFactory.getWebDriver()
//If you want to click your input would be:
WebUI.click(WebUI.convertWebElementToTestObject(driver.findElement(By.xpath("(//input[#id='a-select-paCricteriaId_6908'])"))))
//**you just can click on "TestObject" type, and findElement returns "Element" type**
And if you want to select the option you need to know the whole path (I cannot get it with the given information).
An important tip for testing the xpath is to use this function in console mode (F12):
function getElementByXpath(path) {
return document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
}
//And this code in the same console to test your xpath:
getElementByXpath("YOURTESTXPATH")
Furthermore, there are other ways to reach the same objetive with xpath, for example:
import com.kms.katalon.core.testobject.TestObject as TestObject
...
TestObject tobj = new TestObject('myTestObject')
String expr = '/some/valid/xpath/expression'
tobj.addProperty('xpath', ConditionType.EQUALS, expr)
WebUI.click(tobj)
You have a lot of information if you google "how to get elements by xpath katalon".
Here you can get official information about it:
https://docs.katalon.com/katalon-studio/tutorials/detect_elements_xpath.html#what-is-xpath
Test in the browser console
$x('//*[contains(#class, "pa-criteria-select a-select initialized")]')
if more than one result appear then you can access it like this
$x('(//*[contains(#class, "pa-criteria-select a-select initialized")])[1]')
then you can also access their children
$x('(//*[contains(#class, "pa-criteria-select a-select initialized")])[1]/option')
Use WebUI.selectOptionByIndex keyword but the object should point to the select tag instead of the div.
Update the object element and your code should work
I've read lots of discussions on here about how to setup VSCode to allow linting of Javascript files when // #flow is enabled at the top of the file.
I believe I've implemented things properly but am still getting mysterious errors that seem to indicate otherwise.
For example, I'm getting a Missing type annotation for destructuring.Flow(InferError) for classes here:
const AddCustomer = ({ classes }) => {
So I changed it to this:
const AddCustomer = ({ classes:any }) => {
but the error persisted.
Here is another observation of the way things are working in my VSCode at the moment:
export const useFetch = (initialUrl, initialData) => {
With this code I get warnings that the two parameters are not typed. So I changed the code to this:
export const useFetch = (initialUrl:string, initialData:any) => {
Nothing happened immediately but when I saved the file then the warnings went away. Not a biggie but that's not the way I expect linters to work.
Might anyone have any thoughts on why #flow linting is not quite working correctly in my VSCode?
So, for the first issue regarding Missing type annotation for destructuring.Flow(InferError), I believe the type is placed in the wrong place. The syntax ({ classes: any }) is renaming the classes property on the first parameter to any. A more thorough explanation can be read in MDN's page Destructuring assignment. To correctly specify the type of the object parameter, you will want to place the type definition after the object
const addCustomer = ({ classes }: { classes: any }) => { ... };
This may feel verbose and repetitive, but the idea is to separate the code from the types. For example, the type definition of a customer may be imported from another file, so the code would look more like
// types.js
export type Customer = { classes: any };
// index.js
import type { Customer } from './types';
const addCustomer = ({ classes }: Customer) => { ... };
This allows the parameter to be specified in any way (e.g., without destructuring) and the type to be specified in any way.
For your second issue, check to make sure that the setting flow.runOnEdit is set to true. This will allow Flow to check your files without saving. If that does not seem to fix the problem, then I would raise an issue with the maintainers of the VSCode extension.