I have a button that allows to hide itself and another widget when pressed. When it is hidden, a new button appears on the screen which can undo (show) the previous button and widget again.
I'm pretty sure my implementation for this works because I've tested it on multiple devices without any problems, but whenever I try to write a formal test for it, something goes wrong. I'm using the following code to test my widget:
await tester.tap(find.widgetWithText(GestureDetector, "HIDE"));
expect(testContainerState.ifContainerWithOptionsIsDisplayed, false);
print(find.byType(GestureDetector));
await tester.tap(find.widgetWithText(GestureDetector, "SHOW"));
expect(testContainerState.ifContainerWithOptionsIsDisplayed, true);
The first two lines are there to tap the button and check whether ifContainerWithOptionsIsDisplayed changed. In my implementation, this is done in a setState method and should repaint to hide the widget and button and show the new button.
In the third line, I check how many GestureDetectors I can still find after what should be a repaint. The output of that print statement still shows me that all of the GestureDetectors of the widget that should now be hidden are still being found.
In the 4th line, I try to find my SHOW button that should now be visible because of the repaint. But no element is found.
Again, I'm pretty sure the code for my widgets are correct because I've tested this test case manually without any issues. Perhaps I'm missing some knowledge about Flutter tests. Could someone please fill me in?
await tester.pump();
or just
tester.pump();
should do that
See also
https://docs.flutter.io/flutter/flutter_test/WidgetTester/pump.html
https://docs.flutter.io/flutter/flutter_test/WidgetTester/pumpAndSettle.html
https://flutter.institute/flutter-and-widget-tests/
Related
I have a close button on a ViewController that is being presented as a ChildViewController. I have this button's accessibility turned on and the accessibility identifier is closeButton. This button does not have any text, it just has an image.
I am attempting to test the presentation and dismissal of this view, but am running into an issue, the XCUITest cannot find the element. My test code is:
app.buttons["PresentChild"].tap()
XCTAssertTrue(app.otherElements["ChildViewController"].exists)
XCTAssertTrue(app.buttons["closeButton"].exists)
The first assert passes, but the second assert fails.
I tried to do the "Record UI Test" to select the button to have it be automatically generated, but then I just get an error saying Failed to find Matching Element. I tried erasing all the content on the simulator and deleting all derived data, and that didn't work either.
Does anyone know a workaround to this obvious bug in Xcode? I can't access the element through the recording, I can't access the element through the accessibility feature, I have zero idea how else to access this button.
I don't know what is the exact problem with your assertion. But this steps may help you.
Put a breakpoint on this line XCTAssertTrue(app.otherElements["ChildViewController"].exists)
Now run the test case. When the control reaches this line, type this line in the debugger po XCUIApplication().buttons.debugDescription then tap the enter button
It will print all buttons in your current view. Now check whether the "closeButton" exists in that list
If it exists, check the identifier name. Make sure that it is "closeButton" (Identifier is case sensitive, also spaces in the identifiers matters)
If the identifier is right, try to find out the closeButton's exact view hierarchy. Means, instead of just checking like app.buttons["closeButton"].exists, try like app.navigationBars.otherElements["someName"].buttons["closeButton"].exists
(This seems funny, but giving the exact location path of the element is a good practice, and it will work sometimes)
Note: This error "Failed to find Matching Element" on UI recording will happen if the system can not locate the element with proper identifier while doing action on it. So my guess is, your closeButton does not have proper identifier or it is not added to the current window.
Cheers!!
I am working to automate an android app which have some screen of webview too. I am unable to click the right element through xpath class, with index or even with giving name text.
If you see these screenshots it is visible that when I inspect element i get link to somewhere else. i tried using getlocation and then pass it for click but it also getting me wrong click.
I tried touchaction class methods but they are not working. My code get pass through appium but the methods tap or press nothing.
I tried this way too but no luck.
WebElement Quiz1 = (new WebDriverWait(driver , 20))
.until(ExpectedConditions.presenceOfElementLocated(By.xpath("//android.view.View[contains(#content-desc,'Die Wish App')]")));
Quiz1.click();
Any help would be appreciated. Also how can I use webview rather than webelement? and which one is preferable?
You can click on the element which you have highlighted in the screenshot.Below is the locator to identify that element
By.accessibilityId("Die Wish App")
We're using Appium with iOS Simulator and test functions written in Java.
We have an iOS App with screen 1 containing a UICollection view, and tell Appium to click on one of its elements.
This opens screen 2 (and the scrolling animation takes about 500 ms), which also contains an UICollection view. I want to find out the size of the UICollection view of the second screen with Appium.
The problem is that Appium is too fast and executes the findElements() method directly after the click, which causes it to find the UICollection view of the first screen.
clickOnElementOnFirstScreen();
webDriver.findElements( By.className( "UIACollectionCell" ) ).size();
// is supposed to find the UICollection view on the second screen,
// but actually finds the UICollection view on the first screen
Appium provides several waiting functions. However as far as I can see all of them are intended to be used in this fashion:
"wait until element at location X / with name X becomes visible"
If I try to use these waiting functions, they don't wait at all because they immediately find the UICollection view of the first screen, which has the same location and name as the one on the second screen.
The only solution I have found is to use Thread.sleep:
Thread.sleep(1000);
webDriver.findElements( By.className( "UIACollectionCell" ) ).size();
But we don't want to use Thread.sleep in code that will run on the client's server on hundreds of tests.
We might be able to modify the App and enter metadata into the views so that Appium is able to distinguish them, but this situation occurs in several places and the App is being programmed by the client, so we want to avoid this too.
What is a simple and safe way to wait for the new screen to appear, without modifying the code of the iOS App?
I have found only dirty workaround for this issue.
static waitFor(Duration duration) {
try {
def WebDriverWait wait = new WebDriverWait(mobileDriver, duration.standardSeconds)
wait.until(visibilityOfElementLocated(By.xpath("//Fail")))
//Wait until false case is visible to ensure proper timeout
} catch (Exception e) {
}
}
Another workaround/solution that has been posted on the Appium forums is:
First search for some other element that distinguishes the 2. screen from the 1. screen; once that is visible, it's safe to search for the originally desired element.
I'm using $mdToast (Angular Material framework) directive to show several status messages in my Angular(-Material) web app.
When the user signs-in, if the login is successful a toast is shown by calling:
$scope.showToastMessage = function() {
var toast = $mdToast.simple()
.content("Login successful);
.action('OK')
.highlightAction(false)
.position($scope.getToastPosition());
$mdToast.show(toast).then(function(toast) {
//...
}
});
};
After login success I need to make another check (e.g. valid session cookie) and show another toast message without overriding the previous one and after the previous one is actually showed.
The issues I get here are:
the second toast is shown before the new one (probably due to $mdTost's async nature)
this second toast is shown for less than one second and then disappears leaving on screen only the first one (basicly the second one is shown first and then hidden when the first one appears)
A solution could be either:
creating the second toast inside then .then callback: this doesn't work either because requires the user interventions to press the "OK" action button
calling $mdToast.updateContent(); (https://material.angularjs.org/#/api/material.components.toast/service/$mdToast) which would overwrite previous toast message (this is not the best solution but would be fine either) but I can't figure out how:
(1) choose a specific toast shown on screen (let's suppose I have several toasts shown by different calls) , and
(2) update the toast message after a delay (let's say 3 seconds) in order to show to make the user undersand that the login was successful but there is some other information.
Any clue?
I was not sure if you wanted to show both toasts at the same time or not. If you wanted to show the sequentially you can put the second call to toast inside of the then because the action (OK) resolves the promise of the first toast. This is what I've tried:
var toast = $mdToast.simple()
.content('top left')
.action('OK')
.highlightAction(false)
.position($scope.getToastPosition());
var toast2 = $mdToast.simple()
.content('Checking some other things')
.highlightAction(false)
.position('top left');
$mdToast.show(toast).then(function() {
$mdToast.show(toast2);
});
See this CodePen.
I'm using Delphitwain (delphitwain.sourceforge.net) to add scan functionality to my app. Everything was fine, when i click scan button on my app it will show scan mode with scanner's Properties such as Page Size, Scanning Side (canon dr-3010c) and there is a Scan button and Cancel button. If i click cancel of course all the properties back to it's value before.
How can I show this Scanner's Properties only to change properties without Scan, since i can do scan without showing properties
Twain.LoadLibrary;
Twain.LoadSourceManager;
Twain.Source[CurrentSource].Loaded := TRUE;
Twain.Source[CurrentSource].TransferMode := TTwainTransferMode(0);
Twain.Source[CurrentSource].EnableSource(True, True);
while Twain.Source[CurrentSource].Enabled do Application.ProcessMessages;
Twain.UnloadLibrary;
Twain.Source[CurrentSource].EnableSource(True, True);
The first True for ShowUI and the second True for Modal
I know it can be achieved 'cos i've seen another application that can show scanner's properties without scan, only OK and Cancel button, i've searched google all over but no luck, or maybe it just the limitation of the delphitwain component? Thanks, any suggestion appreciated
It has a boolean property in TTwainSource class named ShowUI. Using that property, you can control whether native UI of the scanner should be shown or not.
But take note that some scanners show their UI forcefully whether you set ShowUI to True or False.