Multiple firefox profiles in protractor

2019-06-06 03:04发布

问题:

Following Configuring multiple capabilities with promises topic.

Use case: I have two separate tests that require Firefox to be fired with javascript disabled and local storage disabled. Which means that I need two firefox profiles with javascript.enabled = false and dom.storage.enabled = false desired capabilities/preferences set.

I'm using getMultiCapabilities() that was introduced in protractor 1.6. Till this moment, I needed only one custom firefox profile and it worked, here is the configuration:

getMultiCapabilities: function() {
    var deferred = q.defer();

    var multiCapabilities = [
        {
            browserName: "chrome",
            specs: [
                "*.spec.js"
            ],
            exclude: [
                "footer.disabledJavascript.spec.js"
            ]
        }
    ];

    // Wait for a server to be ready or get capabilities asynchronously.
    setTimeout(function() {
        var firefoxProfile = new FirefoxProfile();
        firefoxProfile.setPreference("javascript.enabled", false);
        firefoxProfile.encoded(function (encodedProfile) {
            var capabilities = {
                "browserName": "firefox",
                "firefox_profile": encodedProfile,
                "specs": [
                    "footer.disabledJavascript.spec.js"
                ]
            };
            multiCapabilities.push(capabilities);
            deferred.resolve(multiCapabilities);
        });
    }, 1000);

    return deferred.promise;
},

Problem: Now I need the second firefox profile instance with dom.storage.enabled = false, but I'm stuck at how should I resolve the deferred in this case, since there are now two encoded() calls and two capabilities added to multiCapabilities.

Question: How can I configure multiple firefox profiles using getMultiCapabilities?


The only way I made it work is nesting one profile into another and calling resolve() at the deepest level (in case of two profiles it might be okay - but this solution doesn't really scale):

var multiCapabilities = [
        {
            browserName: "chrome",
            specs: [
                "*.spec.js"
            ],
            exclude: [
                "footer.disabledJavascript.spec.js",
                "disabledLocalStorage.spec.js"
            ]
        }
    ];

    // Wait for a server to be ready or get capabilities asynchronously.
    setTimeout(function() {
        // profile with disabled javascript
        var firefoxProfile = new FirefoxProfile();
        firefoxProfile.setPreference("javascript.enabled", false);
        firefoxProfile.encoded(function (encodedProfile) {
            var capabilities = {
                browserName: "firefox",
                directConnect: true,
                firefox_profile: encodedProfile,
                specs: [
                    "footer.disabledJavascript.spec.js"
                ]
            };
            multiCapabilities.push(capabilities);

            // profile with disabled local storage
            var newFirefoxProfile = new FirefoxProfile();
            newFirefoxProfile.setPreference("dom.storage.enabled", false);
            newFirefoxProfile.encoded(function (newEncodedProfile) {
                var newCapabilities = {
                    browserName: "firefox",
                    directConnect: true,
                    firefox_profile: newEncodedProfile,
                    specs: [
                        "disabledLocalStorage.spec.js"
                    ]
                };
                multiCapabilities.push(newCapabilities);
                deferred.resolve(multiCapabilities);
            });
        });
    }, 1000);

    return deferred.promise;
},

回答1:

You can use q.all to do this. Essentially you want to do something like this:

return q.all([
    capabilityPromise1,
    capabilityPromise2,
    ...
]);

Exactly how you get the capability promises is up to you. Here's one generic way:

var makeFirefoxProfile = function(preferenceMap, capabilityMap) {
    var deferred = q.defer();
    var firefoxProfile = new FirefoxProfile();
    // TODO: iterate over preferenceMap and set preference for each
    firefoxProfile.encoded(function (encodedProfile) {
        var capabilities = {
            "browserName": "firefox",
            "firefox_profile": encodedProfile,
        };
        // TODO: iterate over capabilityMap and set key/value for each
        deferred.resolve(capabilities);
    });
    return deferred.promise;
};

getMultiCapabilities: function() {
    return q.all([
        makeFirefoxProfile({javascript.enabled: false}, {specs: ['spec1.js']})
        makeFirefoxProfile({dom.storage.enabled: false}, {specs: ['spec2.js']})
    ]);
}

If you don't want to create a helper function and want to generate the capability promises in 1 function, that's up to you. Essentially, I think the key here is to use q.all, the rest really depends on how complex your capabilities objects are and how you want to structure your code



回答2:

Following @hakduan's suggestion to use q.all() and have a reusable function, here is the configuration that worked for me (note how clean it is):

var makeFirefoxProfile = function(preferenceMap, specs) {
    var deferred = q.defer();
    var firefoxProfile = new FirefoxProfile();

    for (var key in preferenceMap) {
        firefoxProfile.setPreference(key, preferenceMap[key]);
    };

    firefoxProfile.encoded(function (encodedProfile) {
        var capabilities = {
            browserName: "firefox",
            directConnect: true,
            firefox_profile: encodedProfile,
            specs: specs
        };

        deferred.resolve(capabilities);
    });
    return deferred.promise;
};

exports.config = {
    getMultiCapabilities: function() {
        return q.all([
            {
                browserName: "chrome",
                directConnect: true,
                specs: [
                    "*.spec.js"
                ],
                exclude: [
                    "footer.disabledJavascript.spec.js",
                    "disabledLocalStorage.spec.js"
                ]
            },
            makeFirefoxProfile({"javascript.enabled": false}, ["footer.disabledJavascript.spec.js"]),
            makeFirefoxProfile({"dom.storage.enabled": false}, ["disabledLocalStorage.spec.js"])
        ]);
    },

    ...
};