在试用selenium-ide 插件录制页面时,我们可以得到这样的界面。
上图的例子就是执行百度,搜索 nihao。
可以发现生成的命令还是比较通俗易懂的。
那么我们如何获取到当前的脚本的的原始代码呢。
经过研究调试,发现可以通过_state.project.toJS()
的形式获取到。
例如在这个项目当中,我获取到的数据就是这样
在这里可以看到每个命令里面的细节,当然这个我也不是很关注。
下面我先尝试将这数据转换成py的可执行代码试试。
通过前一章节讲到的内容
我们可以在exportCodeToFile
函数中找到转换的方式。直接调用即可。
export async function exportCodeToFile(
selectedLanguages,
{ test, suite },
{ enableOriginTracing, beforeEachOptions, enableDescriptionAsComment }
) {
const project = UiState.project.toJS()
const { url, tests } = project
for (const language of selectedLanguages) {
let emittedCode
let options = {
url,
tests,
project,
enableOriginTracing,
beforeEachOptions: {
browserName: userAgent.browserName,
...beforeEachOptions,
},
enableDescriptionAsComment,
}
options.test = test ? test : undefined
options.suite = suite
? projectProcessor.normalizeTestsInSuite({ suite, tests })
: undefined
if (vendorLanguages.hasOwnProperty(language)) {
const result = await PluginManager.emitMessage({
action: 'export',
entity: 'vendor',
language,
options,
})
emittedCode = result[0].response
} else if (test) {
emittedCode = await exporter.emit.test(language, options)
下面我们新建一个简单的项目进行测试
var project = `{"id":"f82b2216-7207-4952-8339-019abfebfde3","version":"2.0","name":"test","url":"https://baidu.com","tests":[{"id":"706b803d-b284-4a34-8102-7975b67306eb","name":"baidu","commands":[{"id":"a95c059d-6185-4d0e-9088-19f1a9b24dcd","comment":"","command":"open","target":"https://www.baidu.com/","targets":[],"value":""},{"id":"c2afbb00-c6f2-4a3d-af92-61f975eb383e","comment":"","command":"setWindowSize","target":"1050x567","targets":[],"value":""},{"id":"286f42e7-da80-444c-a308-7c5eaaab0eba","comment":"","command":"click","target":"id=kw","targets":[["id=kw","id"],["name=wd","name"],["css=#kw","css:finder"],["xpath=//input[@id='kw']","xpath:attributes"],["xpath=//span[@id='s_kw_wrap']/input","xpath:idRelative"],["xpath=//input","xpath:position"]],"value":""},{"id":"e3e75ce9-1220-4fb6-98cc-61cc806dbfc8","comment":"","command":"type","target":"id=kw","targets":[["id=kw","id"],["name=wd","name"],["css=#kw","css:finder"],["xpath=//input[@id='kw']","xpath:attributes"],["xpath=//span[@id='s_kw_wrap']/input","xpath:idRelative"],["xpath=//input","xpath:position"]],"value":"nihao"},{"id":"42be1ed9-d4c3-4696-b242-131bbc5e3741","comment":"","command":"click","target":"id=su","targets":[["id=su","id"],["css=#su","css:finder"],["xpath=//input[@id='su']","xpath:attributes"],["xpath=//span[@id='s_btn_wr']/input","xpath:idRelative"],["xpath=//span[2]/input","xpath:position"]],"value":""},{"id":"d9e54ccb-b849-4eba-8ebc-9f45768f758e","comment":"","command":"close","target":"","targets":[],"value":""}]}],"suites":[{"id":"656f702c-9973-4ec2-a3c8-def3ba081212","name":"Default Suite","persistSession":false,"parallel":false,"timeout":300,"tests":[]}],"urls":["https://element.eleme.io/"],"plugins":[]}`
project = JSON.parse(project)
const { url, tests } = project
for (const language of selectedLanguages) {
let emittedCode
let options = {
url,
tests,
project,
enableOriginTracing, // 是否导入注释
beforeEachOptions: {
browserName: userAgent.browserName, // 浏览器名称
...beforeEachOptions,
},
enableDescriptionAsComment, // 使用描述作为注释
}
options.test = test ? test : undefined
options.suite = suite
? projectProcessor.normalizeTestsInSuite({ suite, tests })
: undefined
if (vendorLanguages.hasOwnProperty(language)) {
const result = await PluginManager.emitMessage({
action: 'export',
entity: 'vendor',
language,
options,
})
emittedCode = result[0].response
} else if (test) {
emittedCode = await exporter.emit.test(language, options)
可以看到代码里面还有一些我们当前没有获取到的数据options.test
以及 options.suite
这里我也简单看了下源码,可以在导出时通过 _modalState.exportPayload
来获取到内容
比如在当前代码片段这里的内容为
因此我们可以断定,正常导出代码逻辑时,这里的逻辑判断将会走test的分支来运行
通过前一节的内容也可以指定,上面一段转换PluginManager.emitMessage
是没必要的
因此精简下我们的代码逻辑,给能确定后的代码块赋值
// project 原始数据太长就不贴了
project = JSON.parse(project)
const { url, tests } = project
let emittedCode
let options = {
url,
tests,
project,
enableOriginTracing: true, // 是否导入注释
beforeEachOptions: {
browserName: userAgent.browserName, // 浏览器名称
...beforeEachOptions,
},
enableDescriptionAsComment:true, // 使用描述作为注释
}
options.test = test ? test : undefined
options.suite = undefined
emittedCode = await exporter.emit.test(language, options)
好了,现在仅仅缺少 userAgent.browserName
和 beforeEachOptions
当中的数据了
从源码可得知,引用自@seleniumhq/side-utils
import { userAgent, project as projectProcessor } from '@seleniumhq/side-utils'
这里就可以很清晰的看到,获取方式其实就是通过window.navigator.userAgent
来判断当前浏览器环境。
并且browserName
也可以清楚的看到是在Chrome
当中Firefox
二选一
现在还剩下最后一个beforeEachOptions
通过它使用解构赋值的方式,我们知道它一定是object
这里的传递比较复杂, 加上我对react了解不是特别深入。因此切换下查找方案。
通过在测试代码中可以找到它是个配置项,并且通常只用于配置selenium-grid
的地址
因此很明显我们可以忽略它。
好了,现在我们的代码是这样
import exporter from '@seleniumhq/code-export'
project = JSON.parse(project)
const { url, tests } = project
let emittedCode
let options = {
url,
tests,
project,
enableOriginTracing: true, // 是否导入注释
beforeEachOptions: {
browserName: 'Chrome', // 浏览器名称
},
enableDescriptionAsComment:true, // 使用描述作为注释
}
options.test = test ? test : undefined
options.suite = undefined
emittedCode = await exporter.emit.test(language, options)
console.log(emittedCode)
因为我是用node
环境调试,所以代码引入需要做一些转换。
await
也需要使用异步方案来包含。
const exporter = require('@seleniumhq/code-export').default;
(async ()=>{
project = JSON.parse(project)
const { url, tests } = project
let emittedCode
let options = {
url,
tests,
project,
enableOriginTracing: true, // 是否导入注释
beforeEachOptions: {
browserName: 'Chrome', // 浏览器名称
},
enableDescriptionAsComment:true, // 使用描述作为注释
}
options.test = tests[0]
emittedCode = await exporter.emit.test('python-pytest', options)
})()
现在万事俱备,之差转换代码了
让我们运行一下
ok,可以看到我们成功完成了代码转换。
下一篇讲下,转换时注意事项,以及原始字符串的拼接。