I'm try to test my ReactJS mixin for drag and drop functionality using jasmine, karma and React TestUtils.
No exception is thrown but when debugging it seems that the function bound to the event listener not being executed when the event is simulated.
You can clone the it here:
https://github.com/itsh01/react-dragdrop/tree/testing-simutale-events
Thank you very much in advance.
Here is my test:
beforeEach(function () {
var CompDrag = React.createClass({
mixins: [DragDropMixin],
dragDrop: function dragDrop() {
return {
draggable: true,
dropType: 'test',
dataTransfer: {
test: true
}
};
},
render: function render() {
return React.createElement('div', {});
}
});
var CompDrop = React.createClass({
mixins: [DragDropMixin],
dragDrop: function dragDrop() {
var self = this;
return {
droppable: true,
acceptableTypes: ['test'],
drop: function (data) {
self.setState(data);
}
};
},
render: function render() {
return React.createElement('div', {});
}
});
elementDrag = React.createElement(CompDrag, {});
elementDrop = React.createElement(CompDrop, {});
});
...
it('should attach drop functionality when configured', function () {
var renderedDrag = TestUtils.renderIntoDocument(elementDrag);
var renderedDrop = TestUtils.renderIntoDocument(elementDrop);
var nodeDrag = renderedDrag.getDOMNode();
var nodeDrop = renderedDrop.getDOMNode();
var mockEvent = {
preventDefault: function () {},
dataTransfer: {
types: ["objtopass"],
setData: function () {},
getData: function () {
return JSON.parse({
dropType: 'test',
data: {
test: true
}
});
}
}
};
TestUtils.SimulateNative.dragStart(nodeDrag, mockEvent);
TestUtils.Simulate.dragOver(nodeDrop, mockEvent);
TestUtils.Simulate.drop(nodeDrop, mockEvent);
expect(renderedDrop.state).not.toBeNull();
});
Here is the mixin:
'use strict';
var _ = lodash;
var DragDropMixin = {
/*
* usage:
*
* mixins: [DragDropMixin],
* dragDrop: function () {
*
* return {
*
* // when dragging an item
* draggable: true,
* dropType: 'myItem',
* dataTransfer: { myItemData: property }
*
* // when dropping an item:
* droppable: true,
* acceptableDrops: ['myItem'],
* drop: function (myItem) {},
* };
* }
*
*/
isAttrEnabled: function (attr) {
return this.dragDropData && this.dragDropData[attr];
},
isDroppable: function () {
return this.isAttrEnabled('droppable');
},
isDraggable: function () {
return this.isAttrEnabled('draggable');
},
componentDidMount: function () {
var node = this.getDOMNode();
this.dragDropData = this.dragDrop();
if (this.isDroppable()) {
node.addEventListener('dragover', this.handleDragOver, this);
node.addEventListener('drop', this.handleDrop, this);
}
if (this.isDraggable()) {
node.draggable = true;
node.addEventListener('dragstart', this.handleDragStart, this);
}
},
componentWillUnmount: function () {
var node = this.getDOMNode();
if (this.isDroppable()) {
node.removeEventListener('dragover', this.handleDragOver);
node.removeEventListener('drop', this.handleDrop);
}
if (this.isDraggable()) {
node.removeEventListener('dragstart', this.handleDragStart);
}
},
handleDragOver: function (e) {
e.preventDefault();
},
handleDrop: function (e) {
var jsonData = e.dataTransfer.getData('objToPass'),
passedObj = JSON.parse(jsonData),
acceptableDrops = this.dragDropData.acceptableDrops;
e.preventDefault();
if (!this.dragDropData.drop) {
throw new Error('Must define drop function when using droppable');
}
if (_.includes(acceptableDrops, passedObj.dropType)) {
this.dragDropData.drop(passedObj.data);
}
},
handleDragStart: function (e) {
var objToPass = {
data: this.dragDropData.dataTransfer,
dropType: this.dragDropData.dropType
};
e.dataTransfer.setData('objToPass', JSON.stringify(objToPass));
}
};
Thanks again.
OK, got it.
I was actually listening to native events and simulating React synthetic events.
Fixed it by changing the mixin:
componentDidMount: function () {
var node = this.getDOMNode();
this.dragDropData = this.dragDrop();
if (this.isDroppable()) {
node.ondragover = this.handleDragOver;
node.ondrop = this.handleDrop;
}
if (this.isDraggable()) {
node.draggable = true;
node.ondragstart = this.handleDragStart;
}
},
And testing by triggering a native event
nodeDrag.ondragstart(mockEvent);
nodeDrop.ondragover(mockEvent);
nodeDrop.ondrop(mockEvent);
expect(DragDropMixin.handleDrop).toHaveBeenCalled();
expect(renderedDrop.state).toBeNull();
Related
I want the use set method of factory but both of return default how can I fix that problem?
app.factory("DualListShareFactory", function(){
var selectedArray=[];
return{
getSelectedArray: function () {
return selectedArray;
},
setSelectedArray: function (array){
selectedArray=array;
}
}
});
Using ng-dual List from https://github.com/tushariscoolster/ng-duallist
I'm tkining it not working: DualListShareFactory.setSelectedArray(vm.rightValue);
I use other method for and push but I am received same error .
app.controller("duallist2", function($scope,DualListShareFactory){
var vm=this;
vm.property='duallist2';
activate();
function activate() {
vm.leftValue = [];
vm.rightValue = [];
vm.addValue = [];
vm.removeValue = [];
function loadMoreLeft() {
for (var i = 0; i < $scope.incomingItem.length; i++) {
vm.leftValue.push({
'name': $scope.incomingItem[i]
});
}
};
function loadMoreRight() {
}
vm.options = {
leftContainerScrollEnd: function () {
},
rightContainerScrollEnd: function () {
},
leftContainerSearch: function (text) {
console.log(text)
vm.leftValue = $filter('filter')(leftValue, {
'name': text
})
},
rightContainerSearch: function (text) {
vm.rightValue = $filter('filter')(rightValue, {
'name': text
})
},
leftContainerLabel: 'Gelen Parçalar',
rightContainerLabel: 'Seçilen Parçalar',
onMoveRight: function () {
console.log('right');
console.log(vm.addValue);
},
onMoveLeft: function () {
console.log('left');
console.log(vm.removeValue);
}
};
loadMoreLeft();
var leftValue = angular.copy(vm.leftValue);
var rightValue = angular.copy(vm.rightValue);
} console.log(vm.rightValue);
DualListShareFactory.setSelectedArray(vm.rightValue);
});
I am not this will work but try "this",
app.factory("DualListShareFactory", function(){
this.selectedArray=[];
return{
getSelectedArray: function () {
return this.selectedArray;
},
setSelectedArray: function (array){
this.selectedArray = array;
}
}
});
var app = angular.module("testapp", ["ng-duallist"]);
app.factory("DualListShareFactory", function(){
var selectedArray = [];
return{
getSelectedArray: function () {
return selectedArray
},
setSelectedArray: function (array){
angular.copy(array, selectedArray);
}
}
});
using for this add the other code block before ending function.
onMoveRight: function () {
DualListShareFactory.setSelectedArray(vm.rightValue);
},
onMoveLeft: function () {
DualListShareFactory.setSelectedArray(vm.rightValue);
}
};
loadMoreLeft();
var leftValue = angular.copy(vm.leftValue);
var rightValue = angular.copy(vm.rightValue);
The problem is that when I am binding this to function in .then() of Promise all variables is binded but 1 which is function, not.
define([
'Service/service',
'core/widget'], function (service, widget) {
return widget.extend({
init: function (options) {
this.options = options;
console.log('this.options: ', this.options); //{actionToDo:function(),variables...}
service.getFile('app/Core/Widgets/Button/Views/button.html')
.then(
function(){
console.log('this.options: ', this.options); //{actionToDo:undefined,...}
}.bind(this)
)
}
});});
I am creating the object by:
new Button(
{
elementToAppend: this.className + ' .actions > .actionButtons',
class: action.class,
icon: action.icon,
text: action.text,
unique: action.unique,
actionToDo: function(){//some code}
}
);
And the widget:
define(['underscore'], function (_) {
function Widget() {
}
return {
extend: function (methods) {
var widget = new Widget();
widget.prototype = {
trigger: function (event) {
switch (event) {
case 'click':
{
this.onClick.call(this);
break;
}
}
}
};
var Widget_Extended = _.extend(widget.prototype, methods);
return function (options) {
Widget_Extended.init(options);
return Widget_Extended;
};
}
};});
Could you tell me why inside function in .then() 1 parametr of options is undefined?
The solve of the problem (I guess) is:
define(['underscore'], function (_) {
function Widget() {
}
return {
extend: function (methods) {
return function (options) {
var widget = new function () {
};
widget.prototype = {
trigger: function (event) {
switch (event) {
case 'click':
{
this.onClick.call(this);
break;
}
}
}
};
var Widget_Extended = _.extend(widget.prototype, methods);
Widget_Extended.init(options);
return Widget_Extended;
};
}
};});
I have 2 request
html: <div>{{name}}</div>
json {"name": "Vasya"}
How with React parse this data and return <div>Vasya</div> ?
module.exports = React.createClass({
getInitialState: function () {
return {
previewData: {}, // {"name":"Vasya"}
previewHtml: {} // "<div>{{name}}</div>"
},
getTemplateDataStore: function (event, previewData) {
this.setState({
previewData: previewData
});
},
getTemplateHTMLStore: function (event, previewHtml) {
this.setState({
previewHtml: previewHtml
});
},
render: function () {
return // ?????????? need return <div>Vaysa</div>?
}
},
});
how does one test a code inside a callback function using sinon.js framework for mocking?
JSFiddle: http://jsfiddle.net/ruslans/CE5e2/
var service = function () {
return {
getData: function (callback) {
return callback([1, 2, 3, 4, 5]);
}
}
};
var model = function (svc) {
return {
data: [],
init: function () {
var self = this;
svc.getData(function (serviceData) {
self.data = serviceData; // *** test this line ***
});
}
}
};
I use mocha tests with chai but am familiar with qUnit, so any of these tests would be accepted.
callsArgWith(0, dataMock) does the trick:
http://jsfiddle.net/ruslans/3UtdF/
var target,
serviceStub,
dataMock = [0];
module("model tests", {
setup: function () {
serviceStub = new service();
sinon.stub(serviceStub);
serviceStub.getData.callsArgWith(0, dataMock);
target = new model(serviceStub);
},
teardown: function () {
serviceStub.getData.restore();
}
});
test("data is populated after service.getData callback", function () {
target.init();
equal(target.data, dataMock);
});
I have this code (also shown below) that is giving me an error in IE8 but is fine in Chrome and PhantomJS.
The error is "Object doesn't support this property or method knockout-2.2.1.debug.js, line 2319 character 35", which is called from currentPage(pages[pages.indexOf(current) + steps]);
I have no clue why it's not working, so any help would be greatly appreciated!
var Page = (function () {
function Page(index, name, canNavigateToPage, navigatedToThisPage) {
this.index = index;
this.name = name;
this.canNavigateToPage = canNavigateToPage;
this.navigatedToThisPage = navigatedToThisPage;
}
Page.prototype.navigateToPage = function () {
if (this.canNavigateToPage()) {
this.navigatedToThisPage(this);
}
};
return Page;
})();
var AccountSearchParameters = (function () {
function AccountSearchParameters() {
this.reference = ko.observable();
this.scheme = ko.observable();
this.lastName = ko.observable();
this.sufficientInputToSearchForAccount = ko.computed(function () {
return this.reference() && this.scheme() && this.lastName();
}, this);
}
return AccountSearchParameters;
})();
function viewModel() {
var self = this,
currentPage = ko.observable(),
accountSearchParameters = new AccountSearchParameters(),
forwardPageProgressionGuards = {
'1': function canMoveToPage2() {
return accountSearchParameters.sufficientInputToSearchForAccount();
},
'2': function canMoveToPage3() {
return true;
},
'3': function canMoveToPage4() {
return true;
}
},
canMoveToNextPage = function (currentlyOnPage) {
function disallowPageMovementNotExplicitlyDefined() {
return false;
}
return (forwardPageProgressionGuards[currentlyOnPage] || disallowPageMovementNotExplicitlyDefined)();
},
canMoveToPreviousPage = function (currentlyOnPage) {
return currentlyOnPage > 1;
},
pages = [
new Page(1, 'Customer details', function () {
return true;
}, function (page) {
currentPage(page);
}),
new Page(2, 'Bank details', forwardPageProgressionGuards['1'], currentPage),
new Page(3, 'Payment details', forwardPageProgressionGuards['2'], currentPage),
new Page(4, 'Confirmation', function () {
return true;
}, currentPage)],
pageNavigator = function (canNavigate, steps) {
current = currentPage();
console.log(canNavigate(current.index));
if (canNavigate(current.index)) {
currentPage(pages[pages.indexOf(current) + steps]);
}
};
currentPage(pages[0]);
self.page = ko.computed(function () {
return currentPage();
});
self.accountSearchParameters = accountSearchParameters;
self.nextPage = function () {
pageNavigator(canMoveToNextPage, 1);
};
self.previousPage = function () {
pageNavigator(canMoveToPreviousPage, -1);
};
self.canMoveToNext = ko.computed(function () {
return canMoveToNextPage(currentPage().index);
});
return self;
}
$(function () {
ko.applyBindings(viewModel());
});
indexOf in IE8 does not supported, use $.inArray