diff --git a/tinymce-angular-component/src/test/ts/browser/FormControlTest.ts b/tinymce-angular-component/src/test/ts/browser/FormControlTest.ts index f88683d6..eb3459f6 100644 --- a/tinymce-angular-component/src/test/ts/browser/FormControlTest.ts +++ b/tinymce-angular-component/src/test/ts/browser/FormControlTest.ts @@ -1,39 +1,132 @@ import '../alien/InitTestEnvironment'; -import { Component } from '@angular/core'; -import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { ChangeDetectionStrategy, Component, ViewChild, ElementRef } from '@angular/core'; +import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; import { Assertions } from '@ephox/agar'; -import { describe, it } from '@ephox/bedrock-client'; +import { context, describe, it } from '@ephox/bedrock-client'; import { EditorComponent } from '../../../main/ts/public_api'; -import { eachVersionContext, editorHook } from '../alien/TestHooks'; +import { eachVersionContext, editorHook, fixtureHook } from '../alien/TestHooks'; +import { By } from '@angular/platform-browser'; +import { first, firstValueFrom, switchMap } from 'rxjs'; +import { Editor } from 'tinymce'; +import { fakeTypeInEditor } from '../alien/TestHelpers'; + +type FormControlProps = Partial>; describe('FormControlTest', () => { - eachVersionContext([ '4', '5', '6', '7' ], () => { - @Component({ - standalone: true, - imports: [ EditorComponent, ReactiveFormsModule ], - template: ``, - }) - class EditorWithFormControl { - public control = new FormControl(); + const assertFormControl = (label: string, control: FormControlProps, expected: FormControlProps) => { + for (const [ key, value ] of Object.entries(expected)) { + Assertions.assertEq(`${label} - ${key}`, value, control[key as keyof FormControlProps]); } - const createFixture = editorHook(EditorWithFormControl); + }; + + eachVersionContext([ '4', '5', '6', '7' ], () => { + [ ChangeDetectionStrategy.Default, ChangeDetectionStrategy.OnPush ].forEach((changeDetection) => { + context(`[formControl] with change detection: ${changeDetection}`, () => { + @Component({ + standalone: true, + imports: [ EditorComponent, ReactiveFormsModule ], + changeDetection, + template: ``, + }) + class EditorWithFormControl { + public control = new FormControl(); + } + const createFixture = editorHook(EditorWithFormControl); + + it('FormControl interaction', async () => { + const fixture = await createFixture(); + + Assertions.assertEq('Expect editor to have no initial value', '', fixture.editor.getContent()); + + fixture.componentInstance.control.setValue('

Some Value

'); + fixture.detectChanges(); + + Assertions.assertEq('Expect editor to have a value', '

Some Value

', fixture.editor.getContent()); - it('FormControl interaction', async () => { - const fixture = await createFixture(); + fixture.componentInstance.control.reset(); + fixture.detectChanges(); - Assertions.assertEq('Expect editor to have no initial value', '', fixture.editor.getContent()); + Assertions.assertEq('Expect editor to be empty after reset', '', fixture.editor.getContent()); + }); + }); - fixture.componentInstance.control.setValue('

Some Value

'); - fixture.detectChanges(); + context(`[formGroup] with change detection: ${changeDetection}`, () => { + @Component({ + standalone: true, + changeDetection, + imports: [ EditorComponent, ReactiveFormsModule ], + template: ` +
+ + + + + `, + }) + class FormWithEditor { + @ViewChild('resetBtn') public resetBtn!: ElementRef; + @ViewChild('submitBtn') public submitBtn!: ElementRef; + public readonly form = new FormGroup({ + editor: new FormControl('', { + validators: Validators.compose([ + // eslint-disable-next-line @typescript-eslint/unbound-method + Validators.required, + Validators.minLength(10), + ]), + }), + }); + } + const createFixture = fixtureHook(FormWithEditor, { imports: [ FormWithEditor ] }); - Assertions.assertEq('Expect editor to have a value', '

Some Value

', fixture.editor.getContent()); + it('interaction', async () => { + const fixture = createFixture(); + fixture.detectChanges(); + const editorComponent: EditorComponent = fixture.debugElement.query( + By.directive(EditorComponent) + ).componentInstance; + const editor = await firstValueFrom( + editorComponent.onInit.pipe( + first(), + switchMap((ev) => new Promise((resolve) => ev.editor.on('SkinLoaded', () => resolve(ev.editor)))) + ) + ); + const form = fixture.componentInstance.form; + const initialProps: FormControlProps = { valid: false, dirty: false, pristine: true, touched: false }; + // const editorCtrl = form.get('editor')!; - fixture.componentInstance.control.reset(); - fixture.detectChanges(); + assertFormControl('Initial form', form, initialProps); + editor.fire('blur'); + assertFormControl('Form after editor blur', form, { ...initialProps, touched: true }); + fixture.componentInstance.resetBtn.nativeElement.click(); + fixture.detectChanges(); + assertFormControl('Form after reset', form, initialProps); - Assertions.assertEq('Expect editor to be empty after reset', '', fixture.editor.getContent()); + fakeTypeInEditor(fixture, 'x'); + assertFormControl('Form after typing one character', form, { + valid: false, + dirty: true, + pristine: false, + touched: false, + }); + editor.fire('blur'); + assertFormControl('Form after editor blur', form, { + valid: false, + dirty: true, + pristine: false, + touched: true, + }); + fakeTypeInEditor(fixture, 'x'.repeat(20)); + assertFormControl('Form after typing 10 characters', form, { + valid: true, + dirty: true, + pristine: false, + touched: true, + }); + Assertions.assertEq('Editor value has expected value', `

${'x'.repeat(20)}

`, form.value.editor); + }); + }); }); }); });