Talent-Catalog / talentcatalog

https://tctalent.org
GNU Affero General Public License v3.0
13 stars 4 forks source link

Create Unit tests for [PreviewLinkComponent] #1356

Closed EhsanEhrari closed 1 month ago

EhsanEhrari commented 1 month ago

When running my tests, I encountered the following issue: TypeError: Cannot read properties of undefined (reading 'url'). This occurs because the linkPreview object is not properly initialized before the template tries to access it.

Explanation:

In Angular, @Input() values may not always be available during the component's initialization lifecycle (e.g., during ngOnInit). If the template attempts to access an undefined or null object, it leads to this type of error.

Potential Fixes:

  1. Use the Safe Navigation (?.) Operator:
    Modify the template to safely access properties like {{linkPreview?.url}}. This prevents errors when the object is null or undefined.

  2. Provide a Mock linkPreview Before Running Tests:
    In unit tests, providing a mock linkPreview object is assigned to the component before change detection occurs. This ensures that the template has the necessary data to render correctly during the test.

I’ve applied the third approach in the tests, where a mock linkPreview object is provided before the component is initialized, which resolved the issue.

EhsanEhrari commented 1 month ago

LinkPreview HTML:

<a href="{{linkPreview.url}}" target="_blank" class="link-wrapper">
  <div *ngIf="!linkPreview.blocked" class="link-preview">
    <i *ngIf="userIsPostAuthor"
      class="fa-solid fa-xmark fa-xs block-button"
      (click)="blockLinkPreview($event)"
    ></i>
    <div class="content">
      <div class="domain">
        <img class="favicon"
             *ngIf="linkPreview.faviconUrl; else linkIcon"
             src="{{linkPreview.faviconUrl}}"
             alt="{{linkPreview.domain}} favicon"
        ><ng-template #linkIcon><i class="fa-solid fa-link link-icon"></i></ng-template>
        {{linkPreview.domain}}
      </div>
      <div class="title">{{linkPreview.title}}</div>
      <div class="description">{{linkPreview.description}}</div>
    </div>
    <div>
      <img class="preview-img"
           *ngIf="linkPreview.imageUrl"
           src="{{linkPreview.imageUrl}}"
           alt="{{linkPreview.domain}} preview image"
      >
    </div>
  </div>
</a>
EhsanEhrari commented 1 month ago

Recommended way:

<a *ngIf="linkPreview?.url" href="{{linkPreview?.url}}" target="_blank" class="link-wrapper">
  <div *ngIf="!linkPreview?.blocked" class="link-preview">
    <i *ngIf="userIsPostAuthor" class="fa-solid fa-xmark fa-xs block-button" (click)="blockLinkPreview($event)"></i>
    <div class="content">
      <div class="domain">
        <img class="favicon" *ngIf="linkPreview?.faviconUrl; else linkIcon" src="{{linkPreview?.faviconUrl}}" alt="{{linkPreview?.domain}} favicon">
        <ng-template #linkIcon><i class="fa-solid fa-link link-icon"></i></ng-template>
        {{linkPreview?.domain}}
      </div>
      <div class="title">{{linkPreview?.title}}</div>
      <div class="description">{{linkPreview?.description}}</div>
    </div>
    <div>
      <img class="preview-img" *ngIf="linkPreview?.imageUrl" src="{{linkPreview?.imageUrl}}" alt="{{linkPreview?.domain}} preview image">
    </div>
  </div>
</a>