What is the best possible Explicit Wait implementation in Appium?
There are 3 possibilities I am aware of:
Use wait FluentWait provided by Selenium
Use WebDriverWait from Selenium-Support which internally extends FluentWait only
Use Appium's native AppiumFluentWait which also extends FluentWait from Selenium.
Our framework is going through some major changes and this is the perfect time to make this future ready.
Current implementation is using, WebDriverWait but for this we have to explicitly add import for selenium-support library as Appium's implementation imports it in runtime only scopy.
Is there some issue using explicitly importing selenium-support library because of which Appium team thought of adding library import in this scope, could AppiumFluentWait be a better approach?
But Again appium has removed some common functions which are there in selenium ex: MobileElement with its new version, is this method prone to be removed in future?
Output for: mvn dependency:tree
+- io.appium:java-client:jar:8.3.0:compile
[INFO] | +- org.seleniumhq.selenium:selenium-api:jar:4.7.1:compile (version selected from constraint [4.7.0,5.0))
[INFO] | +- org.seleniumhq.selenium:selenium-remote-driver:jar:4.7.1:compile (version selected from constraint [4.7.0,5.0))
[INFO] | | +- com.google.auto.service:auto-service-annotations:jar:1.0.1:compile
[INFO] | | +- com.google.auto.service:auto-service:jar:1.0.1:compile
[INFO] | | | \- com.google.auto:auto-common:jar:1.2:compile
[INFO] | | +- io.netty:netty-buffer:jar:4.1.84.Final:compile
[INFO] | | +- io.netty:netty-codec-http:jar:4.1.84.Final:compile
[INFO] | | | \- io.netty:netty-codec:jar:4.1.84.Final:compile
[INFO] | | +- io.netty:netty-common:jar:4.1.84.Final:compile
[INFO] | | +- io.netty:netty-transport-classes-epoll:jar:4.1.84.Final:compile
[INFO] | | +- io.netty:netty-transport-classes-kqueue:jar:4.1.84.Final:compile
[INFO] | | +- io.netty:netty-transport-native-epoll:jar:4.1.84.Final:linux-x86_64
[INFO] | | +- io.netty:netty-transport-native-kqueue:jar:4.1.84.Final:osx-x86_64
[INFO] | | +- io.netty:netty-transport-native-unix-common:jar:4.1.84.Final:compile
[INFO] | | +- io.netty:netty-transport:jar:4.1.84.Final:compile
[INFO] | | +- io.opentelemetry:opentelemetry-api:jar:1.19.0:compile
[INFO] | | +- io.opentelemetry:opentelemetry-context:jar:1.19.0:compile
[INFO] | | +- io.opentelemetry:opentelemetry-exporter-logging:jar:1.19.0:compile
[INFO] | | | +- io.opentelemetry:opentelemetry-sdk-metrics:jar:1.19.0:compile
[INFO] | | | \- io.opentelemetry:opentelemetry-sdk-logs:jar:1.19.0-alpha:compile
[INFO] | | | \- io.opentelemetry:opentelemetry-api-logs:jar:1.19.0-alpha:compile
[INFO] | | +- io.opentelemetry:opentelemetry-sdk-common:jar:1.19.0:compile
[INFO] | | +- io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi:jar:1.19.0:compile
[INFO] | | +- io.opentelemetry:opentelemetry-sdk-extension-autoconfigure:jar:1.19.0-alpha:compile
[INFO] | | | \- io.opentelemetry:opentelemetry-exporter-common:jar:1.19.0:runtime
[INFO] | | +- io.opentelemetry:opentelemetry-sdk-trace:jar:1.19.0:compile
[INFO] | | +- io.opentelemetry:opentelemetry-sdk:jar:1.19.0:compile
[INFO] | | +- io.opentelemetry:opentelemetry-semconv:jar:1.19.0-alpha:compile
[INFO] | | +- io.ous:jtoml:jar:2.0.0:compile
[INFO] | | +- net.bytebuddy:byte-buddy:jar:1.12.18:compile
[INFO] | | +- org.apache.commons:commons-exec:jar:1.3:compile
[INFO] | | +- org.asynchttpclient:async-http-client:jar:2.12.3:compile
[INFO] | | | +- org.asynchttpclient:async-http-client-netty-utils:jar:2.12.3:compile
[INFO] | | | +- io.netty:netty-codec-socks:jar:4.1.60.Final:compile
[INFO] | | | +- io.netty:netty-transport-native-epoll:jar:linux-x86_64:4.1.60.Final:compile
[INFO] | | | +- io.netty:netty-transport-native-kqueue:jar:osx-x86_64:4.1.60.Final:compile
[INFO] | | | +- org.reactivestreams:reactive-streams:jar:1.0.3:compile
[INFO] | | | +- com.typesafe.netty:netty-reactive-streams:jar:2.0.4:compile
[INFO] | | | \- com.sun.activation:jakarta.activation:jar:1.2.2:compile
[INFO] | | +- org.seleniumhq.selenium:selenium-http:jar:4.7.1:compile
[INFO] | | | \- dev.failsafe:failsafe:jar:3.3.0:compile
[INFO] | | +- org.seleniumhq.selenium:selenium-json:jar:4.7.1:compile
[INFO] | | \- org.seleniumhq.selenium:selenium-manager:jar:4.7.1:compile
[INFO] | +- org.seleniumhq.selenium:selenium-support:jar:4.7.1:runtime (version selected from constraint [4.7.0,5.0))
[INFO] | +- com.google.code.gson:gson:jar:2.10:compile
[INFO] | +- cglib:cglib:jar:3.3.0:runtime
[INFO] | | \- org.ow2.asm:asm:jar:7.1:runtime
[INFO] | +- commons-validator:commons-validator:jar:1.7:runtime
[INFO] | | +- commons-beanutils:commons-beanutils:jar:1.9.4:runtime
[INFO] | | +- commons-digester:commons-digester:jar:2.1:runtime
[INFO] | | +- commons-logging:commons-logging:jar:1.2:compile
[INFO] | | \- commons-collections:commons-collections:jar:3.2.2:runtime
[INFO] | +- org.apache.commons:commons-lang3:jar:3.12.0:compile
[INFO] | +- commons-io:commons-io:jar:2.11.0:compile
[INFO] | \- org.slf4j:slf4j-api:jar:2.0.5:compile
So first of all it depends on the architecture.
Second, Do you really need FluentWait? The WebDriverWait class has optional arguments: timeout, poll_frequency, and ignored_exceptions and you could supply them there.
:Args:
- driver - Instance of WebDriver (Ie, Firefox, Chrome or Remote)
- timeout - Number of seconds before timing out
- poll_frequency - sleep interval between calls
By default, it is 0.5 second.
- ignored_exceptions - iterable structure of exception classes ignored during calls.
By default, it contains NoSuchElementException only.
How I see it:
wait = WebDriverWait(driver, 15)
s_wait = WebDriverWait(driver, 5)
l_wait = WebDriverWait(driver, 30)
fl_wait = WebDriverWait(driver, 15, poll_frequency=1,
ignored_exceptions=[ElementNotVisibleException])
Then implement methods that return: waits
def wait(self, locator, wait: WebDriverWait = None):
if wait is None:
wait = self._wait
return wait.until(ec.presence_of_element_located(locator))
Then call the necessary method when it is needed, in general, it can be implemented within base class
An example in python, but you can reuse the logic
Related
UPDATE:
It's working but I don't know what happened so I will leave the question open.
I am trying to add zlib. For this purpose I have added the following configuration file that is included in my main CMakeLists.txt.
include(ExternalProject)
set(DEPS_BUILD ${CMAKE_BINARY_DIR}/deps/build)
set(DEPS_LOG ${CMAKE_BINARY_DIR}/deps/log)
set(DEPS_STAMP ${CMAKE_BINARY_DIR}/deps/stamp)
set(DEPS_TMP ${CMAKE_BINARY_DIR}/deps/tmp)
set(DEPS_SRC ${CMAKE_BINARY_DIR}/deps/src)
ExternalProject_Add(zlib
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/deps/zlib
INSTALL_DIR ${CMAKE_INSTALL_PREFIX}
DOWNLOAD_DIR ${DEPS_SRC}/zlib
TMP_DIR ${DEPS_TMP}/zlib
STAMP_DIR ${DEPS_STAMP}/zlib
LOG_DIR ${DEPS_LOG}/zlib
BINARY_DIR ${DEPS_BUILD}/zlib
SOURCE_DIR ${DEPS}/zlib
INSTALL_COMMAND cmake -E echo "Skipping install step for dependency zlib"
INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}
)
I am using CMake 2.21 (latest as of 9th of September 2021) and Visual Studio 2017. I have of course added zlib as a dependency like this:
add_dependencies(${MY_LIB} zlib)
where MY_LIB is the library. The ${DEPS} variable points at a subdirectory (inside the root directory of my project) where all git submodules are currently being initialized.
${CMAKE_SOURCE_DIR}
|
+ --- CMakeLists.txt
|
+ --- ${DEPS}
| |
| + --- dependencies.cmake
| |
| + --- zlib git submodule
| |
| + --- libpng git submodule
| |
| + --- libjpeg-turbo git submodule
...
Also the reason why I define all the variables below is mostly for structural purposes. The first time I added the ExternalProject stuff and ran my configuration it created a lot of directories all over the place inside my build directory. By defining specific locations I can ensure the structure I want and come in terms with:
${CMAKE_BINARY_DIR}
|
+ --- CMakeFiles
|
+ --- CMakeCache.txt
|
...
|
+ --- deps
| |
| + --- build
| | |
| | + --- jpeg
| | |
| | + --- png
| | |
| | + --- zlib
| |
| + --- src
| | |
| | + --- jpeg
| | |
| | + --- png
| | |
| | + --- zlib
| |
| |
| + --- stamp
| | |
| | ...
| |
| + --- tmp
| |
| ...
|
...
I am working on and which uses zlib's functionality internally. After generating the VS solution (with the ZERO_BUILD, ALL_BUILD etc. projects added to it) for VS 2017 64bit debug build I tried to build the zlib project just to see if it work properly but I am getting the following error:
Performing build step for 'zlib'
CUSTOMBUILD : error : could not load cache
I have successfully added turbojpeg to my project (with the same code) and it works without any issues. Given my previous experience with zlib when building 3rd party software (libs, executables) I am inclined to think that there is some configuration step missing. What that step might be is beyond me. I am also new to the ExternalProject module of CMake.
I'm trying to include libheif into my project using cmake. Libheif is more complicated than what I've worked with before because it requires you externally build and include libde265.
Attempt #1:
I have used vcpkg to export pre-built binary packages, this creates a directory called libheif which includes everything here:
+---bin
| heif.dll
| libde265.dll
| libx265.dll
| libx265.pdb
|
+---debug
| +---bin
| | heif.dll
| | libde265.dll
| | libx265.dll
| | libx265.pdb
| |
| \---lib
| | heif.lib
| | libde265.lib
| | libx265.lib
| | x265-static.lib
| |
| \---pkgconfig
| libheif.pc
| x265.pc
|
+---include
| | x265.h
| | x265_config.h
| |
| +---libde265
| | de265.h
| |
| \---libheif
| heif.h
|
+---lib
| | heif.lib
| | libde265.lib
| | libx265.lib
| | x265-static.lib
| |
| \---pkgconfig
| libheif.pc
| x265.pc
|
+---share
| +---libde265
| | copyright
| | libde265Config-debug.cmake
| | libde265Config-release.cmake
| | libde265Config.cmake
| | libde265ConfigVersion.cmake
| | vcpkg_abi_info.txt
| |
| +---libheif
| | | copyright
| | | libheif-config-debug.cmake
| | | libheif-config-release.cmake
| | | libheif-config-version.cmake
| | | libheif-config.cmake
| | | vcpkg_abi_info.txt
| | |
| | \---.vs
| | ProjectSettings.json
| | slnx.sqlite
| |
| \---x265
| copyright
| vcpkg_abi_info.txt
|
\---tools
+---libde265
| dec265.exe
| enc265.exe
| libde265.dll
|
\---x265
x265.exe
(There were more headers, I removed them because one illustrates the point) I put folder libheif in my external folder in my project. Then in CMakeLists.txt I have tried using
target_link_libraries(my_project ${CMAKE_SOURCE_DIR}/external/libheif/lib/heif)
that then fails looking for heif.obj file that is not there. It does find the dlls though.
After that failed, I tried again, this time using the .cmake files in the share directory:
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/external/libheif/share/libheif)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/external/libheif/share/libde265)
include(libheif-config)
include(libde265Config)
This I get unresolved external symbol when trying to use anything in libheif.
Attempt #2:
I tried including libeheif by adding it as a submodule git submodule add https://github.com/strukturag/libheif.git external/libheif
and then in CMakeLists.txt I added:
include_directories(external/libheif/include)
include_directories(external/libheif/include/libheif)
include_directories(external/libheif/include/libde265)
add_subdirectory(external/libheif)
target_link_libraries(my_project libheif)
This results in unresolved external symbols whenever I try to use anything in the libheif library.
Other information
The only successful thing I have been able to do is include the headers directory so intellisence recognizes when I #include <heif.h>
I have looked all over on how to include dll and libraries, but all the results either need me to use the cmake GUI, which I am not sure I can because I'm working on this project with other people and I want to make sure it works on their computer without having to use the cmake GUI.
Same with just using vcpkg to include it, I dont want my teammates to have to use it as well, I need to just use CMakeLists.txt
This tutorial would be helpful but the generate stuff is above my head and I couldnt find what it meant by generate. It might be a rabbit hole I loose a day over.
I am working on Windows 10, I will eventually need to make it so it can build on OSX but I'm just trying to get it to work on windows for now.
I am trying to understand why each of these approaches failed. I would rather go down the path of attempt #2 because I feel like that is better for down the road when I need to make it compile for mac as well. Thank you.
Then in CMakeLists.txt I have tried usingļ¼
target_link_libraries(my_project
${CMAKE_SOURCE_DIR}/external/libheif/lib/heif)
I think you should use:
target_link_directories( ${PROJECT_NAME}
PRIVATE ./external/libheif/lib/heif
)
target_link_libraries( ${PROJECT_NAME} PRIVATE
heif
xxx
)
target_link_directories : Add link directories to a target.
I'm trying to apply modern CMake practices in my project.
And I've came up with an issue with the {fmt} library dependency.
The structure of a project is the following (in a brief):
dev/
|
+--- fmt/ *unpacked archive of 4.1.0 version*
|
+--- mylib/
| |
| +--- mylib.hpp
| |
| +--- CMakeLists.txt
| ***************************
| * ...
| * add_library(mylib INTERFACE)
| * TARGET_LINK_LIBRARIES(mylib PUBLIC fmt-header-only)
| * set(MYLIB_HEADERS_ALL mylib.hpp )
| * ...
| ***************************
|
+--- sample/
| |
| +--- main.cpp
| |
| +--- CMakeLists.txt
| ***************************
| * set(SAMPLE sample.hello_world)
| * add_executable(${SAMPLE} main.cpp)
| * TARGET_LINK_LIBRARIES(${SAMPLE} PRIVATE mylib)
| * install(TARGETS ${SAMPLE} DESTINATION bin)
| ***************************
|
+--- CMakeLists.txt
***************************
* include_directories(${CMAKE_CURRENT_SOURCE_DIR})
* add_subdirectory(fmt EXCLUDE_FROM_ALL)
* add_subdirectory(sample/hello_world)
***************************
When I try to build it I receive an error:
PATH/mylib/mylib.hpp:6:10: fatal error: fmt/format.hpp: No such file or directory
#include <fmt/format.hpp>
^~~~~~~~~~~~~~~~
compilation terminated.
Full reproduction can be found here:
https://bitbucket.org/ngrodzitski/cmake-issue-fmt-20180410
Any suggestions on the issue?
With the help from Mathieu Ropert in slack, I've resolved the issue in following steps:
TARGET_LINK_LIBRARIES(mylib INTERFACE fmt::fmt-header-only) in mylib/CMakeLists.txt (PUBLIC before).
add the following to root CMakeLists.txt: add_subdirectory(mylib) (that what makes a change).
I pushed final version to repo: https://bitbucket.org/ngrodzitski/cmake-issue-fmt-20180410.
I'm trying to split the string "1 out of 20"
Is there a way to store 1 in a variable and 20 in another variable?
|store | 1 out of 20 | Text |
|storeEval | "${Text}".split(" ")[0] | firstsection |
|echo | ${firstsection} | |
[info] echo: 1
|storeEval | "${Text}".split(" ")[3] | lastsection |
|echo | ${lastsection} | |
[info] echo: 20
I'm not an expert in this field but probbaly this coudl help you
Selenium split date string working example?
It looks that splitting a string is possible via Selenium
One script we have asks the user for a few values via successive JavaScript calls to window.prompt(). Selenium records this action, both the prompt texts and the values I typed in, but it doesn't seem to be able to play it back properly. It 'succeeds' in that no errors occur, but only the first prompt value actually makes it back to my script. Furthermore, the default ordering Selenium records makes the second value get returned in the first one's spot, and the rest still blank:
# [info] Executing: |answerOnNextPrompt | TEXT1 | |
# [info] Executing: |select | id | label=mychoice |
# [info] Executing: |answerOnNextPrompt | TEXT2 | |
# [info] Executing: |assertPrompt | Please enter a value for q1 | |
# [info] Executing: |answerOnNextPrompt | TEXT3 | |
# [info] Executing: |assertPrompt | Please enter a value for q2 | |
# [info] Executing: |answerOnNextPrompt | TEXT4 | |
# [info] Executing: |assertPrompt | Please enter a value for q3 | |
# [info] Executing: |assertPrompt | Please enter a value for q4 | |
I reordered it into what seems more sensible to me:
# [info] Executing: |answerOnNextPrompt | TEXT1 | |
# [info] Executing: |select | id | label=mychoice |
# [info] Executing: |assertPrompt | Please enter a value for q1 | |
# [info] Executing: |answerOnNextPrompt | TEXT2 | |
# [info] Executing: |assertPrompt | Please enter a value for q2 | |
# [info] Executing: |answerOnNextPrompt | TEXT3 | |
# [info] Executing: |assertPrompt | Please enter a value for q3 | |
# [info] Executing: |answerOnNextPrompt | TEXT4 | |
# [info] Executing: |assertPrompt | Please enter a value for q4 | |
After that I get TEXT1 as the first value, but the rest still blank.
I also tried waitForPrompt in place of each assertPrompt, but no dice.
My guess is that Selenium can't actually handle this situation because answerOnNextPrompt seems to need to come before the action that triggers the prompt, but it is the action that triggers the next prompt, so after the first one triggered by select there's no way to do it because they don't stack.
I'd like to be proven wrong, though...any ideas?
(If not, I might report it as a bug / something they need to change in the API, maybe by combining answerOnNextPrompt with assertPrompt: it could just take an optional argument with how the prompt ought to be answered.)
Platform is Selenium IDE 1.0.2 on Firefox 3.5.3 on win32.
This definately looks like a limitation in Selenium. The following is from the source of selenium-browserbot.js:
windowToModify.prompt = function(message) {
browserBot.recordedPrompts.push(message);
var result = !browserBot.nextConfirmResult ? null : browserBot.nextPromptResult;
browserBot.nextConfirmResult = true;
browserBot.nextPromptResult = '';
self.relayBotToRC.call(self, "browserbot.recordedPrompts");
return result;
};
It appears to process all prompts when the window is 'modified', and after each it sets the next answer to empty. I would raise a request for an improvement. Without giving it much thought I would suggest allowing stacking of the anwerOnNextPrompt command so that you can queue up the answers you want to give to each prompt in turn.
Update:
Something similar will also happen for consecutive JavaScript confirmations. The first will use the response set by choose*OnNextConfirmation, and all following confirmations will automatically select OK (true).
windowToModify.confirm = function(message) {
browserBot.recordedConfirmations.push(message);
var result = browserBot.nextConfirmResult;
browserBot.nextConfirmResult = true;
self.relayBotToRC.call(self, "browserbot.recordedConfirmations");
return result;
};
How about this one:
# [info] Executing: |select | id | label=mychoice |
# [info] Executing: |answerOnNextPrompt | TEXT1 | |
# [info] Executing: |assertPrompt | Please enter a value for q1 | |
# [info] Executing: |answerOnNextPrompt | TEXT2 | |
# [info] Executing: |assertPrompt | Please enter a value for q2 | |
# [info] Executing: |answerOnNextPrompt | TEXT3 | |
# [info] Executing: |assertPrompt | Please enter a value for q3 | |
# [info] Executing: |answerOnNextPrompt | TEXT4 | |
# [info] Executing: |assertPrompt | Please enter a value for q4 | |
BTW, why not using a regular HTML form instead so many of those annoying javascript prompts?