UNPKG

uirecorder

Version:
907 lines (893 loc) 95 kB
var path = require('path'); var fs = require('fs'); var os = require('os'); var http = require('http'); var url = require('url'); var cp = require('child_process'); var inquirer = require('inquirer'); var async = require('async'); var co = require('co'); var chai = require("chai"); var should = chai.should(); var JWebDriver = require('jwebdriver'); chai.use(JWebDriver.chaiSupportChainPromise); var chromedriver = require('chromedriver'); const $ = require('jquery'); const resemble = require('resemblejs-node'); resemble.outputSettings({ errorType: 'flatDifferenceIntensity' }); var WebSocketServer = require('websocket').server; var i18n = require('./i18n'); var colors = require('colors'); var detectPort = require('detect-port'); var symbols = { ok: '✓', err: '✖' }; var recorderBrowserTimeout = 1000; var checkerBrowserTimeout = 0; if (process.platform === 'win32') { symbols.ok = '\u221A'; symbols.err = '\u00D7'; recorderBrowserTimeout = 0; checkerBrowserTimeout = 1000; } var defaultOpenChecker = true; var defaultBrowserSize = '1024x768'; var wsConnection; var rootPath = getRootPath(); var pkg = require('../package.json'); function startRecorder(options){ var locale = options.locale; var cmdFilename = options.cmdFilename; var mobile = options.mobile; var debug = options.debug; var raw = options.raw; var defaultOption = options.default; var mobileDevice = options.mobileDevice; var wdproxy = process.env['wdproxy'] || ''; if(locale){ i18n.setLocale(locale); } var configPath = 'config.json'; var configFile = path.resolve(rootPath + '/' + configPath); var configJson = {}; if (fs.existsSync(configFile)) { var content = fs.readFileSync(configFile).toString(); try { configJson = JSON.parse(content); } catch (e) { console.log(configPath.bold + ' ' + __('json_parse_failed').red, e); process.exit(1); } } else { console.log(configPath.bold + ' ' + __('file_missed').red); process.exit(1); } if(!configJson.webdriver){ console.log(__('please_reinit').red); process.exit(1); } var recorderConfig = configJson.recorder || {}; var pathAttrs = recorderConfig.pathAttrs; if(pathAttrs){ pathAttrs = pathAttrs.replace(/^\s+|\s+$/g, ''); pathAttrs = pathAttrs.split(/\s*,\s*/).map(function(name){ return { name: name, on: true }; }); pathAttrs.unshift({ name: 'value', on: true }); pathAttrs.unshift({ name: 'name', on: true }); pathAttrs.unshift({ name: 'text', on: true }); pathAttrs.unshift({ name: 'id', on: true }); } var attrValueBlack = recorderConfig.attrValueBlack; var classValueBlack = recorderConfig.classValueBlack; var hideBeforeExpect = recorderConfig.hideBeforeExpect; var recorderFirst = recorderConfig.recorderFirst // 用来确定录制窗口和校验窗口的打开顺序,用来解决某些特殊场景下,窗口显示上面顺序问题 if(recorderFirst !== undefined){ recorderBrowserTimeout = recorderFirst ? 0 : 1000; checkerBrowserTimeout = recorderFirst ? 1000 : 0; } var testVars = configJson.vars; var isConfigEdited = false; var hostsPath = 'hosts'; var hostsFile = path.resolve(rootPath + '/' + hostsPath); var hosts = ''; if(fs.existsSync(hostsFile)){ hosts = fs.readFileSync(hostsFile).toString(); } // read spec list var commonSpecRelPath = 'commons/'; var commonSpecPath = rootPath + '/' + commonSpecRelPath; if(fs.existsSync(commonSpecPath) == false || fs.statSync(commonSpecPath).isDirectory() === false){ commonSpecRelPath = ''; commonSpecPath = rootPath; } var dirList = fs.readdirSync(commonSpecPath); var specLists = []; dirList.forEach(function(item){ if(/.*\.js$/.test(item)){ specLists.push(commonSpecRelPath + item); } }); var wdPort; if(fs.existsSync(chromedriver.path)){ detectPort(6789).then(function(port) { wdPort = port; chromedriver = chromedriver.start(['--url-base=wd/hub', '--port='+wdPort]); chromedriver.stdout.unpipe(process.stdout) chromedriver.stderr.unpipe(process.stderr) }); } else{ console.log('chromedriver bin file no existed, please reinstall uirecorder again.'.red); process.exit(1); } var questions = []; if(cmdFilename){ console.log('? '.green+__('input_spec_name').white.bold + ' ' + cmdFilename.cyan); } else{ questions.push({ 'type': 'input', 'name': 'fileName', 'message': __('input_spec_name'), 'default': cmdFilename || 'sample/test.spec.js', 'filter': function(input){ return input.replace(/(^\s+|\s+$)/g, '').replace(/\\/g,'/'); }, 'validate': function(input){ return input !== '' && /\.js$/.test(input); } }); } questions.push({ 'type': 'confirm', 'name': 'continueRecord', 'message': __('continue_to_record'), 'default': false, 'when': function(answers){ var fileName = cmdFilename ||answers.fileName; if(fs.existsSync(fileName)){ var content = fs.readFileSync(fileName).toString(); return /\s*function _\(str\)/.test(content); } return false; } }); if(mobile){ questions = questions.concat([ { 'type': 'input', 'name': 'mobileAppPath', 'message': __('mobile_app_path'), 'default': '', 'filter': function(input){ return input.replace(/(^\s+|\s+$)/g, ''); }, 'validate': function(input){ return (/^https?:\/\//.test(input) || (/\.(apk|app|zip)$/.test(input) && fs.existsSync(input))); }, 'when': function(answers){ if(answers.continueRecord){ var fileName = cmdFilename || answers.fileName; var content = fs.readFileSync(fileName).toString(); var match = content.match(/appPath = '([^']+)';/); if(match){ answers.mobileAppPath = match[1]; match = content.match(/platformName = '([^']+)';/); answers.mobilePlatform = match[1]; } } return !answers.mobileAppPath; } }, { 'type': 'list', 'name': 'mobilePlatform', 'choices': ['Android', 'iOS'], 'message': __('mobile_platform'), 'when': function(answers){ if(!answers.mobilePlatform){ var mobileAppPath = answers.mobileAppPath; var mobilePlatform = null; if(/(\bandroid\b|\.apk$)/i.test(mobileAppPath)){ mobilePlatform = 'Android'; } if(/(\bios\b|\.app$)/i.test(mobileAppPath)){ mobilePlatform = 'iOS'; } if(mobilePlatform){ answers.mobilePlatform = mobilePlatform; } else{ return true; } } } } ]); } else { if(defaultOption){ console.log('? '.green+__('open_checker_browser').white.bold + ' ' + (defaultOpenChecker?'Yes':'No').cyan); console.log('? '.green+__('browser_size').white.bold + ' ' + defaultBrowserSize.cyan); } else { questions = questions.concat([ { 'type': 'confirm', 'name': 'checker', 'message': __('open_checker_browser'), 'default': true }, { 'type': 'input', 'name': 'browserSize', 'message': __('browser_size'), 'default': '1024x768', 'filter': function(input){ return input.replace(/(^\s+|\s+$)/g, ''); }, 'validate': function(input){ return input === 'maximize' || /^\d+\s*[x, ]\s*\d+$/.test(input); }, 'when': function(answers){ if(answers.continueRecord){ var fileName = cmdFilename || answers.fileName; var content = fs.readFileSync(fileName).toString(); var match = content.match(/\.windowSize\((\d+), (\d+)\)/); if(match){ answers.browserSize = match[1] + ' x ' + match[2]; } } return !answers.continueRecord; } } ]); } } inquirer.prompt(questions).then(function(answers){ var fileName = answers.fileName || cmdFilename; var testFile = path.resolve(fileName); fileName = path.relative(rootPath, testFile).replace(/\\/g,'/'); var specName = fileName.replace(/\.js$/,''); var caseName = specName + ' : chrome'; var continueRecord = answers.continueRecord; var openChecker = defaultOption ? defaultOpenChecker : answers.checker; var browserSize = defaultOption ? defaultBrowserSize : answers.browserSize || ''; var match = browserSize.match(/^(\d+)\s*[x, ]\s*(\d+)$/); if(match){ browserSize = [ parseInt(match[1], 10), parseInt(match[2], 10)]; } else{ browserSize = null; } var mobileAppPath = answers.mobileAppPath; var mobilePlatform = answers.mobilePlatform; var arrTestCodes = []; var recorderBrowser, checkerBrowser, recorderMobileApp; var lastWindowId = 0; var lastFrameId = null; var lastTestTitle = ''; var arrLastTestCodes = []; var arrRawCmds = []; var allCaseCount = 0; var failedCaseCount = 0; var isModuleLoading = false; function escapeStr(str){ return str.replace(/\\/g, '\\\\').replace(/\r?\n/g, '\\n').replace(/\'/g, "\\'"); } function pushRawCmd(cmd, data){ arrRawCmds.push({ type: cmd, data: data }); } function pushTestCode(cmd, text, ext, codes){ var title = cmd +': '; title += text ? text + ' ( '+ext+' )' : ext; lastTestTitle = title; arrLastTestCodes = []; if(Array.isArray(codes)){ codes.forEach(function(line){ arrLastTestCodes.push(' '+line); }); } else{ arrLastTestCodes.push(' '+codes); } title = title.replace(/^\w+:/, function(all){ return all.cyan; }); console.log(' '+title); } function saveTestCode(success, error){ if(checkerBrowser || recorderMobileApp){ if(success){ console.log(' '+symbols.ok.green+__('exec_succeed').green); } else{ console.log(' '+symbols.err.red+__('exec_failed').red, error && error.message || error); } } allCaseCount ++; if(!success){ failedCaseCount ++; } if(arrLastTestCodes.length > 0){ (checkerBrowser || recorderMobileApp) && sendWsMessage('checkResult', { title: lastTestTitle, success: success }); if(!success){ lastTestTitle = '\u00D7 ' + lastTestTitle; } arrTestCodes.push('it(\''+escapeStr(lastTestTitle)+'\', async function(){'); arrTestCodes = arrTestCodes.concat(arrLastTestCodes); arrTestCodes.push("});"); arrTestCodes.push(""); lastTestTitle = ''; arrLastTestCodes = []; } } var cmdQueue = async.priorityQueue(function(cmdInfo, next) { if(isModuleLoading){ return next(); } var window = cmdInfo.window; var frame = cmdInfo.frame; var cmd = cmdInfo.cmd; var data = cmdInfo.data; if(cmd === '!updateMobile'){ if(recorderMobileApp){ var screenshot; recorderMobileApp.getScreenshot(function(error, png64){ screenshot = png64; }).source(function(error, source){ if(screenshot && source){ sendWsMessage('mobileAppInfo', { screenshot: screenshot, source: JSON.parse(source) }); } else{ console.log(error); } next(); }); } else{ next(); } return; } else if(cmd === '!updateAttrValueBlack'){ configJson.recorder.attrValueBlack = data; recorderConfig.attrValueBlack = data; sendWsMessage('config', recorderConfig); isConfigEdited = true; return next(); } else if(cmd === 'end'){ return next(); } var arrTasks = []; arrTasks.push(function(callback){ if(mobile){ // skip window switch when mobile mode return callback(); } function doNext(){ saveTestCode(true); callback(); } function catchError(error){ saveTestCode(false, error); callback(); } if(window !== lastWindowId){ lastWindowId = window; lastFrameId = null; pushRawCmd('switchWindow', window); pushTestCode('switchWindow', '', window, 'await driver.sleep(500).switchWindow('+window+');') checkerBrowser && checkerBrowser.sleep(500).switchWindow(window).then(doNext).catch(catchError) || doNext(); } else{ callback(); } }); arrTasks.push(function(callback){ if(mobile){ // skip frame switch when mobile mode return callback(); } function doNext(){ saveTestCode(true); callback(); } function catchError(error){ saveTestCode(false, error); callback(); } if(frame !== lastFrameId){ lastFrameId = frame; var arrCodes = []; if(frame !== null){ arrCodes.push('await driver.switchFrame(null)'); arrCodes.push(' .wait(\''+frame+'\', 30000).then(function(element){'); arrCodes.push(' return this.switchFrame(element).wait(\'body\');'); arrCodes.push(' });'); } else{ arrCodes.push('await driver.switchFrame(null);'); } pushRawCmd('switchFrame', frame); pushTestCode('switchFrame', '', frame, arrCodes); checkerBrowser && checkerBrowser.switchFrame(null, function(error){ if(frame !== null){ return this.wait(frame, 10000).then(function(element){ return this.switchFrame(element).wait('body'); }); } }).then(doNext).catch(catchError) || doNext(); } else{ callback(); } }); arrTasks.push(function(callback){ function doNext(){ saveTestCode(true); callback(); } function catchError(error){ saveTestCode(false, error); callback(); } pushRawCmd(cmd, data); var arrCodes = []; if(mobile){ switch(cmd){ case 'click': if(data.path){ pushTestCode('tap', data.text, data.path, 'await driver.wait(\''+escapeStr(data.path)+'\', 30000).sendElementActions(\'tap\');'); recorderMobileApp.wait(data.path, 10000).sendElementActions('tap').then(doNext).catch(catchError); } else{ pushTestCode('tap', '', data.x+', '+data.y, 'await driver.sendActions(\'tap\', {x: '+data.x+', y: '+data.y+'});'); recorderMobileApp.sendActions('tap', {x: data.x, y: data.y}).then(doNext).catch(catchError); } break; case 'dblClick': if(data.path){ pushTestCode('doubleTap', data.text, data.path, 'await driver.wait(\''+escapeStr(data.path)+'\', 30000).sendElementActions(\'doubleTap\');'); recorderMobileApp.wait(data.path, 10000).sendElementActions('doubleTap').then(doNext).catch(catchError); } else{ pushTestCode('doubleTap', '', data.x+', '+data.y, 'await driver.sendActions(\'doubleTap\', {x: '+data.x+', y: '+data.y+'});'); recorderMobileApp.sendActions('doubleTap', {x: data.x, y: data.y}).then(doNext).catch(catchError); } break; case 'press': if(data.path){ pushTestCode('press', data.text, data.path+', '+data.duration, 'await driver.wait(\''+escapeStr(data.path)+'\', 30000).sendElementActions(\'press\', {duration: '+data.duration+'});'); recorderMobileApp.wait(data.path, 10000).sendElementActions('press', {duration : data.duration}).then(doNext).catch(catchError); } else{ pushTestCode('press', '', data.x+', '+data.y+', '+data.duration, 'await driver.sendActions(\'press\', {x: '+data.x+', y: '+data.y+', duration: '+data.duration+'});'); recorderMobileApp.sendActions('press', {x: data.x, y: data.y, duration: data.duration}).then(doNext).catch(catchError); } break; case 'drag': pushTestCode('drag', '', data.fromX+', '+data.fromY+', '+data.toX+', '+data.toY+', '+data.duration, 'await driver.sendActions(\'drag\', {fromX: '+data.fromX+', fromY:'+data.fromY+', toX:'+data.toX+', toY:'+data.toY+', duration: '+data.duration+'});'); recorderMobileApp.sendActions('drag', {fromX: data.fromX, fromY: data.fromY, toX: data.toX, toY: data.toY, duration: data.duration}).then(doNext).catch(catchError); break; case 'sendKeys': pushTestCode('sendKeys', '', data, 'await driver.sendKeys(_(\`'+escapeStr(data)+'\`));'); recorderMobileApp.sendKeys(getVarStr(eval('\`'+data+'\`'))).then(doNext).catch(catchError); break; case 'sleep': pushTestCode('sleep', '', data, 'await driver.sleep('+data+');'); recorderMobileApp.sleep(data).then(doNext).catch(catchError); break; case 'acceptAlert': pushTestCode('acceptAlert', '', '', 'await driver.acceptAlert();'); recorderMobileApp.acceptAlert().then(doNext).catch(catchError); break; case 'dismissAlert': pushTestCode('dismissAlert', '', '', 'await driver.dismissAlert();'); recorderMobileApp.dismissAlert().then(doNext).catch(catchError); break; case 'back': pushTestCode('back', '', '', 'await driver.back();'); recorderMobileApp.back().then(doNext).catch(catchError); break; case 'expect': co(function*(){ var expectSleep = data.sleep; var expectType = data.type; var expectPath = data.path; var expectCompare = data.compare; var expectTo = data.to; arrCodes = []; if(expectType === 'count'){ arrCodes.push('await driver.wait(\''+escapeStr(expectPath)+'\', {timeout: 1000, noerror: true})'); arrCodes.push(' .then(function(elements){'); arrCodes.push(' return elements.length;'); arrCodes.push(' })'); } else if(expectType === 'imgdiff'){ arrCodes.push("let self = this;"); arrCodes.push("let imgBasePath = self.diffbasePath + '/' + self.caseName + '_' + self.stepId + '.png';"); arrCodes.push("let imgNewPath = self.screenshotPath + '/' + self.caseName + '_' + self.stepId + '_new.png';"); arrCodes.push("let imgDiffPath = self.screenshotPath + '/' + self.caseName + '_' + self.stepId + '_diff.png';"); arrCodes.push("let elemshot = await driver.sleep(300).getScreenshot({"); arrCodes.push(" elem: '"+escapeStr(expectPath)+"',"); arrCodes.push(" filename: imgNewPath"); arrCodes.push("});"); arrCodes.push("elemshot = new Buffer(elemshot, 'base64');"); arrCodes.push("if(!fs.existsSync(imgBasePath) || process.env['npm_config_rebuilddiff']){"); arrCodes.push(" fs.writeFileSync(imgBasePath, elemshot);"); arrCodes.push("}"); arrCodes.push("let diff = resemble(elemshot).compareTo(imgBasePath).ignoreColors();"); arrCodes.push("let diffResult = await new Promise((resolve) => diff.onComplete(resolve));"); arrCodes.push("diffResult.getDiffImage().pack().pipe(fs.createWriteStream(imgDiffPath));"); arrCodes.push("diffResult.rawMisMatchPercentage"); } else{ arrCodes.push('await driver.sleep('+expectSleep+').wait(\''+escapeStr(expectPath)+'\', 30000)'); switch(expectType){ case 'text': arrCodes.push(' .text()'); break; } arrCodes.push(' .should.not.be.a(\'error\')'); } var codeExpectTo = expectTo.replace(/"/g, '\\"').replace(/\n/g, '\\n'); switch(expectCompare){ case 'equal': arrCodes.push(' .should.equal(_('+(/^(true|false)$/.test(codeExpectTo)?codeExpectTo:'\`'+escapeStr(codeExpectTo)+'\`')+'));'); break; case 'notEqual': arrCodes.push(' .should.not.equal(_('+(/^(true|false)$/.test(codeExpectTo)?codeExpectTo:'\`'+escapeStr(codeExpectTo)+'\`')+'));'); break; case 'contain': arrCodes.push(' .should.contain(_(\`'+escapeStr(codeExpectTo)+'\`));'); break; case 'notContain': arrCodes.push(' .should.not.contain(_(\`'+escapeStr(codeExpectTo)+'\`));'); break; case 'above': arrCodes.push(' .should.above('+codeExpectTo+');'); break; case 'below': arrCodes.push(' .should.below('+codeExpectTo+');'); break; case 'match': arrCodes.push(' .should.match('+escapeStr(codeExpectTo)+');'); break; case 'notMatch': arrCodes.push(' .should.not.match('+escapeStr(codeExpectTo)+');'); break; } pushTestCode('expect', '', expectType + ', ' + expectPath + ', ' + expectCompare + ', ' + expectTo, arrCodes); var element, value; if(expectType === 'count'){ value = yield recorderMobileApp.wait(expectPath, { timeout: 1000, noerror: true }).then(function(elements){ return elements.length; }); } else if(expectType === 'imgdiff'){ // 录制时,不需要进行即时的图片校验 value = 0; } else{ element = yield recorderMobileApp.sleep(expectSleep).wait(expectPath, 10000); switch(expectType){ case 'text': value = yield element.text(); break; } value.should.not.be.a('error'); } switch(expectCompare){ case 'equal': expectTo = /^(true|false)$/.test(expectTo)?eval(expectTo):eval('\`'+expectTo+'\`'); value.should.equal(getVarStr(expectTo)); break; case 'notEqual': expectTo = /^(true|false)$/.test(expectTo)?eval(expectTo):eval('\`'+expectTo+'\`'); value.should.not.equal(getVarStr(expectTo)); break; case 'contain': value.should.contain(getVarStr(eval('\`'+expectTo+'\`'))); break; case 'notContain': value.should.not.contain(getVarStr(eval('\`'+expectTo+'\`'))); break; case 'above': value.should.above(Number(expectTo)); break; case 'below': value.should.below(Number(expectTo)); break; case 'match': value.should.match(eval(expectTo)); break; case 'notMatch': value.should.not.match(eval(expectTo)); break; } }).then(doNext).catch(catchError); break; // 插入用例 case 'module': var moduleName = /[\/\\]/.test(data) ? data : commonSpecRelPath + data; loadModule(moduleName, function(error){ if(error !== null){ catchError(error); } else{ console.log(' module'.cyan+': ', moduleName); arrTestCodes.push('callSpec(\''+escapeStr(moduleName)+'\');\r\n'); doNext(); } }); break; } } else{ var reDomRequire = /^(val|text|displayed|enabled|selected|attr|css|count|imgdiff)$/; var reParamRequire = /^(attr|css|cookie|localStorage|sessionStorage|alert)$/; switch(cmd){ case 'url': pushTestCode('url', '', data, 'await driver.url(_(\`'+escapeStr(data)+'\`));'); checkerBrowser && checkerBrowser.url(getVarStr(eval('\`'+data+'\`'))).then(doNext).catch(catchError) || doNext(); break; case 'closeWindow': pushTestCode('closeWindow', '', '', 'await driver.closeWindow();'); checkerBrowser && checkerBrowser.closeWindow().then(doNext).catch(catchError) || doNext(); break; case 'sleep': pushTestCode('sleep', '', data, 'await driver.sleep('+data+');'); checkerBrowser && checkerBrowser.sleep(data).then(doNext).catch(catchError) || doNext(); break; case 'waitBody': arrCodes = []; arrCodes.push('await driver.sleep(500).wait(\'body\', 30000).html().then(function(code){'); arrCodes.push(' isPageError(code).should.be.false;'); arrCodes.push('});'); pushTestCode('waitBody', '', '', arrCodes); checkerBrowser && checkerBrowser.sleep(500).wait('body', 10000).html().then(function(code){ isPageError(code).should.be.false; }).then(doNext).catch(catchError) || doNext(); break; case 'eval': pushTestCode('eval', '', data.replace(/\n/g, ' \\n '), 'await driver.eval(_(\''+escapeStr(data)+'\'));'); checkerBrowser && checkerBrowser.eval(getVarStr(data)).then(doNext).catch(catchError) || doNext(); break; case 'mouseMove': arrCodes = []; arrCodes.push('await driver.sleep(300).wait(\''+escapeStr(data.path)+'\', 30000)'); arrCodes.push(' .sleep(300).mouseMove('+(data.x ? data.x + ', ' + data.y : '')+');'); pushTestCode('mouseMove', data.text, data.path+(data.x !== undefined?', '+data.x+', '+data.y:''), arrCodes); checkerBrowser && checkerBrowser.sleep(300).wait(data.path, 10000).sleep(300).mouseMove(data.x, data.y).then(doNext).catch(catchError) || doNext(); break; case 'mouseDown': arrCodes = []; arrCodes.push('await driver.sleep(300).wait(\''+escapeStr(data.path)+'\', 30000)'); arrCodes.push(' .sleep(300).mouseMove('+data.x+', '+data.y+').mouseDown('+data.button+');'); pushTestCode('mouseDown', data.text, data.path + ', ' + data.x + ', ' + data.y + ', ' + data.button, arrCodes); checkerBrowser && checkerBrowser.sleep(300).wait(data.path, 10000).sleep(300).mouseMove(data.x, data.y).mouseDown(data.button).then(doNext).catch(catchError) || doNext(); break; case 'mouseUp': arrCodes = []; arrCodes.push('await driver.sleep(300).wait(\''+escapeStr(data.path)+'\', 30000)'); arrCodes.push(' .sleep(300).mouseMove('+data.x+', '+data.y+').mouseMove('+data.x+', '+data.y+').mouseUp('+data.button+');'); pushTestCode('mouseUp', data.text, data.path + ', ' + data.x + ', ' + data.y + ', ' + data.button, arrCodes); checkerBrowser && checkerBrowser.sleep(300).wait(data.path, 10000).sleep(300).mouseMove(data.x, data.y).mouseMove(data.x, data.y).mouseUp(data.button).then(doNext).catch(catchError) || doNext(); break; case 'click': arrCodes = []; var option = data.option; arrCodes.push('await driver.sleep(300).wait(\''+escapeStr(data.path)+'\', '+(option?'5000':'30000')+')'); arrCodes.push(' .sleep(300).mouseMove('+data.x+', '+data.y+').click('+data.button+')'+(option?'.catch(catchError)':'')+';'); pushTestCode(option?'optionClick':'click', data.text, data.path + ', ' + data.x + ', ' + data.y + ', ' + data.button, arrCodes); checkerBrowser && checkerBrowser.sleep(300).wait(data.path, 10000).sleep(300).mouseMove(data.x, data.y).click(data.button).then(doNext).catch(catchError) || doNext(); break; case 'touchClick': arrCodes = []; arrCodes.push('await driver.sleep(300).wait(\''+escapeStr(data.path)+'\', 30000)'); arrCodes.push(' .sleep(300).touchClick();'); pushTestCode('touchClick', data.text, data.path, arrCodes); checkerBrowser && checkerBrowser.sleep(300).wait(data.path, 10000).sleep(300).touchClick().then(doNext).catch(catchError) || doNext(); break; case 'dblClick': arrCodes = []; arrCodes.push('await driver.sleep(300).wait(\''+escapeStr(data.path)+'\', 30000)'); arrCodes.push(' .sleep(300).mouseMove('+data.x+', '+data.y+').click(0).click(0);'); pushTestCode('dblClick', data.text, data.path + ', ' + data.x + ', ' + data.y + ', ' + data.button, arrCodes); checkerBrowser && checkerBrowser.sleep(300).wait(data.path, 10000).sleep(300).mouseMove(data.x, data.y).click(0).click(0).then(doNext).catch(catchError) || doNext(); break; case 'sendKeys': pushTestCode('sendKeys', '', data.keys, 'await driver.sendKeys(\''+escapeStr(data.keys)+'\');'); checkerBrowser && checkerBrowser.sendKeys(data.keys).then(doNext).catch(catchError) || doNext(); break; case 'keyDown': pushTestCode('keyDown', '', data.character, 'await driver.keyDown(\''+escapeStr(data.character)+'\');'); checkerBrowser && checkerBrowser.keyDown(data.character).then(doNext).catch(catchError) || doNext(); break; case 'keyUp': pushTestCode('keyUp', '', data.character, 'await driver.keyUp(\''+escapeStr(data.character)+'\');'); checkerBrowser && checkerBrowser.keyUp(data.character).then(doNext).catch(catchError) || doNext(); break; case 'scrollTo': pushTestCode('scrollTo', '', data.x + ', ' + data.y, 'await driver.scrollTo('+data.x+', '+data.y+');'); checkerBrowser && checkerBrowser.scrollTo(data.x, data.y).then(doNext).catch(catchError) || doNext(); break; case 'scrollElementTo': arrCodes = []; arrCodes.push('await driver.sleep(300).wait(\''+escapeStr(data.path)+'\', 30000)'); arrCodes.push(' .sleep(300).scrollElementTo('+ data.x + ', ' + data.y +');'); pushTestCode('scrollElementTo', data.text, data.path+(data.x !== undefined?', '+data.x+', '+data.y:''), arrCodes); checkerBrowser && checkerBrowser.sleep(300).wait(data.path, 10000).sleep(300).scrollElementTo(data.x, data.y).then(doNext).catch(catchError) || doNext(); break; case 'select': arrCodes = []; arrCodes.push('await driver.sleep(300).wait(\''+escapeStr(data.path)+'\', 30000)'); arrCodes.push(' .sleep(300).select({'); arrCodes.push(' type: \''+data.type+'\','); arrCodes.push(' value: \''+data.value+'\''); arrCodes.push(' });'); pushTestCode('select', data.text, data.path + ', ' + data.type + ', ' + data.value, arrCodes); checkerBrowser && checkerBrowser.sleep(300).wait(data.path, 10000).sleep(300).select({ type: data.type, value: data.value }).then(doNext).catch(catchError) || doNext(); break; case 'acceptAlert': pushTestCode('acceptAlert', '', '', 'await driver.acceptAlert();'); checkerBrowser && checkerBrowser.acceptAlert().then(doNext).catch(catchError) || doNext(); break; case 'dismissAlert': pushTestCode('dismissAlert', '', '', 'await driver.dismissAlert();'); checkerBrowser && checkerBrowser.dismissAlert().then(doNext).catch(catchError) || doNext(); break; case 'setAlert': pushTestCode('setAlert', '', data.text, 'await driver.setAlert("'+data.text+'");'); checkerBrowser && checkerBrowser.setAlert(data.text).then(doNext).catch(catchError) || doNext(); break; case 'uploadFile': arrCodes = []; arrCodes.push('await driver.sleep(300).wait(\''+escapeStr(data.path)+'\', {timeout: 30000, displayed: false})'); arrCodes.push(' .sleep(300).uploadFile(rootPath+\'/uploadfiles/'+data.filename+'\');'); pushTestCode('uploadFile', data.text, data.path + ', ' + data.filename, arrCodes); checkerBrowser && checkerBrowser.sleep(300).wait(data.path, {timeout: 10000, displayed: false}) .sleep(300).sendElementKeys(rootPath+'/uploadfiles/'+data.filename).then(doNext).catch(catchError) || doNext(); break; // 添加断言 case 'expect': co(function*(){ var sleepTime = data.sleep; var expectType = data.type; var expectParams = data.params; var expectCompare = data.compare; var expectTo = data.to; arrCodes = []; if(expectType === 'count'){ arrCodes.push('await driver.sleep('+sleepTime+').wait(\''+escapeStr(expectParams[0])+'\', {timeout: 1000, noerror: true})'); arrCodes.push(' .then(function(elements){'); arrCodes.push(' return elements.length;'); arrCodes.push(' })'); } else if(expectType === 'imgdiff'){ arrCodes.push("let self = this;"); arrCodes.push("let imgBasePath = self.diffbasePath + '/' + self.caseName + '_' + self.stepId + '.png';"); arrCodes.push("let imgNewPath = self.screenshotPath + '/' + self.caseName + '_' + self.stepId + '_new.png';"); arrCodes.push("let imgDiffPath = self.screenshotPath + '/' + self.caseName + '_' + self.stepId + '_diff.png';"); arrCodes.push("let elemshot = await driver.sleep(300).getScreenshot({"); arrCodes.push(" elem: '"+escapeStr(expectParams[0])+"',"); arrCodes.push(" filename: imgNewPath"); arrCodes.push("});"); arrCodes.push("elemshot = new Buffer(elemshot, 'base64');"); arrCodes.push("if(!fs.existsSync(imgBasePath) || process.env['npm_config_rebuilddiff']){"); arrCodes.push(" fs.writeFileSync(imgBasePath, elemshot);"); arrCodes.push("}"); arrCodes.push("let diff = resemble(elemshot).compareTo(imgBasePath).ignoreColors();"); arrCodes.push("let diffResult = await new Promise((resolve) => diff.onComplete(resolve));"); arrCodes.push("diffResult.getDiffImage().pack().pipe(fs.createWriteStream(imgDiffPath));"); arrCodes.push("diffResult.rawMisMatchPercentage"); } else{ if(reDomRequire.test(expectType)){ arrCodes.push('await driver.sleep('+sleepTime+').wait(\''+escapeStr(expectParams[0])+'\', 30000)'); } else{ arrCodes.push('await driver'); } switch(expectType){ case 'val': arrCodes.push(' .val()'); break; case 'text': arrCodes.push(' .text()'); break; case 'displayed': arrCodes.push(' .displayed()'); break; case 'enabled': arrCodes.push(' .enabled()'); break; case 'selected': arrCodes.push(' .selected()'); break; case 'attr': arrCodes.push(' .attr(\''+escapeStr(expectParams[1])+'\')'); break; case 'css': arrCodes.push(' .css(\''+escapeStr(expectParams[1])+'\')'); break; case 'url': arrCodes.push(' .url()'); break; case 'title': arrCodes.push(' .title()'); break; case 'cookie': arrCodes.push(' .cookie(\''+escapeStr(expectParams[0])+'\')'); break; case 'localStorage': arrCodes.push(' .localStorage(\''+escapeStr(expectParams[0])+'\')'); break; case 'sessionStorage': arrCodes.push(' .sessionStorage(\''+escapeStr(expectParams[0])+'\')'); break; case 'alert': arrCodes.push(' .getAlert()'); break; case 'jscode': arrCodes.push(' .eval(\''+escapeStr(expectParams[0])+'\')'); break; } arrCodes.push(' .should.not.be.a(\'error\')'); } var codeExpectTo = expectTo.replace(/"/g, '\\"').replace(/\n/g, '\\n'); switch(expectCompare){ case 'equal': arrCodes.push(' .should.equal(_('+(/^(true|false)$/.test(codeExpectTo)?codeExpectTo:'\`'+escapeStr(codeExpectTo)+'\`')+'));'); break; case 'notEqual': arrCodes.push(' .should.not.equal(_('+(/^(true|false)$/.test(codeExpectTo)?codeExpectTo:'\`'+escapeStr(codeExpectTo)+'\`')+'));'); break; case 'contain': arrCodes.push(' .should.contain(_(\`'+escapeStr(codeExpectTo)+'\`));'); break; case 'notContain': arrCodes.push(' .should.not.contain(_(\`'+escapeStr(codeExpectTo)+'\`));'); break; case 'above': arrCodes.push(' .should.above('+codeExpectTo+');'); break; case 'below': a