Skip to content

Commit

Permalink
test(integration-karma): test CustomElementConstructor attributes (#3505
Browse files Browse the repository at this point in the history
)
  • Loading branch information
nolanlawson committed May 18, 2023
1 parent 736ef6e commit 5a6188e
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import LifecycleParent from 'x/lifecycleParent';
import WithChildElms from 'x/withChildElms';
import DefinedComponent from 'x/definedComponent';
import UndefinedComponent from 'x/undefinedComponent';
import AttrChanged from 'x/attrChanged';
import ReflectCamel from 'x/reflectCamel';

// We can't register standard custom elements if we run compat because of the transformation applied to the component
// constructor.
Expand Down Expand Up @@ -121,8 +123,9 @@ if (SUPPORTS_CUSTOM_ELEMENTS) {

describe('attribute reflection', () => {
beforeAll(() => {
const ReflectCustomElement = ReflectElement.CustomElementConstructor;
customElements.define('test-reflect', ReflectCustomElement);
customElements.define('test-reflect', ReflectElement.CustomElementConstructor);
customElements.define('test-reflect-camel', ReflectCamel.CustomElementConstructor);
customElements.define('test-attr-changed', AttrChanged.CustomElementConstructor);
});

it('should reflect attribute to properties before the first render', () => {
Expand Down Expand Up @@ -160,5 +163,68 @@ if (SUPPORTS_CUSTOM_ELEMENTS) {
expect(elm.title).toBe('foo');
expect(elm.number).toBe(10);
});

it('reflects kebab-case attributes to camel-case props', () => {
const elm = document.createElement('test-reflect-camel');
document.body.appendChild(elm);

elm.setAttribute('my-prop', 'foo');

expect(elm.getAttribute('my-prop')).toBe('foo');
expect(elm.myProp).toBe('foo');
});

// TODO [#2972]: support attributeChangedCallback
it('never calls attributeChangedCallback', async () => {
const elm = document.createElement('test-attr-changed');
document.body.appendChild(elm);

elm.setAttribute('observed', 'foo');
elm.setAttribute('api', 'foo');
elm.setAttribute('track', 'foo');

await Promise.resolve(); // just in case attributeChangedCallback is called async

// attributeChangedCallback is not called for any of these
expect(elm.attributeChangedCallbackCalls).toEqual([]);
});

it('only reflects @api, not @track or observedAttributes', () => {
const elm = document.createElement('test-attr-changed');
document.body.appendChild(elm);

elm.setAttribute('observed', 'foo');
elm.setAttribute('api', 'foo');
elm.setAttribute('track', 'foo');

// attrs are all set
expect(elm.getAttribute('observed')).toBe('foo');
expect(elm.getAttribute('api')).toBe('foo');
expect(elm.getAttribute('track')).toBe('foo');

// for props, only @api props are set
expect(elm.observed).toBeUndefined();
expect(elm.api).toBe('foo');
expect(elm.track).toBeUndefined();
});

it('does not call setter more than once if unchanged', () => {
const elm = document.createElement('test-attr-changed');
document.body.appendChild(elm);

expect(elm.apiSetterCallCounts).toEqual(0);

elm.setAttribute('api', 'foo');
expect(elm.api).toBe('foo');
expect(elm.apiSetterCallCounts).toEqual(1);

elm.setAttribute('api', 'foo');
expect(elm.api).toBe('foo');
expect(elm.apiSetterCallCounts).toEqual(1);

elm.setAttribute('api', 'bar');
expect(elm.api).toBe('bar');
expect(elm.apiSetterCallCounts).toEqual(2);
});
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { LightningElement, track, api } from 'lwc';

export default class extends LightningElement {
@api attributeChangedCallbackCalls = [];
@api apiSetterCallCounts = 0;

_api;
@track track;

get api() {
return this._api;
}
@api
set api(val) {
this.apiSetterCallCounts++;
this._api = val;
}

attributeChangedCallback(attrName, oldValue, newValue) {
this.attributeChangedCallbackCalls.push([attrName, oldValue, newValue]);
}

static observedAttributes = ['observed'];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { LightningElement, api } from 'lwc';

export default class extends LightningElement {
@api myProp;
}

0 comments on commit 5a6188e

Please sign in to comment.