Can you uncover the secrets of static generator functions through espionage?

My current project involves an utility function that exposes a generator:

export class Utility {
    // This utility function provides a generator that streams 2^n binary combinations for n variables
    public static *binaryCombinationGenerator(numVars: number): IterableIterator<boolean[]> {
        for (let i = 0; i < Math.pow(2, numVars); i++) {
            const c = [];
           // Fill up the binary combination array
            yield c;
        }
    }
}

Now, I am incorporating this generator in my code in the following manner:

myFuncion(input){
    const n = numberOfVariables(input);
    const binaryCombinations = Utility.binaryCombinationGenerator(n);
    let combination: boolean[] = binaryCombinations.next().value;
    while (till termination condition is met) {
      // Perform actions and check for termination condition         
      combination = binaryCombinations.next().value;
    }
}

During my unit tests (using Jasmine), I aim to monitor how many times the generator function is invoked (i.e., how many combinations are generated) before termination. Below is what I have attempted:

it("My spec", () => {
    // Arrange
    const generatorSpy = spyOn(Utility, "binaryCombinationGenerator").and.callThrough();
    // Act
    // Assert
    expect(generatorSpy).toHaveBeenCalledTimes(16); // This fails with the message: Expected spy binaryCombinationGenerator to have been called 16 times. It was called 1 time.
});

However, the assertion fails since binaryCombinationGenerator is only called once. What I truly intend to spy on is the next method of IterableIterator.

Yet, I am uncertain about how to achieve this. Any suggestions would be appreciated.

Answer №1

One way to enhance your test is to have the

Utility.binaryCombinationGenerator
method return a jasmine spy object.

let binaryCombinationsSpy = jasmine.createSpyObject('binaryCombinations', ['next']);
binaryCombinationsSpy.next.and.returnValues(value1, value2);
spyOn(Utility, "binaryCombinationGenerator").and.returnValue(binaryCombinationsSpy);

expect(binaryCombinationsSpy.next).toHaveBeenCalledTimes(2);

Answer №2

Sharing my approach as an answer on how I mocked the generator function. Credit goes to @0mpurdy's solution.

In order to properly mock the generator function, it's necessary to invoke a fake function that will return different values (potentially limited) for each call to next() within the generator.

Here's a simple way to achieve this:

//setup
const streamSpy= jasmine.createSpyObj("myGenerator", ["next", "counter"]);
streamSpy.counter = 0;
const values = [{ value: here }, { value: goes }, { value: your }, { value: limited }, 
                { value: values }]; // adjust as needed for infinite streams

// call fake function for each next call
streamSpy.next.and.callFake(() => {
    if (streamSpy.counter < values.length) {
        streamSpy.counter++;
        return values[streamSpy.counter - 1];
    }
    return { value: undefined }; // End of Stream
});
spyOn(Utility, "myGenerator").and.returnValue(streamSpy);

...
//validate
expect(streamSpy.next).toHaveBeenCalledTimes(2);

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

When utilizing webpack in Angular 5, the :host selector does not get converted into a component entity

