Let's imagine we have a basic A-Frame component:
AFRAME.registerComponent('scale-on-mouseenter', {
schema: {
to: {
default: '2 2 2'
}
},
init: function () {
this.el.addEventListener('mouseneter', function () {
this.setAttribute('scale', data.to);
});
}
});
And I want to test through QUnit. How to test if this component creates the scale
attribute?
Should I create a "testing A-Scene" for this purpose and verify the DOM? Or is there a more "unit" way to test?
The problem presented here is divided in two parts.
The link provided by ngokevin gives a solution. More especially, looking at existing tests shows that we need to create a testing a-scene
https://github.com/aframevr/aframe/blob/master/tests/components/scale.test.js
That's not really a unitary test, but hey, I do not want to mock all the A-Frame library!
Let's start with a more basic code to test, without an EventListener
.
// Set a scale factor to 2 2 2
AFrame.registerComponent('big', {
init: function () {
this.el.setAttribute('scale', '2 2 2');
}
});
The associated test needs to create a testing a-scene
. We can use QUnit.module
for that.
QUnit.module('Component testing', {
before: function () {
var scene = document.createElement('a-scene');
document.querySelector('#qunit-fixture').appendChild(scene);
},
after: function () {
var scene = document.querySelector('#qunit-fixture > a-scene');
scene.parentNode.removeChild(scene);
}
});
And now, we can test the component by creating an a-entity
, and see if the attribute is created when the component is added to the tag. We just have to wait for the component to be loaded. Otherwise, the assert is made before the component is loaded, and will eventually fail.
QUnit.test('Big add scale to 2 2 2', function (assert) {
// Create the entity to test
var entity = document.createElement('a-entity');
entity.setAttribute('big', '');
// Add it to the testing a-scene
var scene = document.querySelector('#qunit-fixture > a-scene');
scene.appendChild(entity);
// Wait for the component to be loaded
var done = assert.async()
entity.addEventListener('loaded', function () {
// Actual test
assert.deepEqual(
entity.getAttribute('scale'),
{'x': 2, 'y': 2, 'z': 2});
done();
});
});
The original problem involved an EventListener
. As a reminding purpose, this was the code to test.
AFRAME.registerComponent('scale-on-mouseenter', {
schema: {
to: {
default: '2 2 2'
}
},
init: function () {
this.el.addEventListener('mouseneter', function () {
this.setAttribute('scale', data.to);
});
}
});
Testing this needs another trick. One solution is to create a named function, then add this function as handler in the EventListener
as described here. The tests will test the named function alone, but not the addEventListener
part.
A second solution is to use the setTimeout
trick as described here
. The final test will use the previous work to test the component, then dispatch an Event
, then use the assert
part inside a setTimeout
to queue the test. A timeout of 0 works very well.
QUnit.test('scale-on-mouseenter add eventlistener', function (assert) {
// Create the entity to test
var entity = document.createElement('a-entity');
entity.setAttribute('scale-on-mouseenter', '');
// Add it to the testing a-scene
var scene = document.querySelector('#qunit-fixture > a-scene');
scene.appendChild(entity);
// Wait for the component to be loaded
var done = assert.async()
entity.addEventListener('loaded', function () {
// Dispatch the event
entity.dispatchEvent(new Event("mouseenter"));
// Queue the test with a timeout of 0
setTimeout(function () {
// Actual test
assert.deepEqual(
entity.getAttribute('scale'),
{'x': 2, 'y': 2, 'z': 2});
done();
});
});
});