Make sure to have only one description per file enforced

The Scenario:

In our extensive test codebase utilizing Protractor+Jasmine, we are encountering an issue where some test/spec files contain multiple describe blocks. This has caused issues during debugging, as using fdescribe/fit to run tests individually or in batches can inadvertently skip portions of the tests due to overlooked additional describe blocks at the bottom of the file.

This situation resembles the "one assertion per test" principle, aiming to maintain a tidy and concise test codebase.

The Query:

We are exploring methods to restrict the presence of more than one describe block per file. Our initial thoughts revolve around employing static code analysis tools like ESLint; however, we welcome alternative suggestions for addressing this issue effectively.

Instances:

An example illustrating a violation:

describe("Test 1", function () {
    it("should do something", function () {
        expect(true).toBe(true);
    });
});

describe("Test 2", function () {
    it("should do something else", function () {
        expect(false).toBe(false);
    });
});

If a single describe block contains nested describes, it should not be flagged as a violation. For instance, the following structure is permissible:

describe("Test 1", function () {
    it("should do something", function () {
        expect(true).toBe(true);
    });

    describe("Test 2", function () {
        it("should do something else", function () {
             expect(false).toBe(false);
        });
    });
});

Answer №1

Identifying stand-alone describe blocks, known as "top-level" describes, can be a challenge. Fortunately, ESLint offers a solution for this!

ESLint makes two passes through the abstract syntax tree (AST) of your JavaScript code: descending the tree and ascending back up. The traversal is depth-first, so if you have 3 describe blocks in your code like this:

describe("Test 1", function () {
    it("should do something", function () {
        expect(true).toBe(true);
    });

    describe("Test 2", function () {
        it("should do something else", function () {
             expect(false).toBe(false);
        });
    });
});

describe("Test 3", function () {
    it("should do something", function () {
        expect(true).toBe(true);
    });
});

The nodes would be visited in the following order:

enter "Test 1" -> enter "Test 2" -> exit "Test 2" -> exit "Test 1" -> enter "Test 3" -> exit "Test 3"

This process involves keeping track of all the describe calls in a stack while going "down" a subtree, then popping them one by one while going "up" that subtree. If there is only one node left to pop from the stack while ascending, then that node is a "top-level" describe.

In the end, if more than one "top-level" describe is found, our rule should flag an error. I've created a small prototype to demonstrate this concept:

Answer №3

If you're looking to enforce certain syntax restrictions, consider using the no-restricted-syntax rule.

Here's an example of a selector you can utilize:

Program > ExpressionStatement[expression.type='CallExpression'][expression.callee.type='Identifier'][expression.callee.name='describe'] ~ ExpressionStatement[expression.type='CallExpression'][expression.callee.type='Identifier'][expression.callee.name='describe']

For a complete illustration, refer to the snippet below:


    "no-restricted-syntax": [2,
      {
        "selector": "Program > ExpressionStatement[expression.type='CallExpression'][expression.callee.type='Identifier'][expression.callee.name='describe'] ~ ExpressionStatement[expression.type='CallExpression'][expression.callee.type='Identifier'][expression.callee.name='describe']",
        "message": "Only one top level describe per test file"
      }
    ],

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

Choose the DIV element based on its data attribute using JSON

When using each(), my goal is to: Hide all divs where the data-infos.grpid = $jQuery(this).data('infos').grpid Show the next div where data-infos.ordre = $jQuery(this).data('infos').next_ordre I am unsure how to apply a "where" ...

Error encountered: Nitrogen is undefined

For the past three years, my Nitrogen web framework powered site has been functioning smoothly across all browsers. However, I recently encountered an issue where postbacks would randomly fail to respond in Google Chrome and Opera, with the console display ...

Submit a form using Ajax without having to reload the page

Seeking help for implementing an ajax form submission with four answer options to a question. The goal is to submit the form without reloading the page upon selecting an option. Below is the code I have been working on. Any suggestions or solutions are wel ...

Oops, looks like there's been an issue with the webpack build. It seems we're

I encountered an issue while building and running the development server using Webpack. My project is based on Vue.js, and I utilized vue-cli to generate it. Jest is used for testing, and running npm test poses no problems. However, when I run npm run bui ...

