siesta-lite
Version:
Stress-free JavaScript unit testing and functional testing tool, works in NodeJS and browsers
523 lines (379 loc) • 17.4 kB
JavaScript
/*
Siesta 5.6.1
Copyright(c) 2009-2022 Bryntum AB
https://bryntum.com/contact
https://bryntum.com/products/siesta/license
*/
Role('Siesta.Project.Browser.Automation', {
does : [
Siesta.Util.Role.CanStyleOutput,
Siesta.Util.Role.CanFormatStrings
],
has : {
outputLog : Joose.I.Array,
currentTestTimeout : null,
lastActivity : null,
exitStatus : null,
activeTestAutomationId : null,
testResults : Joose.I.Array,
streamAssertions : false,
eventLog : Joose.I.Array,
enableCodeCoverage : false,
manuallyProcessCoverageResults : true,
codeCoverageResults : Joose.I.Array
},
override : {
setup : function () {
if (this.isAutomated) {
this.autoLaunchTests = false
this.forceDOMVisible = true
if (this.speedRun !== false) {
this.speedRun = true
}
this.forcedRunCore = 'sequential'
this.transparentEx = false
this.keepNLastResults = 0
this.waitForTimeout = this.waitForTimeout * 3
this.defaultTimeout = this.defaultTimeout * 3
this.isReadyTimeout = this.isReadyTimeout * 3
this.lastActivity = new Date()
var me = this
if (typeof window != 'undefined')
window.onerror = function (message, url, lineNumber, col, error) {
// ignore exit exception
if (/__SIESTA_TEST_EXIT_EXCEPTION__/.test(message)) return
me.warn("[ERROR] message : " + message)
me.warn("[ERROR] url : " + url)
me.warn("[ERROR] line : " + lineNumber)
if (col) me.warn("[ERROR] col : " + col)
if (error && error.stack) me.warn("[ERROR] stack : " + error.stack)
}
this.on('maxtimeoutchanged', function (event, timeout) {
me.onTestMaxTimeoutChanged(event.source, timeout)
})
this.on('focuslost', function (event) {
me.onTestFocusLost(event.source)
})
}
this.SUPERARG(arguments)
}
},
after : {
markMissingFile : function (desc) {
this.warn(Siesta.Resource('Siesta.Role.ConsoleReporter', 'missingFileText').replace("{URL}", desc.url))
if (this.isAutomated) {
this.lastActivity = new Date()
var result = {
automationElementId : desc.automationElementId,
url : desc.url,
ERROR : "Can't open test file: " + desc.url
}
if (this.streamAssertions)
this.eventLog.push({
isResult : true,
data : result
})
else
this.testResults.push(result)
}
},
onTestSuiteStart : function (descriptors, contenManager, launchState) {
// if (this.isAutomated && this.initialContentManagerState) contenManager.setState(this.initialContentManagerState)
},
onTestSuiteEnd : function (descriptors, contenManager, launchState) {
if (this.isAutomated && !launchState.needToStop) this.exit()
},
onTestStart : function (test) {
if (this.isAutomated && this.isTestActionActual(test)) {
this.currentTestTimeout = test.getMaximalTimeout() * 2
this.activeTestAutomationId = test.automationElementId
this.lastActivity = new Date()
if (this.streamAssertions)
if (!test.parent)
this.eventLog.push({
isUpdate : true,
data : test.getResults().toJSON()
})
}
},
onTestEnd : function (test) {
if (this.isAutomated && this.isTestActionActual(test)) {
this.lastActivity = new Date()
this.activeTestAutomationId = null
if (this.streamAssertions)
this.eventLog.push({
isResult : true,
data : test.getResults().toJSON()
})
else
this.testResults.push(test.getResults().toJSON())
if (this.enableCodeCoverage && this.manuallyProcessCoverageResults) {
var result = test.global.__coverage__
result && this.codeCoverageResults.push(result)
}
}
},
onTestUpdate : function (test, result, parentResult) {
if (this.isAutomated && this.isTestActionActual(test)) {
this.lastActivity = new Date()
if (this.streamAssertions)
if (!(result.isWaitFor && !result.completed) && !(result instanceof Siesta.Result.Summary)) {
this.eventLog.push({
isUpdate : true,
data : result.toJSON()
})
// in "breakOnFail" case the failed assertion will switch "launchState" to "needToStop"
// and "isTestActionActual" will return false for any following updates/results,
// so, adding total test result manually
if (this.breakOnFail && ((result instanceof Siesta.Result.Assertion) && !result.isPassed()))
this.eventLog.push({
isResult : true,
data : test.getResults().toJSON()
})
}
}
}
},
methods : {
isTestActionActual : function (test) {
if (test.launchId != this.currentLaunchId) return false
var launchState = this.launches[ this.currentLaunchId ]
return launchState ? !launchState.needToStop : false
},
onTestFocusLost : function (test) {
if (this.isAutomated) {
test.warn(Siesta.Resource('Siesta.Test.Browser').get('focusLostWarningLauncher', { url : test.url }))
this.stopCurrentLaunch()
this.exit('focus_lost')
}
},
onTestMaxTimeoutChanged : function (test, timeout) {
if (this.isAutomated) this.currentTestTimeout = timeout * 2
},
filterDescriptors : function (includeTests, excludeTests, descriptors) {
includeTests = includeTests ? new RegExp(includeTests) : null
excludeTests = excludeTests ? new RegExp(excludeTests) : null
var filtered = []
if (includeTests || excludeTests) {
Joose.A.each(this.flattenDescriptors(descriptors || this.descriptors), function (desc) {
if (includeTests && !includeTests.test(desc.url)) return
if (excludeTests && excludeTests.test(desc.url)) return
filtered.push(desc)
})
} else
filtered = this.flattenDescriptors(descriptors || this.descriptors)
return filtered
},
getLastActivity : function () {
return this.lastActivity - 0
},
log : function (text) {
if (this.isAutomated) {
if (this.streamAssertions)
this.eventLog.push({
isLog : true,
data : text
})
else
this.outputLog.push(text)
}
},
exit : function (status) {
this.exitStatus = status || 'all_processed'
},
getAutomationState : function () {
var launchState = this.launches[ this.currentLaunchId ]
var state = {
activeTestAutomationId : this.activeTestAutomationId,
activityTimeout : this.currentTestTimeout,
lastActivity : this.lastActivity - 0,
testResults : this.flushTestResults(),
log : this.flushLog(),
exitStatus : this.exitStatus,
commands : this.flushAutomationCommands && this.flushAutomationCommands(),
// launchState is deleted upon launch completion
notLaunched : launchState ? launchState.notLaunchedByAutomationId : {}
}
if (this.streamAssertions) {
state.eventLog = this.flushEventLog()
}
if (this.enableCodeCoverage) {
state.coverageResult = this.flushCoverageResults()
}
return state
},
flushLog : function () {
var outputLog = this.outputLog
if (outputLog.length) {
this.outputLog = []
return outputLog
}
},
flushCoverageResults : function () {
var results = this.codeCoverageResults
if (results.length) {
this.codeCoverageResults = []
return results
}
},
flushTestResults : function () {
var testResults = this.testResults
if (testResults.length) {
this.testResults = []
return testResults
}
},
flushEventLog : function () {
var eventLog = this.eventLog
if (eventLog.length) {
this.eventLog = []
return eventLog
}
},
cascadeStructureLeafOnly : function (func, list) {
var me = this
Joose.A.each(list, function (desc) {
if (desc.group) {
me.cascadeStructureLeafOnly(func, desc.items)
} else
func(desc)
})
},
getDescriptorStructure : function (desc, visibleById) {
var me = this
if (visibleById && desc.id != '__ROOT__' && !visibleById[ desc.id ]) return null
if (desc.group) {
var items = []
Joose.A.each(desc.items, function (desc) {
var res = me.getDescriptorStructure(desc, visibleById)
if (res) items.push(res)
})
return {
id : desc.id,
group : desc.group || desc.title || desc.name,
items : items
}
} else {
return desc.id
}
},
getConfigInfo : function (includeTest, excludeTests, filterValue, projectConfig) {
var me = this
var visibleById
// need to configure project first, because some command line options (like `simulation`) overrides
// default project config and affect the result of this method
if (projectConfig) this.configure(projectConfig)
if (filterValue) {
var filterer = new Siesta.Util.TreeStoreFilterer({
idProp : 'id',
childNodesProp : 'items',
parentNodeProp : 'parent',
isLeaf : function (node) { return !node.group }
})
var res = filterer.parseFilterValue(filterValue)
var testFilterRegexps = res.testFilterRegexps
var groupFilterRegexps = res.groupFilterRegexps
var getTitle = function (node) {
// do not consider a test suite title as a "root group", otherwise, for the suite title "Test suite"
// the --filter="ui>" will match all top-level tests
if (node == me)
return ''
else
return node.group || node.title || node.name
}
visibleById = filterer.collectNodes({
id : '__ROOT__',
group : '__ROOT__',
items : this.descriptors
}, {
filter : function (node) {
return filterer.checkCommonFilter(node, getTitle, testFilterRegexps, groupFilterRegexps)
}
})
}
var structure = this.getDescriptorStructure(
{ id : '__ROOT__', group : '__ROOT__', items : this.descriptors },
visibleById
)
var list
if (filterValue) {
list = []
this.cascadeStructureLeafOnly(function (id) { list.push(me.getDescById(id)) }, structure.items)
} else
list = this.descriptors
var filteredFlattenList = this.filterDescriptors(includeTest, excludeTests, list)
return {
// system info
VERSION : Siesta.meta.VERSION,
title : this.title,
structure : structure,
descriptors : this.sortDescriptors(filteredFlattenList, 'sequential', true),
// environment
hostName : typeof location != 'undefined' ? location.host : require('os').hostname(),
userAgent : typeof navigator != 'undefined' ? navigator.userAgent : 'NodeJS/' + process.version,
platform : typeof navigator != 'undefined' ? navigator.platform : process.platform,
hasNativeSimulation : this.hasDescriptorWithNativeEventsSimulation(filteredFlattenList),
// options
breakOnFail : this.breakOnFail,
screenshotCompareConfig : this.screenshotCompareConfig
}
},
// chunk task - [ { descId : descId, automationElementId : elId }, ... ]
launchAutomatedTests : function (task, options) {
if (!this.setupDone) {
this.on('setupdone', function () { this.launchAutomatedTests(task, options) })
return
}
if (options.projectConfig) this.configure(options.projectConfig)
this.enableCodeCoverage = Boolean(options.enableCodeCoverage)
this.streamAssertions = Boolean(options.streamAssertions)
this.showCursor = Boolean(options.showCursor)
if (options.pause != null) this.pauseBetweenTests = options.pause
if (options.restartOnBlur != null) this.restartOnBlur = options.restartOnBlur
var me = this
var descriptors = Joose.A.map(task, function (el) {
var desc = me.getScriptDescriptor(el.descId)
desc.automationElementId = el.automationElementId
return desc
})
this.launch(descriptors)
},
warn : function (text) {
this.log({
text : text,
isWarning : true
})
if (typeof window != 'undefined')
window.console && console.warn(text)
if (this.viewport) {
Ext.toast({
cls : 'tr-warn-toast',
title : 'Warning',
html : text.replace(/\n/g, '<br>'),
align : 't',
autoCloseDelay : 3000
})
}
},
getExitCode : function () {
return this.allPassed() ? 0 : 1
}
}
})
//eof Siesta.Project.Browser.Automation
if (!Siesta.Project.NodeJS)
Siesta.Project.Browser.meta.extend({
does : [
Siesta.Project.Browser.Automation,
Siesta.Project.Browser.Automation.Selenium,
Siesta.Project.Browser.Automation.Puppeteer
]
})
else
if (Siesta.Project.NodeJS)
Siesta.Project.NodeJS.meta.extend({
does : [
Siesta.Project.Browser.Automation,
Siesta.Project.Browser.Automation.NodeJS
]
})