Verify if a personalized angular directive is able to display or conceal an element

I have a custom directive that toggles the visibility of an element based on the value of another service. I attempted to write a test to verify if the directive functions as intended. Initially, I used the ":visible" selector in my test, but it consistently returned false even though the element was supposed to be visible.

it('Should show element if logged', function () {
    element = angular.element('<p hc-auth>Some Text</p>');
    AuthService.Logged = true;
    scope = $rootScope.$new();
    scope.$apply(function () {
        $compile(element)(scope);
    });
    expect(element.is(":visible")).toBeTruthy();
});

After some troubleshooting, I discovered that during testing, the element had zero width and height, even when the display property was set to block. This caused the ":visible" selector to always return false. I modified the test to check against the display property instead, which now accurately tests the element. However, this approach seems overly reliant on specific implementation details related to showing an element.

it('Should show element if logged', function () {
    element = angular.element('<p hc-auth>Some Text</p>');
    AuthService.Logged = true;
    scope = $rootScope.$new();
    scope.$apply(function () {
        $compile(element)(scope);
    });
    expect(element.css('display')).toBe('block');
});

What would be the most effective strategy for handling this scenario?

Answer №1

I was curious about how angular handles tests for `ngHide` and `ngShow`, so I took a look at their spec file:

it('should show if the expression is a function with no arguments', function() {
  element = jqLite('<div ng-show="exp"></div>');
  element = $compile(element)($scope);
  $scope.exp = function() {};
  $scope.$digest();
  expect(element).toBeShown();
});

