Best Python code snippet using fMBT_python
fmbtandroid.py
Source:fmbtandroid.py
...865 use given View object or view file instead of reading866 items from the device.867 uiautomatorDump (boolean, optional):868 use uiautomator to read view dump from the device.869 If not given, uiautomatorDump() default will be used.870 Returns created View object.871 """872 def formatErrors(errors, filename):873 return 'refreshView parse errors in "%s":\n %s' % (874 filename,875 "\n ".join(["line %s: %s error: %s" % e for e in errors]),)876 if self._conn:877 displayToScreen = self._conn._displayToScreen878 else:879 displayToScreen = None880 if forcedView != None:881 if isinstance(forcedView, View):882 self._lastView = forcedView883 elif type(forcedView) == str:884 self._lastView = View(self.screenshotDir(), self.serialNumber, file(forcedView).read(), displayToScreen, self.itemOnScreen, self.intCoords)885 _adapterLog(formatErrors(self._lastView.errors(), self._lastView.filename()))886 else:887 raise ValueError("forcedView must be a View object or a filename")888 return self._lastView889 retryCount = 0890 while True:891 if uiautomatorDump == True or (uiautomatorDump == None and self.uiautomatorDump()):892 dump = self.existingConnection().recvUiautomatorDump()893 else:894 try:895 dump = self.existingConnection().recvViewData()896 except AndroidConnectionError:897 self._lastView = None898 raise899 if dump != None:900 viewDir = os.path.dirname(self._newScreenshotFilepath())901 view = View(viewDir, self.serialNumber, dump, displayToScreen, self.itemOnScreen, self.intCoords)902 else:903 _adapterLog("refreshView window dump reading failed")904 view = None905 # fail quickly if there is no answer906 retryCount += self._PARSE_VIEW_RETRY_LIMIT / 2907 if dump == None or len(view.errors()) > 0:908 if view:909 _adapterLog(formatErrors(view.errors(), view.filename()))910 if retryCount < self._PARSE_VIEW_RETRY_LIMIT:911 retryCount += 1912 time.sleep(0.2) # sleep before retry913 else:914 self._lastView = None915 raise AndroidConnectionError("Cannot read window dump")916 else:917 # successfully parsed or parsed with errors but no more retries918 self._lastView = view919 self._screenSize = self.existingConnection().recvScreenSize()920 return view921 def screenLocked(self):922 """923 Return True if showing lockscreen, otherwise False.924 """925 if self._conn:926 return self._conn.recvShowingLockscreen()927 else:928 return None929 def screenSize(self):930 if self._screenSize:931 return self._screenSize932 else:933 self._screenSize = fmbtgti.GUITestInterface.screenSize(self)934 return self._screenSize935 def setAccelerometer(self, abc):936 """937 Set emulator accelerometer readings938 Parameters:939 abc (tuple of floats):940 new 3-axis accelerometer readings, one to three values.941 Returns True if successful, False if failed. Raises an exception942 if emulator cannot be connected to. Does not work with real hardware.943 Note: to rotate display with real hardware, see setUserRotation().944 Example:945 d.setAccelerometer((9.8, 0))946 d.setAccelerometer((0, 9.8))947 d.setAccelerometer((-9.6, 0.2, 0.8))948 """949 if self._conn:950 return self._conn.sendAcceleration(abc)951 else:952 return False953 def setAccelerometerRotation(self, value):954 """955 Enable or disable accelerometer-based screen rotation956 Parameters:957 value (boolean):958 True: enable accelerometer-based rotation959 False: disable accelerometer-based rotation.960 Returns True if successful, otherwise False.961 """962 if self._conn:963 return self._conn.sendAccelerometerRotation(value)964 else:965 return False966 def setAutoRotateScreenshot(self, value):967 """968 Enable or disable automatic screenshot rotation.969 Parameters:970 value (boolean):971 If True, rotate screenshot automatically to compensate972 current display rotation.973 refreshScreenshot()'s optional rotate parameter overrides this974 setting.975 See also autoRotateScreenshot(), displayRotation().976 """977 if value:978 self._autoRotateScreenshot = True979 else:980 self._autoRotateScreenshot = False981 def setConnection(self, connection):982 self._lastConnectionSettings = {}983 fmbtgti.GUITestInterface.setConnection(self, connection)984 if hasattr(self.connection(), "_serialNumber"):985 self.serialNumber = self.connection()._serialNumber986 def setDisplaySize(self, size=(None, None)):987 """988 Transform coordinates of synthesized events from screenshot989 resolution to given input area size. By default events are990 synthesized directly to screenshot coordinates.991 Parameters:992 size (pair of integers (width, height), optional):993 width and height of display in pixels. If not994 given, values from Android system properties995 "mDisplayWidth" and "mDisplayHeight" will be used.996 Returns None.997 """998 width, height = size999 if width == None or height == None:1000 w, h = self.existingConnection().recvScreenSize()1001 if w == h == 0:1002 w, h = self.existingConnection().recvDefaultViewportSize()1003 if width == None:1004 width = w1005 if height == None:1006 height = h1007 screenWidth, screenHeight = self.screenSize()1008 self.existingConnection().setScreenToDisplayCoords(1009 lambda x, y: (x * width / screenWidth,1010 y * height / screenHeight))1011 self.existingConnection().setDisplayToScreenCoords(1012 lambda x, y: (x * screenWidth / width,1013 y * screenHeight / height))1014 def setUiautomatorDump(self, uiautomatorDump):1015 """1016 Enable or disable using uiautomator on refreshView()1017 Parameters:1018 uiautomatorDump (boolean):1019 If True, uiautomator will be used on refreshView()1020 by default.1021 """1022 self._uiautomatorDump = uiautomatorDump1023 def setUserRotation(self, rotation):1024 """1025 Enable or disable accelerometer-based screen rotation1026 Parameters:1027 rotation (integer):1028 values 0, 1, 2 and 3 correspond to1029 ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270.1030 Returns True if successful, otherwise False.1031 Example:1032 # Disable accelerometer-based rotation for user rotation1033 # to take effect.1034 d.setAccelerometerRotation(False)1035 d.setUserRotation(fmbtandroid.ROTATION_90)1036 time.sleep(2)1037 d.setUserRotation(fmbtandroid.ROTATION_0)1038 time.sleep(2)1039 d.setAccelerometerRotation(True)1040 """1041 if rotation in ROTATIONS:1042 pass # already in correct scale1043 elif rotation in ROTATION_DEGS:1044 rotation = ROTATION_DEGS.index(rotation)1045 else:1046 raise ValueError('invalid rotation "%s"' % (rotation,))1047 if self._conn:1048 return self._conn.sendUserRotation(rotation)1049 else:1050 return False1051 def shell(self, shellCommand, timeout=None):1052 """1053 Execute shellCommand in adb shell.1054 Parameters:1055 shellCommand (string):1056 command to be executed in adb shell.1057 Arguments separated by whitespace.1058 timeout (optional, integer):1059 time in seconds after which the command1060 will timeout. The default is None (no timeout).1061 Returns output of "adb shell" command, or None if timed out.1062 If you wish to receive exitstatus or standard output and error1063 separated from shellCommand, refer to shellSOE().1064 """1065 try:1066 output = self.existingConnection()._runAdb(1067 ["shell", shellCommand],1068 expectedExitStatus=EXITSTATUS_ANY,1069 timeout=timeout)[1]1070 except FMBTAndroidRunError:1071 output = None1072 return output1073 def shellSOE(self, shellCommand, timeout=None):1074 """1075 Execute shellCommand in adb shell.1076 Parameters:1077 shellCommand (string):1078 command to be executed in adb shell.1079 Arguments separated by whitespace.1080 timeout (optional, integer):1081 time in seconds after which the command1082 will timeout. The default is None (no timeout).1083 Returns tuple (exitStatus, standardOutput, standardError)1084 or (None, None, None) if timed out.1085 Requires tar and uuencode to be available on the device.1086 """1087 return self.existingConnection().shellSOE(shellCommand, timeout)1088 def smsNumber(self, number, message):1089 """1090 Send message using SMS to given number.1091 Parameters:1092 number (string)1093 phone number to which the SMS will be sent1094 message (string)1095 the message to be sent.1096 Returns True on success, otherwise False.1097 """1098 smsCommand = ('am start -a android.intent.action.SENDTO ' +1099 '-d sms:%s --es sms_body "%s"' +1100 ' --ez exit_on_sent true') % (number, message)1101 status, out, err = self.shellSOE(smsCommand)1102 if status != 0:1103 _logFailedCommand("sms", smsCommand, status, out, err)1104 return False1105 _adapterLog("SMS command returned %s" % (out + err,))1106 time.sleep(2)1107 if 'talk' in self.topWindow():1108 _adapterLog("Messaging app is Hangouts")1109 self.pressKey("KEYCODE_ENTER")1110 time.sleep(1)1111 self.pressKey("KEYCODE_BACK")1112 time.sleep(1)1113 self.pressKey("KEYCODE_BACK")1114 else:1115 self.pressKey("KEYCODE_DPAD_RIGHT")1116 time.sleep(1)1117 self.pressKey("KEYCODE_ENTER")1118 return True1119 def statusBarVisible(self):1120 """1121 Returns True if the status bar is showing, otherwise False.1122 """1123 return self.existingConnection().recvStatusBarVisible()1124 def supportsView(self):1125 """1126 Check if connected device supports reading view data.1127 View data is needed by refreshView(), view(), verifyText() and1128 waitText(). It is produced by Android window dump.1129 Returns True if view data can be read, otherwise False.1130 """1131 if self._supportsView == None:1132 try:1133 if self.uiautomatorDump():1134 if self.existingConnection().recvUiautomatorDump():1135 self._supportsView = True1136 else:1137 self._supportsView = False1138 else:1139 self.existingConnection().recvViewData()1140 self._supportsView = True1141 except AndroidConnectionError:1142 self._supportsView = False1143 return self._supportsView1144 def swipeText(self, text, direction, partial=False, **swipeKwArgs):1145 """1146 Find an item with given text from the latest view, and swipe it.1147 Parameters:1148 text (string):1149 text to be swiped.1150 direction (string or integer):1151 refer to swipe documentation1152 distance (float, optional):1153 refer to swipe documentation1154 partial (boolean, optional):1155 refer to verifyText documentation. The default is1156 False.1157 startPos1158 refer to swipeItem documentation.1159 delayBeforeMoves, delayBetweenMoves, delayAfterMoves,1160 movePoints1161 refer to drag documentation.1162 Returns True if successful, otherwise False.1163 """1164 assert self._lastView != None, "View required."1165 items = self._lastView.findItemsByText(text, partial=partial, count=1, onScreen=True)1166 if len(items) == 0: return False1167 return self.swipeItem(items[0], direction, **swipeKwArgs)1168 def systemProperty(self, propertyName):1169 """1170 Returns Android Monkey Device properties, such as1171 "clock.uptime", refer to Android Monkey documentation.1172 """1173 return self.existingConnection().recvVariable(propertyName)1174 def tapId(self, viewItemId, **tapKwArgs):1175 """1176 Find an item with given id from the latest view, and tap it.1177 """1178 assert self._lastView != None, "View required."1179 items = self._lastView.findItemsById(viewItemId, count=1, onScreen=True)1180 if len(items) > 0:1181 return self.tapItem(items[0], **tapKwArgs)1182 else:1183 _adapterLog("tapItemById(%s): no items found" % (viewItemId,))1184 return False1185 def tapText(self, text, partial=False, **tapKwArgs):1186 """1187 Find an item with given text from the latest view, and tap it.1188 Parameters:1189 partial (boolean, optional):1190 refer to verifyText documentation. The default is1191 False.1192 tapPos (pair of floats (x, y), optional):1193 refer to tapItem documentation.1194 long, hold, count, delayBetweenTaps (optional):1195 refer to tap documentation.1196 Returns True if successful, otherwise False.1197 """1198 assert self._lastView != None, "View required."1199 items = self._lastView.findItemsByText(text, partial=partial, count=1, onScreen=True)1200 if len(items) == 0: return False1201 return self.tapItem(items[0], **tapKwArgs)1202 def tapContentDesc(self, contentDesc, **tapKwArgs):1203 """1204 Find an item with given content description, and tap it.1205 Parameters:1206 contentDesc (string):1207 content description of the item to be tapped.1208 tapPos (pair of floats (x, y), optional):1209 refer to tapItem documentation.1210 long, hold, count, delayBetweenTaps (optional):1211 refer to tap documentation.1212 Returns True if successful, otherwise False.1213 Note: Requires that the latest refreshView used the uiautomator1214 backend for fetching the view data. Example:1215 d.refreshView(uiautomatorDump=True)1216 d.tapContentDesc("Apps")1217 """1218 assert self._lastView != None, "View required."1219 items = self._lastView.findItemsByContentDesc(contentDesc)1220 if len(items) == 0: return False1221 return self.tapItem(items[0], **tapKwArgs)1222 def topApp(self):1223 """1224 Returns the name of the top application.1225 """1226 if not self._conn:1227 return None1228 else:1229 return self._conn.recvTopAppWindow()[0]1230 def topWindow(self):1231 """1232 Returns the name of the top window.1233 """1234 # the top window may be None during transitions, therefore1235 # retry a couple of times if necessary.1236 if not self._conn:1237 return None1238 timeout = 0.51239 pollDelay = 0.21240 start = time.time()1241 tw = self.existingConnection().recvTopAppWindow()[1]1242 while tw == None and (time.time() - start < timeout):1243 time.sleep(pollDelay)1244 tw = self.existingConnection().recvTopAppWindow()[1]1245 return tw1246 def topWindowStack(self):1247 """1248 Returns window names in the stack of the top fullscreen application.1249 The topmost window is the last one in the list.1250 """1251 return self.existingConnection().recvTopWindowStack()1252 def uiautomatorDump(self):1253 """1254 Returns whether or not uiautomator is used for refreshView()1255 """1256 return self._uiautomatorDump1257 def uninstall(self, apkname, keepData=False):1258 """1259 Uninstall a package from the device.1260 Parameters:1261 package (string):1262 the package to be uninstalled.1263 keepData (boolean, optional):1264 keep app data and cache.1265 Corresponds to adb uninstall "-k".1266 The default is False.1267 Returns True on success, otherwise False.1268 Example:1269 d.uninstall("com.android.python27")1270 """1271 if self._conn:1272 return self._conn.uninstall(apkname, keepData)1273 else:1274 return False1275 def userRotation(self):1276 """1277 Returns rotation set with setUserRotation.1278 """1279 return self.existingConnection().recvUserRotation()1280 def verifyText(self, text, partial=False):1281 """1282 Verify that the last view has at least one item with given1283 text.1284 Parameters:1285 text (string):1286 text to be searched for in items.1287 partial (boolean, optional):1288 if True, match items if item text contains given1289 text, otherwise match only if item text is equal to1290 the given text. The default is False (exact match).1291 """1292 assert self._lastView != None, "View required."1293 return self._lastView.findItemsByText(text, partial=partial, count=1, onScreen=True) != []1294 def view(self):1295 """1296 Returns the last view (the most recently refreshed view).1297 """1298 return self._lastView1299 def waitAnyText(self, listOfTexts, partial=False, uiautomatorDump=False, **waitKwArgs):1300 """1301 Wait until any of texts is on the screen.1302 Parameters:1303 listOfTexts (list of string):1304 texts to be waited for.1305 partial (boolean, optional):1306 refer to verifyText. The default is False.1307 uiautomatorDump (boolean, optional):1308 use uiautomator to read view dump from the device.1309 If not given, uiautomatorDump() default will be used.1310 waitTime, pollDelay, beforeRefresh, afterRefresh (optional):1311 refer to wait documentation.1312 Returns list of texts that appear in the first refreshed view1313 that contains at least one of the texts. If none of the texts1314 appear within the time limit, returns empty list.1315 If any of texts is not found from the latest refreshed1316 view, waitAnyText will update the view in pollDelay interval until1317 waitTime is exceeded.1318 """1319 if listOfTexts == []: return []1320 if not self._lastView: self.refreshView(uiautomatorDump=uiautomatorDump)1321 waitArgs, rest = fmbtgti._takeWaitArgs(waitKwArgs)1322 foundTexts = []1323 def observe():1324 for text in listOfTexts:1325 if self.verifyText(text, partial=partial):1326 foundTexts.append(text)1327 return foundTexts != []1328 self.wait(1329 lambda: self.refreshView(uiautomatorDump=uiautomatorDump),1330 observe, **waitArgs)1331 return foundTexts1332 def waitText(self, text, *waitAnyTextArgs, **waitAnyTextKwArgs):1333 """1334 Wait until text appears in any view item.1335 Parameters:1336 text (string):1337 text to be waited for.1338 partial (boolean, optional):1339 refer to verifyText. The default is False.1340 uiautomatorDump (boolean, optional):1341 use uiautomator to read view dump from the device.1342 If not given, uiautomatorDump() default will be used.1343 waitTime, pollDelay, beforeRefresh, afterRefresh (optional):1344 refer to wait documentation.1345 Returns True if text appeared within given time limit,1346 otherwise False.1347 Updates the last view if the text is not found in the latest view1348 and waitTime > 0.1349 """1350 return self.waitAnyText(1351 [text], *waitAnyTextArgs, **waitAnyTextKwArgs) != []1352 def wake(self):1353 """1354 Force the device to wake up.1355 """1356 return self.existingConnection().sendWake()...
test.py
Source:test.py
1import shlex2from subprocess import Popen, PIPE3import xml.etree.ElementTree as ET4import time5def get_exitcode_stdout_stderr(cmd):6 """7 Execute the external command and get its exitcode, stdout and stderr.8 """9 args = shlex.split(cmd)10 proc = Popen(args, stdout=PIPE, stderr=PIPE)11 out, err = proc.communicate()12 exitcode = proc.returncode13 #14 return exitcode, out, err15 16 17def capture(filename):18 get_exitcode_stdout_stderr("adb shell screencap -p /sdcard/"+filename+".png")19 exitcode,out,err = get_exitcode_stdout_stderr('adb pull /sdcard/'+filename+'.png "D:\long term\uiautomator simple_automation"')20 #print exitcode21 #print err22 get_exitcode_stdout_stderr("adb shell rm /sdcard/"+filename+".png ")23 return24def xmlParse():25 return26 27def bounds2array(boundsString):28 #print boundsString29 first=boundsString.split("][")30 31 return first[0].split("[")[1].split(",") , first[1].split("]")[0].split(",")32 33def swipeBar(a,b):34 x=a35 y=b36 x[0] = str(int(x[0]) + 50) 37 y[0] = str(int(y[0]) - 50)38 39 x[1] = str ( ( int(y[1]) + int(x[1]) ) / 2 + ( int(y[1]) - int(x[1]) ) /4 )40 41 y[1] = x[1]42 43 cmd = "adb shell input swipe "+x[0]+" "+x[1] +" "+ y[0]+" "+y[1] + " 100 " # arbitrary external command, e.g. "python mytest.py"44 print cmd45 exitcode, out, err = get_exitcode_stdout_stderr(cmd)46 return 47 48def horizswipe(a,b,step):49 x=a50 y=b51 temp = int(x[0]) + int(y[0]) 52 x[0] = str( temp /2 + step/2 ) 53 y[0] = str( temp /2 - step/2) 54 55 x[1] = str ( ( int(y[1]) + int(x[1]) ) / 2 + ( int(y[1]) - int(x[1]) ) /4 )56 57 y[1] = x[1]58 #print x[0]59 #print y[0] 60 61 #swipe <x1> <y1> <x2> <y2> [duration(ms)] 62 cmd = "adb shell input swipe "+x[0]+" "+x[1] +" "+y[0]+" "+y[1] + " 100 " # arbitrary external command, e.g. "python mytest.py"63 print cmd64 #print "adb shell input swipe "+x[0]+" "+x[1] +" "+y[0]+" "+y[1] + " 100 " 65 exitcode, out, err = get_exitcode_stdout_stderr(cmd)66 return67 68def uiautomatordump():69 cmd = "adb shell uiautomator dump " # arbitrary external command, e.g. "python mytest.py"70 exitcode, out, err = get_exitcode_stdout_stderr(cmd)71 # get the dump xml 72 cmd = "adb shell cat /storage/emulated/legacy/window_dump.xml" 73 exitcode, out, err = get_exitcode_stdout_stderr(cmd)74 if exitcode != 0:75 print err76 else:77 print 78 #print out 79 80 root = ET.fromstring(out)81 #print root 82 return root83def getfee(root): 84 85 86 daily_fee_tv = root.findall(".//node[@resource-id='com.ucredit.paydayloan:id/daily_fee_tv']")[0]87 #ET.dump(daily_fee_tv[0])88 #print daily_fee_tv.attrib['text']89 collected_amount_tv = root.findall(".//node[@resource-id='com.ucredit.paydayloan:id/collected_amount_tv']")[0]90 #print collected_amount_tv.attrib['text']91 total_fee_tv = root.findall(".//node[@resource-id='com.ucredit.paydayloan:id/total_fee_tv']")[0]92 #print total_fee_tv.attrib['text']93 return daily_fee_tv.attrib['text'],collected_amount_tv.attrib['text'],total_fee_tv.attrib['text']94 95root = uiautomatordump()96loan_amount_view = root.findall(".//node[@resource-id='com.ucredit.paydayloan:id/loan_amount_view']")[0]97#print loan_amount_view.attrib['bounds']98a,b = bounds2array(loan_amount_view.attrib['bounds'])99swipeBar(a,b)100loan_days_view = root.findall(".//node[@resource-id='com.ucredit.paydayloan:id/loan_days_view']")[0]101#print loan_days_view.attrib['bounds']102#print type(loan_days_view.attrib['bounds'])103c,d = bounds2array(loan_days_view.attrib['bounds'])104swipeBar(c,d)105root = uiautomatordump()106feea,feeb,feec = getfee(root)107last = 0108 109#print "fees:"110#print (feea,feeb,feec)111#capture("test-500-7days")112y=7113for x in range(500, 1100,100):114 if x!=500:115 horizswipe(a,b, 120)116 print "amount to right"117 time.sleep(2) 118 root = uiautomatordump()119 #capture("test-"+str(x)+"-"+str(y)+"days")120 loan_amount_view = root.findall(".//node[@resource-id='com.ucredit.paydayloan:id/loan_amount_view']")[0]121 loan_days_view = root.findall(".//node[@resource-id='com.ucredit.paydayloan:id/loan_days_view']")[0]122 #print loan_amount_view.attrib['bounds']123 a,b = bounds2array(loan_amount_view.attrib['bounds']) 124 c,d = bounds2array(loan_days_view.attrib['bounds'])125 feea,feeb,feec = getfee(root) 126 for y in range(7, 31):127 print str(y)+" days"+" amount "+str(x)128 if y!=7:129 horizswipe(c,d, 40)130 time.sleep(2) 131 root = uiautomatordump()132 capture("test-"+str(x)+"-"+str(y)+"days")133 loan_amount_view = root.findall(".//node[@resource-id='com.ucredit.paydayloan:id/loan_amount_view']")[0]134 loan_days_view = root.findall(".//node[@resource-id='com.ucredit.paydayloan:id/loan_days_view']")[0]135 #print loan_amount_view.attrib['bounds']136 a,b = bounds2array(loan_amount_view.attrib['bounds']) 137 c,d = bounds2array(loan_days_view.attrib['bounds']) 138 feea,feeb,feec = getfee(root) 139 140 while feeb == last:141 142 horizswipe(c,d, 40)143 time.sleep(2) 144 root = uiautomatordump()145 capture("test-"+str(x)+"-"+str(y)+"days")146 loan_amount_view = root.findall(".//node[@resource-id='com.ucredit.paydayloan:id/loan_amount_view']")[0]147 loan_days_view = root.findall(".//node[@resource-id='com.ucredit.paydayloan:id/loan_days_view']")[0]148 #print loan_amount_view.attrib['bounds']149 a,b = bounds2array(loan_amount_view.attrib['bounds']) 150 c,d = bounds2array(loan_days_view.attrib['bounds']) 151 feea,feeb,feec = getfee(root) 152 f = open('paydayloan_test_result.csv', 'a')153 f.write(feea+','+feeb+','+feec+'\n')154 f.close()155 last = feeb156 157 swipeBar(c,d)158 print "swipe day bar to left"159 time.sleep(2)160 161 162'''163 164time.sleep(3)165horizswipe(a,b, 120)166print "1"167time.sleep(3)168horizswipe(a,b, 120)169print "2"170time.sleep(3)171horizswipe(a,b, 120)172print "3"173time.sleep(3)174time.sleep(3)175horizswipe(c,d, 80)176print "1"177time.sleep(3)178horizswipe(c,d, 80)179print "2"180time.sleep(3)181horizswipe(c,d, 80)182print "3"183time.sleep(3)...
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!