context-provider-controller prevents replacement (#519)
* context-provider-controller prevents replacement * correct import order * do not re-provide self providing context * define and test controller-host-test element
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
import { expect, fixture, html } from '@open-wc/testing';
|
||||
import { UmbContextConsumer } from '../consume/context-consumer';
|
||||
import { UmbContextProviderController } from './context-provider.controller';
|
||||
import { UmbControllerHostTestElement, UmbLitElement } from '@umbraco-cms/element';
|
||||
|
||||
class MyClass {
|
||||
prop = 'value from provider';
|
||||
}
|
||||
|
||||
describe('UmbContextProviderController', () => {
|
||||
let instance: MyClass;
|
||||
let provider: UmbContextProviderController;
|
||||
let element: UmbLitElement;
|
||||
|
||||
beforeEach(async () => {
|
||||
element = await fixture(html`<umb-controller-host-test></umb-controller-host-test>`);
|
||||
instance = new MyClass();
|
||||
provider = new UmbContextProviderController(element, 'my-test-context', instance);
|
||||
});
|
||||
|
||||
it('is defined with its own instance', () => {
|
||||
expect(element).to.be.instanceOf(UmbControllerHostTestElement);
|
||||
});
|
||||
|
||||
describe('Public API', () => {
|
||||
describe('properties', () => {
|
||||
it('has a unique property', () => {
|
||||
expect(provider).to.have.property('unique');
|
||||
});
|
||||
it('has a unique property, is equal to the unique', () => {
|
||||
expect(provider.unique).to.eq('my-test-context');
|
||||
});
|
||||
});
|
||||
|
||||
describe('methods', () => {
|
||||
it('has an providerInstance method', () => {
|
||||
expect(provider).to.have.property('providerInstance').that.is.a('function');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('works with UmbContextConsumer', (done) => {
|
||||
const localConsumer = new UmbContextConsumer(element, 'my-test-context', (_instance: MyClass) => {
|
||||
expect(_instance.prop).to.eq('value from provider');
|
||||
done();
|
||||
localConsumer.hostDisconnected();
|
||||
});
|
||||
localConsumer.hostConnected();
|
||||
});
|
||||
|
||||
it('Fails providing the same instance with another controller using the same unique', () => {
|
||||
let secondCtrl;
|
||||
|
||||
// Tests that the creations throws:
|
||||
expect(() => {
|
||||
secondCtrl = new UmbContextProviderController(element, 'my-test-context', instance);
|
||||
}).to.throw();
|
||||
|
||||
// Still has the initial controller:
|
||||
expect(element.hasController(provider)).to.be.true;
|
||||
// The secondCtrl was never set as a result of the creation failing:
|
||||
expect(secondCtrl).to.be.undefined;
|
||||
});
|
||||
});
|
||||
@@ -13,10 +13,19 @@ export class UmbContextProviderController<T = unknown>
|
||||
constructor(host: UmbControllerHostInterface, contextAlias: string | UmbContextToken<T>, instance: T) {
|
||||
super(host, contextAlias, instance);
|
||||
|
||||
// TODO: What if this API is already provided with this alias? maybe handle this in the controller:
|
||||
// TODO: Remove/destroy existing controller of same alias.
|
||||
|
||||
host.addController(this);
|
||||
// If this API is already provided with this alias? Then we do not want to register this controller:
|
||||
const existingControllers = host.getControllers((x) => x.unique === this.unique);
|
||||
if (
|
||||
existingControllers.length > 0 &&
|
||||
(existingControllers[0] as UmbContextProviderController).providerInstance?.() === instance
|
||||
) {
|
||||
// Back out, this instance is already provided, by another controller.
|
||||
throw new Error(
|
||||
`Context API: The context of '${this.unique}' is already provided with the same API by another Context Provider Controller.`
|
||||
);
|
||||
} else {
|
||||
host.addController(this);
|
||||
}
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
|
||||
@@ -8,10 +8,12 @@ class MyClass {
|
||||
}
|
||||
|
||||
describe('UmbContextProvider', () => {
|
||||
let instance: MyClass;
|
||||
let provider: UmbContextProvider;
|
||||
|
||||
beforeEach(() => {
|
||||
provider = new UmbContextProvider(document.body, 'my-test-context', new MyClass());
|
||||
instance = new MyClass();
|
||||
provider = new UmbContextProvider(document.body, 'my-test-context', instance);
|
||||
provider.hostConnected();
|
||||
});
|
||||
|
||||
|
||||
@@ -12,6 +12,15 @@ export class UmbContextProvider<HostType extends EventTarget = EventTarget> {
|
||||
protected _contextAlias: string;
|
||||
#instance: unknown;
|
||||
|
||||
/**
|
||||
* Method to enable comparing the context providers by the instance they provide.
|
||||
* Note this method should have a unique name for the provider controller, for it not to be confused with a consumer.
|
||||
* @returns {*}
|
||||
*/
|
||||
public providerInstance() {
|
||||
return this.#instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of UmbContextProvider.
|
||||
* @param {EventTarget} host
|
||||
@@ -54,9 +63,8 @@ export class UmbContextProvider<HostType extends EventTarget = EventTarget> {
|
||||
event.callback(this.#instance);
|
||||
};
|
||||
|
||||
|
||||
destroy(): void {
|
||||
// I want to make sure to call this, but for now it was too overwhelming to require the destroy method on context instances.
|
||||
(this.#instance as any).destroy?.();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user