2

I am making use of ComponentHarness from @angular/cdk/testing and have a scenario in my protractor test suite where I need to wait for a number of elements to become visible.

I have a custom list component which displays a bunch of custom card components and contains a filter input for searching on these.

e.g.

My component harnesses are setup like so:

import { ComponentHarness, TestElement } from '@angular/cdk/testing';
import { browser } from 'protractor';

export class AcCardListHarness extends ComponentHarness {
    static hostSelector = 'ac-cardlist';

    getCardstackList = this.locatorFor('.ac-card-list .ac-list');
    getCardstackListItems = this.locatorForAll(AcBaseCardHarness);
    getCardstackSearchInput = this.locatorFor('.ac-search-input');

    async performTextFilter(searchTerm: string) {
        const input = await this.getCardstackSearchInput();
        return input.sendKeys(searchTerm);
    }

    async getCardStackListItem(index: number) {
        const items = await this.getCardstackListItems();
        return items[index];
    }

    public waitForPresenceOfNumberOfElements(elements: Promise<TestElement[]|ComponentHarness[]>, numberOfElements: number) {
        return browser.wait(async() => {
            const items = await elements;
            return items.length === numberOfElements;
        }, 60000, `Could not find exactly ${numberOfElements} elements on the page.`);
    }
}

export class AcBaseCardHarness extends ComponentHarness {
    static hostSelector = 'ac-basecard';
}

I am able to use these in my protractor test suite perfectly fine, apart from the waitForPresenceOfNumberOfElements method, which is meant to resolve when a specified number of elements for an array of TestElement or ComponentHarness instances are found.

The idea is that I am wanting to perform some filtering during my test and wait for the filter operation to complete in my component by checking the number of items that are displayed after calling the performTextFilter function in the AcCardListHarness.

it('should be able to find the item in the list view', async() => {
    harness = await harnessLoader.getHarness(AlCardstackHarness);
    await harness.performTextFilter('<serach_term_here>');
    await harness.waitForPresenceOfNumberOfElements(harness.getCardstackListItems(), 1);
    const items = await harness.getCardstackListItems();
    expect(items.length).toEqual(1);
});

During the test run, I can see the text filter being interacted with and can see the list component (ac-cardlist) correctly filtering down to the number of items I expect to see (1), but the call to await harness.waitForPresenceOfNumberOfElements(harness.getCardstackListItems(), 1); in my test spec never resolves, it just times out with my default error message in the browser.wait().

Before using ComponentHarness, I was using regular Protractor page objects and was using this helper method with ElementArrayFinder instances and works fine for me in that setup.

public static waitForPresenceOfNumberOfElements(elementArrayFinder: ElementArrayFinder, numberOfElements: number) {
        return browser.wait(() => {
            return elementArrayFinder.count().then((actualCount) => {
            return actualCount === numberOfElements;
            });
        }, 60000, `Could not find exactly ${numberOfElements} elements on the page`);
    }

What am I missing to get this same behaviour working with the ComponentHarness approach?

Nano Adam
  • 285
  • 1
  • 5
mindparse
  • 6,115
  • 27
  • 90
  • 191
  • You are using Protractor in unit tests? Just wondering why there is a Protractor tag. – cnishina Jan 13 '21 at 21:29
  • Is this being used in a reactive form? – sadako1287 Jan 13 '21 at 21:35
  • @cnishina - yes I am using these harnesses with Protractor test suites. – mindparse Jan 13 '21 at 21:43
  • @sadako1287 - no not being used in a reactive form – mindparse Jan 13 '21 at 21:44
  • @mindparse please can you share [MWE](https://en.wikipedia.org/wiki/Minimal_working_example#:~:text=In%20computing%2C%20a%20minimal%20working,to%20be%20demonstrated%20and%20reproduced.&text=A%20minimal%20working%20example%20may,short%20self-contained%20correct%20example.). – Chandan Jan 16 '21 at 05:46

2 Answers2

0

Can you try to change waitForPresenceOfNumberOfElements() as following:

    public async waitForPresenceOfNumberOfElements(elements: Promise<TestElement[]|ComponentHarness[]>, numberOfElements: number) {
        return browser.wait(async() => {
            const count = await elements.count();
            return count === numberOfElements;
        }, 60000, `Could not find exactly ${numberOfElements} elements on the page.`);
    }
yong
  • 13,357
  • 1
  • 16
  • 27
0

I think that returning a promise im waitForPresenceOfNumberOfElements might work, as you are using await with its call in the test.

return browser.wait(async() => {
        return elements.then(items => {
            return items.length === numberOfElements;
        });
    }, 60000, `Could not find exactly ${numberOfElements} elements on the page.`);

This answer explains very well this topic: https://stackoverflow.com/a/27805350/1974681

adrisons
  • 3,443
  • 3
  • 32
  • 48