chore(field): introduction test suites (for InteractionStateMixin)
This commit is contained in:
parent
93ce388403
commit
22bb75a868
6 changed files with 260 additions and 190 deletions
23
.eslintrc.js
23
.eslintrc.js
|
|
@ -1,3 +1,26 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
extends: ['@open-wc/eslint-config', 'eslint-config-prettier'].map(require.resolve),
|
extends: ['@open-wc/eslint-config', 'eslint-config-prettier'].map(require.resolve),
|
||||||
|
rules: {
|
||||||
|
'import/no-extraneous-dependencies': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
devDependencies: [
|
||||||
|
'**/test-suites/**/*.js',
|
||||||
|
'**/test/**/*.js',
|
||||||
|
'**/stories/**/*.js',
|
||||||
|
'**/*.config.js',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: ['**/test-suites/**/*.js', '**/test/**/*.js', '**/stories/**/*.js', '**/*.config.js'],
|
||||||
|
rules: {
|
||||||
|
'no-console': 'off',
|
||||||
|
'no-unused-expressions': 'off',
|
||||||
|
'class-methods-use-this': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@
|
||||||
"src",
|
"src",
|
||||||
"stories",
|
"stories",
|
||||||
"test",
|
"test",
|
||||||
|
"test-suites",
|
||||||
"translations",
|
"translations",
|
||||||
"*.js"
|
"*.js"
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,14 @@ import { ObserverMixin } from '@lion/core/src/ObserverMixin.js';
|
||||||
import { Unparseable } from '@lion/validate';
|
import { Unparseable } from '@lion/validate';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* `InteractionStateMixin` adds meta information about touched and dirty states, that can
|
* @desc `InteractionStateMixin` adds meta information about touched and dirty states, that can
|
||||||
* be read by other form components (ing-uic-input-error for instance, uses the touched state
|
* be read by other form components (ing-uic-input-error for instance, uses the touched state
|
||||||
* to determine whether an error message needs to be shown).
|
* to determine whether an error message needs to be shown).
|
||||||
* Interaction states will be set when a user:
|
* Interaction states will be set when a user:
|
||||||
* - leaves a form field(blur) -> 'touched' will be set to true. 'prefilled' when a
|
* - leaves a form field(blur) -> 'touched' will be set to true. 'prefilled' when a
|
||||||
* field is left non-empty
|
* field is left non-empty
|
||||||
* - on keyup (actually, on the model-value-changed event) -> 'dirty' will be set to true
|
* - on keyup (actually, on the model-value-changed event) -> 'dirty' will be set to true
|
||||||
|
* @param {HTMLElement} superclass
|
||||||
*/
|
*/
|
||||||
export const InteractionStateMixin = dedupeMixin(
|
export const InteractionStateMixin = dedupeMixin(
|
||||||
superclass =>
|
superclass =>
|
||||||
|
|
@ -58,13 +59,15 @@ export const InteractionStateMixin = dedupeMixin(
|
||||||
if (modelValue instanceof Unparseable) {
|
if (modelValue instanceof Unparseable) {
|
||||||
value = modelValue.viewValue;
|
value = modelValue.viewValue;
|
||||||
}
|
}
|
||||||
// Checks for empty objects and arrays
|
// Checks for empty platform types: Objects, Arrays, Dates
|
||||||
if (typeof value === 'object' && value !== null) {
|
if (typeof value === 'object' && value !== null) {
|
||||||
return !!Object.keys(value).length;
|
return !!Object.keys(value).length;
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line no-mixed-operators
|
// eslint-disable-next-line no-mixed-operators
|
||||||
|
// Checks for empty platform types: Numbers, Booleans
|
||||||
const isNumberValue = typeof value === 'number' && (value === 0 || Number.isNaN(value));
|
const isNumberValue = typeof value === 'number' && (value === 0 || Number.isNaN(value));
|
||||||
const isBooleanValue = typeof value === 'boolean' && value === false;
|
const isBooleanValue = typeof value === 'boolean' && value === false;
|
||||||
|
|
||||||
return !!value || isNumberValue || isBooleanValue;
|
return !!value || isNumberValue || isBooleanValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
207
packages/field/test-suites/InteractionStateMixin.suite.js
Normal file
207
packages/field/test-suites/InteractionStateMixin.suite.js
Normal file
|
|
@ -0,0 +1,207 @@
|
||||||
|
import {
|
||||||
|
expect,
|
||||||
|
fixture,
|
||||||
|
unsafeStatic,
|
||||||
|
html,
|
||||||
|
defineCE,
|
||||||
|
triggerFocusFor,
|
||||||
|
triggerBlurFor,
|
||||||
|
} from '@open-wc/testing';
|
||||||
|
import sinon from 'sinon';
|
||||||
|
import { LitElement } from '@lion/core';
|
||||||
|
import { InteractionStateMixin } from '../src/InteractionStateMixin.js';
|
||||||
|
|
||||||
|
export function runInteractionStateMixinSuite(customConfig) {
|
||||||
|
const cfg = {
|
||||||
|
tagString: null,
|
||||||
|
allowedModelValueTypes: [Array, Object, Number, Boolean, String],
|
||||||
|
suffix: '',
|
||||||
|
...customConfig,
|
||||||
|
};
|
||||||
|
|
||||||
|
describe(`InteractionStateMixin ${cfg.suffix ? `(${cfg.suffix})` : ''}`, async () => {
|
||||||
|
let tag;
|
||||||
|
before(() => {
|
||||||
|
if (!cfg.tagString) {
|
||||||
|
cfg.tagString = defineCE(
|
||||||
|
class IState extends InteractionStateMixin(LitElement) {
|
||||||
|
connectedCallback() {
|
||||||
|
super.connectedCallback();
|
||||||
|
this.tabIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
set modelValue(v) {
|
||||||
|
this._modelValue = v;
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent('model-value-changed', { bubbles: true, composed: true }),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
get modelValue() {
|
||||||
|
return this._modelValue;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
tag = unsafeStatic(cfg.tagString);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets states to false on init', async () => {
|
||||||
|
const el = await fixture(html`<${tag}></${tag}>`);
|
||||||
|
expect(el.dirty).to.be.false;
|
||||||
|
expect(el.touched).to.be.false;
|
||||||
|
expect(el.prefilled).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets dirty when value changed', async () => {
|
||||||
|
const el = await fixture(html`<${tag}></${tag}>`);
|
||||||
|
expect(el.dirty).to.be.false;
|
||||||
|
el.modelValue = 'foobar';
|
||||||
|
expect(el.dirty).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets touched to true when field left after focus', async () => {
|
||||||
|
const el = await fixture(html`<${tag}></${tag}>`);
|
||||||
|
await triggerFocusFor(el);
|
||||||
|
await triggerBlurFor(el);
|
||||||
|
expect(el.touched).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
// classes are added only for backward compatibility - they are deprecated
|
||||||
|
it('sets a class "state-(touched|dirty)"', async () => {
|
||||||
|
const el = await fixture(html`<${tag}></${tag}>`);
|
||||||
|
el.touched = true;
|
||||||
|
await el.updateComplete;
|
||||||
|
expect(el.classList.contains('state-touched')).to.equal(true, 'has class "state-touched"');
|
||||||
|
|
||||||
|
el.dirty = true;
|
||||||
|
await el.updateComplete;
|
||||||
|
expect(el.classList.contains('state-dirty')).to.equal(true, 'has class "state-dirty"');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets an attribute "touched', async () => {
|
||||||
|
const el = await fixture(html`<${tag}></${tag}>`);
|
||||||
|
el.touched = true;
|
||||||
|
await el.updateComplete;
|
||||||
|
expect(el.hasAttribute('touched')).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets an attribute "dirty', async () => {
|
||||||
|
const el = await fixture(html`<${tag}></${tag}>`);
|
||||||
|
el.dirty = true;
|
||||||
|
await el.updateComplete;
|
||||||
|
expect(el.hasAttribute('dirty')).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fires "(touched|dirty)-state-changed" event when state changes', async () => {
|
||||||
|
const touchedSpy = sinon.spy();
|
||||||
|
const dirtySpy = sinon.spy();
|
||||||
|
const el = await fixture(
|
||||||
|
html`<${tag} @touched-changed=${touchedSpy} @dirty-changed=${dirtySpy}></${tag}>`,
|
||||||
|
);
|
||||||
|
|
||||||
|
el.touched = true;
|
||||||
|
expect(touchedSpy.callCount).to.equal(1);
|
||||||
|
|
||||||
|
el.dirty = true;
|
||||||
|
expect(dirtySpy.callCount).to.equal(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets prefilled once instantiated', async () => {
|
||||||
|
const el = await fixture(html`
|
||||||
|
<${tag} .modelValue=${'prefilled'}></${tag}>
|
||||||
|
`);
|
||||||
|
expect(el.prefilled).to.be.true;
|
||||||
|
|
||||||
|
const nonPrefilled = await fixture(html`
|
||||||
|
<${tag} .modelValue=${''}></${tag}>
|
||||||
|
`);
|
||||||
|
expect(nonPrefilled.prefilled).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// This method actually tests the implementation of the _isPrefilled method.
|
||||||
|
it(`can determine "prefilled" based on different modelValue types
|
||||||
|
(${cfg.allowedModelValueTypes.map(t => t.name).join(', ')})`, async () => {
|
||||||
|
const el = await fixture(html`<${tag}></${tag}>`);
|
||||||
|
|
||||||
|
const changeModelValueAndLeave = modelValue => {
|
||||||
|
const targetEl = el.inputElement || el;
|
||||||
|
targetEl.dispatchEvent(new Event('focus', { bubbles: true }));
|
||||||
|
el.modelValue = modelValue;
|
||||||
|
targetEl.dispatchEvent(new Event(el._leaveEvent, { bubbles: true }));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Prefilled
|
||||||
|
if (cfg.allowedModelValueTypes.includes(Array)) {
|
||||||
|
changeModelValueAndLeave(['not-empty']);
|
||||||
|
expect(el.prefilled, 'not empty array should be "prefilled"').to.be.true;
|
||||||
|
changeModelValueAndLeave([]);
|
||||||
|
expect(el.prefilled, 'empty array should not be "prefilled"').to.be.false;
|
||||||
|
}
|
||||||
|
if (cfg.allowedModelValueTypes.includes(Object)) {
|
||||||
|
changeModelValueAndLeave({ not: 'empty' });
|
||||||
|
expect(el.prefilled, 'not empty object should be "prefilled"').to.be.true;
|
||||||
|
changeModelValueAndLeave({});
|
||||||
|
expect(el.prefilled, 'empty object should not be "prefilled"').to.be.false;
|
||||||
|
}
|
||||||
|
if (cfg.allowedModelValueTypes.includes(Number)) {
|
||||||
|
changeModelValueAndLeave(0);
|
||||||
|
expect(el.prefilled, 'numbers should be "prefilled"').to.be.true;
|
||||||
|
}
|
||||||
|
if (cfg.allowedModelValueTypes.includes(String)) {
|
||||||
|
changeModelValueAndLeave(false);
|
||||||
|
expect(el.prefilled, 'booleans should be "prefilled"').to.be.true;
|
||||||
|
changeModelValueAndLeave('');
|
||||||
|
expect(el.prefilled, 'empty string should not be "prefilled"').to.be.false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not prefilled
|
||||||
|
changeModelValueAndLeave(null);
|
||||||
|
expect(el.prefilled, 'null should not be "prefilled"').to.be.false;
|
||||||
|
changeModelValueAndLeave(undefined);
|
||||||
|
expect(el.prefilled, 'undefined should not be "prefilled"').to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('has a method resetInteractionState()', async () => {
|
||||||
|
const el = await fixture(html`<${tag}></${tag}>`);
|
||||||
|
el.dirty = true;
|
||||||
|
el.touched = true;
|
||||||
|
el.prefilled = true;
|
||||||
|
el.resetInteractionState();
|
||||||
|
expect(el.dirty).to.be.false;
|
||||||
|
expect(el.touched).to.be.false;
|
||||||
|
expect(el.prefilled).to.be.false;
|
||||||
|
|
||||||
|
el.dirty = true;
|
||||||
|
el.touched = true;
|
||||||
|
el.prefilled = false;
|
||||||
|
el.modelValue = 'Some value';
|
||||||
|
el.resetInteractionState();
|
||||||
|
expect(el.dirty).to.be.false;
|
||||||
|
expect(el.touched).to.be.false;
|
||||||
|
expect(el.prefilled).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('SubClassers', () => {
|
||||||
|
it('can override the `_leaveEvent`', async () => {
|
||||||
|
const tagLeaveString = defineCE(
|
||||||
|
class IState extends InteractionStateMixin(LitElement) {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this._leaveEvent = 'custom-blur';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const tagLeave = unsafeStatic(tagLeaveString);
|
||||||
|
const el = await fixture(html`<${tagLeave}></${tagLeave}>`);
|
||||||
|
el.dispatchEvent(new Event('custom-blur'));
|
||||||
|
expect(el.touched).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can override the deprecated `leaveEvent`', async () => {
|
||||||
|
const el = await fixture(html`<${tag} .leaveEvent=${'custom-blur'}></${tag}>`);
|
||||||
|
expect(el._leaveEvent).to.equal('custom-blur');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -1,189 +1,3 @@
|
||||||
import {
|
import { runInteractionStateMixinSuite } from '../test-suites/InteractionStateMixin.suite.js';
|
||||||
expect,
|
|
||||||
fixture,
|
|
||||||
unsafeStatic,
|
|
||||||
html,
|
|
||||||
defineCE,
|
|
||||||
triggerFocusFor,
|
|
||||||
triggerBlurFor,
|
|
||||||
} from '@open-wc/testing';
|
|
||||||
import sinon from 'sinon';
|
|
||||||
import { LitElement } from '@lion/core';
|
|
||||||
|
|
||||||
import { InteractionStateMixin } from '../src/InteractionStateMixin.js';
|
runInteractionStateMixinSuite();
|
||||||
|
|
||||||
describe('InteractionStateMixin', async () => {
|
|
||||||
let tagString;
|
|
||||||
let tag;
|
|
||||||
before(() => {
|
|
||||||
tagString = defineCE(
|
|
||||||
class IState extends InteractionStateMixin(LitElement) {
|
|
||||||
connectedCallback() {
|
|
||||||
super.connectedCallback();
|
|
||||||
this.tabIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
set modelValue(v) {
|
|
||||||
this._modelValue = v;
|
|
||||||
this.dispatchEvent(
|
|
||||||
new CustomEvent('model-value-changed', { bubbles: true, composed: true }),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
get modelValue() {
|
|
||||||
return this._modelValue;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
tag = unsafeStatic(tagString);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets states to false on init', async () => {
|
|
||||||
const el = await fixture(html`<${tag}></${tag}>`);
|
|
||||||
expect(el.dirty).to.be.false;
|
|
||||||
expect(el.touched).to.be.false;
|
|
||||||
expect(el.prefilled).to.be.false;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets dirty when value changed', async () => {
|
|
||||||
const el = await fixture(html`<${tag}></${tag}>`);
|
|
||||||
expect(el.dirty).to.be.false;
|
|
||||||
el.modelValue = 'foobar';
|
|
||||||
expect(el.dirty).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets touched to true when field left after focus', async () => {
|
|
||||||
const el = await fixture(html`<${tag}></${tag}>`);
|
|
||||||
await triggerFocusFor(el);
|
|
||||||
await triggerBlurFor(el);
|
|
||||||
expect(el.touched).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
// classes are added only for backward compatibility - they are deprecated
|
|
||||||
it('sets a class "state-(touched|dirty)"', async () => {
|
|
||||||
const el = await fixture(html`<${tag}></${tag}>`);
|
|
||||||
el.touched = true;
|
|
||||||
await el.updateComplete;
|
|
||||||
expect(el.classList.contains('state-touched')).to.equal(true, 'has class "state-touched"');
|
|
||||||
|
|
||||||
el.dirty = true;
|
|
||||||
await el.updateComplete;
|
|
||||||
expect(el.classList.contains('state-dirty')).to.equal(true, 'has class "state-dirty"');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets an attribute "touched', async () => {
|
|
||||||
const el = await fixture(html`<${tag}></${tag}>`);
|
|
||||||
el.touched = true;
|
|
||||||
await el.updateComplete;
|
|
||||||
expect(el.hasAttribute('touched')).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets an attribute "dirty', async () => {
|
|
||||||
const el = await fixture(html`<${tag}></${tag}>`);
|
|
||||||
el.dirty = true;
|
|
||||||
await el.updateComplete;
|
|
||||||
expect(el.hasAttribute('dirty')).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fires "(touched|dirty)-state-changed" event when state changes', async () => {
|
|
||||||
const touchedSpy = sinon.spy();
|
|
||||||
const dirtySpy = sinon.spy();
|
|
||||||
const el = await fixture(
|
|
||||||
html`<${tag} @touched-changed=${touchedSpy} @dirty-changed=${dirtySpy}></${tag}>`,
|
|
||||||
);
|
|
||||||
|
|
||||||
el.touched = true;
|
|
||||||
expect(touchedSpy.callCount).to.equal(1);
|
|
||||||
|
|
||||||
el.dirty = true;
|
|
||||||
expect(dirtySpy.callCount).to.equal(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets prefilled once instantiated', async () => {
|
|
||||||
const el = await fixture(html`
|
|
||||||
<${tag} .modelValue=${'prefilled'}></${tag}>
|
|
||||||
`);
|
|
||||||
expect(el.prefilled).to.be.true;
|
|
||||||
|
|
||||||
const nonPrefilled = await fixture(html`
|
|
||||||
<${tag} .modelValue=${''}></${tag}>
|
|
||||||
`);
|
|
||||||
expect(nonPrefilled.prefilled).to.be.false;
|
|
||||||
});
|
|
||||||
|
|
||||||
// This method actually tests the implementation of the _isPrefilled method.
|
|
||||||
it(`can determine "prefilled" based on different modelValue types (Arrays, Objects, Numbers,
|
|
||||||
Booleans, Strings)`, async () => {
|
|
||||||
const el = await fixture(html`<${tag}></${tag}>`);
|
|
||||||
|
|
||||||
const changeModelValueAndLeave = modelValue => {
|
|
||||||
el.dispatchEvent(new Event('focus', { bubbles: true }));
|
|
||||||
el.modelValue = modelValue;
|
|
||||||
el.dispatchEvent(new Event('blur', { bubbles: true }));
|
|
||||||
};
|
|
||||||
|
|
||||||
// Prefilled
|
|
||||||
changeModelValueAndLeave(['not-empty']);
|
|
||||||
expect(el.prefilled, 'not empty array should be "prefilled"').to.be.true;
|
|
||||||
changeModelValueAndLeave({ not: 'empty' });
|
|
||||||
expect(el.prefilled, 'not empty object should be "prefilled"').to.be.true;
|
|
||||||
changeModelValueAndLeave(0);
|
|
||||||
expect(el.prefilled, 'numbers should be "prefilled"').to.be.true;
|
|
||||||
changeModelValueAndLeave(false);
|
|
||||||
expect(el.prefilled, 'booleans should be "prefilled"').to.be.true;
|
|
||||||
|
|
||||||
// Not prefilled
|
|
||||||
changeModelValueAndLeave([]);
|
|
||||||
expect(el.prefilled, 'empty array should not be "prefilled"').to.be.false;
|
|
||||||
changeModelValueAndLeave({});
|
|
||||||
expect(el.prefilled, 'empty object should not be "prefilled"').to.be.false;
|
|
||||||
changeModelValueAndLeave('');
|
|
||||||
expect(el.prefilled, 'empty string should not be "prefilled"').to.be.false;
|
|
||||||
changeModelValueAndLeave(null);
|
|
||||||
expect(el.prefilled, 'null should not be "prefilled"').to.be.false;
|
|
||||||
changeModelValueAndLeave(undefined);
|
|
||||||
expect(el.prefilled, 'undefined should not be "prefilled"').to.be.false;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('has a method resetInteractionState()', async () => {
|
|
||||||
const el = await fixture(html`<${tag}></${tag}>`);
|
|
||||||
el.dirty = true;
|
|
||||||
el.touched = true;
|
|
||||||
el.prefilled = true;
|
|
||||||
el.resetInteractionState();
|
|
||||||
expect(el.dirty).to.be.false;
|
|
||||||
expect(el.touched).to.be.false;
|
|
||||||
expect(el.prefilled).to.be.false;
|
|
||||||
|
|
||||||
el.dirty = true;
|
|
||||||
el.touched = true;
|
|
||||||
el.prefilled = false;
|
|
||||||
el.modelValue = 'Some value';
|
|
||||||
el.resetInteractionState();
|
|
||||||
expect(el.dirty).to.be.false;
|
|
||||||
expect(el.touched).to.be.false;
|
|
||||||
expect(el.prefilled).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('SubClassers', () => {
|
|
||||||
it('can override the `_leaveEvent`', async () => {
|
|
||||||
const tagLeaveString = defineCE(
|
|
||||||
class IState extends InteractionStateMixin(LitElement) {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this._leaveEvent = 'custom-blur';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
const tagLeave = unsafeStatic(tagLeaveString);
|
|
||||||
const el = await fixture(html`<${tagLeave}></${tagLeave}>`);
|
|
||||||
el.dispatchEvent(new Event('custom-blur'));
|
|
||||||
expect(el.touched).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can override the deprecated `leaveEvent`', async () => {
|
|
||||||
const el = await fixture(html`<${tag} .leaveEvent=${'custom-blur'}></${tag}>`);
|
|
||||||
expect(el._leaveEvent).to.equal('custom-blur');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
|
||||||
22
packages/field/test/field-integrations.test.js
Normal file
22
packages/field/test/field-integrations.test.js
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { defineCE } from '@open-wc/testing';
|
||||||
|
import { runInteractionStateMixinSuite } from '../test-suites/InteractionStateMixin.suite.js';
|
||||||
|
import '../lion-field.js';
|
||||||
|
|
||||||
|
const fieldTagString = defineCE(
|
||||||
|
class extends customElements.get('lion-field') {
|
||||||
|
get slots() {
|
||||||
|
return {
|
||||||
|
...super.slots,
|
||||||
|
// LionField needs to have an inputElement defined in order to work...
|
||||||
|
input: () => document.createElement('input'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
describe('<lion-field> integrations', () => {
|
||||||
|
runInteractionStateMixinSuite({
|
||||||
|
tagString: fieldTagString,
|
||||||
|
suffix: 'lion-field',
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in a new issue