siesta-lite
Version:
Stress-free JavaScript unit testing and functional testing tool, works in NodeJS and browsers
624 lines (512 loc) • 20.9 kB
JavaScript
/*
Siesta 5.6.1
Copyright(c) 2009-2022 Bryntum AB
https://bryntum.com/contact
https://bryntum.com/products/siesta/license
*/
Ext.define('Siesta.Project.Browser.UI.ResultPanel', {
extend : 'Ext.Panel',
alias : 'widget.resultpanel',
requires : [
'Siesta.Project.Browser.UI.AssertionGrid',
'Siesta.Project.Browser.UI.DomContainer',
'Siesta.Project.Browser.UI.SourcePanel',
'Siesta.Recorder.UI.RecorderPanel'
],
slots : true,
test : null,
testListeners : null,
maintainViewportSize : true,
scaleToFit : true,
scaleToFitMode : 'full',
viewDOM : false,
border : false,
canManageDOM : true,
project : null,
isStandalone : false,
showToolbar : true,
title : 'Result panel',
header : false,
minWidth : 100,
layout : 'border',
sourceButton : null,
filterButton : null,
inspectionButton : null,
recorderPanel : null,
recorderConfig : null,
recorderPanelClass : 'Siesta.Recorder.UI.RecorderPanel',
domContainerRegion : 'east',
isReadOnlyReport : false,
initComponent : function () {
var me = this;
var R = Siesta.Resource('Siesta.Project.Browser.UI.ResultPanel');
var domContainerRegion = this.domContainerRegion || 'east'
Ext.apply(this, {
cls : 'tr-container',
tbar : {
cls : 'resultpanel-toolbar',
defaults : {
tooltipType : 'title',
scope : this
},
items : this.getTopToolbarItems(R)
},
items : [
// a card container
{
region : 'center',
slot : 'cardContainer',
xtype : 'container',
layout : {
type : 'card',
deferredRender : true
},
activeItem : 0,
minWidth : 100,
items : [
// grid with assertion
{
xtype : 'assertiongrid',
slot : 'grid',
isStandalone : this.isStandalone,
listeners : {
itemdblclick : this.onAssertionDoubleClick,
scope : this
}
},
// eof grid with assertion
{
xtype : 'sourcepanel',
slot : 'source',
listeners : {
render : function(panel) {
var el = panel.getEl().appendChild({
cls : 'si-sourcepanel-close fa-close',
style : 'right:' + (Ext.getScrollbarSize().width + 5) + 'px'
});
el.on('click', this.hideSource, this);
},
scope : this
}
}
].concat(
Ext.ClassManager.getByAlias('widget.coveragereport') ?
{
// to avoid coverage report to be picked up as a dependency by sencha cmd compiler
xtype : 'coverage' + 'report',
slot : 'coverageReport',
project : this.project
} : []
)
},
{
xtype : 'domcontainer',
region : domContainerRegion,
collapsible : true,
hidden : this.isReadOnlyReport,
split : { size : 7 },
bodyStyle : 'text-align : center',
slot : 'domContainer',
stateful : true, // Turn off for recursive siesta demo
id : this.id + '-domContainer',
width : (domContainerRegion == 'east' || domContainerRegion == 'west') ? '50%' : null,
height : (domContainerRegion == 'south' || domContainerRegion == 'north') ? '50%' : null,
cls : 'siesta-domcontainer',
collapsed : !this.viewDOM,
scaleToFit : this.scaleToFit,
scaleToFitMode : this.scaleToFitMode
}
]
})
this.callParent()
this.slots.domContainer && this.slots.domContainer.on({
expand : this.onDomContainerExpand,
collapse : this.onDomContainerCollapse,
inspectionstart : function () {
this.inspectionButton.toggle(true);
},
inspectionstop : function () {
this.inspectionButton.toggle(false);
},
scope : this
});
},
onLoadReportFileChange : function (field) {
var me = this
var file = field.fileInputEl.dom.files[ 0 ]
var reader = new FileReader()
reader.onload = function () {
try {
var json = JSON.parse(reader.result)
} catch (e) {
Ext.Msg.alert("Error", "Error parsing JSON")
}
if (json) me.fireEvent('newjsonreport', me, json)
}
reader.onerror = function () {
Ext.Msg.alert("Error", "Error loading file")
}
reader.readAsText(file)
},
getTopToolbarItems : function (R) {
var me = this;
if (!this.showToolbar) return null
var state = this.stateConfig;
var isReadOnlyReport = this.isReadOnlyReport
var items = []
if (!isReadOnlyReport) items.push(
{
text : R.get('rerunText'),
cls : 'rerun-button',
glyph : 0xf04b,
scale : 'medium',
handler : this.onRunTestClick
}
)
items.push(
{
xtype : 'label',
cls : 'resultpanel-testtitle',
itemId : 'resultpanel-testtitle',
margin : '0 0 0 10',
height : 48,
text : ' ',
flex : 1
}
)
if (isReadOnlyReport && window.FileReader) items.push(
{
xtype : 'fileuploadfield',
buttonOnly : true,
buttonText : 'Load data file',
listeners : {
change : this.onLoadReportFileChange,
scope : this
}
}
)
if (!isReadOnlyReport) items.push(
{
xtype : 'label',
cls : 'speedlabel',
margin : '0 20',
text : 'Mouse speed',
// need some dummy id to avoid some warning in FF (requested by Sergey)
forId : 'dummyId'
},
{
xtype : 'segmentedbutton',
cls : 'speed-button',
scale : 'small',
margin : '0 30 0 0',
items : [{
text : 'Slow',
tooltip : 'Slow and accurate mouse simulation',
pressed : !state.speedRun && !state.turboMode,
option : 'mouseSimSlow'
}, {
text : 'Fast',
tooltip : 'Fast, but still accurate mouse simulation',
pressed : state.speedRun && !state.turboMode,
option : 'mouseSimFast'
}, {
text : 'Turbo',
pressed : state.turboMode,
tooltip : 'Turbo mode! Super fast with reduced mouse precision (read docs before using)',
option : 'mouseSimFastest'
}],
listeners : {
toggle : function (segmentedButton, button) {
me.fireEvent('optionchange', button, button.option, true);
}
}
},
this.viewDomButton = new Ext.Button({
tooltip : "Force native events simulation",
cls : 'testaction-button',
action : 'force-native',
scale : 'medium',
glyph : 0xf25a,
enableToggle : true,
scope : this,
pressed : this.project.simulation == 'native',
handler : function (btn) {
this.project.simulation = btn.pressed ? 'native' : 'synthetic'
}
}),
this.viewDomButton = new Ext.Button({
tooltip : R.get('toggleDomVisibleText'),
cls : 'testaction-button',
action : 'view-dom',
scale : 'medium',
glyph : 0xf26c,
enableToggle : true,
scope : this,
pressed : this.viewDOM,
handler : function (btn) {
this.setViewDOM(btn.pressed);
}
}),
this.scaleToFitButton = new Ext.SplitButton({
tooltip : 'Scale to fit',
cls : 'testaction-button',
action : 'scale-to-fit',
scale : 'medium',
glyph : 0xf065,
enableToggle : true,
pressed : Boolean(this.scaleToFit),
menu : {
items : [
{ glyph : 0xf0b2, text : 'Fit full', itemId : 'full' },
{ glyph : 0xf07e, text : 'Fit width', itemId : 'width' },
{ glyph : 0xf07d, text : 'Fit height', itemId : 'height' }
],
listeners: {
click : function(menu, item) {
this.slots.domContainer.setScaleToFit(true, item.itemId)
this.scaleToFitButton.setPressed(true);
},
scope : this
}
},
scope : this,
handler : function(btn) {
this.slots.domContainer.setScaleToFit(btn.pressed)
}
}),
this.sourceButton = new Ext.Button({
tooltip : R.get('viewSourceText'),
action : 'view-source',
cls : 'testaction-button',
glyph : 0xf0f6,
scale : 'medium',
tooltipType : 'title',
disabled : true,
enableToggle : true,
scope : this,
handler : function (btn) {
if (btn.pressed) {
this.showSource();
} else {
this.hideSource()
}
}
}),
this.filterButton = new Ext.Button({
tooltip : R.get('showFailedOnlyText'),
action : 'show-failed-only',
cls : 'testaction-button',
scale : 'medium',
glyph : 0xf188,
tooltipType : 'title',
scope : this,
enableToggle : true,
handler : this.onAssertionFilterClick
}),
this.inspectionButton = new Ext.Button({
glyph : 0xf002,
cls : 'testaction-button cmp-inspector',
action : 'toggle-cmp-inspector',
scale : 'medium',
tooltip : 'Target highlighter',
tooltipType : 'title',
handler : this.toggleComponentInspectionMode,
scope : this,
enableToggle : true
}),
this.recorderButton = new Ext.Button({
glyph : 0xf03d,
action : 'toggle-recorder',
cls : 'testaction-button',
scale : 'medium',
disabled : !Siesta.Recorder || Ext.isIE9m,
tooltip : R.get('eventRecorderText'),
handler : this.onRecorderClick,
margin : '0 30 0 0',
scope : this,
enableToggle : true
}),
{
xtype : 'versionupdatebutton'
},
{
xtype : 'component',
id : 'siesta-logo'
}
)
return items
},
// This method makes sure that the min width of the card panel is respected when
// the width of this class changes (after resizing Test TreePanel).
ensureLayout : function () {
var availableWidth = this.getWidth();
var cardPanel = this.slots.cardContainer;
var domContainer = this.slots.domContainer;
var domContainerWidth = domContainer.getWidth();
var minimumForCard = cardPanel.minWidth + 20; // Some splitter space
if (availableWidth - domContainerWidth < minimumForCard) {
domContainer.setWidth(Math.max(0, availableWidth - minimumForCard));
}
},
showSource : function (lineNbr) {
var test = this.test
if (!this.test) return;
var sourceLines = [];
var slots = this.slots
var cardContainer = slots.cardContainer
var sourceCt = slots.source;
// Do this first since rendering is deferred
cardContainer.layout.setActiveItem(sourceCt);
if (arguments.length === 0) {
// Highlight all failed rows
Ext.each(test.getFailedAssertions(), function (assertion) {
if (assertion.sourceLine != null) {
sourceLines.push(assertion.sourceLine)
}
});
}
else {
// Highlight just a single row (user double clicked a failed row)
sourceLines = [lineNbr];
}
sourceCt.setSource(test.getSource(), sourceLines);
},
hideSource : function () {
var slots = this.slots
var cardContainer = slots.cardContainer
if (cardContainer.layout.getActiveItem() === slots.source) {
this.sourceButton.setPressed(false);
cardContainer.layout.setActiveItem(slots.grid);
}
},
setViewDOM : function (value) {
var domContainer = this.slots.domContainer
if (value)
domContainer.expand(false)
else
domContainer.collapse(null, false)
},
onDomContainerCollapse : function () {
this.viewDOM = false;
this.viewDomButton.toggle(false);
this.fireEvent('viewdomchange', this, false);
},
onDomContainerExpand : function () {
this.viewDOM = true;
this.viewDomButton.toggle(true);
this.fireEvent('viewdomchange', this, true);
},
onRunTestClick : function () {
this.fireEvent('runbuttonclick', this);
},
showTest : function (test, assertionsStore) {
var recorder = this.slots.recorderPanel;
this.slots.source.clear();
this.filterButton && this.filterButton.toggle(false)
this.hideSource();
this.sourceButton && this.sourceButton.enable()
var url = test.url;
Ext.suspendLayouts();
this.slots.grid.showTest(test, assertionsStore)
this.slots.domContainer.showTest(test, assertionsStore)
if (recorder) {
if (!recorder.test || test.url !== recorder.test.url) {
recorder.stop();
recorder.attachTo(test);
}
}
this.setTestTitle(url === '/' ? recorder.getRecordingName() : url);
Ext.resumeLayouts();
this.test = test;
},
setTestTitle : function (url) {
this.testTitle.setText(url);
},
onAssertionFilterClick : function (btn) {
var grid = this.slots.grid;
var assertionsStore = grid.store;
// need this check for cases when users clicks on the button
// before running any test - in this case assertion grid will have an empty Ext.data.TreeStore instance
if (!assertionsStore.filterTreeBy) return
if (btn.pressed) {
grid.addCls('assertiongrid-filtered');
assertionsStore.filterTreeBy(function (resultRecord) {
var result = resultRecord.getResult()
// this covers the cases when "result" is a summary record, diagnostic record, etc
return result.passed === false && !result.isTodo
})
} else {
grid.removeCls('assertiongrid-filtered');
assertionsStore.clearTreeFilter()
}
},
alignIFrame : function () {
this.slots.domContainer.alignIFrame()
},
hideIFrame : function () {
this.slots.domContainer.hideIFrame()
},
setInitializing : function (initializing) {
this.slots.grid.setInitializing(initializing)
},
onAssertionDoubleClick : function (view, record) {
var result = record.getResult()
if ((result instanceof Siesta.Result.Assertion) && !result.isPassed(true)) {
this.showSource(result.sourceLine);
}
},
toggleComponentInspectionMode : function (btn) {
this.slots.domContainer.toggleInspectionMode(btn.pressed);
},
onRecorderClick : function () {
var cardContainer = this.slots.cardContainer
if (!this.recorderPanel) {
this.recorderPanel = Ext.create(this.recorderPanelClass, {
slot : 'recorderPanel',
project : this.project,
domContainer : this.slots.domContainer,
recorderConfig : this.recorderConfig,
closeButton : {
text : Siesta.Resource('Siesta.Project.Browser.UI.ResultPanel', 'closeText'),
cls : 'recorder-tool',
handler : function () {
cardContainer.layout.setActiveItem(0);
}
},
listeners : {
startrecord : function (pnl, test) {
this.fireEvent('startrecord', pnl, test);
this.showTest(test);
},
show : function () {
this.recorderButton.toggle(true);
},
play : function (pnl, test) {
this.showTest(test);
},
hide : function () {
this.recorderButton.toggle(false);
},
scope : this
}
});
this.slots.cardContainer.add(this.recorderPanel);
this.relayEvents(this.recorderPanel, [ 'startrecord', 'play' ], 'recorder');
if (this.test) {
this.slots.recorderPanel.attachTo(this.test);
}
}
if (cardContainer.layout.getActiveItem() === this.recorderPanel) {
cardContainer.layout.setActiveItem(this.slots.grid);
} else {
cardContainer.layout.setActiveItem(this.recorderPanel);
}
},
afterRender : function () {
this.callParent(arguments);
var splitter = this.child('bordersplitter');
this.testTitle = this.down('#resultpanel-testtitle');
// To avoid the DOM container splitter getting stuck
splitter && (splitter.tracker.tolerance = 0);
}
});