Encountered an error: Unexpected symbol < at the beginning of JSON data (JavaScript and PHP)

I've been struggling with this challenge for days and I hope someone can assist me with it. The issue revolves around passing data from JavaScript to PHP. My aim is to send the lostid from an HTML page to a JavaScript page, then have the JavaScript pa ...

Transfer a Sencha Touch application from iOS to Android and Windows devices

I am a dedicated Android developer who is diving into the world of Sencha Touch, Windows app development, and VisualStudio environments for the first time. Please excuse the detailed explanation of my problem, as I want to make sure all crucial details are ...

Submission event in jQuery fails to trigger

I'm struggling with submitting a form in jQuery <form id="solicitud" action="ventas.php?content=nuevo" method="post"> ... </form> Even though I have the code to submit the form, it's not working as expected $("#nombres").click(fu ...

Aligning event with angular (similar to the 'join()' function in threads)

I am searching for a straightforward equivalent to join() for threads in Angular. In my Controller: vehiclesService.getVehicles().then(function(sth){ $scope.vehicles = sth.data; $scope.isend();//this call is not ideal }); vehiclesService.getFitme ...

An issue occurred while testing with React-Native Testing Library/Jest, where the property 'TouchableOpacity' could not be read

I am currently in the process of conducting tests using jest and react-native testing. Unfortunately, I have encountered an issue where TouchableOpacity is not being recognized and causing errors. Card.test.js import Card from "../Card" import R ...

Can flexbox be constrained to a grid while wrapping text?

Admiring the way this design wraps seamlessly while still maintaining aligned boxes on both sides, creating a visually appealing and fully utilized space. <head> <style> * { padding: 0px; margin: 0px; text-transform: none; font-style ...

Is it possible to call a function directly from useEffect?

Code VersionA: useEffect(() => doRequest(), []); Code VersionB: useEffect(() => { doRequest(); }, []); I used to believe that both versions were the same, with VersionA being a shortcut and VersionB allowing for multiple commands within the inlin ...

gmap3 has encountered an error: undefined is not a valid function

I am working on a WordPress site and trying to integrate a Google map into the contact page. However, I'm encountering an error Uncaught TypeError: undefined is not a function in the JavaScript console. Below is the code snippet causing the issue, can ...

Having troubles with your jQuery script on Internet Explorer?

I am facing an issue with my script. It is located in an external file and called at the beginning of my HTML page. The script involves an Ajax request that constantly checks a database for updates. When an update is detected, it triggers a specific functi ...

What is the best way to retrieve the value of an Object nested inside an array?

When I iterate through a RSS data, I need to fetch the URL value from an object. $.ajax({ url : 'http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&num=30&callback=?&q=' + encodeURIComponent('http://www.dnoticias.pt/ ...

Instructions for converting a blob URL into an audio file and securely storing it on the server

After successfully recording and adding the audio to my HTML page within the audio tag, I managed to obtain the blob source URL from the tag using the following line: var source = document.getElementById("Audio").src; The blob source URL looks ...

Use Angular ng-route's $route.next feature to smoothly transition between different page views

I am currently developing an application that incorporates sliding between different views with the use of next and previous buttons for navigation. However, I am encountering an issue where the $route.next and $route.previous methods are not functioning a ...

How can TypeScript objects be serialized?

Is there a reliable method for preserving type information during JSON serialization/deserialization of Typescript objects? The straightforward JSON.parse(JSON.stringify) approach has proven to have several limitations. Are there more effective ad-hoc sol ...

Keeping your webpage current as time progresses

Currently I am in the process of creating an online multiplayer turn-based strategy game inspired by Risk. At this stage, it seems like the most straightforward approach is to develop it as a standard webpage. Each time a player refreshes the page, it ret ...

Inquiry regarding the process of object creation in JavaScript

I recently discovered a method to create your own 'class' as shown below: function Person(name, age){ this.name = name; this.age = age; } Person.prototype.foo = function(){ // do something } Person.prototype.foo2 = function(){ ...

How is the time complexity of merging two sorted arrays to create one larger sorted array determined?

This is my solution to a problem that involves merging two arrays of integers sorted in ascending order into one larger sorted array. The function merges the arrays by comparing elements from each array and appending them to a new array in an orderly fashi ...