Initially, I set up Angular with webpack following the configuration in this guide, including configuring webpack sass-loader. Everything was working smoothly until I encountered an issue today: app.component.ts @Component({ selector: 'ng-app&ap ...

Removing double double quotes for Javascript

My problem involves a string that represents longitude/latitude in the format of dd°mm'ss''W (note 2 single quotes after ss). To convert this string into its decimal representation, I am using the following code snippet: function dmsTodeg ...

Enhance your Angularfire experience with $firebaseArray by enabling dynamic counting and summing

Is there a way to dynamically count certain nodes if they are defined? The current implementation requires explicitly calling sum(). app.factory("ArrayWithSum", function($firebaseArray) { return $firebaseArray.$extend({ sum: function() { var ...

Unable to retrieve elements from the eBay website using JavaScript within a Chrome extension

I recently developed a Chrome extension that scrapes all orders from an eBay orders page. It was working flawlessly last month, but suddenly I am facing issues accessing some elements. Here is the snippet of code causing trouble: let elGridComp = document ...

Increase the gap between the legend and the chart when utilizing charts.js

I'm currently working on a project using charts.js and running into a slight issue. The legend for my bar chart is overlapping with the values displayed. I've been attempting to troubleshoot this problem without much success so far, so I would g ...

Encountering a 404 error while trying to refresh the page in a React App hosted on Her

After deploying a React App on Heroku, I encountered a frustrating issue: every time a page is refreshed, a 404 error appears, such as: Cannot GET /create In my search for a solution, I came across a related issue: Question about 404 with React Router ...

What is the best way to merge different Vue JS instances (each linked to different html divs) into one cohesive unit using Vue

Essentially, I have a scenario where I've created two HTML divs named vueapp1 and vueapp2. Both of these divs serve the same purpose of displaying information and are linked to their individual Vue instances for extracting JSON data and presenting it. ...

Implementing CKEditor instances within AngularJS Controller scopes

Greetings everyone, Recently, I have been exploring Angular JS. Everything is going smoothly - my controllers, services, and so on. However, when attempting to make a Div editable that is within the ng-controller, the ckeditor toolbar fails to appear. On ...

Having trouble locating modules or properties with ANTLR4 TypeScript target?

Having reached a frustrating impasse, I am seeking assistance with a perplexing issue. My attempt to integrate TypeScript with ANTLR4 has hit a snag, and despite exhaustive efforts, I am unable to pinpoint the root cause (with limited documentation availab ...

making changes to the JS node dependency package results in a syntax error during compilation process, particularly within the npm/Vue.js environment

After creating a Js library and encountering stability issues and a few bugs that need fixing, the dilemma of developing a library arises when HMR does not work with dependencies. Here's a possible solution: To start, create a new Vue project using ...

I encountered an issue where the error "data.map is not a function" occurs whenever I try to execute a React component

I have implemented the HorizontalScrollbar component and passed data as a prop. When I try to run the HorizontalScrollbar component, I encounter the following error in the console tab of Chrome: Error: Uncaught TypeError: data.map is not a function Horiz ...

Heroku experiences unexpected surge in memory consumption while using Puppeteer

Yesterday, a commit caused the process to hit Heroku's memory limit resulting in an R15 error. The code worked perfectly during testing and on Heroku until it reached a certain number of checked items, triggering the error. What's intriguing is t ...

What is the best way to intentionally make a Node unit test fail when catching a Promise rejection?

When conducting unit tests with Node.js, I encountered a scenario where I needed to intentionally fail a test within a promise's catch block: doSomething() .then(...) .catch(ex => { // I need this test to fail at this point }); ...

What is the best way to manage the package-lock.json file during deployment from git using SSH?

In my deployment process, I utilize a Git repository to check code in. By using web hooks, a deployment script is triggered on the production server. Once connected to Git via SSH and a .pem key on the server, I perform a Git pull, npm install, webpack bui ...

Effortless navigation with smooth scrolling on anchor links in react/next.js

Can smooth scrolling be achieved using only CSS when clicking on an anchor link within a react component? ... render( <a href="#smooth-link">Link To There</a> .... <div id="smooth-link"> .... ...

What is the best method for interacting with multiple links in Puppeteer?

As a beginner with puppeteer, I am diving into the world of web scraping by attempting to create a simple scraping task. My Plan of Action The plan is straightforward: Visit a page, Extract all <li> links under a <ul> tag, Click on each < ...

Tips for creating a condensed header

As a newcomer to HTML, I am facing challenges in creating a simple header similar to the one displayed on this website or the example in the image below. Below is the snippet of HTML that I have attempted: <header class="header"> <div ...

Using Angular to make GET requests with JSON data in PHP

Seeking assistance with connecting Angular frontend to PHP backend. Upon calling the service, I am receiving an empty array in the console. Controller: angular.module('pageModule') .controller('pageController', ['$scope', &a ...

attempting to pass a boolean type through props resulting in a type error

Hey, check out this component I created: import * as Styled from './styles'; export type HeadingProps = { children: React.ReactNode | string; colorDark: boolean; }; export const Heading = ({ children, colorDark }: HeadingProps) => { re ...

Limit the execution speed of a JavaScript function

My JavaScript code is set up to trigger a click event when the user scrolls past a specific element with the class .closemenu. This is meant to open and close a header menu automatically as the user scrolls through the page. The problem I'm facing is ...