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

Having trouble with ejs.filters?

I'm having trouble grasping ejs filters and getting them to work correctly: Server.js var ejs = require('ejs'); ejs.filters.example = function() { //placeholder for example }; Routes.js app.get('/home', function(req, res) { ...

FireFox is showing inconsistencies in response to the jQuery GET request, while Chrome is responding correctly

$.ajax({ url: 'https://api.imgur.com/3/album/' + sharedAlbumID, type: 'GET', beforeSend: function(xhr){xhr.setRequestHeader('Authorization', 'Client-ID '+imgurClientID);}, success: function(resp) { ...

Dealing with currency symbols in Datatables and linking external sources

I'm having trouble linking an external link to the "customer_id" field. The link should look like this: /edit-customer.php?customer_id=$customer_id (which is a link to the original customer id). I am creating a detailed page with most of the informati ...

Changes to the model cannot be realized unless $scope.$apply is used

Are there alternative methods to achieve the desired model change without utilizing $scope injection in an Angular "controller as" approach within the given setup? The HTML: <div data-ng-controller="Buildings as vm"> <select data-ng-model="vm. ...

Generating a JSON file using JavaScript amidst the presence of unconventional characters in JSON keys

In my Node Red Function Node, I'm currently facing a challenge of generating a JSON file from JavaScript code. The specific format I need for the JSON file is as follows: [ { "H-Nr.":"1", "Pos.-Nr.":"1" }, { "H-Nr.":"1", ...

I am looking for assistance constructing a task management application using vue.js

I am facing an issue with developing a to-do list using Vue.js. The goal is to add tasks to the list by entering them and clicking a button. Once added, the new task should show up under "All Tasks" and "Not finished". Buttons for marking tasks as " ...

Adjust Sidebar Height to Match Document Height (using React Pro Sidebar)

Having an issue with the height of a sidebar component in Next.js using React Pro Sidebar. It seems to be a JavaScript, HTML, and CSS related problem. I've tried several suggested solutions from Stack Overflow, but none of them seem to work. Surprisin ...

What is the process for importing a class (.js file) into a .vue file?

I am facing an issue with my Vue application. I have created a class named `Authenticator` in the file `Authenticator.js`, and now I need to utilize its functions in my `Login.vue` file. Could someone guide me on how to properly export the `Authenticator` ...

Understanding the behavior of the enter key in Angular and Material forms

When creating forms in my MEAN application, I include the following code: <form novalidate [formGroup]="thesisForm" enctype="multipart/form-data" (keydown.enter)="$event.preventDefault()" (keydown.shift.enter)="$ev ...

What is the best way to hide a section of an image using the background of a different div?

How can I make the background of div2 cover the image in div1 when setting margin-top=-50px? Code snippet: <html> <head> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"> ...

Tips on obtaining the element's ID as a function parameter

I am currently learning front-end development and I am just starting to delve into JavaScript. Recently, when I tried to execute a piece of JavaScript code from the backend by passing some element ids, I encountered an error that says Cannot read property ...

iOS emphasizes special characters by printing them in bold

Some parts of the website I am managing are showing German umlauts in bold (as seen in the screenshot). The font style being used is font-family: Source Sans Pro, Arial, sans-serif; with font-weight: 300. This font is sourced from Google Fonts. When I cha ...

Using Vue to perform multiplication on data table entries

Is there a way I can use Vue.js to multiply values in a table? The values provided are for 100g of the product. For example, if I input 200g, I would like the values to double: 318kcal, 12 fat, 48 carbs, 8 protein, and 2% iron. Similarly, inputting 50g sho ...

Having trouble fetching AJAX POST data in PHP?

Attempting to send a variable as an object to my PHP file, but it's not receiving any data. Testing with window.alert(u.un) in the AJAX call shows that data is being passed successfully without errors in the console. However, the PHP file still does n ...

Only submit fields that have been altered in Angular

Imagine I have a form like the one below, and I need to send a patch request that only includes values being modified to the server. I've identified two methods to achieve this: 1) Manually iterate through the $scope.form and identify non-pristine ...

Tips on extracting json information from Dataset by utilizing JsonConvert's SerializeObject function

Utilizing a WCF service to retrieve and send data from a database using jQuery AJAX has been challenging. Despite multiple attempts, parsing JSON data remains problematic. WCF Service: [ServiceContract] public interface IService { [OperationContract] ...

`Javascript framework suggests ajax navigation as the preferred method`

What is the best way to handle ajax navigation using jQuery? I have recently experimented with a simple jQuery ajax code to implement ajax-based navigation for all the links on a webpage. $('a').click(function(e){ e.preventDefault(); ...

The issue of missing _token in Laravel arises when there are two forms present on a single page, each with ajax submit

There are two different forms on a single page. One form accepts the registration number to display user information through ajax. The other form saves the information into another table along with additional data. The issue arises because both forms have ...

Angular 6 throws an error stating: "The property 'push' cannot be read of null."

The Cart model is defined as follows: //declaring a cart model for products to add export class Cart{ id:string; name:string; quantity:number; picture:string; } Below is the code for my app.service.ts: import { Injectable, Inject } fro ...

The UglifyJsPlugin in Webpack encounters an issue when processing Node modules that contain the "let" keyword

Below is the code snippet from my project which utilizes Vue.js' Webpack official template: .babelrc: "presets": [ "babel-preset-es2015", "babel-preset-stage-2", ] webpack.prod.config.js new webpack.optimize.UglifyJsPlugin({ compress: { ...