I'm starting to lean more on `reactiveUtils.watch()` for reactivity that isn't easily handled by my JavaScript framework. Generally, things are going well, but I'm running into an issue with unit/integration tests:
A common issue is that I will want to stub or mock a JS SDK class. For example, I frequently create a fake WebMap with fake layers:
class FakeLayer {
constructor({ id, listMode, visible, type }) {
this.id = id;
this.listMode = listMode;
this.visible = visible;
this.type = type;
}
when = async () => true;
}
const fakeWebMap = {
allLayers: [
new FakeLayer({
id: 'layer-1',
listMode: 'hide',
visible: true,
}),
new FakeLayer({
id: 'layer-2',
listMode: 'hide',
visible: false,
}),
new FakeLayer({
id: 'layer-3',
listMode: 'show',
visible: true,
}),
};
My problem is this: reactiveUtils.watch() does not seem to work on POJOs or custom classes like FakeLayer above.
In the example above, I might be testing code that watches the `visible` property on each FakeLayer and mutates `listMode` if `visible` changes. How can I implement a mock/stub testing class that works with reactiveUtils.watch()?
Solved! Go to Solution.
Have you considered extending the Accessor class? See also https://developers.arcgis.com/javascript/latest/implementing-accessor/
Have you considered extending the Accessor class? See also https://developers.arcgis.com/javascript/latest/implementing-accessor/
This looks like exactly the starting point I was looking for, thanks. I'll come back and accept as solution once I've seen if it works for what I need.
Did this end up working out, or did you find something else more suitable?
Actually, yes! I just got it to work moments ago. I used this section of the article you linked: https://developers.arcgis.com/javascript/latest/implementing-accessor/#define-a-simple-property
Here's what my solution looks like for setting up a single property that I can use reactiveUtils.watch() on:
const MyCustomClass = Accessor.createSubclass({
constructor: function () {
this.myProperty = null;
},
properties: {
myProperty: {},
},
});
I wanted to use native classes, but neither of the following were working for me (I'm not using TypeScript):
// native class using the @property decorator
class MyCustomClass extends Accessor {
@property
state = null;
}
// native class, no decorators
class MyCustomClass extends Accessor {
constructor() {
super(...arguments);
this.myProperty= null;
}
properties = {
myProperty: {},
};
}