how to mock/test a window.prompt feature using sinon.js

492 views Asked by At

I have a javascript function hat uses prompt to ask details from user:

export function askUserForTeamDetails() {
    const emoji = window.prompt( 'Enter new team’s emoji:' );
    if ( null === emoji ) {
        return;
    }
    const name = window.prompt( 'Enter new team’s name:' );
    if ( null === name ) {
        return;
    }
    return { name, emoji };
}

Then I have Qunit and Sinon.js setup inside an HTML file like this:

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <meta name="viewport" content="width=device-width">
            <title>Rusty Inc. Org Chart WordPress Plugin JavaScript Tests</title>
            <link rel="stylesheet" href="https://code.jquery.com/qunit/qunit-2.7.1.css">
            
        </head>
        <body>
            <div id="qunit"></div>
            <div id="qunit-fixture"></div>
            <div  >
                <h1>Here is the playground</h1>
                <div id="playground"></div>
    
            </div>
           
            <script src="../node_modules/sinon/pkg/sinon.js"></script>
            <script type="module">
                import sinon from "../node_modules/sinon/pkg/sinon-esm.js";
                console.log('is sinon', sinon)
            </script>
              <script src="https://code.jquery.com/qunit/qunit-2.7.1.js"></script>
            <script type="module">
                import { subscribe, updateTree, updateSecretURL, getTree , createExpandCollapseCallback } from '../framework.js';
                import { ui , askUserForTeamDetails } from '../ui.js';
                const q = QUnit;
                
    
                q.test('test details function', assert => {
                let windowSpy = sinon.spy(window, 'prompt');

                //Dont  want  to call the  real function because it will cause propmts to display 

                let  askDetailsSub = sinon.stub(askUserForTeamDetails)
                const fake =  sinon.fake(askUserForTeamDetails);


                 // this gives an error
                sinon.assert.calledOnce(windowSpy); 

                //how to simulate the process of entering  inouts to prompt progamttaically?

                // verify that  the returned values are the ones inout by users


            } )
            </script>
        </body>
    </html>

I feel I have setup the fake function incorrectly and it's giving me an error: failing test description message

The text description of the error is:

Died on test #1     at https://923f663c4822.wp.prod1.devex.live/wp-content/plugins/rusty-inc-org-chart/tests/test.html:68:6: expected prompt to be called once but was called 0 times@ 6 ms
Source:     
AssertError: expected prompt to be called once but was called 0 times
    at Object.fail (https://923f663c4822.wp.prod1.devex.live/wp-content/plugins/rusty-inc-org-chart/node_modules/sinon/pkg/sinon.js:174:25)
    at failAssertion (https://923f663c4822.wp.prod1.devex.live/wp-content/plugins/rusty-inc-org-chart/node_modules/sinon/pkg/sinon.js:120:20)
    at Object.assert.<computed> [as calledOnce] (https://923f663c4822.wp.prod1.devex.live/wp-content/plugins/rusty-inc-org-chart/node_modules/sinon/pkg/sinon.js:149:17)
    at Object.<anonymous> (https://923f663c4822.wp.prod1.devex.live/wp-content/plugins/rusty-inc-org-chart/tests/test.html:76:18)

shouldn't the prompt be called?

I want to test the prompts are being called and then simulate entering values to the prompts. Also that the function returns the correct values. How Do I test it?

1

There are 1 answers

0
codiMonster On BEST ANSWER

You don't have to mock the askUserForTeamDetails function but can rather stub the window.prompt function and fake taking an input by stubbing it's return value like this:

let windowStub = sinon.stub(window, 'prompt');

//fakes taking input by stubbing the return value of prompt
// use `withArgs` to provide return value for the specific call
windowStub.withArgs('Enter new team’s emoji:').returns(testEmoji);
windowStub.withArgs('Enter new team’s name:').returns(testTeam);

A solution would look like this:

q.test('tes inputs function', assert => {
                const testEmoji = ``;             
                const testTeam = 'newTeama';
                let windowStub = sinon.stub(window, 'prompt');

                //fakes taking input but stubbing the return value of prompt
                windowStub.withArgs('Enter new team’s emoji:').returns(testEmoji);
                windowStub.withArgs('Enter new team’s name:').returns(testTeam);
                //call the details functions
                const answers = askUserForTeamDetails();
                // restore/free window.prompt from stubbing
                windowSpy.restore();
                //perform the neessary assertions
                assert.ok(  windowStub.withArgs('Enter new team’s emoji:').callCount === 1  , 'Prompt is opened for emoji' );
                assert.ok(  windowStub.withArgs('Enter new team’s name:').callCount === 1  , 'Prompt is opened for  team’s name:' );
                assert.ok( (answers.name === testTeam ) && (answers.emoji === testEmoji)  , 'Returns the values enter in prompt ' );
                

            } )