We are using uiveri5 for testing our application. Our scenario is this,
- Create a plan in first application
- Go to second application with created plan id using application navigation functionlity.
- Make some steps there, upadte the plan
- Return to first application, maintain data in second application will be available in first application.
Issue :
When we create a plan and go to second application with new plan id, the controls of second appliation are not identified.
browser.wait(()=>{
browser.getCurrentUrl().then((url)=>{
publicUrl = url;
browser.get(url);
});
});
Our code to redirect to second application
sap.m.URLHelper.redirect(url);
Expectation FAILED: Failed: No element found using locator:
by.control({"searchOpenDialogs":true,"controlType":"sap.m.Button",
"bindingPath":{"path":"/actionMenu"}})
The problem is that the redirection creates a new JS context e.g. reloads the JavaScript VM. And in this new context, you don't have the uiveri5 helper scripts that implements the synchronization and control locators (by.control()).
We have some guidelines how to implement such workflow here: https://github.com/SAP/ui5-uiveri5/blob/master/docs/usage/browser.md
Related
I have a scenario which is a series of rest api calls but in the middle is a section that executes a few steps within a chrome browser. The browser steps are common to another scenario so I tried to extract the browser steps into a separate feature that could then be called from multiple scenarios.
When the main scenario executes it executes the browser feature but fails to auto-close the browser after execution. I read in the documentation "Karate will close the browser automatically after a Scenario unless the driver instance was created before entering the Scenario" . The configure driver code is in the callable scenario.
I also tried caling quit() but this resulted in the error: "The forked VM terminated without properly saying goodbye. VM crash or System.exit called?"
Does anyone know how I can ensure the browser closes in this circumstance?
UPDATE: As suggested by #PeterThomas I started to craft a full example to replicate this when I discovered that to replicate is actually quite simple.
If the UI feature is called like this then the browser is closed after execution:
* call read('classpath:/ui/callable/GoogleSearch.feature')
If called like this then the browser remains open:
* def result = call read('classpath:/ui/callable/GoogleSearch.feature')
My UI scenario scrapes a value from a web page which I then stored within a '* def ticket' within the called feature. I was hoping to access it via result.ticket. As I am unable to do this I am successfully using the following:
* def extractedTicket = { value: '' }
* call read('classpath:/ui/callable/GoogleSearch.feature')
* def ticket = extractedTicket.value
And within the called feature:
* set extractedTicket.value = karate.extract(val, '.ticket=(.*?)&', 1)
First, I think you should provide a way to replicate this, so that we can investigate and fix this for everyone. Please follow this process: https://github.com/karatelabs/karate/wiki/How-to-Submit-an-Issue
That said, maybe for just getting Chrome to do a few steps you should just use the Java API - and you can call it from wherever you want, even within a feature file using Java interop: https://github.com/karatelabs/karate#java-api
Also see if this answer gives you any pointers: https://stackoverflow.com/a/60387907/143475
In my application code, there are a lot of calls (like 100+) to the "top object" referring to window.top such as top.$("title") and so forth. Now, I've run into the problem using Cypress to perform end-to-end testing. When trying to log into the application, there are some calls to top.$(...) but the DevTools shows a Uncaught TypeError: top.$ is not a function. This resulted in my team and I discovering that the "top" our application is trying to reach is the Cypress environment itself.
The things I've tried before coming here are:
1) Trying to stub the window.top with the window object referencing our app. This resulted in us being told window.top is a read-only object.
2) Researching if Cypress has some kind of configuration that would smartly redirect calls to top in our code to be the top-most environment within our app. We figured we probably weren't the only ones coming across this issue.
If there were articles, I couldn't find any, so I came to ask if there was a way to do that, or if anyone would know of an alternate solution?
Another solution we considered: Looking into naming window objects so we can reference them by name instead of "window" or "top". If there isn't a way to do what I'm trying to do through Cypress, I think we're willing to do this as a last resort, but hopefully, we don't have to change that, since we're not sure how much of the app it will break upfront.
#Mikkel Not really sure what code I can provide to be useful, but here's the code that causes Cypress to throw the uncaught exception
if (sample_condition) {
top.$('title').text(...).find('content') // Our iframe
} else {
top.$('title').text(page_title)
}
And there are more instances in our code where we access the top object, but they are generally similar. We found out the root cause of the issue is that within Cypress calls to "top" actually interface with Cypress instead of their intended environment which is our app.
This may not be a direct answer to your question, it's just expanding on your request for more information about the technique that I used to pass info from one script to another. I tried to do it within the same script without success - basically because the async nature of .then() stopped it from working.
This snippet is where I read a couple of id's from sessionStorage, and save them to a json file.
//
// At this point the cart is set up, and in sessionStorage
// So we save the details to a fixtures file, which is read
// by another test script (e2e-purchase.js)
//
cy.window().then(window => {
const contents = {
memberId: window.sessionStorage.getItem('memberId'),
cartId: window.sessionStorage.getItem('mycart')
}
cy.writeFile(`tests/cypress/fixtures/cart.json`, contents)
})
In another script, it loads the file as a fixture (fixtures/cart.json) to pull in a couple of id's
cy.fixture(`cart`).then(cart => {
cy.visit(`/${cart.memberId}/${cart.cartId}`)
})
We have an old Yii application along with new Symfony one.
The basic idea is simple - I need to check if there is a route matching in Symfony application then it is cool, if not then bootstrap Yii application and try to handle the request with it.
The main idea to not instantiate AppKernel (and do not load autoload.php - since there is two different autoload.php for each project) before I am sure there is route matching.
Can I do it somehow?
We've done this before with legacy applications.
There are two approaches you can take.
Wrap your old application inside a symfony project (recommended).
Unfortunately this will indeed load the symfony front-controller and kernel. No way around that. You need to make sure that symfony can't handle the request and to do that the kernel needs to be booted up.
Use sub-directories and apache virtual hosts to load one application vs the other as needed.
Given option 1,
You can either create your own front controller that loads either symfony or yii by reading routes (from static files if using yml or xml, or annotations which will be more complex) OR EventListener (RequestListener) that listens to the HttpKernelInterface::MASTER_REQUEST and ensures that a route can be returned.
Creating your own front controller is the only way that you can make it not load the symfony kernel, but it will require you to write something that understands the routes in both frameworks (or at least symfony's) and hands off the request appropriately.
Event listener example:
public function onkernelRequest(GetResponseEvent $event)
{
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
return;
}
... Code to continue normally, or bootstrap yii and return a custom response... (Can include and ob_start, or make an http request, etc)
}
public function getSubscribedEvents()
{
return [
KernelEvents::REQUEST => ['onKernelRequest']
];
}
As you see, the kernel needs to be booted to ensure symfony can't serve the route. Unless creating your own front controller (as stated above).
A third approach would be to create a fallback controller, which would load up a specified URL if no route was found within symfony. Although this approach is generally used for legacy projects that lack a framework and use page scripts instead of proper routes, and definitely requires the use/help of output buffering.
The EventListener approach gives you the opportunity to create a proper Request to hand off to yii, and using what is returned to create a Response as proper symfony object (can also use ob or other options).
Thank you.
This is an alternative to vpassapera's solution -http://stovepipe.systems/post/migrating-your-project-to-symfony
I've tried to implement one of our app modules by using PageFactory (for iOS)
Most of the elements are located by name and others by classname
In general everything works (more or less) but the thing is that the appium server has tons of logs , it seems that each time I'm trying to use some page control , and all the declared controls within that page are being update (?) which cause to longer time execution.
In case and I'm trying to debug my test , it takes a lot of time to move step by step (the appium server works extra hours ...)
I do use "CacheLookup" whenever it possible ...
Where my mistake is, or it's just should be like that ?
Thanks
Updated
Not enough info provided to say for sure. If you have a bunch of cucumber steps and each step is creating a new page instance then yes, you could create a class variable to communicate between cucumber steps
Class variables get thrown out at the end of each scenario so no cross scenario contamination. However, if a single scenario leaves a page and comes back you would need to explicitly set the class page handle to nil/null so that it is reinitialized upon reentry to that page. You want to avoid stale element errors.
I'm going to preface this by saying that I understand the new Windows 8 application lifecycle and how it is now 100% up to the user to decide if they want to terminate the app or not. So, I guess what I'm looking to find is a way to pseudo-restart my app, although I'm open to other suggestions as I'm pretty new to designing Modern UI apps.
I'm building an app that interfaces with a Web 2.0 service that requires authentication via OAuth. Fortunately the Windows 8 WebAuthenticationBroker makes this simple: it displays an asynchronous modal window that houses the web frame to allow the user to sign in and I get to provide a callback method when its done.
Now, obviously I only want to display this sign-in screen if I don't already have a session key stored for the user in roamingSettings.values. I used the Grid App template in Visual Studio, and I execute these functions in default.js as soon as the app is activated (checking roamingStorage, calling WebAuthBroker, etc). Now, the Grid App template provides a data.js to allow me to define some of the REST endpoints that I want to fetch. The main problem is that I can't fetch these REST endpoints until the user is authenticated! Yet they still have to (at least, I think) be declared in data.js ahead of time. So what I'm doing now to avoid errors in the event that the user isn't signed in, is the following:
if (roamingSettings.values[sessionKey]){
list = getFeedItems(); // my function that issues all the REST calls
} else {
list = new WinJS.Binding.List();
}
This works fine if the app is manually restarted after authentication is complete, but I would really rather have a way of completely reloading the app asynchronously after authentication is complete. I've spent a ton of time on this already and I'm getting extremely annoyed because I've seen other apps do this (Instametrogram, for example).
Any ideas?
To answer the core question here, how do you soft restart: window.location.reload() is all you need. This just does the refresh in place.
However, what you are actually looking to do is reset the datasource on the ListView instance -- all you need to do is get hold of that control at runtime, and re-assign the data source to it. E.g.:
var lv = document.getElementById("myListView");
lv.winControl.itemSource = list;
An example of this should also be in the app you have from when it currently assigns the list to the listview.