2

So I have already written the testing script which:

1) Logs into the application framework, then

2) Clicks menu to launch the app which I am testing ("MyAwesomeApp.html" for this post)

And my main problem is: In navpanel-spec.js below, I want to target the https://server/apps/Default.aspx?r=1 URL, then click within the iframe where MyAwesomeApp is running.

**** ERROR Trying to switch to the iframe this way, but it does NOT work:

browser.switchTo().frame(element(by.id('1')).getWebElement());

Error in cmd prompt:

 Started
 [15:43:29] E/launcher - No element found using locator: By(css selector, *[id="\31 "])
 ...
 sat-navpanel-spec.js:52:24)

So there are two URLs going on here:

1) https://server/apps/Default.aspx?r=1 (the main app framework with menu system in top nav).

2) https://server/apps/MyAwesomeApp.html (the web app which the test script launches within the <iframe> tag.

The html looks like this, where the application renders within the <iframe> :

<body>
<div id="top">
    <!-- top nav menu systems rendered here -->
</div>
<div id="middle">
    <div id="m1">
        <div id="m2" class="hidden">
            <div id="m3">
                <div id="right" class="hidden">
                    <div>
                        <div id="frame_holder" style="height: 940px;">
                            <iframe style="width: 100%; height: 100%;" name="1" id="1" src="https://server/apps/MyAwesomeApp.html">
                            </iframe>
                        </div>
                    </div>
                </div>
            </div>
            <div id="left" style="display: none;"></div>
        </div>
    </div>
</div>
</body>

In my Protractor.config.js file I have a few specs :

specs: [     
 'spec/login.js',
 'spec/launch-awesome-app.js',
 'spec/navpanel-spec.js',        
 'spec/another-spec.js',
 'spec/yet-another-spec.js'
]

login.js and launch-awesome-app.js work fine. They log into the menu system, then click thru the menus in order to launch myAwesomeapp - no problem.

MY PROBLEM:

In navpanel-spec.js I want to target the https://server/apps/Default.aspx?r=1 URL, then click within the iframe where MyAwesomeApp is running.

However, it is NOT selecting any of my elements.

If I target https://server/apps/MyAwesomeApp.html in navpanel-spec.js, of course it launches a new browser window and runs the test just fine.

Here's my navpanel-spec.js test spec:

describe('Testing My Awesome App', function () {
    
    var panelObj = new PanelObjects();
    
    var urlDefault = 'https://server/apps/Default.aspx?r=1';
    var urlApp = 'https://server/apps/MyAwesomeApp.html';

    browser.get(urlApp);    // Runs my AwesomeApp tests okay, HOWEVER it launches a new browser window.

    browser.get(urlDefault);    // Launches app framework with top nav menus and embedded <iframe>, 
                                // HOWEVER I cannot select iframe and successfully run tests here.

    beforeEach(function () {
        browser.sleep(5000);
        browser.waitForAngular();
    });    

    // USE-CASE OBJECT !!
    var items = browser.params.useCaseJsonFile["navigatePanels"];


    browser.getAllWindowHandles().then(function (handles) {
        handles.map(function (win, idx) {
    
            browser.driver.getCurrentUrl().then(function (curr) {
                if (curr.indexOf('Default.aspx') >= 0) {
                    browser.driver.switchTo().window(handles[idx]);        
                }
            });
        });

    });

    browser.switchTo().frame(element(by.id('1')).getWebElement());
    var testId =  element(by.id('middle'));
    console.log(testId);

    items.map(function (item) {
        if (item.enableTest) {
            var specItem = it(item.name, function () {

                console.log('------------------------------');
                console.log('---- ' + item.describe);

                browser.waitForAngular();

                // select panels, etc..
                panelObj.panelClick(item.panelName).then(function () {                    
                    // ...
                });
                
                panelObj.getPanelText(item.panelName).then(function (title) {
                    expect(title).toContain(item.panelTitle);
                });
                
            });
        }
    });

});

UPDATE

var LoginObjects = require('../pageObjects/login-objects.js');
describe('Testing My Awesome App', function () {

var panelObj = new PanelObjects();
var loginObj = new LoginObjects();

//var urlDefault = 'https://server/apps/Default.aspx?r=1';        
//browser.get(urlApp);    // Runs my AwesomeApp tests okay, HOWEVER it launches a new browser window.

browser.ignoreSynchronization = true;

// LOGIN AND LAUNCH APP !!!    
loginObj.Login();
loginObj.Launch();

beforeEach(function () {
    browser.sleep(5000);
    browser.waitForAngular();
});    

// USE-CASE OBJECT !!
var items = browser.params.useCaseJsonFile["navigatePanels"];

// SWITCH TO iframe ELEMENT
loginObj.switchWindowAndFrame();

items.map(function (item) {
    if (item.enableTest) {
 var specItem = it(item.name, function () {

     console.log('------------------------------');
     console.log('---- ' + item.describe);

     browser.waitForAngular();

     // select panels, etc..
     panelObj.panelClick(item.panelName).then(function () {                    
  // ...
     });

     panelObj.getPanelText(item.panelName).then(function (title) {
  expect(title).toContain(item.panelTitle);
     });

 });
    }
});

});

