@riovir/wc-fontawesome
Version:
Web components for Font Awesome
139 lines (116 loc) • 4.57 kB
JavaScript
import { definePropsOn, Prop } from './core';
/**
* The structure of the property descriptor is inspired by Hybrids.js
* However, the implementation is merely a naive subset of the library.
* See: https://hybrids.js.org/core-concepts/descriptors#structure
*
* One important difference is the lack of a caching mechanism.
* Derived values are recomputed on every access and don't trigger
* the observe until something accesses them.
*/
describe('definePropsOn', () => {
test('descriptor config is optional resulting in mutable prop', () => {
const props = {
defaults: {
connect: (_host, _key) => { /* ignore */ },
get: (_host, value) => value,
set: (_host, value) => value,
observe: (_host, _key) => { /* ignore */ },
},
blank: {},
};
const { host } = setup({ props });
const expectMutable = prop => {
expect(prop in host).toBe(true);
expect(host[prop]).toBe(undefined);
host[prop] = 'value';
expect(host[prop]).toBe('value');
};
expectMutable('blank');
expectMutable('defaults');
});
test('calls connect hook on host.connectedCallback()', () => {
const descriptor = { connect: jest.fn() };
const { host } = setup({ descriptor, connect: false });
expect(descriptor.connect).not.toHaveBeenCalled();
host.connectedCallback();
expect(descriptor.connect).toHaveBeenCalled();
});
test('calls observe on prop change', () => {
const descriptor = { observe: jest.fn() };
const { host } = setup({ props: { descriptor } });
expect(descriptor.observe).not.toHaveBeenCalled();
host.descriptor = 'one';
expect(descriptor.observe).toHaveBeenCalledWith(host, 'one', undefined);
host.descriptor = 'two';
expect(descriptor.observe).toHaveBeenCalledWith(host, 'two', 'one');
});
test('set returning undefined prevents update', () => {
const descriptor = {
set: (_, value) => value === 'invalid' ? undefined : value,
observe: jest.fn(),
};
const { host } = setup({ props: { descriptor } });
host.descriptor = 'ok';
expect(host.descriptor).toBe('ok');
expect(descriptor.observe).toHaveBeenCalledTimes(1);
host.descriptor = 'invalid';
expect(descriptor.observe).toHaveBeenCalledTimes(1);
expect(host.descriptor).toBe('ok');
});
test('setting identical value skips observe', () => {
const descriptor = { observe: jest.fn() };
const { host } = setup({ props: { descriptor } });
host.descriptor = 'clone';
expect(descriptor.observe).toHaveBeenCalledTimes(1);
host.descriptor = 'clone';
expect(descriptor.observe).toHaveBeenCalledTimes(1);
});
test('changing derived value triggers observe only when used', () => {
const triple = { get: ({ number }) => number * 3, observe: jest.fn() };
const { host } = setup({ props: { number: {}, triple } });
expect(triple.observe).not.toHaveBeenCalled();
host.number = 2;
expect(triple.observe).not.toHaveBeenCalled(); // This Hybrids.js would've called this.
expect(host.triple).toBe(6);
expect(triple.observe).toHaveBeenCalled();
});
function setup({ descriptor, props = { descriptor }, connect = true } = {}) {
class TestClass {}
const host = new TestClass();
definePropsOn(TestClass, props);
connect && host.connectedCallback();
return { host };
}
});
describe('Prop factory function', () => {
test('connect returns when attribute not set', () => {
const { host, connect } = setup({ attribute: 'the-foo' });
connect(host, 'theFoo');
expect(host.theFoo).toBe(undefined);
});
test('connect returns when prop is already defined', () => {
const { host, connect } = setup({ attribute: 'the-foo' });
host.theFoo = 'test prop';
host.setAttribute('the-foo', 'test attribute');
connect(host, 'theFoo');
expect(host.theFoo).toBe('test attribute');
});
test('sets boolean prop to true when blank attribute is present', () => {
const { host, connect } = setup({ attribute: 'the-foo', defaultValue: false });
host.setAttribute('the-foo', '');
connect(host, 'theFoo');
expect(host.theFoo).toBe(true);
});
test('sets prop value when attribute is set', () => {
const { host, connect } = setup({ attribute: 'the-foo' });
host.setAttribute('the-foo', 'a-string');
connect(host, 'theFoo');
expect(host.theFoo).toBe('a-string');
});
function setup({ attribute, defaultValue = null }) {
const prop = Prop({ attribute, defaultValue });
const host = document.createElement('div');
return { host, ...prop };
}
});