siesta-lite
Version:
Stress-free JavaScript unit testing and functional testing tool, works in NodeJS and browsers
306 lines (212 loc) • 9.92 kB
JavaScript
/*
Siesta 5.6.1
Copyright(c) 2009-2022 Bryntum AB
https://bryntum.com/contact
https://bryntum.com/products/siesta/license
*/
Role('Siesta.Launcher.Dispatcher.TaskQueue', {
requires : [
'onCanNotRunElement'
],
has : {
structure : null,
sharedContextGroups : null,
regularTestsGroup : null,
streamedUpdatesHash : Joose.I.Object
},
methods : {
getAllResults : function () {
var results = []
this.forEachTestElement(function (el) {
// result can be missing in case of early test suite finalization on "breakOnFail"
if (el.result) results.push(el.result)
})
return results
},
getAllResultsStructured : function (structurePoint) {
var isSeedingCall = !arguments.length
structurePoint = isSeedingCall ? this.structure : structurePoint
if (structurePoint.group) {
var me = this
var items = []
Joose.A.each(structurePoint.items, function (point) {
var res = me.getAllResultsStructured(point)
if (res) items.push(res)
})
return items.length || isSeedingCall ? {
group : structurePoint.group,
items : items
} : null
} else {
var el = this.getElementByDescId(structurePoint)
if (el) {
return el.result
} else
return null
}
},
allPassed : function () {
var allPassed = true
this.forEachTestElement(function (el) {
// if some element has not been processed yet, or for some element
// the test result is missing - then it is treated as failure
if (!el.processed || !el.result || !el.result.passed) { allPassed = false; return false }
})
return allPassed
},
allDone : function () {
var allDone = true
this.forEachTestElement(function (el) {
if (!el.processed) { allDone = false; return false }
})
return allDone
},
forEachTestElement : function (func, scope) {
scope = scope || this
var res = Joose.A.each(this.sharedContextGroups, function (sharedGroup) {
return sharedGroup.forEachElement(func, scope)
})
if (res === false) return false
return this.regularTestsGroup.forEachElement(func, scope)
},
consumeStreamedUpdate : function (update, page) {
var pageId = page.id
if (update.id)
update.id = pageId + update.id
if (update.parentId)
update.parentId = pageId + update.parentId
if (update.id)
this.streamedUpdatesHash[ update.id ] = update
return update
},
getStreamedUpdate : function (id) {
return this.streamedUpdatesHash[ id ]
},
getParentOfStreamedUpdate : function (update) {
return update.parentId ? this.streamedUpdatesHash[ update.parentId ] : null
},
consumeTestResult : function (testResult, page) {
var el = this.getElementById(testResult.automationElementId)
var sessionId = page.getSessionId()
if (sessionId != null) testResult.sessionId = sessionId
el.endProgress(testResult)
return el
},
// [ { descId : descId, automationElementId : elId }, ... ]
releaseChunkTask : function (chunkTask, notLaunchedById) {
this.forEachTestElementInChunkTask(chunkTask, function (el, group) {
if (el.inProgress) {
// as the 2nd arg, `releaseChunkTask` can receive either null, `true`
// or object values
var thereWasNoError = notLaunchedById === true ? true : notLaunchedById && notLaunchedById[ el.id ]
// thereWasNoError means the element was not even attempted to launch, for example, it is at the end of the
// tests list, and chunk has been terminated in the middle, this does not count as an attempt to run the
// element
if (el.reset(thereWasNoError)) this.onCanNotRunElement(el, group)
}
})
},
// returns true if chunk "passes" (all tests in it passed) Some tests may still be failed,
// because we allow re-run on exceptions (maxProcessedCount) and re-run on failure (reRunFailed)
// those tests will be executed again, in a different chunk, which will be marked as failed
chunkPassed : function (chunkTask, notLaunchedById) {
var passed = true
this.forEachTestElementInChunkTask(chunkTask, function (el, group) {
if (el.inProgress) {
// as the 2nd arg, `releaseChunkTask` can receive either null, `true`
// or object values
var thereWasNoError = notLaunchedById === true ? true : notLaunchedById && notLaunchedById[ el.id ]
// thereWasNoError means the element was not even attempted to launch, for example, it is at the end of the
// tests list, and chunk has been terminated in the middle, this does not count as an attempt to run the
// element
// thereWasNoError == false indicates there were an attempt to launch the element (test), but it is still marked
// as `inProgress` which means there were some infrastructure problem during the test
// it happens sometimes, we allow (maxProcessedCount) attempts
if (!thereWasNoError && !el.canRunAgain(true)) {
passed = false
return false
}
} else
if (!el.result.passed) {
passed = false
return false
}
})
return passed
},
forEachTestElementInChunkTask : function (chunkTask, func, scope) {
var me = this
scope = scope || this
Joose.A.each(chunkTask, function (scopeTask) {
var elGroup = me.getElementById(scopeTask.automationElementId, true)
if (func.call(scope, elGroup.el, elGroup.group) === false) return false
})
},
// chunk - a set of tests each with own sandbox (iframe), all runs on the same project page
getChunkTask : function (pagesPerChunk) {
var chunk = []
for (var i = 0; i < pagesPerChunk; i++) {
var scopeTask = this.getScopeTask()
if (scopeTask)
chunk.push.apply(chunk, scopeTask)
else
break
}
return chunk.length ? chunk : null
},
// scope task - a set of tests for 1 sandbox (1 iframe), normally only 1 test, but can be more in case of
// disabled sandboxing
getScopeTask : function () {
var me = this
var toProcess
Joose.A.each(this.sharedContextGroups, function (group) {
toProcess = group.fetchNSpareElements(1e10, true)
if (toProcess) return false
})
if (toProcess) return toProcess
return this.regularTestsGroup.fetchNSpareElements(1, true)
},
getElementById : function (id, withGroup) {
var el
var group
Joose.A.each(this.sharedContextGroups, function (sharedGroup) {
if (el = sharedGroup.getElementById(id)) {
group = sharedGroup
return false
}
})
if (el) return withGroup ? { el : el, group : group } : el
el = this.regularTestsGroup.getElementById(id)
return withGroup ? { el : el, group : this.regularTestsGroup } : el
},
getElementByDescId : function (id, withGroup) {
var el
var group
Joose.A.each(this.sharedContextGroups, function (sharedGroup) {
if (el = sharedGroup.getElementByDescId(id)) {
group = sharedGroup
return false
}
})
if (el) return withGroup ? { el : el, group : group } : el
el = this.regularTestsGroup.getElementByDescId(id)
return withGroup ? { el : el, group : this.regularTestsGroup } : el
},
reviseFailedTests : function () {
var totalCount = 0
var failedCount = 0
this.forEachTestElement(function (el, group) {
totalCount++
var result = el.result
// don't count tests that finalized with ERROR
if (!result.ERROR && !result.passed) failedCount++
})
if (failedCount <= Math.max(totalCount * 0.1, 1))
this.forEachTestElement(function (el, group) {
var result = el.result
if (!result.ERROR && !result.passed && el.canRunAgain()) el.setProcessed(false)
})
return { totalCount : totalCount, failedCount : failedCount }
}
}
})