diff --git a/packages/field/test-suites/FormRegistrationMixins.suite.js b/packages/field/test-suites/FormRegistrationMixins.suite.js
new file mode 100644
index 000000000..948e6dc17
--- /dev/null
+++ b/packages/field/test-suites/FormRegistrationMixins.suite.js
@@ -0,0 +1,149 @@
+import { expect, fixture, html, defineCE, unsafeStatic } from '@open-wc/testing';
+import { LitElement } from '@lion/core';
+
+import { FormRegistrarMixin } from '../src/FormRegistrarMixin.js';
+import { FormRegisteringMixin } from '../src/FormRegisteringMixin.js';
+import { formRegistrarManager } from '../src/formRegistrarManager.js';
+
+export const runRegistrationSuite = customConfig => {
+ const cfg = {
+ baseElement: HTMLElement,
+ suffix: null,
+ ...customConfig,
+ };
+
+ describe(`FormRegistrationMixins${cfg.suffix ? ` (${cfg.suffix})` : ''}`, () => {
+ let parentTag;
+ let childTag;
+
+ before(async () => {
+ if (!cfg.parentTagString) {
+ cfg.parentTagString = defineCE(class extends FormRegistrarMixin(cfg.baseElement) {});
+ }
+ if (!cfg.childTagString) {
+ cfg.childTagString = defineCE(class extends FormRegisteringMixin(cfg.baseElement) {});
+ }
+
+ parentTag = unsafeStatic(cfg.parentTagString);
+ childTag = unsafeStatic(cfg.childTagString);
+ });
+
+ it('can register a formElement', async () => {
+ const el = await fixture(html`
+ <${parentTag}>
+ <${childTag}>${childTag}>
+ ${parentTag}>
+ `);
+ await el.registrationReady;
+ expect(el.formElements.length).to.equal(1);
+ });
+
+ it('supports nested registration parents', async () => {
+ const el = await fixture(html`
+ <${parentTag}>
+ <${parentTag}>
+ <${childTag}>${childTag}>
+ <${childTag}>${childTag}>
+ ${parentTag}>
+ ${parentTag}>
+ `);
+ await el.registrationReady;
+ expect(el.formElements.length).to.equal(1);
+ expect(el.querySelector(cfg.parentTagString).formElements.length).to.equal(2);
+ });
+
+ it('forgets disconnected registrars', async () => {
+ const el = await fixture(html`
+ <${parentTag}>
+ <${parentTag}>
+ <${childTag}${childTag}
+ ${parentTag}>
+ ${parentTag}>
+ `);
+
+ const secondRegistrar = await fixture(html`
+ <${parentTag}>
+ <${childTag}${childTag}
+ ${parentTag}>
+ `);
+
+ el.appendChild(secondRegistrar);
+ expect(formRegistrarManager.__elements.length).to.equal(3);
+
+ el.removeChild(secondRegistrar);
+ expect(formRegistrarManager.__elements.length).to.equal(2);
+ });
+
+ it('works for components that have a delayed render', async () => {
+ const tagWrapperString = defineCE(
+ class extends FormRegistrarMixin(LitElement) {
+ async performUpdate() {
+ await new Promise(resolve => setTimeout(() => resolve(), 10));
+ await super.performUpdate();
+ }
+
+ render() {
+ return html`
+
+ `;
+ }
+ },
+ );
+ const tagWrapper = unsafeStatic(tagWrapperString);
+ const el = await fixture(html`
+ <${tagWrapper}>
+ <${childTag}>${childTag}>
+ ${tagWrapper}>
+ `);
+ await el.registrationReady;
+ expect(el.formElements.length).to.equal(1);
+ });
+
+ it('can dynamically add/remove elements', async () => {
+ const el = await fixture(html`
+ <${parentTag}>
+ <${childTag}>${childTag}>
+ ${parentTag}>
+ `);
+ const newField = await fixture(html`
+ <${childTag}>${childTag}>
+ `);
+
+ expect(el.formElements.length).to.equal(1);
+
+ el.appendChild(newField);
+ expect(el.formElements.length).to.equal(2);
+
+ el.removeChild(newField);
+ expect(el.formElements.length).to.equal(1);
+ });
+
+ describe('Unregister', () => {
+ it.skip('requests update of the resetModelValue function of its parent formGroup on unregister', async () => {
+ const ParentFormGroupClass = class extends FormRegistrarMixin(LitElement) {
+ _updateResetModelValue() {
+ this.resetModelValue = this.formElements.length;
+ }
+ };
+ const ChildFormGroupClass = class extends FormRegisteringMixin(LitElement) {
+ constructor() {
+ super();
+ this.__parentFormGroup = this.parentNode;
+ }
+ };
+
+ const formGroupTag = unsafeStatic(defineCE(ParentFormGroupClass));
+ const childFormGroupTag = unsafeStatic(defineCE(ChildFormGroupClass));
+ const parentFormEl = await fixture(html`
+ <${formGroupTag}>
+ <${childFormGroupTag} name="child[]">${childFormGroupTag}>
+ <${childFormGroupTag} name="child[]">${childFormGroupTag}>
+ ${formGroupTag}>
+ `);
+ expect(parentFormEl.resetModelValue.length).to.equal(2);
+ parentFormEl.removeChild(parentFormEl.children[0]);
+ expect(parentFormEl.resetModelValue.length).to.equal(1);
+ });
+ });
+ });
+};
diff --git a/packages/field/test/FormRegistrationMixins.test.js b/packages/field/test/FormRegistrationMixins.test.js
index 19802c592..932d7d6b8 100644
--- a/packages/field/test/FormRegistrationMixins.test.js
+++ b/packages/field/test/FormRegistrationMixins.test.js
@@ -1,129 +1,19 @@
-import { expect, fixture, html, defineCE, unsafeStatic } from '@open-wc/testing';
-import sinon from 'sinon';
-import { LitElement, UpdatingElement } from '@lion/core';
+import { html } from '@open-wc/testing';
+import { UpdatingElement, LitElement } from '@lion/core';
+import { runRegistrationSuite } from '../test-suites/FormRegistrationMixins.suite.js';
-import { formRegistrarManager } from '../src/formRegistrarManager.js';
-import { FormRegisteringMixin } from '../src/FormRegisteringMixin.js';
-import { FormRegistrarMixin } from '../src/FormRegistrarMixin.js';
-
-describe('FormRegistrationMixins', () => {
- before(async () => {
- const FormRegistrarEl = class extends FormRegistrarMixin(UpdatingElement) {};
- customElements.define('form-registrar', FormRegistrarEl);
- const FormRegisteringEl = class extends FormRegisteringMixin(UpdatingElement) {};
- customElements.define('form-registering', FormRegisteringEl);
- });
-
- it('can register a formElement', async () => {
- const el = await fixture(html`
-
-
-
- `);
- await el.registrationReady;
- expect(el.formElements.length).to.equal(1);
- });
-
- it('supports nested registrar', async () => {
- const el = await fixture(html`
-
-
-
-
-
- `);
- await el.registrationReady;
- expect(el.formElements.length).to.equal(1);
- expect(el.querySelector('form-registrar').formElements.length).to.equal(1);
- });
-
- it('forgets disconnected registrars', async () => {
- const el = await fixture(html`
-
-
-
-
-
- `);
-
- const secondRegistrar = await fixture(html`
-
-
-
- `);
-
- el.appendChild(secondRegistrar);
- expect(formRegistrarManager.__elements.length).to.equal(3);
-
- el.removeChild(secondRegistrar);
- expect(formRegistrarManager.__elements.length).to.equal(2);
- });
-
- it('works for component that have a delayed render', async () => {
- const tagWrapperString = defineCE(
- class extends FormRegistrarMixin(LitElement) {
- async performUpdate() {
- await new Promise(resolve => setTimeout(() => resolve(), 10));
- await super.performUpdate();
- }
-
- render() {
- return html`
-
- `;
- }
- },
- );
- const tagWrapper = unsafeStatic(tagWrapperString);
- const registerSpy = sinon.spy();
- const el = await fixture(html`
- <${tagWrapper} @form-element-register=${registerSpy}>
-
- ${tagWrapper}>
- `);
- await el.registrationReady;
- expect(el.formElements.length).to.equal(1);
- });
-
- it('requests update of the resetModelValue function of its parent formGroup', async () => {
- const ParentFormGroupClass = class extends FormRegistrarMixin(LitElement) {
- _updateResetModelValue() {
- this.resetModelValue = 'foo';
- }
- };
- const ChildFormGroupClass = class extends FormRegisteringMixin(LitElement) {
- constructor() {
- super();
- this.__parentFormGroup = this.parentNode;
- }
- };
-
- const parentClass = defineCE(ParentFormGroupClass);
- const formGroup = unsafeStatic(parentClass);
- const childClass = defineCE(ChildFormGroupClass);
- const childFormGroup = unsafeStatic(childClass);
- const parentFormEl = await fixture(html`
- <${formGroup}><${childFormGroup} id="child" name="child[]">${childFormGroup}>${formGroup}>
- `);
- expect(parentFormEl.resetModelValue).to.equal('foo');
- });
-
- it('can dynamically add/remove elements', async () => {
- const el = await fixture(html`
-
-
-
- `);
- const newField = await fixture(html`
-
- `);
-
- expect(el.formElements.length).to.equal(1);
-
- el.appendChild(newField);
- expect(el.formElements.length).to.equal(2);
-
- el.removeChild(newField);
- expect(el.formElements.length).to.equal(1);
- });
+runRegistrationSuite({
+ suffix: 'with UpdatingElement',
+ baseElement: UpdatingElement,
+});
+
+runRegistrationSuite({
+ suffix: 'with LitElement, using shadow dom',
+ baseElement: class ShadowElement extends LitElement {
+ render() {
+ return html`
+
+ `;
+ }
+ },
});