Appium 2.0:移动自动化测试的革新之旅
关注开源优测不迷路
大数据测试过程、策略及挑战
测试框架原理,构建成功的基石
在自动化测试工作之前,你应该知道的10条建议
在自动化测试中,重要的不是工具
在移动应用开发的领域中,Appium 作为一款强大的自动化测试工具,不断演进和发展,为开发者提供了更高效、更灵活的测试解决方案。Appium 2.0 相较于之前的版本,在多个方面进行了优化和改进,带来了全新的功能和体验。以下将从变化、核心特色以及与 Python 结合的基本使用过程三个方面来详细介绍 Appium 2.0。
一、Appium 2.0 相对 Appium 1.0 的变化
(一)架构层面
驱动与服务器分离:在 Appium 1.0 中,平台驱动与 Appium Server 紧密耦合,导致更新和维护较为困难。而 Appium 2.0 实现了平台驱动与 Appium Server 的分离,驱动可以独立安装和升级,不再受 Appium Server 更新的限制。这大大提高了 Appium 的灵活性和可扩展性,使得开发者能够根据不同的平台和设备需求,单独安装和更新所需的驱动,更好地应对多样化的测试场景。
插件系统引入:Appium 2.0 引入了插件生态系统,将一些非核心功能从核心代码中分离出来,转移到插件中。这不仅简化了 Appium 的核心功能,使其更加简洁和易于维护,还为开发者提供了更多的可能性,能够通过安装和使用插件来扩展 Appium 的功能,满足各种特定的测试需求。例如,官方的 images 插件支持图像识别定位元素,第三方插件 appium - device - farm 可集中管理测试设备。
(二)协议与标准遵循
严格遵循 W3C 协议:Appium 2.0 严格遵循 W3C 协议,与 Selenium 4 的协议规范相似。这意味着在编写测试脚本时,需要按照 W3C 标准来填写 capabilities。在 Appium 1.0 中,可能存在一些非标准的协议和 capabilities,而在 2.0 中,这种情况得到了改善,所有的 capabilities 都需要遵循 W3C 标准,这使得 Appium 与其他遵循 W3C 协议的测试工具更加兼容,提高了测试的互操作性。
(三)安装与配置
依赖环境变化:Appium 2.0 的安装和配置需要基于 Node.js 环境,并且对 Node.js 的版本有特定要求。在安装过程中,需要使用 appium@next 参数进行安装(正式发布后可使用 appium 参数)。这种变化要求开发者在使用 Appium 2.0 之前,需要确保系统中安装了符合要求的 Node.js 环境,这也增加了使用 Appium 2.0 的门槛,但同时也保证了 Appium 在不同环境中的稳定性和一致性。
扩展安装模式:Appium 2.0 引入了 Appium Extension CLI 模式,用于更方便地扩展安装各种平台驱动和插件。这种模式使得开发者能够更轻松地管理和扩展 Appium 的功能,根据具体的测试需求,快速安装所需的驱动和插件,提高了测试的效率和灵活性。
(四)测试脚本相关
服务器访问地址变更:Appium 2.0 中,Appium Server 的访问地址发生了变化,不再需要后缀 /wd/hub。这意味着在测试脚本中,需要相应地更新访问地址,以确保与 Appium Server 的正确连接。开发者需要使用新的地址格式来连接 Appium Server,这对于一些习惯了旧版本地址格式的开发者来说,可能需要进行一些调整和适应。
驱动和插件配置调整:由于 Appium 2.0 引入了驱动和插件分离的概念,开发者在使用测试脚本时,需要根据具体的测试需求,安装和配置相应的驱动和插件。这需要开发者对 Appium 的架构和插件系统有更深入的了解,以便正确地配置和使用各种驱动和插件,确保测试的顺利进行。
Capabilities 格式更新:因为 Appium 2.0 严格遵循 W3C 协议,所以测试脚本中的 capabilities 格式也需要进行更新,以确保与 Appium Server 的兼容性。开发者需要按照 W3C 标准来填写 capabilities,这可能需要对现有测试脚本进行一些修改和调整,以适应 Appium 2.0 的新要求。
二、Appium 2.0 的核心特色
(一)跨平台兼容性
统一测试框架:Appium 2.0 提供了一个统一的测试框架,能够在不同的操作系统和移动设备上运行相同的测试脚本。无论是 Android 还是 iOS 设备,开发者都可以使用相同的测试代码来进行自动化测试,大大提高了测试的效率和可移植性。
一致的测试体验:在不同的平台上,Appium 2.0 能够提供一致的自动化测试体验。开发者可以使用相同的方法和接口来操作界面元素,进行各种测试操作,如点击、输入、滑动等。这种一致性使得测试脚本更加简洁和易于维护,同时也提高了测试的准确性和可靠性。
(二)强大的功能支持
多种定位方式:Appium 2.0 支持多种元素定位方式,包括通过 ID、Name、XPath、Class Name 等常见方式,还支持通过图片定位、iOS 谓词定位、Android UIAutomator 定位等高级定位方式。这使得开发者能够根据不同的应用界面结构和需求,选择最合适的定位方式来定位界面元素,提高了测试的灵活性和准确性。
丰富的操作模拟
用户操作模拟:能够模拟用户的各种操作,如点击、输入、滑动、长按等。开发者可以使用相应的方法来实现这些操作,从而实现对应用的自动化测试。
设备功能模拟:除了界面操作模拟,Appium 2.0 还支持对设备功能的模拟,如模拟键盘操作、手机通知栏操作等。这使得开发者能够更全面地测试应用在各种设备环境下的功能和表现。
(三)高度的可定制性
配置灵活性:Appium 2.0 提供了丰富的配置选项,开发者可以根据自己的需求对 Appium 进行灵活配置。例如,可以设置测试环境、设备信息、测试参数等,以满足不同的测试场景和需求。
插件扩展能力:如前所述,Appium 2.0 的插件生态系统使得开发者能够通过安装和使用插件来扩展 Appium 的功能。开发者可以根据自己的需求,选择合适的插件来满足特定的测试需求,从而实现 Appium 的高度可定制化。
三、Appium 2.0 + Python 基本使用过程
(一)环境搭建
安装 Node.js
下载与安装:首先,确保你的系统上安装了 Node.js。可以从 Node.js 官网下载并安装最新版本的 Node.js。在安装过程中,按照安装向导的指示进行操作,确保安装成功。
安装 Appium
使用 npm 安装:使用 npm 命令全局安装 Appium。打开命令行工具,输入以下命令:
npm install -g appium。这将在系统中全局安装 Appium,并使其可以在命令行中直接使用。
安装 Appium 客户端库
Python 客户端:如果使用 Python 作为开发语言,需要安装 Appium 的 Python 客户端库。可以使用 pip 命令进行安装:
pip install Appium - Python - Client。
启动 Appium 服务器
命令行启动:在命令行中输入
appium命令启动 Appium 服务器。这将启动 Appium 服务器,并在后台运行。你可以在命令行中查看服务器的启动日志,以确保服务器启动成功。Appium Desktop:此外,还可以使用 Appium Desktop 工具来启动和管理 Appium 服务器。Appium Desktop 是一个图形化工具,提供了更直观的界面来操作 Appium 服务器,同时还支持元素定位和调试等功能。
(二)基本使用步骤
设置 Desired Capabilities
{"platformName": "Android","platformVersion": "10","deviceName": "emulator - 5554","app": "/path/to/your/app.apk","appPackage": "com.example.app","appActivity": ".MainActivity" }平台信息:
platformName指定了操作系统平台,如Android或iOS;platformVersion指定了操作系统的版本。设备信息:
deviceName指定了设备的名称,这通常是在设备连接到计算机时自动识别的名称。应用信息:
app指定了要测试的应用的路径,appPackage指定了应用的包名,appActivity指定了应用的启动活动。参数说明
配置信息定义:Desired Capabilities 是一个 JSON 对象,用于描述测试会话的配置信息,如平台名称、设备名称、应用路径等。以下是一个示例:
初始化 Appium Driver
from appium import webdriverfrom appium.options.common.base import AppiumOptionsoptions = AppiumOptions() options.load_capabilities({'platformName': 'Android','platformVersion': '10','deviceName': 'emulator - 5554','app': '/path/to/your/app.apk','appPackage': 'com.example.app','appActivity': '.MainActivity' })driver = webdriver.Remote('http://localhost:4723', options=options)连接服务器:在代码中,通过
webdriver.Remote方法连接到 Appium 服务器,并传递服务器地址和配置选项。这里的服务器地址是http://localhost:4723,这是 Appium 服务器的默认地址。如果服务器运行在其他地址或端口上,需要相应地修改地址。导入模块:使用 Python 的
appium库来初始化 Appium Driver,并连接到 Appium 服务器。以下是一个示例代码:
定位元素
常见定位方式:Appium 支持多种元素定位方式,如通过 ID、Name、XPath、Class Name 等。以下是一些常用的定位方式示例:
ID 定位:
element = driver.find_element(by=AppiumBy.ID, value='ID'),通过指定元素的 ID 来定位元素。Name 和 Accessibility ID 定位:
element = driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value='ACCESSIBILITY_ID'),通过元素的 Accessibility ID 来定位元素;element = driver.find_element(by=AppiumBy.NAME, value='NAME'),通过元素的 Name 来定位元素。XPath 定位:
element = driver.find_element(by=AppiumBy.XPATH, value='//*[@text="xpath"]'),使用 XPath 表达式来定位元素。Class Name 定位:
element = driver.find_element_by_css_selector("button[class='btn - class']"),使用 CSS 选择器语法通过元素的类名来定位元素。其他定位方式:除了上述常见的定位方式外,Appium 还支持通过图片定位、iOS 谓词定位、Android UIAutomator 定位等高级定位方式。例如,通过图片定位可以使用
element = driver.find_element(by=AppiumBy.IMAGE, value=base64_image),其中base64_image是将图像文件转换为 base64 编码的字符串。多种定位方式
模拟用户操作
文本内容:
text = element.text用于获取元素的文本内容。位置信息:
location = element.location用于获取元素的位置,返回一个字典,包含元素的 x 和 y 坐标。大小信息:
size = element.size用于获取元素的大小,返回一个字典,包含元素的宽度和高度。属性值:
attribute = element.get_attribute("attribute_name")用于获取元素的指定属性值,其中"attribute_name"是要获取的属性名称。其他信息:还可以获取元素的 ID、父级元素、accessible_name 等信息,具体可查看 Appium 的官方文档。
点击操作:
element.click()用于模拟点击操作,通过找到要点击的元素,并调用click方法来实现点击。driver.tap([(400, 400)], 1000)用于按坐标点击,其中(400, 400)是坐标点,1000是点击时长。输入操作:
element.clear()用于清空输入框的内容,element.send_keys("Hello World")用于向输入框中输入文本。基本操作
获取元素信息:可以通过以下方法获取元素的各种信息:
滑动页面
Appium 2.0 前:在 Appium 2.0 之前,使用
TouchAction类来进行滑动操作,例如:Appium 2.0 后:在 Appium 2.0 以后,
TouchAction类已被弃用,推荐使用ActionChains类来进行滑动操作,例如:滑动方式变化
action = TouchAction(driver)action.press(x=100, y=150).move_to(x=100, y=500).release().perform()element = driver.find_element(by=AppiumBy.ID, value='ID')actions = ActionChains(driver) actions.move_to_element(element) actions.click(hidden_submenu) actions.perform()
等待元素加载
固定等待:使用
time.sleep(10)来进行固定等待,即等待 10 秒。这种方式简单直接,但不够灵活,可能会导致测试时间过长或过短。显示等待:使用
WebDriverWait类和expected_conditions模块来实现显示等待。以下是一个示例:隐式等待:使用
driver.implicitly_wait(10)来设置隐式等待时间为 10 秒。在隐式等待期间,每次查找元素时,如果元素未找到,都会等待一段时间,直到超时。等待方式
在上述代码中,
WebDriverWait类接受两个参数:Driver 和超时时间。until方法用于等待条件满足,这里使用EC.visibility_of_element_located来等待指定元素可见。from selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ECwait = WebDriverWait(driver, 10) element = wait.until(EC.visibility_of_element_located(("id", "your_element_id")))
获取手机截图和网络状态
获取网络状态:
network_connection = driver.network_connection用于获取当前的网络连接状态,返回一个整数值,表示不同的网络连接类型。设置网络状态:
driver.set_network_connection(1)用于设置网络连接为 WiFi 连接,其中 1 表示 WiFi 连接,其他值可能表示不同的网络连接类型,具体可查看 Appium 的文档。多种方式:Appium 提供了多种方式来获取手机截图,例如:
文件保存:
driver.get_screenshot_as_file("screenshot.png")将截图保存为文件。Base64 编码:
driver.get_screenshot_as_base64("screenshot.png")获取截图的 Base64 编码。其他方式:还有
driver.get_screenshot_as_png("screenshot.png")、driver.fullscreen_window("screenshot.png")等方式,可根据具体需求选择使用。获取手机截图
获取网络状态
模拟键盘操作和手机通知栏操作
模拟键盘操作:使用
driver.press_keycode()方法来模拟按下手机物理键,例如driver.press_keycode(4)可能表示按下返回键。手机通知栏操作:使用
driver.open_notifications()方法来打开手机通知栏。
(三)示例代码
以下是一个完整的 Python 示例代码,用于启动一个 Android 模拟器并进行基本的自动化测试:
from appium import webdriverfrom appium.options.common.base import AppiumOptions
from appium.webdriver.common.appiumby import AppiumBy
import time# 设置options
options = AppiumOptions()
options.load_capabilities({'platformName': 'Android','platformVersion': '10','deviceName': 'emulator - 5554','app': '/path/to/your/app.apk','appPackage': 'com.example.app','appActivity': '.MainActivity','resetKeyboard': True, # 重置设备的输入键盘'unicodeKeyboard': True # 采用unicode编码输入
})# 初始化Appium Driver
driver = webdriver.Remote('http://localhost:4723', options=options)try:# 等待应用加载time.sleep(5)# 通过ID定位元素并点击element = driver.find_element(by=AppiumBy.ID, value='your_element_id')element.click()# 通过XPath定位元素并输入文本input_element = driver.find_element(by=AppiumBy.XPATH, value='//*[@text="xpath"]')input_element.clear()input_element.send_keys("Hello World")# 获取元素的文本内容并打印text = input_element.textprint(f"输入框元素的文本信息是: {text}")finally:# 关闭驱动driver.quit() 在上述示例中,首先设置了 Appium 的配置选项,包括平台信息、设备信息、应用信息等。然后,初始化了 Appium Driver,并连接到 Appium 服务器。接下来,通过等待、定位元素、模拟操作等步骤,实现了对应用的基本自动化测试。最后,在测试完成后,关闭了 Appium Driver,释放资源。
相关文章:
Appium 2.0:移动自动化测试的革新之旅
关注开源优测不迷路 大数据测试过程、策略及挑战 测试框架原理,构建成功的基石 在自动化测试工作之前,你应该知道的10条建议 在自动化测试中,重要的不是工具 在移动应用开发的领域中,Appium 作为一款强大的自动化测试工具…...
牛客网最新1129道 Java 面试题及答案整理
前言 面试,跳槽,每天都在发生,而对程序员来说"金三银四"更是面试和跳槽的高峰期,跳槽,更是很常见的,对于每个人来说,跳槽的意义也各不相同,可能是一个人更向往一个更大的…...
Swift Combine 学习(六):自定义 Publisher 和 Subscriber
Swift Combine 学习(一):Combine 初印象Swift Combine 学习(二):发布者 PublisherSwift Combine 学习(三):Subscription和 SubscriberSwift Combine 学习(四&…...
Vue-router知识点汇总
import Vue from vue import Router from vue-router Vue.use(Router) import Layout from /layout export const constantRoutes [{path: /forgetpsd,name: forgetPsd,// 命名路由 ,跳转<router-link :to"{ name: forgetPsdr, params: { userId: 123 }}&q…...
java AQS
什么是AQS AQS(AbstractQueuedSynchronizer,抽象队列同步器)是 Java 中并发控制的一种机制,位于 java.util.concurrent.locks 包下,它为构建锁、信号量等同步工具提供了一个框架。AQS 通过 队列 来管理多个线程之间的…...
L25.【LeetCode笔记】 三步问题的四种解法(含矩阵精彩解法!)
目录 1.题目 2.三种常规解法 方法1:递归做 编辑 方法2:改用循环做 初写的代码 提交结果 分析 修改后的代码 提交结果 for循环的其他写法 提交结果 方法3:循环数组 提交结果 3.方法4:矩阵 算法 代码实践 1.先计算矩阵n次方 2.后将矩阵n次方嵌入递推式中 提…...
sdut-C语言实验-合数分解
sdut-C语言实验-合数分解 分数 12 全屏浏览 切换布局 作者 马新娟 单位 山东理工大学 合数是指在大于1的整数中,除了1和本身外,还能被其他数整除的数。例如,4、6、8、9、10等都是合数。把一个合数分解成若干个质因数乘积的形式(即求质因…...
深入理解 pytest Fixture 方法及其应用
在 Python 自动化测试领域,pytest 是当之无愧的王者。提到 pytest,不得不说它的一大核心功能——Fixture。Fixture 的强大,让复杂的测试流程变得井井有条,让测试代码更加灵活和可复用。 那么,pytest 的 Fixture 究竟是…...
在Linux上获取MS(如Media Server)中的RTP流并录制为双轨PCM格式的WAV文件
在Linux上获取MS(如Media Server)中的RTP流并录制为双轨PCM格式的WAV文件 一、RTP流与WAV文件格式二、实现步骤三、伪代码示例四、C语言示例代码五、关键点说明六、总结在Linux操作系统上,从媒体服务器(如Media Server,简称MS)获取RTP(Real-time Transport Protocol)流…...
Midjourney技术浅析(八):交互与反馈
Midjourney 的用户交互与反馈通过用户输入(User Input)和用户反馈(User Feedback)机制,不断优化和改进图像生成的质量和用户满意度。 一、用户交互与反馈模块概述 用户交互与反馈模块的主要功能包括: 1.…...
【Spring MVC 核心机制】核心组件和工作流程解析
在 Web 应用开发中,处理用户请求的逻辑常常会涉及到路径匹配、请求分发、视图渲染等多个环节。Spring MVC 作为一款强大的 Web 框架,将这些复杂的操作高度抽象化,通过组件协作简化了开发者的工作。 无论是处理表单请求、生成动态页面&#x…...
回归问题的等量分层
目录 一、说明 二、什么是分层抽样? 三、那么回归又如何呢? 四、回归分层(Stratification on Regression) 一、说明 在同一个数据集中,我们可以看成是一个抽样体。然而,我们如果将这个抽样体分成两份&#…...
Unity-Mirror网络框架-从入门到精通之Basic示例
文章目录 前言Basic示例场景元素预制体元素代码逻辑BasicNetManagerPlayer逻辑SyncVars属性Server逻辑Client逻辑 PlayerUI逻辑 最后 前言 在现代游戏开发中,网络功能日益成为提升游戏体验的关键组成部分。Mirror是一个用于Unity的开源网络框架,专为多人…...
CSS 图片廊:网页设计的艺术与技巧
CSS 图片廊:网页设计的艺术与技巧 引言 在网页设计中,图片廊是一个重要的组成部分,它能够以视觉吸引的方式展示图片集合,增强用户的浏览体验。CSS(层叠样式表)作为网页设计的主要语言之一,提供…...
AI 发展的第一驱动力:人才引领变革
在科技蓬勃发展的当下,AI 成为了时代的焦点,然而其发展并非一帆风顺,究竟什么才是推动 AI 持续前行的关键力量呢? 目录 AI 发展现状剖析 期望与现实的落差 落地困境根源 人才:AI 发展的核心动力编辑 技术突破的…...
[创业之路-229]:《华为闭环战略管理》-5-平衡记分卡与战略地图
目录 一、平衡记分卡 1. 财务角度: 2. 客户角度: 3. 内部运营角度: 4. 学习与成长角度: 二、BSC战略地图 1、核心内容 2、绘制目的 3、绘制方法 4、注意事项 一、平衡记分卡 平衡记分卡(Balanced Scorecard&…...
用uniapp写一个播放视频首页页面代码
效果如下图所示 首页有导航栏,搜索框,和视频列表, 导航栏如下图 搜索框如下图 视频列表如下图 文件目录 视频首页页面代码如下 <template> <view class"video-home"> <!-- 搜索栏 --> <view class…...
【视觉SLAM:八、后端Ⅰ】
视觉SLAM的后端主要解决状态估计问题,它是优化相机轨迹和地图点的过程,从数学上看属于非线性优化问题。后端的目标是结合传感器数据,通过最优估计获取系统的状态(包括相机位姿和场景结构),在状态估计过程中…...
PaddleOCROCR关键信息抽取训练过程
步骤1:python版本3.8.20 步骤2:下载代码,安装依赖 git clone https://gitee.com/PaddlePaddle/PaddleOCR.git pip uninstall opencv-python -y # 安装PaddleOCR的依赖 ! pip install -r requirements.txt # 安装关键信息抽取任务的依赖 !…...
用Python操作字节流中的Excel文档
Python能够轻松地从字节流中加载文件,在不依赖于外部存储的情况下直接对其进行读取、修改等复杂操作,并最终将更改后的文档保存回字节串中。这种能力不仅极大地提高了数据处理的灵活性,还确保了数据的安全性和完整性,尤其是在网络…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...
《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...