It seems pretty straightforward. Initially, I thought they might be using a library like `jquery-jasmine` which has a `toBeHidden` matcher (although it seems they have their own `custom matcher` for visibility:

// Custom Jasmine Matcher
toBeShown: function() {
  this.message = valueFn(
      "Expected element " + (this.isNot ? "" : "not ") + "to have 'ng-hide' class");
  return !isNgElementHidden(this.actual);
}

// The helper from elsewhere in the same file
function isNgElementHidden(element) {
  var hidden = true;
  forEach(angular.element(element), function(element) {
    if ((' '  + (element.getAttribute('class') || '') + ' ').indexOf(' ng-hide ') === -1) {
      hidden = false;
    }
  });
  return hidden;
}

It seems like they're using the presence of an `.ng-hide` class to determine visibility, which may seem like cheating. However, considering that Angular already supports this class name, they probably found it to be the most efficient approach.

If you're working with Angular, you could also leverage the `.ng-hide` class for visibility and create a similar helper.

Edit:

On a side note, utilizing the addition/removal of the `.ng-hide` class for setting visibility can benefit from any existing ngAnimations the user has implemented for that class.

Answer №2

When it comes to determining if an element is truly visible, the concept of visibility can be subjective and there is no direct CSS selector like :visible that provides a definitive answer.

Here are a couple of approaches you can consider:

  1. Utilize the not method in Jasmine to check for visibility.

    For example:

    expect(element.css('display')).not.toBe('hidden');

However, this method may not account for scenarios where an element is technically displayed but not visually accessible due to factors like opacity or being obscured by another element.

  1. Another option is to use getBoundingClientRect() to obtain the element's dimensions and then verify if calling document.elementFromPoint on each corner does not return the expected hidden element.

:

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Show or hide the legend on a highchart dynamically

I am currently utilizing highchart in my application and I am interested in learning how to toggle the visibility of the legend within the highchart. Here is what I have attempted: var options = { chart: { type: 'column&a ...

Discovering the exact latitude and longitude coordinates along a specific route using Google Maps

I've encountered a problem with finding the latitude and longitude along a given route using Google Maps DirectionsService. I have a JSON dataset containing latitude, longitude, and price details. My goal is to plot markers on the map and determine wh ...

jQuery/AJAX caching problem

I have a question regarding retrieving data using $.ajax multiple times. I am facing an issue where the data is not getting refreshed with each call, instead I am receiving the same old data every time I make a call to $.ajax. Surprisingly, this code was w ...

The jQuery script removal functionality originated from the use of ajax

I have adapted a nested modal script (jQueryModal) to better suit the project's requirements, but I've encountered an unusual issue that I can't seem to resolve. When I invoke the modal to load some content via ajax, and the response from t ...

New to Angular: Getting Started with NgModel Binding

Novice query: I am facing an issue with a simple input type=text element linked to ng-model="xyz.zyx", where xyz refers to an object. In my controller, I initialize this object and set the value for the property zyx as shown below: xyz { zyx: $scope.zz ...

Two vertical divs stacked on top of each other, each expanding to the entire height and width of the browser window

Is there a way to set the width and height of two divs on a webpage to match the dimensions of the browser window, requiring scrolling to view the second div? In addition, how can I ensure that the content within these divs is vertically centered? To ach ...

Resetting several sticky titles after displaying and hiding elements

Inspired by a popular codepen example, I have successfully implemented sticky titles in my sidebar. However, when integrating these sticky titles with the functionality to show/hide related items on click, I encountered some unexpected issues. The code sni ...

Exploring the best practices for loading state from local storage in VueJS/NuxtJS by leveraging the "useLocalStorage" utility

When attempting to utilize useLocalStorage from pinia, I am encountering an issue where the data in the store's state is not fetched from local storage and instead defaults to the default value. Below is the code snippet from my store method: import ...

Retrieve the AngularJS scope object by using an alternate scope object as the identifier

As I loop through an array of person objects using ng-repeat, imagine the array looks something like this: [{ "display_name": "John Smith", "status": "part-time", "bio": "I am a person. I do people stuff.", }, { "display_name": "Jane Doe", "stat ...

Adjusted position of the viewport if the DOM element containing the renderer is not located at the top of the display

I've come across an issue with a three.js scene within an Angular custom directive in the view. At the top, there's a navigation bar for switching between views (pretty standard so far). I set up a simple scene with a cube and basic camera rotati ...

Converting JSON to Array: A Step-by-Step Guide

Greetings, StackOverflow community! This is my inaugural question here. I believe the answer is not overly complex, but my knowledge of Javascript is quite rudimentary. Currently, I have a JQuery AJAX function that processes this JSON object: { "Users" ...

Using inline JavaScript to style an element when clicked

Looking for assistance with styling a link. I've connected an external stylesheet to my HTML file, so that part is all set. The goal is to modify the text-decoration when the onclick event occurs. Here's what I currently have: <a class="dopel ...

'jQuery' is not recognized as defined, error no-undef

I am currently working on a file that utilizes jQuery for testing purposes: (function($) { "use strict"; // Start of use strict // Configure tooltips for collapsed side navigation $('.navbar-sidenav [data-toggle="tooltip"]').tooltip({ ...

Provide the option to assign values on select options in order to choose specific JSON data

When working with JSON data from an API, I am creating a dynamic select element. The goal is to change some content (text and image src) based on the option selected from this select element. I have successfully populated the select options with names usi ...

Tips for properly passing data from Ajax to PHP and extracting value from it

I'm curious about how to receive a value from Ajax and then send that value to PHP. Can anyone provide some guidance on this? Specifically, I need the percent value obtained from Ajax to be sent to $percent for option value. <div class="form-g ...

Managing multiple JQuery Dialog boxes can be tricky, especially when you can only close one instance at a time

I'm currently working on integrating multiple instances of Jquery's Dialog box on the same website. The issue I'm facing is that I have two instances that I initialize using a new function like this: function Modal(param) { this.modal = ...

"Utilize PHP and AJAX to dynamically filter records based on selected values from a

I am looking to utilize AJAX to dynamically display a list of examinees based on the selected exam date from a dropdown list. I'm new to PHP and AJAX, so any guidance would be appreciated. <?php include 'configuration.php'; $queryselect ...

How to continuously submit a single form field with Jquery using setInterval?

After reviewing this jquery timer on jsfiddle, I must say it works quite effectively. However, my specific requirement is to submit a single form field at regular intervals. Consider the following HTML form structure: <form id="form"> <input ...

Adding Proxy-Authorization Header to an ajax request

It's surprising that there isn't much information available online about this issue I'm facing. When attempting to include a proxy authorization in the header of my ajax call, I encounter some difficulties. If I send it as shown below, no er ...

React - updates to server values do not display in DOM right away

When I work from the client side, I have a modal in my HomeComponent that allows me to select an element. My goal is to then display that selected element within the same HomeComponent (in the productosEnVenta function). The element chosen in the modal is ...