and my page objects :

module.exports = function(){
    this.Login = function(){

        var url = browser.params.loginUrl;        
        browser.driver.get(url);        
        browser.sleep(200);
        
        var userName = browser.params.credential.userId;
        var password = browser.params.credential.password;

        element(by.id('username')).clear().then(function(){
            element(by.id('username')).sendKeys(userName);
            element(by.id('password')).sendKeys(password);
        });
        
        browser.sleep(1000);

        var that = this;

        var submitElement = element(by.id('bthLogin')); 
        submitElement.click().then(function () {
            browser.getAllWindowHandles().then(function (handles) {
                        
                // LOGIN MESSAGE WINDOW
                browser.driver.getCurrentUrl().then(function(curr){                
                    if (curr.indexOf('LoginMsg.aspx') >= 0){
                        // Do we really need to close the login successful browser ???                    
                        browser.driver.close();
                    }
                });
                
                browser.driver.switchTo().window(handles[1]);
                
            });       
        });
        
    },

    this.Launch = function(){
        var sel = '#TheMenu1 > ul > li:first-child'; 

        var elem = element(by.css(sel));
        elem.click().then(function(){
            browser.sleep(1000);

            var elem2 = element(by.cssContainingText('.rmLink', 'The First Menu Item'));               
            elem2.click();  

            // Select menu item; sleep before attempting to click().
            var subElem = element(by.cssContainingText('.rmLink', 'My Awesome App'));
            browser.sleep(1000);
            
            subElem.click();
            browser.waitForAngular(); 
        });
    },

    this.switchWindowAndFrame = function(){

        browser.getAllWindowHandles().then(function (handles) {

            handles.map(function(win, idx){
                browser.driver.getCurrentUrl().then(function(curr){                    
                    if (curr.indexOf('Default.aspx') >= 0){                
                        browser.driver.switchTo().window(handles[idx]);                        
                    }
                });
            });

        });

        browser.switchTo().frame(element(by.css('[name="1"]')).getWebElement());
    }

};
bob.mazzo
  • 5,183
  • 23
  • 80
  • 149
  • 1
    this is the second time i am seeing the same issue. Your locator for id gets prefixed by '\3' . This bug is still on. Try using other locators – radio_head Nov 15 '16 at 09:04
  • Okay I will try a css locator. Thx. – bob.mazzo Nov 15 '16 at 13:15
  • 1
    I'd also try changing the `name` and `id` values from `1` to something else. In HTML4 and lower, these 2 attributes can't start with a digit. – finspin Nov 15 '16 at 17:40
  • @finspin - That's the first thing I thought as well. But of course that application is already rolled out that way; but hey, it's worth a try. I can always request that we change the div ID attribute. Thanks for your input. – bob.mazzo Nov 15 '16 at 18:54
  • Here's something that's bugging me. I'm putting `browser.` statements in my `navpanel-spec.js ` spec above; however, prior to that spec I login and launch the app (those are two different js spec files). Why is my `navpanel-spec.js` file running first - before the login and launch js files ??? In other words, if I add a `browser.pause()` in `navpanel-spec.js`, it pauses immediately - PRIOR to even running my login-spec.js code. CONFUSING ! – bob.mazzo Nov 15 '16 at 19:38
  • 1
    This is not directly related to the issue with iframe but it seems like your spec files are coupled together. You should avoid that because you'll run into all kind of issues. Either include login / launch functionality into your `navpanel-spec.js` directly or call it from a separate node package, using the PageObject pattern http://stackoverflow.com/a/31624445/932210. – finspin Nov 15 '16 at 20:17
  • @finspin - Congrats. Your login/launch suggestions worked out for me. Since I was already using the page object pattern elsewhere, it was easy enough to just move `login.js` and `launch.js` code into a module called `login-objects.js`. Unfortunately I must re-login and launch for every spec.js test, so that's kind of annoying (but I figure there's no solution to that one). I should add a brand new post for this login/launch issue using page objects instead. You deserve the answer on this one. – bob.mazzo Nov 16 '16 at 21:08
  • @Danny - yes, changing the selector worked out. `by.css('[name="1"]')` did the trick, so now it's finding the `iframe` no problem. Add as answer please. Simple fix, but it was key. The `id='1'` was a real problem for me, but thankfully there was also a `name` attribute to grab... +1 – bob.mazzo Nov 16 '16 at 21:10
  • @finspin - here is the post which I've created on this issue. Please post your "page objects" suggestion - http://stackoverflow.com/questions/40642536/protractor-executing-login-scripts-prior-to-launching-my-test-specs – bob.mazzo Nov 16 '16 at 21:19

1 Answers1

1

As mentioned in the comments above, protractor has a bug which prefixes '\3' to your id element with number.

The temporary way is to change you locator. :P

radio_head
  • 1,306
  • 4
  • 13
  • 28