lion/packages/core/test/ObserverMixin.test.js
Thomas Allmer ec8da8f12c feat: release inital public lion version
Co-authored-by: Mikhail Bashkirov <mikhail.bashkirov@ing.com>
Co-authored-by: Thijs Louisse <thijs.louisse@ing.com>
Co-authored-by: Joren Broekema <joren.broekema@ing.com>
Co-authored-by: Gerjan van Geest <gerjan.van.geest@ing.com>
Co-authored-by: Erik Kroes <erik.kroes@ing.com>
Co-authored-by: Lars den Bakker <lars.den.bakker@ing.com>
2019-04-26 10:37:57 +02:00

242 lines
7.1 KiB
JavaScript

/* eslint-env mocha */
/* eslint-disable no-underscore-dangle, class-methods-use-this, no-unused-expressions */
import { expect, fixture, defineCE } from '@open-wc/testing';
import sinon from 'sinon';
import { LionLitElement } from '../src/LionLitElement.js';
import { ObserverMixin } from '../src/ObserverMixin.js';
describe('ObserverMixin', () => {
afterEach(() => {
sinon.restore();
});
it('throws if a syncObserver function is not found', async () => {
class SyncTest extends ObserverMixin(class {}) {
static get properties() {
return { size: { type: 'String' } };
}
static get syncObservers() {
return { _onSyncMissingFunction: ['size'] };
}
get localName() {
return 'SyncTest';
}
}
let error = false;
try {
new SyncTest(); // eslint-disable-line no-new
} catch (err) {
error = err;
}
expect(error).to.be.instanceOf(Error);
expect(error.message).to.equal(
'SyncTest does not have a function called _onSyncMissingFunction',
);
});
it('throws if a asyncObserver function is not found', async () => {
class AsyncTest extends ObserverMixin(class {}) {
static get properties() {
return { size: { type: 'String' } };
}
static get asyncObservers() {
return { _onAsyncMissingFunction: ['size'] };
}
get localName() {
return 'AsyncTest';
}
}
let error = false;
try {
new AsyncTest(); // eslint-disable-line no-new
} catch (err) {
error = err;
}
expect(error).to.be.instanceOf(Error);
expect(error.message).to.equal(
'AsyncTest does not have a function called _onAsyncMissingFunction',
);
});
// TODO: replace with requestUpdate()?
it('provides triggerObserversFor() which can be used within a setter to hook into the observer system', async () => {
const tag = defineCE(
class extends ObserverMixin(LionLitElement) {
static get syncObservers() {
return { _onSyncSizeChanged: ['size'] };
}
static get asyncObservers() {
return { _onAsyncSizeChanged: ['size'] };
}
set size(newValue) {
const oldValue = this.__mySize;
this.__mySize = newValue;
this.triggerObserversFor('size', newValue, oldValue);
}
get size() {
return this.__mySize;
}
_onSyncSizeChanged() {}
_onAsyncSizeChanged() {}
},
);
const el = await fixture(`<${tag}></${tag}>`);
const asyncSpy = sinon.spy(el, '_onAsyncSizeChanged');
const syncSpy = sinon.spy(el, '_onSyncSizeChanged');
el.size = 'tiny';
expect(syncSpy.callCount).to.equal(1);
expect(syncSpy.calledWith({ size: 'tiny' }, { size: undefined })).to.be.true;
el.size = 'big';
expect(syncSpy.callCount).to.equal(2);
expect(syncSpy.calledWith({ size: 'big' }, { size: 'tiny' })).to.be.true;
expect(asyncSpy.callCount).to.equal(0);
await el.updateComplete;
expect(syncSpy.callCount).to.equal(2);
expect(asyncSpy.callCount).to.equal(1);
expect(asyncSpy.calledWith({ size: 'big' }, { size: undefined })).to.be.true;
el.size = 'medium';
await el.updateComplete;
expect(syncSpy.callCount).to.equal(3);
expect(syncSpy.calledWith({ size: 'medium' }, { size: 'big' })).to.be.true;
expect(asyncSpy.calledWith({ size: 'medium' }, { size: 'big' })).to.be.true;
});
describe('syncObservers', () => {
it('calls observers immediately when the observed property is changed (newValue !== oldValue)', async () => {
const tag = defineCE(
class extends ObserverMixin(LionLitElement) {
static get properties() {
return { size: { type: String } };
}
static get syncObservers() {
return { _onSizeChanged: ['size'] };
}
_onSizeChanged() {}
},
);
const el = await fixture(`<${tag}></${tag}>`);
const observerSpy = sinon.spy(el, '_onSizeChanged');
expect(observerSpy.callCount).to.equal(0);
el.size = 'tiny';
expect(observerSpy.callCount).to.equal(1);
el.size = 'tiny';
expect(observerSpy.callCount).to.equal(1);
el.size = 'big';
expect(observerSpy.callCount).to.equal(2);
});
it('makes call to observer for every observed property change', async () => {
const tag = defineCE(
class extends ObserverMixin(LionLitElement) {
static get properties() {
return {
size: { type: String },
speed: { type: Number },
};
}
static get syncObservers() {
return {
_onSpeedOrTypeChanged: ['size', 'speed'],
};
}
_onSpeedOrTypeChanged() {
this.__testSize = this.size;
}
},
);
const el = await fixture(`<${tag}></${tag}>`);
const observerSpy = sinon.spy(el, '_onSpeedOrTypeChanged');
el.size = 'big';
expect(observerSpy.callCount).to.equal(1);
expect(el.__testSize).to.equal('big');
el.speed = 3;
expect(observerSpy.callCount).to.equal(2);
expect(
observerSpy.calledWith(
{ size: 'big', speed: undefined },
{ size: undefined, speed: undefined },
),
).to.be.true;
expect(observerSpy.calledWith({ size: 'big', speed: 3 }, { size: 'big', speed: undefined }))
.to.be.true;
});
});
describe('asyncObservers', () => {
it('calls observer patched when the observed property is changed', async () => {
const tag = defineCE(
class extends ObserverMixin(LionLitElement) {
static get properties() {
return { size: { type: 'String' } };
}
static get asyncObservers() {
return { _onAsyncSizeChanged: ['size'] };
}
_onAsyncSizeChanged() {}
},
);
const el = await fixture(`<${tag}></${tag}>`);
const observerSpy = sinon.spy(el, '_onAsyncSizeChanged');
el.size = 'tiny';
expect(observerSpy.callCount).to.equal(0);
await el.updateComplete;
expect(observerSpy.callCount).to.equal(1);
});
it('makes only one call to observer even if multiple observed attributes changed', async () => {
const tag = defineCE(
class extends ObserverMixin(LionLitElement) {
static get properties() {
return {
size: { type: 'String' },
speed: { type: 'Number' },
};
}
static get asyncObservers() {
return {
_onAsyncSpeedOrTypeChanged: ['size', 'speed'],
};
}
_onAsyncSpeedOrTypeChanged() {}
},
);
const el = await fixture(`<${tag}></${tag}>`);
const observerSpy = sinon.spy(el, '_onAsyncSpeedOrTypeChanged');
el.size = 'big';
el.speed = 3;
expect(observerSpy.callCount).to.equal(0);
await el.updateComplete;
expect(observerSpy.callCount).to.equal(1);
expect(
observerSpy.calledWith({ size: 'big', speed: 3 }, { size: undefined, speed: undefined }),
).to.be.true;
});
});
});