testing-library / angular-testing-library

šŸ™ Simple and complete Angular testing utilities that encourage good testing practices
https://testing-library.com/angular
MIT License
717 stars 90 forks source link

Directive which overrides Component @Input does not work #397

Closed PauloKoglin closed 1 year ago

PauloKoglin commented 1 year ago

Hi, I'm having an issue with a directive which should override an @Input of a PrimeNG Component. In the real app it does work, but in the test not.

I have such a directive, that overrides the virtualScroll @Input from the PrimeNG p-table:

import { Directive } from '@angular/core';
import { Table } from 'primeng/table';

@Directive({
  selector: 'p-table',
})
export class TableDirective {
  constructor(private table: Table) {
    this.table.virtualScroll = false;
  }
}

In the test, I would expect, that the virtualScroll attribute gets changed, but it's not the case:

import { TableModule } from 'primeng/table';

describe('Table directive', () => {
   it('override input from component with directive', async () => {
    // virtualScroll should be overriden by the p-table directive
    await render('<p-table [value]="[1]" [virtualScroll]="true"></p-table>', {
      declarations: [TableDirective],
      imports: [TableModule],
    });

    screen.debug();
  });

The screen.debug() results are this:

<body>
  <div
    id="root10"
    ng-version="15.2.7"
  >
    <p-table
      class="p-element"
      ng-reflect-value="1"
      ng-reflect-virtual-scroll="true"
    >
      <div
        class="p-datatable p-component"
        id="pr_id_107"
        ng-reflect-ng-class="[object Object]"
      >
        <div
          class="p-datatable-wrapper"
          ng-reflect-ng-style="[object Object]"
        >
          <p-scroller
            class="p-scroller-viewport p-element"
            ng-reflect-auto-size="true"
            ng-reflect-delay="0"
            ng-reflect-inline="true"
            ng-reflect-item-size="28"
            ng-reflect-items="1"
            ng-reflect-lazy="false"
            ng-reflect-loader-disabled="true"
            ng-reflect-options="[object Object]"
            ng-reflect-show-spacer="false"
          >
            <table
              class="p-datatable-table"
              id="pr_id_107-table"
              ng-reflect-ng-class="[object Object]"
              role="table"
            >
              <thead
                class="p-datatable-thead"
              />
              <tbody
                class="p-element p-datatable-tbody"
                ng-reflect-scroller-options="[object Object]"
                ng-reflect-value="1"
              />
            </table>
          </p-scroller>
        </div>
      </div>
    </p-table>
  </div>
</body>

As you can see, the attribute ng-reflect-virtual-scroll from p-table is still true.

Is there anything I`m doing wrong? šŸ˜•

The versions I`m using

timdeschryver commented 1 year ago

Hey @PauloKoglin, thanks for opening this issue. The property should be updated AFAIK (I think we also have a similar test in our codebase). I'll try to reproduce this, but maybe you were able to fix this in the meantime?

timdeschryver commented 1 year ago

@PauloKoglin the "issue" is a different outcome when using input bindings [input]="inputValue" VS just setting an input value input='an input value'. For the latter, the directive overrides the value (in the test, and in a real application), while with an input binding that value always "wins".

For a reproduction see https://github.com/testing-library/angular-testing-library/pull/401 For a working example see https://stackblitz.com/edit/stackblitz-starters-m55vyh?file=src%2Fmain.ts

PauloKoglin commented 1 year ago

Hey @PauloKoglin, thanks for opening this issue. The property should be updated AFAIK (I think we also have a similar test in our codebase). I'll try to reproduce this, but maybe you were able to fix this in the meantime?

Hi @timdeschryver, I still have the same problem. I've used a workaround to manipulate the property without a directive. I really would like to use the directive, like it's the clean way to override the component's properties.

timdeschryver commented 1 year ago

@PauloKoglin did you try https://github.com/testing-library/angular-testing-library/issues/397#issuecomment-1651702501 ?

PauloKoglin commented 1 year ago

@PauloKoglin did you try #397 (comment) ?

Hi @timdeschryver, sorry for not replying your last comment quickly, I haven't seen it. :facepalm:

I just tried your code examples and it works! The problem was that I used the constructor to set/override the input. In your example I noticed that the only case it didn't work, was exactly the directive, which sets the input in the constructor, all others work like expected.

Thank you for bringing light to this issue. šŸ˜„