def get_screen(self, path, log_level=logging.INFO): """ Save screen of mobile device. :param path: Path to image that will be saved. :param log_level: Log level. """ # Ensure folder to save the screen exists File.delete(path) Folder.create(folder=os.path.dirname(path)) if self.type is DeviceType.EMU or self.type is DeviceType.ANDROID: Adb.get_screen(device_id=self.id, file_path=path) if self.type is DeviceType.SIM: Simctl.get_screen(sim_id=self.id, file_path=path) if self.type is DeviceType.IOS: IDevice.get_screen(device_id=self.id, file_path=path) image_saved = False if File.exists(path): size = os.path.getsize(path) if size > 10: image_saved = True if image_saved: message = "Image of {0} saved at {1}".format(self.id, path) Log.log(level=log_level, msg=message) else: message = "Failed to save image of {0} saved at {1}".format( self.id, path) Log.error(message) raise Exception(message)
def test_06_copy_to_not_existing_file_with_restore(self): TestContext.BACKUP_FILES.clear() Folder.clean(Settings.BACKUP_FOLDER) # Path to files file_name = "app.android.add_style.scss" folder_name = os.path.join(self.current_folder, 'resources', 'new') Folder.clean(folder_name) Folder.create(folder_name) old_scss = os.path.join(self.current_folder, 'resources', 'app.android.scss') new_scss = os.path.join(folder_name, file_name) # Test Copy File.copy(source=old_scss, target=new_scss, backup_files=True) assert File.exists(new_scss) assert len(File.read( path=new_scss).splitlines()) == 14, 'Unexpected lines count.' assert not File.exists(os.path.join(Settings.BACKUP_FOLDER, file_name)), "File not backup!" assert TestContext.BACKUP_FILES.items()[0].__getitem__( 0) == new_scss, "File path is not correct!" assert TestContext.BACKUP_FILES.items()[0].__getitem__( 1) == file_name, "File name not correct!" # Revert TnsTest.restore_files() assert not File.exists(new_scss) assert not File.exists(os.path.join(Settings.BACKUP_FOLDER, file_name)), "File not deleted!" assert not TestContext.BACKUP_FILES, "File object not deleted!"
def test_302_test_SBG_works_when_you_have_nativescript_property_in_package_json(self): """ https://github.com/NativeScript/android-runtime/issues/1409 """ source_js = os.path.join(TEST_RUN_HOME, 'assets', 'runtime', 'android', 'files', 'android-runtime-1409', 'package.json') target_js = os.path.join(TEST_RUN_HOME, APP_NAME, 'app', 'package.json') File.copy(source=source_js, target=target_js, backup_files=True) source_js = os.path.join(TEST_RUN_HOME, 'assets', 'runtime', 'android', 'files', 'android-runtime-1409', 'new', 'package.json') target_js = os.path.join(TEST_RUN_HOME, APP_NAME, 'app', 'new', 'package.json') new_folder = os.path.join(TEST_RUN_HOME, APP_NAME, 'app', 'new') Folder.create(new_folder) File.copy(source=source_js, target=target_js, backup_files=True) webpack_config = os.path.join(TEST_RUN_HOME, APP_NAME, 'webpack.config.js') old_string = 'new nsWebpack.GenerateNativeScriptEntryPointsPlugin("bundle"),' new_string = 'new CopyWebpackPlugin(dataToCopy), new nsWebpack.GenerateNativeScriptEntryPointsPlugin("bundle"),' File.replace(path=webpack_config, old_string=old_string, new_string=new_string, backup_files=True) old_string = 'const dist = resolve(projectRoot, nsWebpack.getAppPath(platform, projectRoot));' new_string = """ const dist = resolve(projectRoot, nsWebpack.getAppPath(platform, projectRoot)); const fileName = "package.json" const dataInfo = { from: `../app/new/${fileName}`, to: `${dist}/new/${fileName}`, } env.externals = [fileName]; const dataToCopy = [dataInfo];""" File.replace(path=webpack_config, old_string=old_string, new_string=new_string, backup_files=False) log = Tns.build_android(os.path.join(TEST_RUN_HOME, APP_NAME), verify=False).output test_result = Wait.until(lambda: "Project successfully built." in log, timeout=300, period=5) assert test_result, 'App not build correct! Logs:' + log
def test_454_support_Kotlin_with_jar_without_use_kotlin(self): """ Support gradle.properties file for enable Kotlin https://github.com/NativeScript/android-runtime/issues/1459 https://github.com/NativeScript/android-runtime/issues/1463 """ Tns.plugin_remove("sample-plugin-2", verify=False, path=APP_NAME) Adb.clear_logcat(self.emulator.id) source_app_gradle = os.path.join(TEST_RUN_HOME, 'assets', 'runtime', 'android', 'files', 'android-runtime-1463-1459', 'test-jar-1.0-SNAPSHOT.jar') target_app_gradle = os.path.join(TEST_RUN_HOME, APP_NAME, 'app', 'App_Resources', 'Android', 'libs') Folder.create(target_app_gradle) File.copy(source=source_app_gradle, target=target_app_gradle, backup_files=True) source_js = os.path.join(TEST_RUN_HOME, 'assets', 'runtime', 'android', 'files', 'android-runtime-1463-1459', 'main-view-model.js') target_js = os.path.join(TEST_RUN_HOME, APP_NAME, 'app', 'main-view-model.js') File.copy(source=source_js, target=target_js, backup_files=True) log = Tns.run_android(APP_NAME, device=self.emulator.id, wait=False, verify=False) strings = ['Project successfully built', 'Successfully installed on device with identifier', self.emulator.id, 'Successfully synced application'] test_result = Wait.until(lambda: all(string in File.read(log.log_file) for string in strings), timeout=300, period=5) messages = "App with Kotlin enabled and kotlin jar not build correctly! Logs: " assert test_result, messages + File.read(log.log_file) self.assert_kotlin_is_working(self.emulator)
def test_453_support_gradle_properties_for_enable_Kotlin_with_kotlin_file(self): """ Support gradle.properties file for enable Kotlin https://github.com/NativeScript/android-runtime/issues/1459 https://github.com/NativeScript/android-runtime/issues/1463 """ Tns.platform_remove(APP_NAME, platform=Platform.ANDROID) Tns.platform_add_android(APP_NAME, framework_path=Android.FRAMEWORK_PATH) Adb.clear_logcat(self.emulator.id) source_app_gradle = os.path.join(TEST_RUN_HOME, 'assets', 'runtime', 'android', 'files', 'android-runtime-1463-1459', 'gradle.properties') target_app_gradle = os.path.join(TEST_RUN_HOME, APP_NAME, 'app', 'App_Resources', 'Android') File.copy(source=source_app_gradle, target=target_app_gradle, backup_files=True) source_app_gradle = os.path.join(TEST_RUN_HOME, 'assets', 'runtime', 'android', 'files', 'android-runtime-1463-1459', 'Test.kt') target_app_gradle = os.path.join(TEST_RUN_HOME, APP_NAME, 'app', 'App_Resources', 'Android', 'src', 'main', 'java', 'com') Folder.create(target_app_gradle) File.copy(source=source_app_gradle, target=target_app_gradle, backup_files=True) source_js = os.path.join(TEST_RUN_HOME, 'assets', 'runtime', 'android', 'files', 'android-runtime-1463-1459', 'main-view-model.js') target_js = os.path.join(TEST_RUN_HOME, APP_NAME, 'app', 'main-view-model.js') File.copy(source=source_js, target=target_js, backup_files=True) log = Tns.run_android(APP_NAME, device=self.emulator.id, wait=False, verify=False) strings = ['Project successfully built', 'Successfully installed on device with identifier', self.emulator.id, 'Successfully synced application'] test_result = Wait.until(lambda: all(string in File.read(log.log_file) for string in strings), timeout=300, period=5) messages = "App with Kotlin enabled and kotlin jar not build correctly! Logs: " assert test_result, messages + File.read(log.log_file) self.assert_kotlin_is_working(self.emulator)
def test_115_tns_run_android_add_remove_files_and_folders(self): """ Add/delete files and folders should be synced properly """ # Run app and verify on device result = run_hello_world_js_ts(self.app_name, Platform.ANDROID, self.emu) # Add new file # To verify that file is synced on device we have to refer some function # from it and verify it is executed. We will use console.log app_folder = os.path.join(self.source_project_dir, 'app') new_file = os.path.join(app_folder, 'test.js') renamed_file = os.path.join(app_folder, 'test_2.js') app_js_file = os.path.join(app_folder, 'app.js') File.write(new_file, "console.log('test.js synced!!!');") File.append(app_js_file, "require('./test.js');") strings = ["JS: test.js synced!!!"] TnsLogs.wait_for_log(log_file=result.log_file, string_list=strings) # Rename file os.rename(new_file, renamed_file) File.replace(renamed_file, 'test.js', 'renamed file') time.sleep(1) File.replace(app_js_file, 'test.js', 'test_2.js') strings = ["JS: renamed file synced!!!"] TnsLogs.wait_for_log(log_file=result.log_file, string_list=strings) # Delete file File.delete(renamed_file) strings = ["Module build failed", "Error: ENOENT: no such file or directory", 'Successfully synced application'] TnsLogs.wait_for_log(log_file=result.log_file, string_list=strings) self.emu.wait_for_text(text='Exception') File.replace(app_js_file, "require('./test_2.js');", ' ') strings = TnsLogs.run_messages(app_name=self.app_name, platform=Platform.ANDROID, device=self.emu, run_type=RunType.UNKNOWN) not_existing_strings = ['12345'] TnsLogs.wait_for_log(log_file=result.log_file, string_list=strings, not_existing_string_list=not_existing_strings) self.emu.wait_for_text(text=Changes.JSHelloWord.JS.old_text) # Add folder folder_name = os.path.join(app_folder, 'test_folder') new_file = os.path.join(folder_name, 'test_in_folder.js') Folder.create(folder_name) File.write(new_file, "console.log('test_in_folder.js synced!!!');") File.append(app_js_file, "require('./test_folder/test_in_folder.js');") strings = ["JS: test_in_folder.js synced!!!"] TnsLogs.wait_for_log(log_file=result.log_file, string_list=strings) # Delete folder Folder.clean(folder_name) strings = ["Module build failed", "Error: ENOENT: no such file or directory"] TnsLogs.wait_for_log(log_file=result.log_file, string_list=strings) self.emu.wait_for_text(text='Exception')
def test_01_file_download(self): file_name = "nativescript-logo.png" file_path_default = TEST_RUN_HOME file_path = os.path.join(TEST_RUN_HOME, "test") url = "https://www.nativescript.org/images/default-source/logos/nativescript-logo.png" File.download(file_name, url) Folder.create(file_path) assert File.exists(os.path.join(file_path_default, file_name)) File.download(file_name, url, file_path) assert File.exists(os.path.join(file_path, file_name))
def test_115_tns_run_ios_add_remove_files_and_folders(self): """ Add/delete files and folders should be synced properly """ # Run app and verify on device result = run_hello_world_js_ts(self.app_name, Platform.IOS, self.sim) # Add new file # To verify that file is synced on device we have to refer some function # from it and verify it is executed. We will use console.log app_folder = os.path.join(self.source_project_dir, 'app') new_file = os.path.join(app_folder, 'test.js') renamed_file = os.path.join(app_folder, 'test_2.js') app_js_file = os.path.join(app_folder, 'main-view-model.js') File.write(new_file, "console.log('test.js synced!!!');") File.append(app_js_file, "require('./test.js');") strings = ["test.js synced!!!"] TnsLogs.wait_for_log(log_file=result.log_file, string_list=strings) # Rename file os.rename(new_file, renamed_file) File.replace(renamed_file, 'test.js', 'renamed file') time.sleep(1) File.replace(app_js_file, 'test.js', 'test_2.js') strings = ["renamed file synced!!!"] TnsLogs.wait_for_log(log_file=result.log_file, string_list=strings) # Delete file File.delete(renamed_file) strings = ["Module build failed: Error: ENOENT", "NativeScript debugger detached"] TnsLogs.wait_for_log(log_file=result.log_file, string_list=strings) File.replace(app_js_file, "require('./test_2.js');", ' ') strings = TnsLogs.run_messages(app_name=self.app_name, platform=Platform.IOS, device=self.sim, run_type=RunType.UNKNOWN) not_existing_strings = ['123'] TnsLogs.wait_for_log(log_file=result.log_file, string_list=strings, not_existing_string_list=not_existing_strings) self.sim.wait_for_text(text=Changes.JSHelloWord.JS.old_text) # Add folder folder_name = os.path.join(app_folder, 'test_folder') new_file = os.path.join(folder_name, 'test_in_folder.js') Folder.create(folder_name) File.write(new_file, "console.log('test_in_folder.js synced!!!');") File.append(app_js_file, "require('./test_folder/test_in_folder.js');") strings = ["test_in_folder.js synced!!!"] TnsLogs.wait_for_log(log_file=result.log_file, string_list=strings) self.sim.wait_for_text(text=Changes.JSHelloWord.JS.old_text) # Delete folder Folder.clean(folder_name) strings = ["Module build failed: Error: ENOENT"] TnsLogs.wait_for_log(log_file=result.log_file, string_list=strings)
def setUpClass(cls): # Get class name and log TestContext.STARTED_PROCESSES = [] TestContext.STARTED_DEVICES = [] TestContext.TEST_APP_NAME = None TestContext.CLASS_NAME = cls.__name__ try: for item in inspect.stack(): TestContext.CLASS_NAME = item[0].f_locals['cls'].__name__ except Exception: pass Log.test_class_start(class_name=TestContext.CLASS_NAME) # Kill processes Adb.restart() Tns.kill() Gradle.kill() TnsTest.kill_emulators() TnsTest.__clean_backup_folder_and_dictionary() # Ensure log folders are create Folder.create(Settings.TEST_OUT_HOME) Folder.create(Settings.TEST_OUT_LOGS) Folder.create(Settings.TEST_OUT_IMAGES) Folder.create(Settings.TEST_OUT_TEMP) # Set default simulator based on Xcode version if Settings.HOST_OS == OSType.OSX: if Xcode.get_version() < 10: Settings.Simulators.DEFAULT = Settings.Simulators.SIM_IOS11 else: if Xcode.get_version() < 11: Settings.Simulators.DEFAULT = Settings.Simulators.SIM_IOS12 else: Settings.Simulators.DEFAULT = Settings.Simulators.SIM_IOS13
def test_07_copy_to_existing_file_with_restore(self): TestContext.BACKUP_FILES.clear() Folder.clean(Settings.BACKUP_FOLDER) # Path to files file_name = "app.android.add_style.scss" folder_name = os.path.join(self.current_folder, 'resources', 'new') Folder.clean(folder_name) Folder.create(folder_name) old_scss = os.path.join(self.current_folder, 'resources', 'app.android.scss') new_scss = os.path.join(folder_name, file_name) old_value = 'Android here' new_value = 'Android here\n.page { background-color: red;}' # Create new file (so we don't break original one). File.copy(source=old_scss, target=new_scss) assert len(File.read( path=new_scss).splitlines()) == 14, 'Unexpected lines count.' # Replace File.replace(path=new_scss, old_string=old_value, new_string=new_value) content = File.read(path=new_scss) assert 'red;' in content, 'Failed to replace string.' assert len(content.splitlines()) == 15, 'Unexpected lines count.' # Test Copy File.copy(source=old_scss, target=new_scss, backup_files=True) content = File.read(path=new_scss) assert 'red;' not in content, 'Failed to copy file!' assert len(content.splitlines()) == 14, 'Unexpected lines count.' assert File.exists(new_scss) assert File.exists(os.path.join(Settings.BACKUP_FOLDER, file_name)), "File not backup!" assert TestContext.BACKUP_FILES.items()[0].__getitem__( 0) == new_scss, "File path is not correct!" assert TestContext.BACKUP_FILES.items()[0].__getitem__( 1) == file_name, "File name not correct!" # Revert TnsTest.restore_files() assert File.exists(new_scss) content = File.read(path=new_scss) assert 'red;' in content, 'Failed to replace string.' assert len(content.splitlines()) == 15, 'Unexpected lines count.' assert not File.exists(os.path.join(Settings.BACKUP_FOLDER, file_name)), "File not deleted!" assert not TestContext.BACKUP_FILES, "File object not deleted!" File.delete(path=new_scss)
def test_301_build_project_with_space_release(self): # Ensure ANDROID_KEYSTORE_PATH contain spaces (verification for CLI issue 2650) Folder.create("with space") file_name = os.path.basename(Settings.Android.ANDROID_KEYSTORE_PATH) cert_with_space_path = os.path.join("with space", file_name) File.copy(Settings.Android.ANDROID_KEYSTORE_PATH, cert_with_space_path) Tns.build_android(app_name='"' + self.app_name_with_space + '"', release=True) output = File.read(os.path.join(self.app_name_with_space, "package.json")) assert self.app_identifier in output.lower() output = File.read(os.path.join(TnsPaths.get_platforms_android_src_main_path(self.app_name_with_space), 'AndroidManifest.xml')) assert self.app_identifier in output.lower()
def get_screenshots(): # get host snapshot base_path = os.path.join(Settings.TEST_OUT_IMAGES, TestContext.CLASS_NAME, TestContext.TEST_NAME) try: import pyautogui png_path = os.path.join(base_path, 'host.png') File.delete(png_path) Folder.create(folder=os.path.dirname(png_path)) pyautogui.screenshot().save(png_path) Log.info("Saved host os screen at {0}".format(png_path)) except Exception: Log.warning('Failed to take screenshot of host os.') # get device screenshots for device in TestContext.STARTED_DEVICES: try: png_path = os.path.join(base_path, device.name + '.png') File.delete(png_path) device.get_screen(png_path) except AssertionError: Log.warning('Failed to take screenshot of {0}'.format(device.id))
def test_442_assert_arm64_is_enabled_by_default(self): """ Test arm64-v8 is enabled by default """ Tns.build_android(os.path.join(TEST_RUN_HOME, APP_NAME), verify=True) apk_folder = os.path.join(TEST_RUN_HOME, APP_NAME, "platforms", "android", "app", "build", "outputs", "apk", "debug") apk_file = os.path.join(apk_folder, "app-debug.apk") apk_folder_to_unzip = os.path.join(apk_folder, "apk") Folder.create(apk_folder_to_unzip) command = "unzip " + apk_file + " -d " + apk_folder_to_unzip run(command, wait=False) time.sleep(20) unzip_apk_folder = os.path.join(apk_folder, "apk") arm64_folder = os.path.join(unzip_apk_folder, "lib", "arm64-v8a") assert Folder.exists( arm64_folder), "arm64-v8a architecture is missing!" error_message = "libNativeScript.so in arm64-v8a folder is missing!" assert File.exists(os.path.join(arm64_folder, "libNativeScript.so")), error_message
def setUpClass(cls): Folder.clean(Settings.TEST_OUT_HOME) Folder.create(Settings.TEST_OUT_LOGS) Folder.create(Settings.TEST_OUT_IMAGES) Folder.create(Settings.TEST_OUT_TEMP) Process.kill(proc_name="adb") TnsRunAndroidTest.setUpClass() url = "https://github.com/webdriverio/native-demo-app/releases/download/0.2.1/Android-NativeDemoApp-0.2.1.apk" cls.apk_path = os.path.join(Settings.TEST_RUN_HOME, "test.apk") File.delete(path=cls.apk_path) File.download(file_name='test.apk', url=url, destination_dir=Settings.TEST_RUN_HOME)
def __cleanup(): """ Wipe TEST_OUT_HOME. """ Folder.clean(os.path.join(Settings.TEST_RUN_HOME, 'node_modules')) Folder.clean(Settings.TEST_OUT_HOME) Folder.create(Settings.TEST_OUT_LOGS) Folder.create(Settings.TEST_OUT_IMAGES) Folder.create(Settings.TEST_OUT_TEMP) DeviceManager.Emulator.stop() if Settings.HOST_OS == OSType.OSX: DeviceManager.Simulator.stop() Adb.restart() Tns.kill() Gradle.kill()
def run(cmd, cwd=Settings.TEST_RUN_HOME, wait=True, timeout=600, fail_safe=False, register=True, log_level=logging.DEBUG): # Init result values time_string = datetime.now().strftime('%Y_%m_%d_%H_%M_%S_%f') log_file = os.path.join(Settings.TEST_OUT_LOGS, 'command_{0}.txt'.format(time_string)) complete = False duration = None output = '' # Ensure logs folder exists dir_path = os.path.dirname(os.path.realpath(log_file)) Folder.create(dir_path) # Command settings if not wait: # Redirect output to file File.write(path=log_file, text=cmd + os.linesep + '====>' + os.linesep) cmd = cmd + ' >> ' + log_file + ' 2>&1 &' # Log command that will be executed: Log.log(level=log_level, msg='Execute command: ' + cmd) Log.log(level=logging.DEBUG, msg='CWD: ' + cwd) # Execute command: if wait: start = time.time() with open(log_file, mode='w') as log: if Settings.HOST_OS == OSType.WINDOWS: process = subprocess.Popen(cmd, cwd=cwd, shell=True, stdout=log, stderr=log) else: process = subprocess.Popen(cmd, cwd=cwd, shell=True, stdout=subprocess.PIPE, stderr=log) # Wait until command complete try: process.wait(timeout=timeout) complete = True out, err = process.communicate() if out is not None: if Settings.PYTHON_VERSION < 3: output = str(out.decode('utf8').encode('utf8')).strip() else: output = out.decode("utf-8").strip() except subprocess.TimeoutExpired: process.kill() if fail_safe: Log.error('Command "{0}" timeout after {1} seconds.'.format( cmd, timeout)) else: raise # Append stderr to output stderr = File.read(path=log_file) if stderr: output = output + os.linesep + File.read(path=log_file) # noinspection PyBroadException try: File.delete(path=log_file) except Exception: Log.debug('Failed to clean log file: {0}'.format(log_file)) log_file = None end = time.time() duration = end - start else: process = psutil.Popen(cmd, cwd=cwd, shell=True, stdin=None, stdout=None, stderr=None, close_fds=True) # Get result pid = process.pid exit_code = process.returncode # Log output of the process if wait: Log.log(level=log_level, msg='OUTPUT: ' + os.linesep + output + os.linesep) else: Log.log(level=log_level, msg='OUTPUT REDIRECTED: ' + log_file + os.linesep) # Construct result result = ProcessInfo(cmd=cmd, pid=pid, exit_code=exit_code, output=output, log_file=log_file, complete=complete, duration=duration) # Register in TestContext if psutil.pid_exists(result.pid) and register: TestContext.STARTED_PROCESSES.append(result) # Return the result return result