angular / components

Component infrastructure and Material Design components for Angular
https://material.angular.io
MIT License
24.38k stars 6.75k forks source link

bug(cdk/testing): sendKeys does not update for contenteditable elements #19102

Open ienzam opened 4 years ago

ienzam commented 4 years ago

Reproduction

This is a issue with TestHarness, don't know how I can reproduce it with StackBlitz.

Steps to reproduce:

  1. Add a <div contenteditable="true></div>.
  2. Try sendKeys() to that div via harness.

Expected Behavior

The div will show updated text.

Actual Behavior

<div> remains the same.

Environment

Luminoth commented 4 years ago

Is this possibly related to the bug I've been seeing here: https://github.com/angular/components/issues/18984 ? Where typing in a contenteditable div doesn't do anything (and mine just happens to be from the JSONEditor)?

skoropadas commented 4 years ago

Any news?

Vastlaan commented 7 months ago

Late to the party, but got into this thread while looking for solution to fix unit tests for myself - I will share my workaround.

I see that the typeInElement function (which is used internally when sendKeys method is called) does check if the element is an input or textarea. If so it sets its value property to whatever is passed as parameter to sendKeys. Otherwise it doesn't set any content. Beside that sendKeys dispatch the events: keydown, keypress and keyup.

So the work around is to call sendKeys together with setContenteditableValue. This is how I solve it in my harness:

    private contentEditableDivLocator = this.locatorFor('div[contenteditable="true"');

    async getContentEditable(): Promise<TestElement> {
        return await this.contentEditableDivLocator();
    }

    async typeText(text: string): Promise<void> {
        const contentEditableTestElement = await this.getContentEditable();

        contentEditableTestElement.setContenteditableValue &&
            (await contentEditableTestElement.setContenteditableValue(text));

        await contentEditableTestElement.sendKeys(text);
    }

Note:

  1. For some reason setContenteditableValue is possibly undefined, so need to do this ugly check
  2. It is still worth calling sendKeys as it dispatches events. That way we mock real browser behavior the most.