You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cordova.apache.org by alsorokin <gi...@git.apache.org> on 2016/01/20 17:26:05 UTC

[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

GitHub user alsorokin opened a pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101

    CB-10399 Added Appium tests

    https://issues.apache.org/jira/browse/CB-10399

You can merge this pull request into a Git repository by running:

    $ git pull https://github.com/MSOpenTech/cordova-plugin-contacts ui-tests

Alternatively you can review and apply these changes as the patch at:

    https://github.com/apache/cordova-plugin-contacts/pull/101.patch

To close this pull request, make a commit to your master/trunk branch
with (at least) the following in the commit message:

    This closes #101
    
----
commit 9721fd7d5fd634f6253a43e70fc42bdbbefc3a36
Author: Alexander Sorokin <al...@akvelon.com>
Date:   2016-01-20T16:24:51Z

    CB-10399 Added Appium tests

----


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by asfgit <gi...@git.apache.org>.
Github user asfgit closed the pull request at:

    https://github.com/apache/cordova-plugin-contacts/pull/101


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by alsorokin <gi...@git.apache.org>.
Github user alsorokin commented on a diff in the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#discussion_r55803473
  
    --- Diff: appium-tests/android/android.spec.js ---
    @@ -0,0 +1,338 @@
    +/*jshint node: true, jasmine: true */
    +/*
    + *
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + *
    +*/
    +
    +// these tests are meant to be executed by Cordova Medic Appium runner
    +// you can find it here: https://github.com/apache/cordova-medic/
    +// it is not necessary to do a full CI setup to run these tests
    +// just run "node cordova-medic/medic/medic.js appium --platform android --plugins cordova-plugin-contacts"
    +
    +'use strict';
    +
    +var wdHelper = require('../helpers/wdHelper');
    +var screenshotHelper = require('../helpers/screenshotHelper');
    +var contactsHelper = require('../helpers/contactsHelper');
    +
    +var STARTING_MESSAGE = 'Ready for action!';
    +var MINUTE = 60 * 1000;
    +var DEFAULT_WEBVIEW_CONTEXT = 'WEBVIEW';
    +
    +describe('Contacts Android', function () {
    +    var driver;
    +    // the name of webview context, it will be changed to match needed context if there are named ones:
    +    var webviewContext = DEFAULT_WEBVIEW_CONTEXT;
    +    // this indicates that there was a critical error and we should try to recover:
    +    var errorFlag = false;
    +    // this indicates that we couldn't restore Appium session and should fail fast:
    +    var stopFlag = false;
    +
    +    function win() {
    +        expect(true).toBe(true);
    +    }
    +
    +    function fail(error) {
    +        if (error === 'rethrow') {
    +            throw error;
    +        }
    +        if (error && error.message) {
    +            console.log('An error occured: ' + error.message);
    +            if (error.stack) {
    +                console.log(error.stack);
    +            }
    +            expect(true).toFailWithMessage(error.message);
    +        } else if (error && typeof error === 'string') {
    +            console.log('Failed expectation: ' + error);
    +            expect(true).toFailWithMessage(error);
    +        } else {
    +            // no message provided :(
    +            expect(true).toBe(false);
    +        }
    +        return screenshotHelper
    +            .saveScreenshot(driver)
    +            .finally(function() {
    +                throw 'rethrow';
    +            });
    +    }
    +
    +    function enterTest() {
    +        return driver
    +            // trying to determine where we are
    +            .context(webviewContext)
    +            .fail(function (error) {
    +                return fail(error);
    +            })
    +            .elementById('info')
    +            .then(function () {
    +                return driver; //we're already on the test screen
    +            }, function () {
    +                return driver
    +                    .elementById('middle')
    +                    .then(function () {
    +                        return driver
    +                            // we're on autotests page, we should go to start page
    +                            .execute('window.location = "../index.html"')
    +                            .sleep(5000)
    +                            .fail(function () {
    +                                errorFlag = true;
    +                                throw 'Couldn\'t find start page.';
    +                            });
    +                    }, function () {
    +                        return; // no-op
    +                    })
    +                    // unknown starting page: no 'info' div
    +                    // adding it manually
    +                    .execute('var info = document.createElement("div"); ' +
    +                             'info.id = "info"; ' +
    +                             'document.body.appendChild(info);');
    +            })
    +            .sleep(5000);
    +    }
    +
    +    function getDriver() {
    +        driver = wdHelper.getDriver('Android');
    +        return driver;
    +    }
    +
    +    function checkStopFlag() {
    +        if (stopFlag) {
    +            fail('Something went wrong: the stopFlag is on. Please see the log for more details.');
    +        }
    +        return stopFlag;
    +    }
    +
    +    beforeEach(function () {
    +        jasmine.addMatchers({
    +            toFailWithMessage: function () {
    +                return {
    +                    compare: function (actual, msg) {
    +                        console.log('Failing with message: ' + msg);
    +                        var result = {
    +                            pass: false,
    +                            message: msg
    +                        };
    +                        // status 6 means that we've lost the session
    +                        // status 7 means that Appium couldn't find an element
    +                        // both these statuses mean that the test has failed but
    +                        // we should try to recreate the session for the following tests
    +                        if (msg.indexOf('Error response status: 6') >= 0 ||
    +                            msg.indexOf('Error response status: 7') >= 0) {
    +                            errorFlag = true;
    +                        }
    +                        return result;
    +                    }
    +                };
    +            },
    +            toContain: function () {
    --- End diff --
    
    Yeah, but it looks for the item in an array, not for a substring in a string.
    I guess I'll just have to rename this one.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by dblotsky <gi...@git.apache.org>.
Github user dblotsky commented on the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#issuecomment-197445134
  
    @sgrebnov `fn.toString` is also a pretty nasty pattern. Adding buttons for manual tests is literally what manual tests are. We control both the tests and the UI. Why is that a bad thing? This is one of those cases where applying the DRY (Don't Repeat Yourself) principle doesn't make things much better and makes the code a lot harder to maintain. Just modify the test app. That way we can also test it manually without Appium.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by sgrebnov <gi...@git.apache.org>.
Github user sgrebnov commented on a diff in the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#discussion_r56317001
  
    --- Diff: appium-tests/helpers/contactsHelper.js ---
    @@ -0,0 +1,222 @@
    +/* jshint node: true */
    +/*
    + *
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + *
    +*/
    +
    +'use strict';
    +
    +function prepare(item) {
    +    if (typeof item === 'object') {
    +        return JSON.stringify(item);
    +    }
    +    if (typeof item === 'string') {
    +        return '"' + item + '"';
    +    }
    +    return undefined;
    +}
    +
    +module.exports.getContactName = function (firstName, lastName) {
    +    return {
    +        formatted: firstName == lastName === undefined ? null : firstName + ' ' + lastName,
    +        familyName: lastName,
    +        givenName: firstName,
    +        middleName: ''
    +    };
    +};
    +
    +module.exports.getAddContactCode = function (displayName, contactName, phoneNumber) {
    +    var preparedDisplayName = prepare(displayName);
    +    console.log('preparedDisplayName is ' + preparedDisplayName);
    +    var preparedContactName = prepare(contactName);
    +    var preparedPhoneNumber = prepare(phoneNumber);
    +
    +    var result =
    +        'try {\n' +
    +        '    var results = document.getElementById("info");\n' +
    +        '    var contact = navigator.contacts.create({ "displayName": ' + preparedDisplayName + ', "name": ' + preparedContactName + ', "note": "DeleteMe" });\n' +
    +
    +        '    var phoneNumbers = [1];\n' +
    +        '    phoneNumbers[0] = new ContactField("work", ' + preparedPhoneNumber + ', true);\n' +
    +        '    contact.phoneNumbers = phoneNumbers;\n' +
    +
    +        '    contact.save(function() {\n' +
    +        '        results.innerHTML = "' + (displayName || 'Nameless contact') + ' saved.";\n' +
    +        '    }, function(e) {\n' +
    +        '        if (e.code === ContactError.NOT_SUPPORTED_ERROR) {\n' +
    +        '            results.innerHTML = "Saving contacts not supported.";\n' +
    +        '        } else {\n' +
    +        '            results.innerHTML = "Contact save failed: error " + e.code;\n' +
    +        '        }\n' +
    +        '    });\n' +
    +        '} catch (e) {\n' +
    +        '    var results = document.getElementById("info");\n' +
    +        '    results.innerHTML = "ERROR: " + e.code;\n' +
    +        '}\n';
    +
    +    return result;
    +};
    +
    +module.exports.getGetContactsCode = function (filter) {
    +    var preparedFilter = prepare(filter);
    +
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'var obj = new ContactFindOptions();\n' +
    +        'if (' + preparedFilter + ') {\n' +
    +        '    obj.filter = ' + preparedFilter + ';\n' +
    +        '}\n' +
    +        'obj.multiple = true;\n' +
    +        'navigator.contacts.find(["displayName", "name", "phoneNumbers", "emails", "urls", "note"], function(contacts) {\n' +
    +        '    var s = "";\n' +
    +        '    if (contacts.length === 0) {\n' +
    +        '        s = "No contacts found";\n' +
    +        '    } else {\n' +
    +        '        s = "Number of contacts: " + contacts.length + "<br><table width=100%><tr><th>Name</th><td>Phone</td><td>Email</td></tr>";\n' +
    +        '        for (var i = 0; i < contacts.length; i++) {\n' +
    +        '            var contact = contacts[i];\n' +
    +        '            var contactNameTag = contact.name ? "<tr><td>" + contact.name.formatted + "</td><td>" : "<tr><td>(No Name)</td><td>";\n' +
    +        '            s = s + contactNameTag;\n' +
    +        '            if (contact.phoneNumbers && contact.phoneNumbers.length > 0) {\n' +
    +        '                s = s + contact.phoneNumbers[0].value;\n' +
    +        '            }\n' +
    +        '            s = s + "</td><td>";\n' +
    +        '            if (contact.emails && contact.emails.length > 0) {\n' +
    +        '                s = s + contact.emails[0].value;\n' +
    +        '            }\n' +
    +        '            s = s + "</td></tr>";\n' +
    +        '    }\n' +
    +        '        s = s + "</table>";\n' +
    +        '    }\n' +
    +        '    results.innerHTML = s;\n' +
    +        '}, function(e) {\n' +
    +        '   results.innerHTML = "Search failed: error " + e.code;\n' +
    +        '}, obj);';
    +
    +    return result;
    +};
    +
    +module.exports.getPickContactCode = function () {
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'navigator.contacts.pickContact(\n' +
    +        '    function (contact) {\n' +
    +        '        results.innerHTML = contact ?\n' +
    +        '            "Picked contact: <pre>" + JSON.stringify(contact, null, 4) + "</pre>" :\n' +
    +        '            "No contacts found";\n' +
    +        '    },\n' +
    +        '    function (e) {\n' +
    +        '        results.innerHTML = e && e.code === ContactError.OPERATION_CANCELLED_ERROR ?\n' +
    +        '                "Pick cancelled" :\n' +
    +        '                "Pick failed: " + (e && e.code);\n' +
    +        '    }\n' +
    +        ');';
    +
    +    return result;
    +};
    +
    +module.exports.getRenameContactCode = function (oldDisplayName, newDisplayName, newName) {
    +    // these default values are copied from manual contacts tests
    +    if (!oldDisplayName) {
    +        oldDisplayName = 'Dooney Evans';
    +    }
    +    if (!newDisplayName) {
    +        newDisplayName = 'Urist McContact';
    +    }
    +    if (!newName) {
    +        newName = module.exports.getContactName('Urist', 'McContact');
    +    }
    +    var preparedOldDisplayName = prepare(oldDisplayName);
    +    var preparedNewDisplayName = prepare(newDisplayName);
    +    var preparedNewName = prepare(newName);
    +
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'var obj = new ContactFindOptions();\n' +
    +        'obj.filter = ' + preparedOldDisplayName + ';\n' +
    +        'obj.multiple = false;\n' +
    +
    +        'navigator.contacts.find(["displayName", "name"], function(contacts) {\n' +
    +        '    if (contacts.length === 0) {\n' +
    +        '        results.innerHTML = "No contacts to update.";\n' +
    +        '        return;\n' +
    +        '    }\n' +
    +        '    var contact = contacts[0];\n' +
    +        '    contact.displayName = ' + preparedNewDisplayName + ';\n' +
    +        '    contact.name = ' + preparedNewName + ';\n' +
    +        '    contact.save(function(updated) {\n' +
    +        '        results.innerHTML = "Contact updated.";\n' +
    +        '    },function(e) {\n' +
    +        '        results.innerHTML = "Update failed: error " + e.code;\n' +
    +        '    });\n' +
    +        '}, function(e) {\n' +
    +        '    results.innerHTML = "Search failed: error " + e.code;\n' +
    +        '}, obj);';
    +
    +    return result;
    +};
    +
    +module.exports.getRemoveTestContactsCode = function () {
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'results.innerHTML = "";\n' +
    +        'var obj = new ContactFindOptions();\n' +
    +        'obj.filter = "DeleteMe";\n' +
    +        'obj.multiple = true;\n' +
    +        'navigator.contacts.find(["note"], function(contacts) {\n' +
    +        '    var removes = [];\n' +
    +        '    contacts.forEach(function(contact) {\n' +
    +        '        removes.push(contact);\n' +
    +        '    });\n' +
    +        '    if (removes.length === 0) {\n' +
    +        '        results.innerHTML = "No contacts to remove";\n' +
    +        '        return;\n' +
    +        '    }\n' +
    +
    +        '   var nextToRemove;\n' +
    +        '   if (removes.length > 0) {\n' +
    +        '        nextToRemove = removes.shift();\n' +
    +        '    }\n' +
    +
    +        '    function removeNext(item) {\n' +
    +        '        if (typeof item === "undefined") {\n' +
    +        '            return;\n' +
    +        '        }\n' +
    +
    +        '        if (removes.length > 0) {\n' +
    +        '            nextToRemove = removes.shift();\n' +
    +        '        } else {\n' +
    +        '            nextToRemove = undefined;\n' +
    +        '        }\n' +
    +
    +        '        item.remove(function removeSucceeded() {\n' +
    +        '            results.innerHTML += "Removed a contact with ID " + item.id + "<br/>";\n' +
    +        '            removeNext(nextToRemove);\n' +
    +        '        }, function removeFailed() {\n' +
    +        '            results.innerHTML += "Failed to remove a contact with ID " + item.id + "<br/>";\n' +
    +        '            removeNext(nextToRemove);\n' +
    +        '        });\n' +
    +        '    }\n' +
    +        '    removeNext(nextToRemove);\n' +
    +        '}, function(e) {\n' +
    +        '   results.innerHTML = "Search failed: error " + e.code;\n' +
    +        '}, obj);';
    +
    +    return result;
    +};
    --- End diff --
    
    Looks like there is also executeAsync which could be used to notify when win or fail callback is called: http://webdriver.io/api/protocol/executeAsync.html


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by dblotsky <gi...@git.apache.org>.
Github user dblotsky commented on a diff in the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#discussion_r55780654
  
    --- Diff: appium-tests/android/android.spec.js ---
    @@ -0,0 +1,338 @@
    +/*jshint node: true, jasmine: true */
    +/*
    + *
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + *
    +*/
    +
    +// these tests are meant to be executed by Cordova Medic Appium runner
    +// you can find it here: https://github.com/apache/cordova-medic/
    +// it is not necessary to do a full CI setup to run these tests
    +// just run "node cordova-medic/medic/medic.js appium --platform android --plugins cordova-plugin-contacts"
    +
    +'use strict';
    +
    +var wdHelper = require('../helpers/wdHelper');
    +var screenshotHelper = require('../helpers/screenshotHelper');
    +var contactsHelper = require('../helpers/contactsHelper');
    +
    +var STARTING_MESSAGE = 'Ready for action!';
    +var MINUTE = 60 * 1000;
    +var DEFAULT_WEBVIEW_CONTEXT = 'WEBVIEW';
    +
    +describe('Contacts Android', function () {
    +    var driver;
    +    // the name of webview context, it will be changed to match needed context if there are named ones:
    +    var webviewContext = DEFAULT_WEBVIEW_CONTEXT;
    +    // this indicates that there was a critical error and we should try to recover:
    +    var errorFlag = false;
    +    // this indicates that we couldn't restore Appium session and should fail fast:
    +    var stopFlag = false;
    +
    +    function win() {
    +        expect(true).toBe(true);
    +    }
    +
    +    function fail(error) {
    +        if (error === 'rethrow') {
    +            throw error;
    +        }
    +        if (error && error.message) {
    +            console.log('An error occured: ' + error.message);
    +            if (error.stack) {
    +                console.log(error.stack);
    +            }
    +            expect(true).toFailWithMessage(error.message);
    +        } else if (error && typeof error === 'string') {
    +            console.log('Failed expectation: ' + error);
    +            expect(true).toFailWithMessage(error);
    +        } else {
    +            // no message provided :(
    +            expect(true).toBe(false);
    +        }
    +        return screenshotHelper
    +            .saveScreenshot(driver)
    +            .finally(function() {
    +                throw 'rethrow';
    +            });
    +    }
    +
    +    function enterTest() {
    +        return driver
    +            // trying to determine where we are
    +            .context(webviewContext)
    +            .fail(function (error) {
    +                return fail(error);
    +            })
    +            .elementById('info')
    +            .then(function () {
    +                return driver; //we're already on the test screen
    +            }, function () {
    +                return driver
    +                    .elementById('middle')
    +                    .then(function () {
    +                        return driver
    +                            // we're on autotests page, we should go to start page
    +                            .execute('window.location = "../index.html"')
    +                            .sleep(5000)
    +                            .fail(function () {
    +                                errorFlag = true;
    +                                throw 'Couldn\'t find start page.';
    +                            });
    +                    }, function () {
    +                        return; // no-op
    +                    })
    +                    // unknown starting page: no 'info' div
    +                    // adding it manually
    +                    .execute('var info = document.createElement("div"); ' +
    +                             'info.id = "info"; ' +
    +                             'document.body.appendChild(info);');
    +            })
    +            .sleep(5000);
    +    }
    +
    +    function getDriver() {
    +        driver = wdHelper.getDriver('Android');
    +        return driver;
    +    }
    +
    +    function checkStopFlag() {
    +        if (stopFlag) {
    +            fail('Something went wrong: the stopFlag is on. Please see the log for more details.');
    +        }
    +        return stopFlag;
    +    }
    +
    +    beforeEach(function () {
    +        jasmine.addMatchers({
    +            toFailWithMessage: function () {
    +                return {
    +                    compare: function (actual, msg) {
    +                        console.log('Failing with message: ' + msg);
    +                        var result = {
    +                            pass: false,
    +                            message: msg
    +                        };
    +                        // status 6 means that we've lost the session
    +                        // status 7 means that Appium couldn't find an element
    +                        // both these statuses mean that the test has failed but
    +                        // we should try to recreate the session for the following tests
    +                        if (msg.indexOf('Error response status: 6') >= 0 ||
    +                            msg.indexOf('Error response status: 7') >= 0) {
    +                            errorFlag = true;
    +                        }
    +                        return result;
    +                    }
    +                };
    +            },
    +            toContain: function () {
    --- End diff --
    
    There is a `toContain` matcher in [Jasmine's standard matchers][matchers].
    
    [matchers]: http://jasmine.github.io/edge/introduction.html#section-Included_Matchers


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by dblotsky <gi...@git.apache.org>.
Github user dblotsky commented on a diff in the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#discussion_r55781014
  
    --- Diff: appium-tests/helpers/wdHelper.js ---
    @@ -0,0 +1,68 @@
    +/* jshint node: true */
    +/*
    + *
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + *
    +*/
    +
    +'use strict';
    +
    +var wd = global.WD || require('wd');
    +var driver;
    +
    +module.exports.getDriver = function (platform, callback) {
    +    var serverConfig = {
    +        host: 'localhost',
    +        port: 4723
    --- End diff --
    
    Please factor these out into constants.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by sgrebnov <gi...@git.apache.org>.
Github user sgrebnov commented on a diff in the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#discussion_r56311100
  
    --- Diff: appium-tests/helpers/contactsHelper.js ---
    @@ -0,0 +1,222 @@
    +/* jshint node: true */
    +/*
    + *
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + *
    +*/
    +
    +'use strict';
    +
    +function prepare(item) {
    +    if (typeof item === 'object') {
    +        return JSON.stringify(item);
    +    }
    +    if (typeof item === 'string') {
    +        return '"' + item + '"';
    +    }
    +    return undefined;
    +}
    +
    +module.exports.getContactName = function (firstName, lastName) {
    +    return {
    +        formatted: firstName == lastName === undefined ? null : firstName + ' ' + lastName,
    +        familyName: lastName,
    +        givenName: firstName,
    +        middleName: ''
    +    };
    +};
    +
    +module.exports.getAddContactCode = function (displayName, contactName, phoneNumber) {
    +    var preparedDisplayName = prepare(displayName);
    +    console.log('preparedDisplayName is ' + preparedDisplayName);
    +    var preparedContactName = prepare(contactName);
    +    var preparedPhoneNumber = prepare(phoneNumber);
    +
    +    var result =
    +        'try {\n' +
    +        '    var results = document.getElementById("info");\n' +
    +        '    var contact = navigator.contacts.create({ "displayName": ' + preparedDisplayName + ', "name": ' + preparedContactName + ', "note": "DeleteMe" });\n' +
    +
    +        '    var phoneNumbers = [1];\n' +
    +        '    phoneNumbers[0] = new ContactField("work", ' + preparedPhoneNumber + ', true);\n' +
    +        '    contact.phoneNumbers = phoneNumbers;\n' +
    +
    +        '    contact.save(function() {\n' +
    +        '        results.innerHTML = "' + (displayName || 'Nameless contact') + ' saved.";\n' +
    +        '    }, function(e) {\n' +
    +        '        if (e.code === ContactError.NOT_SUPPORTED_ERROR) {\n' +
    +        '            results.innerHTML = "Saving contacts not supported.";\n' +
    +        '        } else {\n' +
    +        '            results.innerHTML = "Contact save failed: error " + e.code;\n' +
    +        '        }\n' +
    +        '    });\n' +
    +        '} catch (e) {\n' +
    +        '    var results = document.getElementById("info");\n' +
    +        '    results.innerHTML = "ERROR: " + e.code;\n' +
    +        '}\n';
    +
    +    return result;
    +};
    +
    +module.exports.getGetContactsCode = function (filter) {
    +    var preparedFilter = prepare(filter);
    +
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'var obj = new ContactFindOptions();\n' +
    +        'if (' + preparedFilter + ') {\n' +
    +        '    obj.filter = ' + preparedFilter + ';\n' +
    +        '}\n' +
    +        'obj.multiple = true;\n' +
    +        'navigator.contacts.find(["displayName", "name", "phoneNumbers", "emails", "urls", "note"], function(contacts) {\n' +
    +        '    var s = "";\n' +
    +        '    if (contacts.length === 0) {\n' +
    +        '        s = "No contacts found";\n' +
    +        '    } else {\n' +
    +        '        s = "Number of contacts: " + contacts.length + "<br><table width=100%><tr><th>Name</th><td>Phone</td><td>Email</td></tr>";\n' +
    +        '        for (var i = 0; i < contacts.length; i++) {\n' +
    +        '            var contact = contacts[i];\n' +
    +        '            var contactNameTag = contact.name ? "<tr><td>" + contact.name.formatted + "</td><td>" : "<tr><td>(No Name)</td><td>";\n' +
    +        '            s = s + contactNameTag;\n' +
    +        '            if (contact.phoneNumbers && contact.phoneNumbers.length > 0) {\n' +
    +        '                s = s + contact.phoneNumbers[0].value;\n' +
    +        '            }\n' +
    +        '            s = s + "</td><td>";\n' +
    +        '            if (contact.emails && contact.emails.length > 0) {\n' +
    +        '                s = s + contact.emails[0].value;\n' +
    +        '            }\n' +
    +        '            s = s + "</td></tr>";\n' +
    +        '    }\n' +
    +        '        s = s + "</table>";\n' +
    +        '    }\n' +
    +        '    results.innerHTML = s;\n' +
    +        '}, function(e) {\n' +
    +        '   results.innerHTML = "Search failed: error " + e.code;\n' +
    +        '}, obj);';
    +
    +    return result;
    +};
    +
    +module.exports.getPickContactCode = function () {
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'navigator.contacts.pickContact(\n' +
    +        '    function (contact) {\n' +
    +        '        results.innerHTML = contact ?\n' +
    +        '            "Picked contact: <pre>" + JSON.stringify(contact, null, 4) + "</pre>" :\n' +
    +        '            "No contacts found";\n' +
    +        '    },\n' +
    +        '    function (e) {\n' +
    +        '        results.innerHTML = e && e.code === ContactError.OPERATION_CANCELLED_ERROR ?\n' +
    +        '                "Pick cancelled" :\n' +
    +        '                "Pick failed: " + (e && e.code);\n' +
    +        '    }\n' +
    +        ');';
    +
    +    return result;
    +};
    +
    +module.exports.getRenameContactCode = function (oldDisplayName, newDisplayName, newName) {
    +    // these default values are copied from manual contacts tests
    +    if (!oldDisplayName) {
    +        oldDisplayName = 'Dooney Evans';
    +    }
    +    if (!newDisplayName) {
    +        newDisplayName = 'Urist McContact';
    +    }
    +    if (!newName) {
    +        newName = module.exports.getContactName('Urist', 'McContact');
    +    }
    +    var preparedOldDisplayName = prepare(oldDisplayName);
    +    var preparedNewDisplayName = prepare(newDisplayName);
    +    var preparedNewName = prepare(newName);
    +
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'var obj = new ContactFindOptions();\n' +
    +        'obj.filter = ' + preparedOldDisplayName + ';\n' +
    +        'obj.multiple = false;\n' +
    +
    +        'navigator.contacts.find(["displayName", "name"], function(contacts) {\n' +
    +        '    if (contacts.length === 0) {\n' +
    +        '        results.innerHTML = "No contacts to update.";\n' +
    +        '        return;\n' +
    +        '    }\n' +
    +        '    var contact = contacts[0];\n' +
    +        '    contact.displayName = ' + preparedNewDisplayName + ';\n' +
    +        '    contact.name = ' + preparedNewName + ';\n' +
    +        '    contact.save(function(updated) {\n' +
    +        '        results.innerHTML = "Contact updated.";\n' +
    +        '    },function(e) {\n' +
    +        '        results.innerHTML = "Update failed: error " + e.code;\n' +
    +        '    });\n' +
    +        '}, function(e) {\n' +
    +        '    results.innerHTML = "Search failed: error " + e.code;\n' +
    +        '}, obj);';
    +
    +    return result;
    +};
    +
    +module.exports.getRemoveTestContactsCode = function () {
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'results.innerHTML = "";\n' +
    +        'var obj = new ContactFindOptions();\n' +
    +        'obj.filter = "DeleteMe";\n' +
    +        'obj.multiple = true;\n' +
    +        'navigator.contacts.find(["note"], function(contacts) {\n' +
    +        '    var removes = [];\n' +
    +        '    contacts.forEach(function(contact) {\n' +
    +        '        removes.push(contact);\n' +
    +        '    });\n' +
    +        '    if (removes.length === 0) {\n' +
    +        '        results.innerHTML = "No contacts to remove";\n' +
    +        '        return;\n' +
    +        '    }\n' +
    +
    +        '   var nextToRemove;\n' +
    +        '   if (removes.length > 0) {\n' +
    +        '        nextToRemove = removes.shift();\n' +
    +        '    }\n' +
    +
    +        '    function removeNext(item) {\n' +
    +        '        if (typeof item === "undefined") {\n' +
    +        '            return;\n' +
    +        '        }\n' +
    +
    +        '        if (removes.length > 0) {\n' +
    +        '            nextToRemove = removes.shift();\n' +
    +        '        } else {\n' +
    +        '            nextToRemove = undefined;\n' +
    +        '        }\n' +
    +
    +        '        item.remove(function removeSucceeded() {\n' +
    +        '            results.innerHTML += "Removed a contact with ID " + item.id + "<br/>";\n' +
    +        '            removeNext(nextToRemove);\n' +
    +        '        }, function removeFailed() {\n' +
    +        '            results.innerHTML += "Failed to remove a contact with ID " + item.id + "<br/>";\n' +
    +        '            removeNext(nextToRemove);\n' +
    +        '        });\n' +
    +        '    }\n' +
    +        '    removeNext(nextToRemove);\n' +
    +        '}, function(e) {\n' +
    +        '   results.innerHTML = "Search failed: error " + e.code;\n' +
    +        '}, obj);';
    +
    +    return result;
    +};
    --- End diff --
    
    writing code in strings is a bad pattern indeed. But I don't like the idea to rely on buttons/divs from manual tests. 
    
    I propose the following:
    1. Step1. Add helper function to appium which is based on execute, but takes single PARAMETERLESS function as argument repreneting function to be executed on app side. So you will be able to do `return execute(fn.toString())` ti run js code on app side, for example
    ```
    .execute(function() {
        navigator.contacts.create('someParams', winCallback, falseCallback)
    })
    ```
    2. Step2. Inject gloabal win and fail functions to be used on app context as a first step before running tests, so you will be able to pass them in all functions, for example `__appiumWinCallback and __appiumFailCallback`
    
    So you will be able to run the following code
    ```
    .execute(function() {
        navigator.contacts.create('someParams', __appiumWinCallback, __appiumFailCallback)
    })
    ```
    3. Step2. Inject extra function to return  last execution results (should be based on __appiumWinCallback and __appiumFailCallback implementations), sample usage (appium side)
    
    ```
    var result = execute('_appiumLastTestResult')
    result.win <- raw result from __appiumWinCallback callback (if called)
    result.fail <- raw result from __appiumFailCallback fail 
    
    ```
    



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by dblotsky <gi...@git.apache.org>.
Github user dblotsky commented on a diff in the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#discussion_r55780731
  
    --- Diff: appium-tests/android/android.spec.js ---
    @@ -0,0 +1,338 @@
    +/*jshint node: true, jasmine: true */
    +/*
    + *
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + *
    +*/
    +
    +// these tests are meant to be executed by Cordova Medic Appium runner
    +// you can find it here: https://github.com/apache/cordova-medic/
    +// it is not necessary to do a full CI setup to run these tests
    +// just run "node cordova-medic/medic/medic.js appium --platform android --plugins cordova-plugin-contacts"
    +
    +'use strict';
    +
    +var wdHelper = require('../helpers/wdHelper');
    +var screenshotHelper = require('../helpers/screenshotHelper');
    +var contactsHelper = require('../helpers/contactsHelper');
    +
    +var STARTING_MESSAGE = 'Ready for action!';
    +var MINUTE = 60 * 1000;
    +var DEFAULT_WEBVIEW_CONTEXT = 'WEBVIEW';
    +
    +describe('Contacts Android', function () {
    +    var driver;
    +    // the name of webview context, it will be changed to match needed context if there are named ones:
    +    var webviewContext = DEFAULT_WEBVIEW_CONTEXT;
    +    // this indicates that there was a critical error and we should try to recover:
    +    var errorFlag = false;
    +    // this indicates that we couldn't restore Appium session and should fail fast:
    +    var stopFlag = false;
    +
    +    function win() {
    +        expect(true).toBe(true);
    +    }
    +
    +    function fail(error) {
    +        if (error === 'rethrow') {
    +            throw error;
    +        }
    +        if (error && error.message) {
    +            console.log('An error occured: ' + error.message);
    +            if (error.stack) {
    +                console.log(error.stack);
    +            }
    +            expect(true).toFailWithMessage(error.message);
    +        } else if (error && typeof error === 'string') {
    +            console.log('Failed expectation: ' + error);
    +            expect(true).toFailWithMessage(error);
    +        } else {
    +            // no message provided :(
    +            expect(true).toBe(false);
    +        }
    +        return screenshotHelper
    +            .saveScreenshot(driver)
    +            .finally(function() {
    +                throw 'rethrow';
    +            });
    +    }
    +
    +    function enterTest() {
    +        return driver
    +            // trying to determine where we are
    +            .context(webviewContext)
    +            .fail(function (error) {
    +                return fail(error);
    +            })
    +            .elementById('info')
    +            .then(function () {
    +                return driver; //we're already on the test screen
    +            }, function () {
    +                return driver
    +                    .elementById('middle')
    +                    .then(function () {
    +                        return driver
    +                            // we're on autotests page, we should go to start page
    +                            .execute('window.location = "../index.html"')
    +                            .sleep(5000)
    +                            .fail(function () {
    +                                errorFlag = true;
    +                                throw 'Couldn\'t find start page.';
    +                            });
    +                    }, function () {
    +                        return; // no-op
    +                    })
    +                    // unknown starting page: no 'info' div
    +                    // adding it manually
    +                    .execute('var info = document.createElement("div"); ' +
    +                             'info.id = "info"; ' +
    +                             'document.body.appendChild(info);');
    +            })
    +            .sleep(5000);
    +    }
    +
    +    function getDriver() {
    +        driver = wdHelper.getDriver('Android');
    +        return driver;
    +    }
    +
    +    function checkStopFlag() {
    +        if (stopFlag) {
    +            fail('Something went wrong: the stopFlag is on. Please see the log for more details.');
    +        }
    +        return stopFlag;
    +    }
    +
    +    beforeEach(function () {
    +        jasmine.addMatchers({
    +            toFailWithMessage: function () {
    +                return {
    +                    compare: function (actual, msg) {
    +                        console.log('Failing with message: ' + msg);
    +                        var result = {
    +                            pass: false,
    +                            message: msg
    +                        };
    +                        // status 6 means that we've lost the session
    +                        // status 7 means that Appium couldn't find an element
    +                        // both these statuses mean that the test has failed but
    +                        // we should try to recreate the session for the following tests
    +                        if (msg.indexOf('Error response status: 6') >= 0 ||
    +                            msg.indexOf('Error response status: 7') >= 0) {
    +                            errorFlag = true;
    +                        }
    +                        return result;
    +                    }
    +                };
    +            },
    +            toContain: function () {
    +                return {
    +                    compare: function (actual, expected) {
    +                        var result = {
    +                            pass: true,
    +                            message: ''
    +                        };
    +                        if (actual.indexOf(expected) < 0)  {
    +                            result.pass = false;
    +                            result.message = 'Expected ' + actual + ' to contain ' + expected;
    +                        }
    +                        return result;
    +                    }
    +                };
    +            }
    +        });
    +    });
    +
    +    it('camera.ui.util configuring driver and starting a session', function (done) {
    +        stopFlag = true; // just in case of timeout
    +        getDriver().then(function () {
    +            stopFlag = false;
    +        }, function (error) {
    +            return fail(error);
    +        })
    +        .finally(done);
    +    }, 5 * MINUTE);
    +
    +    it('camera.ui.util determine webview context name', function (done) {
    +        var i = 0;
    +        return driver
    +            .contexts(function (err, contexts) {
    +                if (err) {
    +                    console.log(err);
    +                }
    +                for (i = 0; i < contexts.length; i++) {
    +                    if (contexts[i].indexOf('mobilespec') >= 0) {
    +                        webviewContext = contexts[i];
    +                    }
    +                }
    +                done();
    +            });
    +    }, MINUTE);
    +
    +    describe("tests", function () {
    +        beforeEach(function (done) {
    +            // prepare the app for the test
    +            if (!stopFlag) {
    +                return driver
    +                    .context(webviewContext)
    +                    .then(function () {
    +                        return driver; // no-op
    +                    }, function (error) {
    +                        expect(true).toFailWithMessage(error);
    +                    })
    +                    .execute('document.getElementById("info").innerHTML = "' + STARTING_MESSAGE + '";')
    +                    .finally(done);
    +            }
    +            done();
    +        }, 3 * MINUTE);
    +
    +        afterEach(function (done) {
    +            if (!errorFlag || stopFlag) {
    +                // either there's no error or we've failed irrecoverably
    +                // nothing to worry about!
    +                done();
    +                return;
    +            }
    +            // recreate the session if there was a critical error in a previous spec
    +            stopFlag = true; // we're going to set this to false if we're able to restore the session
    --- End diff --
    
    Please place comments on their own line.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by alsorokin <gi...@git.apache.org>.
Github user alsorokin commented on a diff in the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#discussion_r55803572
  
    --- Diff: appium-tests/android/android.spec.js ---
    @@ -0,0 +1,338 @@
    +/*jshint node: true, jasmine: true */
    +/*
    + *
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + *
    +*/
    +
    +// these tests are meant to be executed by Cordova Medic Appium runner
    +// you can find it here: https://github.com/apache/cordova-medic/
    +// it is not necessary to do a full CI setup to run these tests
    +// just run "node cordova-medic/medic/medic.js appium --platform android --plugins cordova-plugin-contacts"
    +
    +'use strict';
    +
    +var wdHelper = require('../helpers/wdHelper');
    +var screenshotHelper = require('../helpers/screenshotHelper');
    +var contactsHelper = require('../helpers/contactsHelper');
    +
    +var STARTING_MESSAGE = 'Ready for action!';
    +var MINUTE = 60 * 1000;
    +var DEFAULT_WEBVIEW_CONTEXT = 'WEBVIEW';
    +
    +describe('Contacts Android', function () {
    +    var driver;
    +    // the name of webview context, it will be changed to match needed context if there are named ones:
    +    var webviewContext = DEFAULT_WEBVIEW_CONTEXT;
    +    // this indicates that there was a critical error and we should try to recover:
    +    var errorFlag = false;
    +    // this indicates that we couldn't restore Appium session and should fail fast:
    +    var stopFlag = false;
    +
    +    function win() {
    +        expect(true).toBe(true);
    +    }
    +
    +    function fail(error) {
    +        if (error === 'rethrow') {
    +            throw error;
    +        }
    +        if (error && error.message) {
    +            console.log('An error occured: ' + error.message);
    +            if (error.stack) {
    +                console.log(error.stack);
    +            }
    +            expect(true).toFailWithMessage(error.message);
    +        } else if (error && typeof error === 'string') {
    +            console.log('Failed expectation: ' + error);
    +            expect(true).toFailWithMessage(error);
    +        } else {
    +            // no message provided :(
    +            expect(true).toBe(false);
    +        }
    +        return screenshotHelper
    +            .saveScreenshot(driver)
    +            .finally(function() {
    +                throw 'rethrow';
    +            });
    +    }
    +
    +    function enterTest() {
    +        return driver
    +            // trying to determine where we are
    +            .context(webviewContext)
    +            .fail(function (error) {
    +                return fail(error);
    +            })
    +            .elementById('info')
    +            .then(function () {
    +                return driver; //we're already on the test screen
    +            }, function () {
    +                return driver
    +                    .elementById('middle')
    +                    .then(function () {
    +                        return driver
    +                            // we're on autotests page, we should go to start page
    +                            .execute('window.location = "../index.html"')
    +                            .sleep(5000)
    +                            .fail(function () {
    +                                errorFlag = true;
    +                                throw 'Couldn\'t find start page.';
    +                            });
    +                    }, function () {
    +                        return; // no-op
    +                    })
    +                    // unknown starting page: no 'info' div
    +                    // adding it manually
    +                    .execute('var info = document.createElement("div"); ' +
    +                             'info.id = "info"; ' +
    +                             'document.body.appendChild(info);');
    +            })
    +            .sleep(5000);
    +    }
    +
    +    function getDriver() {
    +        driver = wdHelper.getDriver('Android');
    +        return driver;
    +    }
    +
    +    function checkStopFlag() {
    +        if (stopFlag) {
    +            fail('Something went wrong: the stopFlag is on. Please see the log for more details.');
    +        }
    +        return stopFlag;
    +    }
    +
    +    beforeEach(function () {
    +        jasmine.addMatchers({
    +            toFailWithMessage: function () {
    +                return {
    +                    compare: function (actual, msg) {
    +                        console.log('Failing with message: ' + msg);
    +                        var result = {
    +                            pass: false,
    +                            message: msg
    +                        };
    +                        // status 6 means that we've lost the session
    +                        // status 7 means that Appium couldn't find an element
    +                        // both these statuses mean that the test has failed but
    +                        // we should try to recreate the session for the following tests
    +                        if (msg.indexOf('Error response status: 6') >= 0 ||
    +                            msg.indexOf('Error response status: 7') >= 0) {
    +                            errorFlag = true;
    +                        }
    +                        return result;
    +                    }
    +                };
    +            },
    +            toContain: function () {
    +                return {
    +                    compare: function (actual, expected) {
    +                        var result = {
    +                            pass: true,
    +                            message: ''
    +                        };
    +                        if (actual.indexOf(expected) < 0)  {
    +                            result.pass = false;
    +                            result.message = 'Expected ' + actual + ' to contain ' + expected;
    +                        }
    +                        return result;
    +                    }
    +                };
    +            }
    +        });
    +    });
    +
    +    it('camera.ui.util configuring driver and starting a session', function (done) {
    +        stopFlag = true; // just in case of timeout
    +        getDriver().then(function () {
    +            stopFlag = false;
    +        }, function (error) {
    +            return fail(error);
    +        })
    +        .finally(done);
    +    }, 5 * MINUTE);
    --- End diff --
    
    There is an expect only if the driver has failed to create the session.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by dblotsky <gi...@git.apache.org>.
Github user dblotsky commented on a diff in the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#discussion_r55780306
  
    --- Diff: appium-tests/ios/ios.spec.js ---
    @@ -0,0 +1,352 @@
    +/*jshint node: true, jasmine: true */
    +/*
    + *
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + *
    +*/
    +
    +// these tests are meant to be executed by Cordova Medic Appium runner
    +// you can find it here: https://github.com/apache/cordova-medic/
    +// it is not necessary to do a full CI setup to run these tests
    +// just run "node cordova-medic/medic/medic.js appium --platform ios --plugins cordova-plugin-contacts"
    +
    +'use strict';
    +
    +var wdHelper = require('../helpers/wdHelper');
    +var screenshotHelper = require('../helpers/screenshotHelper');
    +var contactsHelper = require('../helpers/contactsHelper');
    +var unorm = global.unorm || require("unorm");
    +
    +var STARTING_MESSAGE = 'Ready for action!';
    +var MINUTE = 60 * 1000;
    +var DEFAULT_WEBVIEW_CONTEXT = 'WEBVIEW_1';
    +
    +describe('contacts tests iOS', function () {
    +    var driver;
    +    // the name of webview context, it will be changed to match needed context if there are named ones:
    +    var webviewContext = DEFAULT_WEBVIEW_CONTEXT;
    +    // this indicates that there was a critical error and we should try to recover:
    +    var errorFlag = false;
    +    // this indicates that we couldn't restore Appium session and should fail fast:
    +    var stopFlag = false;
    +
    +    function win() {
    +        expect(true).toBe(true);
    +    }
    +
    +    function fail(error) {
    +        if (error === 'rethrow') {
    +            throw error;
    +        }
    +        if (error && error.message) {
    +            console.log('An error occured: ' + error.message);
    +            if (error.stack) {
    +                console.log(error.stack);
    +            }
    +            expect(true).toFailWithMessage(error.message);
    +        } else if (error && typeof error === 'string') {
    +            console.log('Failed expectation: ' + error);
    +            expect(true).toFailWithMessage(error);
    +        } else {
    +            // no message provided :(
    +            expect(true).toBe(false);
    +        }
    +        return screenshotHelper
    +            .saveScreenshot(driver)
    +            .finally(function() {
    +                throw 'rethrow';
    +            });
    +    }
    +
    +    function enterTest() {
    +        return driver
    +            // trying to determine where we are
    +            .context(webviewContext)
    +            .fail(function (error) {
    +                return fail(error);
    +            })
    +            .elementById('info')
    +            .then(function () {
    +                return driver; //we're already on the test screen
    +            }, function () {
    +                return driver
    +                    .elementById('middle')
    +                    .then(function () {
    +                        return driver
    +                            // we're on autotests page, we should go to start page
    +                            .execute('window.location = "../index.html"')
    +                            .sleep(5000)
    +                            .fail(function () {
    +                                errorFlag = true;
    +                                throw 'Couldn\'t find start page.';
    +                            });
    +                    }, function () {
    +                        return; // no-op
    +                    })
    +                    // unknown starting page: no 'info' div
    +                    // adding it manually
    +                    .execute('var info = document.createElement("div"); ' +
    +                             'info.id = "info"; ' +
    +                             'document.body.appendChild(info);');
    +            })
    +            .then(win, fail)
    +            .sleep(5000);
    +    }
    +
    +    function getDriver() {
    +        driver = wdHelper.getDriver('iOS');
    +        return driver;
    +    }
    +
    +    function checkStopFlag() {
    +        if (stopFlag) {
    +            fail('Something went wrong: the stopFlag is on. Please see the log for more details.');
    +        }
    +        return stopFlag;
    +    }
    +
    +    beforeEach(function () {
    +        jasmine.addMatchers({
    +            toFailWithMessage : function () {
    +                return {
    +                    compare: function (actual, msg) {
    +                        console.log('Failing with message: ' + msg);
    +                        var result = {
    +                            pass: false,
    +                            message: msg
    +                        };
    +                        // status 6 means that we've lost the session
    +                        // status 7 means that Appium couldn't find an element
    +                        // both these statuses mean that the test has failed but
    +                        // we should try to recreate the session for the following tests
    +                        if (msg.indexOf('Error response status: 6') >= 0 ||
    +                            msg.indexOf('Error response status: 7') >= 0) {
    +                            errorFlag = true;
    +                        }
    +                        return result;
    +                    }
    +                };
    +            },
    +            toContain: function () {
    +                return {
    +                    compare: function (actual, expected) {
    +                        var result = {
    +                            pass: true,
    +                            message: ''
    +                        };
    +                        if (actual.indexOf(expected) < 0)  {
    +                            result.pass = false;
    +                            result.message = 'Expected ' + actual + ' to contain ' + expected;
    +                        }
    +                        return result;
    +                    }
    +                };
    +            }
    +        });
    +    });
    +
    +    it('camera.ui.util configuring driver and starting a session', function (done) {
    +        stopFlag = true; // just in case of timeout
    +        getDriver().then(function () {
    +            stopFlag = false;
    +        }, function (error) {
    +            return fail(error);
    +        })
    +        .then(function() {
    +            return driver.contexts();
    +        })
    +        .finally(done);
    +    }, 5 * MINUTE);
    +
    +    it('camera.ui.util determine webview context name', function (done) {
    +        return driver
    +            .contexts()
    +            .then(function onSuccess (contexts) {
    +                var found = false;
    +                var i;
    +                // take the last named context
    +                for (i = 0; i < contexts.length; i++) {
    +                    if (contexts[i].indexOf('mobilespec') >= 0) {
    +                        webviewContext = contexts[i];
    +                        found = true;
    +                    }
    +                }
    +                // if no named context is found then take the last webview context
    +                if (!found) {
    +                    for (i = 0; i < contexts.length ; i++) {
    +                        if (contexts[i].indexOf('WEBVIEW') >= 0) {
    +                            webviewContext = contexts[i];
    +                        }
    +                    }
    +                }
    +                console.log('Webview context is ' + webviewContext);
    +                done();
    +            }, function onError (err) {
    +                console.log(err);
    +            })
    +            .finally(done);
    +    }, MINUTE);
    +
    +    describe('specs', function () {
    --- End diff --
    
    Which specs?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by alsorokin <gi...@git.apache.org>.
Github user alsorokin commented on a diff in the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#discussion_r55803966
  
    --- Diff: appium-tests/helpers/contactsHelper.js ---
    @@ -0,0 +1,222 @@
    +/* jshint node: true */
    +/*
    + *
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + *
    +*/
    +
    +'use strict';
    +
    +function prepare(item) {
    +    if (typeof item === 'object') {
    +        return JSON.stringify(item);
    +    }
    +    if (typeof item === 'string') {
    +        return '"' + item + '"';
    +    }
    +    return undefined;
    +}
    +
    +module.exports.getContactName = function (firstName, lastName) {
    +    return {
    +        formatted: firstName == lastName === undefined ? null : firstName + ' ' + lastName,
    +        familyName: lastName,
    +        givenName: firstName,
    +        middleName: ''
    +    };
    +};
    +
    +module.exports.getAddContactCode = function (displayName, contactName, phoneNumber) {
    +    var preparedDisplayName = prepare(displayName);
    +    console.log('preparedDisplayName is ' + preparedDisplayName);
    +    var preparedContactName = prepare(contactName);
    +    var preparedPhoneNumber = prepare(phoneNumber);
    +
    +    var result =
    +        'try {\n' +
    +        '    var results = document.getElementById("info");\n' +
    +        '    var contact = navigator.contacts.create({ "displayName": ' + preparedDisplayName + ', "name": ' + preparedContactName + ', "note": "DeleteMe" });\n' +
    +
    +        '    var phoneNumbers = [1];\n' +
    +        '    phoneNumbers[0] = new ContactField("work", ' + preparedPhoneNumber + ', true);\n' +
    +        '    contact.phoneNumbers = phoneNumbers;\n' +
    +
    +        '    contact.save(function() {\n' +
    +        '        results.innerHTML = "' + (displayName || 'Nameless contact') + ' saved.";\n' +
    +        '    }, function(e) {\n' +
    +        '        if (e.code === ContactError.NOT_SUPPORTED_ERROR) {\n' +
    +        '            results.innerHTML = "Saving contacts not supported.";\n' +
    +        '        } else {\n' +
    +        '            results.innerHTML = "Contact save failed: error " + e.code;\n' +
    +        '        }\n' +
    +        '    });\n' +
    +        '} catch (e) {\n' +
    +        '    var results = document.getElementById("info");\n' +
    +        '    results.innerHTML = "ERROR: " + e.code;\n' +
    +        '}\n';
    +
    +    return result;
    +};
    +
    +module.exports.getGetContactsCode = function (filter) {
    +    var preparedFilter = prepare(filter);
    +
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'var obj = new ContactFindOptions();\n' +
    +        'if (' + preparedFilter + ') {\n' +
    +        '    obj.filter = ' + preparedFilter + ';\n' +
    +        '}\n' +
    +        'obj.multiple = true;\n' +
    +        'navigator.contacts.find(["displayName", "name", "phoneNumbers", "emails", "urls", "note"], function(contacts) {\n' +
    +        '    var s = "";\n' +
    +        '    if (contacts.length === 0) {\n' +
    +        '        s = "No contacts found";\n' +
    +        '    } else {\n' +
    +        '        s = "Number of contacts: " + contacts.length + "<br><table width=100%><tr><th>Name</th><td>Phone</td><td>Email</td></tr>";\n' +
    +        '        for (var i = 0; i < contacts.length; i++) {\n' +
    +        '            var contact = contacts[i];\n' +
    +        '            var contactNameTag = contact.name ? "<tr><td>" + contact.name.formatted + "</td><td>" : "<tr><td>(No Name)</td><td>";\n' +
    +        '            s = s + contactNameTag;\n' +
    +        '            if (contact.phoneNumbers && contact.phoneNumbers.length > 0) {\n' +
    +        '                s = s + contact.phoneNumbers[0].value;\n' +
    +        '            }\n' +
    +        '            s = s + "</td><td>";\n' +
    +        '            if (contact.emails && contact.emails.length > 0) {\n' +
    +        '                s = s + contact.emails[0].value;\n' +
    +        '            }\n' +
    +        '            s = s + "</td></tr>";\n' +
    +        '    }\n' +
    +        '        s = s + "</table>";\n' +
    +        '    }\n' +
    +        '    results.innerHTML = s;\n' +
    +        '}, function(e) {\n' +
    +        '   results.innerHTML = "Search failed: error " + e.code;\n' +
    +        '}, obj);';
    +
    +    return result;
    +};
    +
    +module.exports.getPickContactCode = function () {
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'navigator.contacts.pickContact(\n' +
    +        '    function (contact) {\n' +
    +        '        results.innerHTML = contact ?\n' +
    +        '            "Picked contact: <pre>" + JSON.stringify(contact, null, 4) + "</pre>" :\n' +
    +        '            "No contacts found";\n' +
    +        '    },\n' +
    +        '    function (e) {\n' +
    +        '        results.innerHTML = e && e.code === ContactError.OPERATION_CANCELLED_ERROR ?\n' +
    +        '                "Pick cancelled" :\n' +
    +        '                "Pick failed: " + (e && e.code);\n' +
    +        '    }\n' +
    +        ');';
    +
    +    return result;
    +};
    +
    +module.exports.getRenameContactCode = function (oldDisplayName, newDisplayName, newName) {
    +    // these default values are copied from manual contacts tests
    +    if (!oldDisplayName) {
    +        oldDisplayName = 'Dooney Evans';
    +    }
    +    if (!newDisplayName) {
    +        newDisplayName = 'Urist McContact';
    +    }
    +    if (!newName) {
    +        newName = module.exports.getContactName('Urist', 'McContact');
    +    }
    +    var preparedOldDisplayName = prepare(oldDisplayName);
    +    var preparedNewDisplayName = prepare(newDisplayName);
    +    var preparedNewName = prepare(newName);
    +
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'var obj = new ContactFindOptions();\n' +
    +        'obj.filter = ' + preparedOldDisplayName + ';\n' +
    +        'obj.multiple = false;\n' +
    +
    +        'navigator.contacts.find(["displayName", "name"], function(contacts) {\n' +
    +        '    if (contacts.length === 0) {\n' +
    +        '        results.innerHTML = "No contacts to update.";\n' +
    +        '        return;\n' +
    +        '    }\n' +
    +        '    var contact = contacts[0];\n' +
    +        '    contact.displayName = ' + preparedNewDisplayName + ';\n' +
    +        '    contact.name = ' + preparedNewName + ';\n' +
    +        '    contact.save(function(updated) {\n' +
    +        '        results.innerHTML = "Contact updated.";\n' +
    +        '    },function(e) {\n' +
    +        '        results.innerHTML = "Update failed: error " + e.code;\n' +
    +        '    });\n' +
    +        '}, function(e) {\n' +
    +        '    results.innerHTML = "Search failed: error " + e.code;\n' +
    +        '}, obj);';
    +
    +    return result;
    +};
    +
    +module.exports.getRemoveTestContactsCode = function () {
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'results.innerHTML = "";\n' +
    +        'var obj = new ContactFindOptions();\n' +
    +        'obj.filter = "DeleteMe";\n' +
    +        'obj.multiple = true;\n' +
    +        'navigator.contacts.find(["note"], function(contacts) {\n' +
    +        '    var removes = [];\n' +
    +        '    contacts.forEach(function(contact) {\n' +
    +        '        removes.push(contact);\n' +
    +        '    });\n' +
    +        '    if (removes.length === 0) {\n' +
    +        '        results.innerHTML = "No contacts to remove";\n' +
    +        '        return;\n' +
    +        '    }\n' +
    +
    +        '   var nextToRemove;\n' +
    +        '   if (removes.length > 0) {\n' +
    +        '        nextToRemove = removes.shift();\n' +
    +        '    }\n' +
    +
    +        '    function removeNext(item) {\n' +
    +        '        if (typeof item === "undefined") {\n' +
    +        '            return;\n' +
    +        '        }\n' +
    +
    +        '        if (removes.length > 0) {\n' +
    +        '            nextToRemove = removes.shift();\n' +
    +        '        } else {\n' +
    +        '            nextToRemove = undefined;\n' +
    +        '        }\n' +
    +
    +        '        item.remove(function removeSucceeded() {\n' +
    +        '            results.innerHTML += "Removed a contact with ID " + item.id + "<br/>";\n' +
    +        '            removeNext(nextToRemove);\n' +
    +        '        }, function removeFailed() {\n' +
    +        '            results.innerHTML += "Failed to remove a contact with ID " + item.id + "<br/>";\n' +
    +        '            removeNext(nextToRemove);\n' +
    +        '        });\n' +
    +        '    }\n' +
    +        '    removeNext(nextToRemove);\n' +
    +        '}, function(e) {\n' +
    +        '   results.innerHTML = "Search failed: error " + e.code;\n' +
    +        '}, obj);';
    +
    +    return result;
    +};
    --- End diff --
    
    This is the code to run on the client side. We inject it by calling `driver.execute()` from the specs.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by dblotsky <gi...@git.apache.org>.
Github user dblotsky commented on a diff in the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#discussion_r55780861
  
    --- Diff: appium-tests/helpers/contactsHelper.js ---
    @@ -0,0 +1,222 @@
    +/* jshint node: true */
    +/*
    + *
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + *
    +*/
    +
    +'use strict';
    +
    +function prepare(item) {
    --- End diff --
    
    Please give this function a more descriptive name.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by alsorokin <gi...@git.apache.org>.
Github user alsorokin commented on a diff in the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#discussion_r55803047
  
    --- Diff: appium-tests/ios/ios.spec.js ---
    @@ -0,0 +1,352 @@
    +/*jshint node: true, jasmine: true */
    +/*
    + *
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + *
    +*/
    +
    +// these tests are meant to be executed by Cordova Medic Appium runner
    +// you can find it here: https://github.com/apache/cordova-medic/
    +// it is not necessary to do a full CI setup to run these tests
    +// just run "node cordova-medic/medic/medic.js appium --platform ios --plugins cordova-plugin-contacts"
    +
    +'use strict';
    +
    +var wdHelper = require('../helpers/wdHelper');
    +var screenshotHelper = require('../helpers/screenshotHelper');
    +var contactsHelper = require('../helpers/contactsHelper');
    +var unorm = global.unorm || require("unorm");
    +
    +var STARTING_MESSAGE = 'Ready for action!';
    +var MINUTE = 60 * 1000;
    +var DEFAULT_WEBVIEW_CONTEXT = 'WEBVIEW_1';
    +
    +describe('contacts tests iOS', function () {
    +    var driver;
    +    // the name of webview context, it will be changed to match needed context if there are named ones:
    +    var webviewContext = DEFAULT_WEBVIEW_CONTEXT;
    +    // this indicates that there was a critical error and we should try to recover:
    +    var errorFlag = false;
    +    // this indicates that we couldn't restore Appium session and should fail fast:
    +    var stopFlag = false;
    +
    +    function win() {
    +        expect(true).toBe(true);
    +    }
    +
    +    function fail(error) {
    +        if (error === 'rethrow') {
    +            throw error;
    +        }
    +        if (error && error.message) {
    +            console.log('An error occured: ' + error.message);
    +            if (error.stack) {
    +                console.log(error.stack);
    +            }
    +            expect(true).toFailWithMessage(error.message);
    +        } else if (error && typeof error === 'string') {
    +            console.log('Failed expectation: ' + error);
    +            expect(true).toFailWithMessage(error);
    +        } else {
    +            // no message provided :(
    +            expect(true).toBe(false);
    +        }
    +        return screenshotHelper
    +            .saveScreenshot(driver)
    +            .finally(function() {
    +                throw 'rethrow';
    +            });
    +    }
    +
    +    function enterTest() {
    +        return driver
    +            // trying to determine where we are
    +            .context(webviewContext)
    +            .fail(function (error) {
    +                return fail(error);
    +            })
    +            .elementById('info')
    +            .then(function () {
    +                return driver; //we're already on the test screen
    +            }, function () {
    +                return driver
    +                    .elementById('middle')
    +                    .then(function () {
    +                        return driver
    +                            // we're on autotests page, we should go to start page
    +                            .execute('window.location = "../index.html"')
    +                            .sleep(5000)
    +                            .fail(function () {
    +                                errorFlag = true;
    +                                throw 'Couldn\'t find start page.';
    +                            });
    +                    }, function () {
    +                        return; // no-op
    +                    })
    +                    // unknown starting page: no 'info' div
    +                    // adding it manually
    +                    .execute('var info = document.createElement("div"); ' +
    +                             'info.id = "info"; ' +
    +                             'document.body.appendChild(info);');
    +            })
    +            .then(win, fail)
    +            .sleep(5000);
    +    }
    +
    +    function getDriver() {
    +        driver = wdHelper.getDriver('iOS');
    +        return driver;
    +    }
    +
    +    function checkStopFlag() {
    +        if (stopFlag) {
    +            fail('Something went wrong: the stopFlag is on. Please see the log for more details.');
    +        }
    +        return stopFlag;
    +    }
    +
    +    beforeEach(function () {
    +        jasmine.addMatchers({
    +            toFailWithMessage : function () {
    +                return {
    +                    compare: function (actual, msg) {
    +                        console.log('Failing with message: ' + msg);
    +                        var result = {
    +                            pass: false,
    +                            message: msg
    +                        };
    +                        // status 6 means that we've lost the session
    +                        // status 7 means that Appium couldn't find an element
    +                        // both these statuses mean that the test has failed but
    +                        // we should try to recreate the session for the following tests
    +                        if (msg.indexOf('Error response status: 6') >= 0 ||
    +                            msg.indexOf('Error response status: 7') >= 0) {
    +                            errorFlag = true;
    +                        }
    +                        return result;
    +                    }
    +                };
    +            },
    +            toContain: function () {
    +                return {
    +                    compare: function (actual, expected) {
    +                        var result = {
    +                            pass: true,
    +                            message: ''
    +                        };
    +                        if (actual.indexOf(expected) < 0)  {
    +                            result.pass = false;
    +                            result.message = 'Expected ' + actual + ' to contain ' + expected;
    +                        }
    +                        return result;
    +                    }
    +                };
    +            }
    +        });
    +    });
    +
    +    it('camera.ui.util configuring driver and starting a session', function (done) {
    +        stopFlag = true; // just in case of timeout
    +        getDriver().then(function () {
    +            stopFlag = false;
    +        }, function (error) {
    +            return fail(error);
    +        })
    +        .then(function() {
    +            return driver.contexts();
    +        })
    +        .finally(done);
    +    }, 5 * MINUTE);
    +
    +    it('camera.ui.util determine webview context name', function (done) {
    +        return driver
    +            .contexts()
    +            .then(function onSuccess (contexts) {
    +                var found = false;
    +                var i;
    +                // take the last named context
    +                for (i = 0; i < contexts.length; i++) {
    +                    if (contexts[i].indexOf('mobilespec') >= 0) {
    +                        webviewContext = contexts[i];
    +                        found = true;
    +                    }
    +                }
    +                // if no named context is found then take the last webview context
    +                if (!found) {
    +                    for (i = 0; i < contexts.length ; i++) {
    +                        if (contexts[i].indexOf('WEBVIEW') >= 0) {
    +                            webviewContext = contexts[i];
    +                        }
    +                    }
    +                }
    +                console.log('Webview context is ' + webviewContext);
    +                done();
    +            }, function onError (err) {
    +                console.log(err);
    +            })
    +            .finally(done);
    +    }, MINUTE);
    +
    +    describe('specs', function () {
    +        beforeEach(function (done) {
    +            // prepare the app for the test
    +            if (!stopFlag) {
    +                return driver
    +                    .context(webviewContext)
    +                    .then(function () {
    +                        return driver; // no-op
    +                    }, function (error) {
    +                        expect(true).toFailWithMessage(error);
    +                    })
    +                    .execute('document.getElementById("info").innerHTML = "' + STARTING_MESSAGE + '";')
    +                    .finally(done);
    +            }
    +            done();
    +        }, 3 * MINUTE);
    +
    +        afterEach(function (done) {
    +            if (!errorFlag || stopFlag) {
    +                // either there's no error or we've failed irrecoverably
    +                // nothing to worry about!
    --- End diff --
    
    At this point, the failure already has been loudly announced, this logic is just to skip current beforeEach function.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by nikhilkh <gi...@git.apache.org>.
Github user nikhilkh commented on a diff in the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#discussion_r57225303
  
    --- Diff: appium-tests/common/common.spec.js ---
    @@ -0,0 +1,321 @@
    +/*jshint node: true, jasmine: true, browser: true */
    +/*global ContactFindOptions, ContactName*/
    +
    +/*
    + *
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + *
    +*/
    +
    +// these tests are meant to be executed by Cordova Medic Appium runner
    +// you can find it here: https://github.com/apache/cordova-medic/
    +// it is not necessary to do a full CI setup to run these tests, just run:
    +// node cordova-medic/medic/medic.js appium --platform android --plugins cordova-plugin-contacts
    +
    +'use strict';
    +
    +var wdHelper = global.WD_HELPER;
    +var screenshotHelper = global.SCREENSHOT_HELPER;
    +var contactsHelper = require('../helpers/contactsHelper');
    +
    +var MINUTE = 60 * 1000;
    +var PLATFORM = global.PLATFORM;
    +var UNORM = global.UNORM;
    +
    +describe('Contacts Android', function () {
    +    var driver;
    +    var webviewContext;
    +    var callbackCount = 0;
    +
    +    function getNextCallbackId() {
    +        return 'appium_callback_' + callbackCount++;
    +    }
    +
    +    function saveScreenshotAndFail(error) {
    +        fail(error);
    +        return screenshotHelper
    +            .saveScreenshot(driver)
    +            .quit()
    +            .then(function () {
    +                return getDriver();
    +            });
    +    }
    +
    +    function getDriver() {
    +        var getWebviewContext = function () {
    +            return driver
    +                .contexts()
    +                .then(function (contexts) {
    +                    var found = false;
    +                    // take the last webview context
    +                    for (var i = 0; i < contexts.length ; i++) {
    +                        if (contexts[i].indexOf('WEBVIEW') >= 0) {
    +                            webviewContext = contexts[i];
    +                            found = true;
    +                        }
    +                    }
    +                    if (!found) {
    +                        // no webview context, the app is still loading
    +                        return driver
    +                            .sleep(10000)
    +                            .then(getWebviewContext);
    +                    }
    +                });
    +        };
    +        driver = wdHelper.getDriver(PLATFORM);
    +        return getWebviewContext();
    +    }
    +
    +    function addContact(firstName, lastName) {
    +        var contactName = contactsHelper.getContactName(firstName, lastName);
    +        return driver
    +            .context(webviewContext)
    +            .setAsyncScriptTimeout(MINUTE)
    +            .executeAsync(function(contactname, callback) {
    +                navigator.contacts
    +                    .create({ 'displayName': contactname.formatted, 'name': contactname, 'note': 'DeleteMe' })
    +                    .save(callback, callback);
    +            }, [contactName])
    +            .then(function(result) {
    +                if (result && result.hasOwnProperty('code')) {
    +                    throw result;
    +                }
    +                return result;
    +            });
    +    }
    +
    +    function pickContact(name) {
    +        var callbackId = getNextCallbackId();
    +        return driver
    +            .context(webviewContext)
    +            .execute(function (cbId) {
    +                var cbEl = document.createElement('div');
    +                cbEl.id = cbId;
    +                cbEl.style.display = 'none';
    +                navigator.contacts.pickContact(function (contact) {
    +                    cbEl.innerHTML = JSON.stringify(contact);
    +                    document.body.appendChild(cbEl);
    +                }, function (err) {
    +                    cbEl.innerHTML = 'ERROR: ' + err;
    +                    document.body.appendChild(cbEl);
    +                });
    +            }, [callbackId])
    +            .context('NATIVE_APP')
    +            .then(function () {
    +                switch (PLATFORM) {
    +                    case 'ios':
    +                        return driver.waitForElementByXPath(UNORM.nfd('//UIAStaticText[@label="' + name + '"]'), MINUTE);
    +                    case 'android':
    +                        return driver.waitForElementByXPath('//android.widget.TextView[@text="' + name + '"]', MINUTE);
    +                }
    +            })
    +            .click()
    +            .context(webviewContext)
    +            .waitForElementById(callbackId)
    +            .getAttribute('innerHTML')
    +            .then(function (result) {
    +                if (result && typeof result === 'string' && result.indexOf('ERROR: ') === 0) {
    +                    throw result.slice(7);
    +                }
    +                return JSON.parse(result);
    +            });
    +    }
    +
    +    function renameContact(oldName, newGivenName, newFamilyName) {
    +        return driver
    +            .context(webviewContext)
    +            .setAsyncScriptTimeout(MINUTE)
    +            .executeAsync(function (oldname, newgivenname, newfamilyname, callback) {
    +                var obj = new ContactFindOptions();
    +                obj.filter = oldname;
    +                obj.multiple = false;
    +
    +                navigator.contacts.find(['displayName', 'name'], function(contacts) {
    +                    if (contacts.length === 0) {
    +                        return;
    +                    }
    +                    var contact = contacts[0];
    +                    contact.displayName = newgivenname + ' ' + newfamilyname;
    +                    var name = new ContactName();
    +                    name.givenName = newgivenname;
    +                    name.familyName = newfamilyname;
    +                    contact.name = name;
    +                    contact.save(callback, callback);
    +                }, callback, obj);
    +            }, [oldName, newGivenName, newFamilyName])
    +            .then(function(result) {
    +                if (result && result.hasOwnProperty('code')) {
    +                    throw result;
    +                }
    +                return result;
    +            });
    +    }
    +
    +    function removeTestContacts() {
    +        return driver
    +            .context(webviewContext)
    +            .setAsyncScriptTimeout(MINUTE)
    +            .executeAsync(function (callback) {
    +                var obj = new ContactFindOptions();
    +                obj.filter = 'DeleteMe';
    +                obj.multiple = true;
    +                navigator.contacts.find(['note'], function(contacts) {
    +                    var removes = [];
    +                    contacts.forEach(function(contact) {
    +                        removes.push(contact);
    +                    });
    +                    if (removes.length === 0) {
    +                        return;
    +                    }
    +
    +                   var nextToRemove;
    +                   if (removes.length > 0) {
    +                        nextToRemove = removes.shift();
    +                    }
    +
    +                    function removeNext(item) {
    +                        if (typeof item === 'undefined') {
    +                            callback();
    +                            return;
    +                        }
    +
    +                        if (removes.length > 0) {
    +                            nextToRemove = removes.shift();
    +                        } else {
    +                            nextToRemove = undefined;
    +                        }
    +
    +                        item.remove(function removeSucceeded() {
    +                            removeNext(nextToRemove);
    +                        }, function removeFailed() {
    +                            removeNext(nextToRemove);
    +                        });
    +                    }
    +                    removeNext(nextToRemove);
    +                }, callback, obj);
    +            }, [])
    +            .then(function(result) {
    +                if (typeof result !== 'undefined') {
    +                    throw result;
    +                }
    +            });
    +    }
    +
    +    it('contacts.ui.util configuring driver and starting a session', function (done) {
    +        getDriver()
    +            .fail(fail)
    +            .finally(done);
    +    }, 5 * MINUTE);
    +
    +    describe('Picking contacts', function () {
    +        afterEach(function (done) {
    +            removeTestContacts()
    +                .finally(done);
    +        }, MINUTE);
    +
    +        it('contacts.ui.spec.1 Pick a contact', function (done) {
    +            driver
    +                .then(function () {
    +                    return addContact('Test', 'Contact');
    +                })
    +                .then(function () {
    +                    return pickContact('Test Contact');
    +                })
    +                .then(function (contact) {
    +                    expect(contact.name.givenName).toBe('Test');
    +                    expect(contact.name.familyName).toBe('Contact');
    +                })
    +                .fail(saveScreenshotAndFail)
    +                .finally(done);
    +        }, 5 * MINUTE);
    +
    +        it('contacts.ui.spec.2 Update an existing contact', function (done) {
    +            driver
    +                .then(function () {
    +                    return addContact('Dooney', 'Evans');
    +                })
    +                .then(function () {
    +                    return renameContact('Dooney Evans', 'Urist', 'McContact');
    +                })
    +                .then(function (contact) {
    +                    expect(contact.name.givenName).toBe('Urist');
    +                    expect(contact.name.familyName).toBe('McContact');
    +                })
    +                .then(function () {
    +                    return pickContact('Urist McContact');
    +                })
    +                .then(function (contact) {
    +                    expect(contact.name.givenName).toBe('Urist');
    +                    expect(contact.name.familyName).toBe('McContact');
    +                })
    +                .fail(saveScreenshotAndFail)
    +                .finally(done);
    --- End diff --
    
    You want to end the promise chain with .done() - otherwise failures can get lost.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by dblotsky <gi...@git.apache.org>.
Github user dblotsky commented on a diff in the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#discussion_r56099992
  
    --- Diff: appium-tests/helpers/contactsHelper.js ---
    @@ -0,0 +1,222 @@
    +/* jshint node: true */
    +/*
    + *
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + *
    +*/
    +
    +'use strict';
    +
    +function prepare(item) {
    +    if (typeof item === 'object') {
    +        return JSON.stringify(item);
    +    }
    +    if (typeof item === 'string') {
    +        return '"' + item + '"';
    +    }
    +    return undefined;
    +}
    +
    +module.exports.getContactName = function (firstName, lastName) {
    +    return {
    +        formatted: firstName == lastName === undefined ? null : firstName + ' ' + lastName,
    +        familyName: lastName,
    +        givenName: firstName,
    +        middleName: ''
    +    };
    +};
    +
    +module.exports.getAddContactCode = function (displayName, contactName, phoneNumber) {
    +    var preparedDisplayName = prepare(displayName);
    +    console.log('preparedDisplayName is ' + preparedDisplayName);
    +    var preparedContactName = prepare(contactName);
    +    var preparedPhoneNumber = prepare(phoneNumber);
    +
    +    var result =
    +        'try {\n' +
    +        '    var results = document.getElementById("info");\n' +
    +        '    var contact = navigator.contacts.create({ "displayName": ' + preparedDisplayName + ', "name": ' + preparedContactName + ', "note": "DeleteMe" });\n' +
    +
    +        '    var phoneNumbers = [1];\n' +
    +        '    phoneNumbers[0] = new ContactField("work", ' + preparedPhoneNumber + ', true);\n' +
    +        '    contact.phoneNumbers = phoneNumbers;\n' +
    +
    +        '    contact.save(function() {\n' +
    +        '        results.innerHTML = "' + (displayName || 'Nameless contact') + ' saved.";\n' +
    +        '    }, function(e) {\n' +
    +        '        if (e.code === ContactError.NOT_SUPPORTED_ERROR) {\n' +
    +        '            results.innerHTML = "Saving contacts not supported.";\n' +
    +        '        } else {\n' +
    +        '            results.innerHTML = "Contact save failed: error " + e.code;\n' +
    +        '        }\n' +
    +        '    });\n' +
    +        '} catch (e) {\n' +
    +        '    var results = document.getElementById("info");\n' +
    +        '    results.innerHTML = "ERROR: " + e.code;\n' +
    +        '}\n';
    +
    +    return result;
    +};
    +
    +module.exports.getGetContactsCode = function (filter) {
    +    var preparedFilter = prepare(filter);
    +
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'var obj = new ContactFindOptions();\n' +
    +        'if (' + preparedFilter + ') {\n' +
    +        '    obj.filter = ' + preparedFilter + ';\n' +
    +        '}\n' +
    +        'obj.multiple = true;\n' +
    +        'navigator.contacts.find(["displayName", "name", "phoneNumbers", "emails", "urls", "note"], function(contacts) {\n' +
    +        '    var s = "";\n' +
    +        '    if (contacts.length === 0) {\n' +
    +        '        s = "No contacts found";\n' +
    +        '    } else {\n' +
    +        '        s = "Number of contacts: " + contacts.length + "<br><table width=100%><tr><th>Name</th><td>Phone</td><td>Email</td></tr>";\n' +
    +        '        for (var i = 0; i < contacts.length; i++) {\n' +
    +        '            var contact = contacts[i];\n' +
    +        '            var contactNameTag = contact.name ? "<tr><td>" + contact.name.formatted + "</td><td>" : "<tr><td>(No Name)</td><td>";\n' +
    +        '            s = s + contactNameTag;\n' +
    +        '            if (contact.phoneNumbers && contact.phoneNumbers.length > 0) {\n' +
    +        '                s = s + contact.phoneNumbers[0].value;\n' +
    +        '            }\n' +
    +        '            s = s + "</td><td>";\n' +
    +        '            if (contact.emails && contact.emails.length > 0) {\n' +
    +        '                s = s + contact.emails[0].value;\n' +
    +        '            }\n' +
    +        '            s = s + "</td></tr>";\n' +
    +        '    }\n' +
    +        '        s = s + "</table>";\n' +
    +        '    }\n' +
    +        '    results.innerHTML = s;\n' +
    +        '}, function(e) {\n' +
    +        '   results.innerHTML = "Search failed: error " + e.code;\n' +
    +        '}, obj);';
    +
    +    return result;
    +};
    +
    +module.exports.getPickContactCode = function () {
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'navigator.contacts.pickContact(\n' +
    +        '    function (contact) {\n' +
    +        '        results.innerHTML = contact ?\n' +
    +        '            "Picked contact: <pre>" + JSON.stringify(contact, null, 4) + "</pre>" :\n' +
    +        '            "No contacts found";\n' +
    +        '    },\n' +
    +        '    function (e) {\n' +
    +        '        results.innerHTML = e && e.code === ContactError.OPERATION_CANCELLED_ERROR ?\n' +
    +        '                "Pick cancelled" :\n' +
    +        '                "Pick failed: " + (e && e.code);\n' +
    +        '    }\n' +
    +        ');';
    +
    +    return result;
    +};
    +
    +module.exports.getRenameContactCode = function (oldDisplayName, newDisplayName, newName) {
    +    // these default values are copied from manual contacts tests
    +    if (!oldDisplayName) {
    +        oldDisplayName = 'Dooney Evans';
    +    }
    +    if (!newDisplayName) {
    +        newDisplayName = 'Urist McContact';
    +    }
    +    if (!newName) {
    +        newName = module.exports.getContactName('Urist', 'McContact');
    +    }
    +    var preparedOldDisplayName = prepare(oldDisplayName);
    +    var preparedNewDisplayName = prepare(newDisplayName);
    +    var preparedNewName = prepare(newName);
    +
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'var obj = new ContactFindOptions();\n' +
    +        'obj.filter = ' + preparedOldDisplayName + ';\n' +
    +        'obj.multiple = false;\n' +
    +
    +        'navigator.contacts.find(["displayName", "name"], function(contacts) {\n' +
    +        '    if (contacts.length === 0) {\n' +
    +        '        results.innerHTML = "No contacts to update.";\n' +
    +        '        return;\n' +
    +        '    }\n' +
    +        '    var contact = contacts[0];\n' +
    +        '    contact.displayName = ' + preparedNewDisplayName + ';\n' +
    +        '    contact.name = ' + preparedNewName + ';\n' +
    +        '    contact.save(function(updated) {\n' +
    +        '        results.innerHTML = "Contact updated.";\n' +
    +        '    },function(e) {\n' +
    +        '        results.innerHTML = "Update failed: error " + e.code;\n' +
    +        '    });\n' +
    +        '}, function(e) {\n' +
    +        '    results.innerHTML = "Search failed: error " + e.code;\n' +
    +        '}, obj);';
    +
    +    return result;
    +};
    +
    +module.exports.getRemoveTestContactsCode = function () {
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'results.innerHTML = "";\n' +
    +        'var obj = new ContactFindOptions();\n' +
    +        'obj.filter = "DeleteMe";\n' +
    +        'obj.multiple = true;\n' +
    +        'navigator.contacts.find(["note"], function(contacts) {\n' +
    +        '    var removes = [];\n' +
    +        '    contacts.forEach(function(contact) {\n' +
    +        '        removes.push(contact);\n' +
    +        '    });\n' +
    +        '    if (removes.length === 0) {\n' +
    +        '        results.innerHTML = "No contacts to remove";\n' +
    +        '        return;\n' +
    +        '    }\n' +
    +
    +        '   var nextToRemove;\n' +
    +        '   if (removes.length > 0) {\n' +
    +        '        nextToRemove = removes.shift();\n' +
    +        '    }\n' +
    +
    +        '    function removeNext(item) {\n' +
    +        '        if (typeof item === "undefined") {\n' +
    +        '            return;\n' +
    +        '        }\n' +
    +
    +        '        if (removes.length > 0) {\n' +
    +        '            nextToRemove = removes.shift();\n' +
    +        '        } else {\n' +
    +        '            nextToRemove = undefined;\n' +
    +        '        }\n' +
    +
    +        '        item.remove(function removeSucceeded() {\n' +
    +        '            results.innerHTML += "Removed a contact with ID " + item.id + "<br/>";\n' +
    +        '            removeNext(nextToRemove);\n' +
    +        '        }, function removeFailed() {\n' +
    +        '            results.innerHTML += "Failed to remove a contact with ID " + item.id + "<br/>";\n' +
    +        '            removeNext(nextToRemove);\n' +
    +        '        });\n' +
    +        '    }\n' +
    +        '    removeNext(nextToRemove);\n' +
    +        '}, function(e) {\n' +
    +        '   results.innerHTML = "Search failed: error " + e.code;\n' +
    +        '}, obj);';
    +
    +    return result;
    +};
    --- End diff --
    
    Currently the tests already depend on the Mobilespec app. This code should live in the app.
    
    There are many reasons why writing code in strings is a bad pattern. Here are just a few:
    - it's very hard to de-duplicate and refactor
    - it's not checked for syntax, therefore:
        - it's easier to make mistakes in it
        - it's more difficult to fix bugs in it
        - even if it looks fine, it can break at runtime because errors can be inserted at runtime
    - it's difficult to edit and read because:
        - it's not highlighted
        - its format is hard to see
    
    In short, it's a very dangerous pattern and we can easily avoid it, so we should definitely not be using it. I agree with you that our UI code lives too far from our UI tests, but I think that's a problem with Mobilespec's design. There are many ways to fix it (e.g. having separate test apps that live with each plugin), and we should discuss fixing Mobilespec as a separate task.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by dblotsky <gi...@git.apache.org>.
Github user dblotsky commented on a diff in the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#discussion_r55780934
  
    --- Diff: appium-tests/helpers/contactsHelper.js ---
    @@ -0,0 +1,222 @@
    +/* jshint node: true */
    +/*
    + *
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + *
    +*/
    +
    +'use strict';
    +
    +function prepare(item) {
    +    if (typeof item === 'object') {
    +        return JSON.stringify(item);
    +    }
    +    if (typeof item === 'string') {
    +        return '"' + item + '"';
    +    }
    +    return undefined;
    +}
    +
    +module.exports.getContactName = function (firstName, lastName) {
    +    return {
    +        formatted: firstName == lastName === undefined ? null : firstName + ' ' + lastName,
    +        familyName: lastName,
    +        givenName: firstName,
    +        middleName: ''
    +    };
    +};
    +
    +module.exports.getAddContactCode = function (displayName, contactName, phoneNumber) {
    +    var preparedDisplayName = prepare(displayName);
    +    console.log('preparedDisplayName is ' + preparedDisplayName);
    +    var preparedContactName = prepare(contactName);
    +    var preparedPhoneNumber = prepare(phoneNumber);
    +
    +    var result =
    +        'try {\n' +
    +        '    var results = document.getElementById("info");\n' +
    +        '    var contact = navigator.contacts.create({ "displayName": ' + preparedDisplayName + ', "name": ' + preparedContactName + ', "note": "DeleteMe" });\n' +
    +
    +        '    var phoneNumbers = [1];\n' +
    +        '    phoneNumbers[0] = new ContactField("work", ' + preparedPhoneNumber + ', true);\n' +
    +        '    contact.phoneNumbers = phoneNumbers;\n' +
    +
    +        '    contact.save(function() {\n' +
    +        '        results.innerHTML = "' + (displayName || 'Nameless contact') + ' saved.";\n' +
    +        '    }, function(e) {\n' +
    +        '        if (e.code === ContactError.NOT_SUPPORTED_ERROR) {\n' +
    +        '            results.innerHTML = "Saving contacts not supported.";\n' +
    +        '        } else {\n' +
    +        '            results.innerHTML = "Contact save failed: error " + e.code;\n' +
    +        '        }\n' +
    +        '    });\n' +
    +        '} catch (e) {\n' +
    +        '    var results = document.getElementById("info");\n' +
    +        '    results.innerHTML = "ERROR: " + e.code;\n' +
    +        '}\n';
    +
    +    return result;
    +};
    +
    +module.exports.getGetContactsCode = function (filter) {
    +    var preparedFilter = prepare(filter);
    +
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'var obj = new ContactFindOptions();\n' +
    +        'if (' + preparedFilter + ') {\n' +
    +        '    obj.filter = ' + preparedFilter + ';\n' +
    +        '}\n' +
    +        'obj.multiple = true;\n' +
    +        'navigator.contacts.find(["displayName", "name", "phoneNumbers", "emails", "urls", "note"], function(contacts) {\n' +
    +        '    var s = "";\n' +
    +        '    if (contacts.length === 0) {\n' +
    +        '        s = "No contacts found";\n' +
    +        '    } else {\n' +
    +        '        s = "Number of contacts: " + contacts.length + "<br><table width=100%><tr><th>Name</th><td>Phone</td><td>Email</td></tr>";\n' +
    +        '        for (var i = 0; i < contacts.length; i++) {\n' +
    +        '            var contact = contacts[i];\n' +
    +        '            var contactNameTag = contact.name ? "<tr><td>" + contact.name.formatted + "</td><td>" : "<tr><td>(No Name)</td><td>";\n' +
    +        '            s = s + contactNameTag;\n' +
    +        '            if (contact.phoneNumbers && contact.phoneNumbers.length > 0) {\n' +
    +        '                s = s + contact.phoneNumbers[0].value;\n' +
    +        '            }\n' +
    +        '            s = s + "</td><td>";\n' +
    +        '            if (contact.emails && contact.emails.length > 0) {\n' +
    +        '                s = s + contact.emails[0].value;\n' +
    +        '            }\n' +
    +        '            s = s + "</td></tr>";\n' +
    +        '    }\n' +
    +        '        s = s + "</table>";\n' +
    +        '    }\n' +
    +        '    results.innerHTML = s;\n' +
    +        '}, function(e) {\n' +
    +        '   results.innerHTML = "Search failed: error " + e.code;\n' +
    +        '}, obj);';
    +
    +    return result;
    +};
    +
    +module.exports.getPickContactCode = function () {
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'navigator.contacts.pickContact(\n' +
    +        '    function (contact) {\n' +
    +        '        results.innerHTML = contact ?\n' +
    +        '            "Picked contact: <pre>" + JSON.stringify(contact, null, 4) + "</pre>" :\n' +
    +        '            "No contacts found";\n' +
    +        '    },\n' +
    +        '    function (e) {\n' +
    +        '        results.innerHTML = e && e.code === ContactError.OPERATION_CANCELLED_ERROR ?\n' +
    +        '                "Pick cancelled" :\n' +
    +        '                "Pick failed: " + (e && e.code);\n' +
    +        '    }\n' +
    +        ');';
    +
    +    return result;
    +};
    +
    +module.exports.getRenameContactCode = function (oldDisplayName, newDisplayName, newName) {
    +    // these default values are copied from manual contacts tests
    +    if (!oldDisplayName) {
    +        oldDisplayName = 'Dooney Evans';
    +    }
    +    if (!newDisplayName) {
    +        newDisplayName = 'Urist McContact';
    +    }
    +    if (!newName) {
    +        newName = module.exports.getContactName('Urist', 'McContact');
    +    }
    +    var preparedOldDisplayName = prepare(oldDisplayName);
    +    var preparedNewDisplayName = prepare(newDisplayName);
    +    var preparedNewName = prepare(newName);
    +
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'var obj = new ContactFindOptions();\n' +
    +        'obj.filter = ' + preparedOldDisplayName + ';\n' +
    +        'obj.multiple = false;\n' +
    +
    +        'navigator.contacts.find(["displayName", "name"], function(contacts) {\n' +
    +        '    if (contacts.length === 0) {\n' +
    +        '        results.innerHTML = "No contacts to update.";\n' +
    +        '        return;\n' +
    +        '    }\n' +
    +        '    var contact = contacts[0];\n' +
    +        '    contact.displayName = ' + preparedNewDisplayName + ';\n' +
    +        '    contact.name = ' + preparedNewName + ';\n' +
    +        '    contact.save(function(updated) {\n' +
    +        '        results.innerHTML = "Contact updated.";\n' +
    +        '    },function(e) {\n' +
    +        '        results.innerHTML = "Update failed: error " + e.code;\n' +
    +        '    });\n' +
    +        '}, function(e) {\n' +
    +        '    results.innerHTML = "Search failed: error " + e.code;\n' +
    +        '}, obj);';
    +
    +    return result;
    +};
    +
    +module.exports.getRemoveTestContactsCode = function () {
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'results.innerHTML = "";\n' +
    +        'var obj = new ContactFindOptions();\n' +
    +        'obj.filter = "DeleteMe";\n' +
    +        'obj.multiple = true;\n' +
    +        'navigator.contacts.find(["note"], function(contacts) {\n' +
    +        '    var removes = [];\n' +
    +        '    contacts.forEach(function(contact) {\n' +
    +        '        removes.push(contact);\n' +
    +        '    });\n' +
    +        '    if (removes.length === 0) {\n' +
    +        '        results.innerHTML = "No contacts to remove";\n' +
    +        '        return;\n' +
    +        '    }\n' +
    +
    +        '   var nextToRemove;\n' +
    +        '   if (removes.length > 0) {\n' +
    +        '        nextToRemove = removes.shift();\n' +
    +        '    }\n' +
    +
    +        '    function removeNext(item) {\n' +
    +        '        if (typeof item === "undefined") {\n' +
    +        '            return;\n' +
    +        '        }\n' +
    +
    +        '        if (removes.length > 0) {\n' +
    +        '            nextToRemove = removes.shift();\n' +
    +        '        } else {\n' +
    +        '            nextToRemove = undefined;\n' +
    +        '        }\n' +
    +
    +        '        item.remove(function removeSucceeded() {\n' +
    +        '            results.innerHTML += "Removed a contact with ID " + item.id + "<br/>";\n' +
    +        '            removeNext(nextToRemove);\n' +
    +        '        }, function removeFailed() {\n' +
    +        '            results.innerHTML += "Failed to remove a contact with ID " + item.id + "<br/>";\n' +
    +        '            removeNext(nextToRemove);\n' +
    +        '        });\n' +
    +        '    }\n' +
    +        '    removeNext(nextToRemove);\n' +
    +        '}, function(e) {\n' +
    +        '   results.innerHTML = "Search failed: error " + e.code;\n' +
    +        '}, obj);';
    +
    +    return result;
    +};
    --- End diff --
    
    Why is there code as strings in this file?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by dblotsky <gi...@git.apache.org>.
Github user dblotsky commented on a diff in the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#discussion_r55895708
  
    --- Diff: appium-tests/helpers/contactsHelper.js ---
    @@ -0,0 +1,222 @@
    +/* jshint node: true */
    +/*
    + *
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + *
    +*/
    +
    +'use strict';
    +
    +function prepare(item) {
    +    if (typeof item === 'object') {
    +        return JSON.stringify(item);
    +    }
    +    if (typeof item === 'string') {
    +        return '"' + item + '"';
    +    }
    +    return undefined;
    +}
    +
    +module.exports.getContactName = function (firstName, lastName) {
    +    return {
    +        formatted: firstName == lastName === undefined ? null : firstName + ' ' + lastName,
    +        familyName: lastName,
    +        givenName: firstName,
    +        middleName: ''
    +    };
    +};
    +
    +module.exports.getAddContactCode = function (displayName, contactName, phoneNumber) {
    +    var preparedDisplayName = prepare(displayName);
    +    console.log('preparedDisplayName is ' + preparedDisplayName);
    +    var preparedContactName = prepare(contactName);
    +    var preparedPhoneNumber = prepare(phoneNumber);
    +
    +    var result =
    +        'try {\n' +
    +        '    var results = document.getElementById("info");\n' +
    +        '    var contact = navigator.contacts.create({ "displayName": ' + preparedDisplayName + ', "name": ' + preparedContactName + ', "note": "DeleteMe" });\n' +
    +
    +        '    var phoneNumbers = [1];\n' +
    +        '    phoneNumbers[0] = new ContactField("work", ' + preparedPhoneNumber + ', true);\n' +
    +        '    contact.phoneNumbers = phoneNumbers;\n' +
    +
    +        '    contact.save(function() {\n' +
    +        '        results.innerHTML = "' + (displayName || 'Nameless contact') + ' saved.";\n' +
    +        '    }, function(e) {\n' +
    +        '        if (e.code === ContactError.NOT_SUPPORTED_ERROR) {\n' +
    +        '            results.innerHTML = "Saving contacts not supported.";\n' +
    +        '        } else {\n' +
    +        '            results.innerHTML = "Contact save failed: error " + e.code;\n' +
    +        '        }\n' +
    +        '    });\n' +
    +        '} catch (e) {\n' +
    +        '    var results = document.getElementById("info");\n' +
    +        '    results.innerHTML = "ERROR: " + e.code;\n' +
    +        '}\n';
    +
    +    return result;
    +};
    +
    +module.exports.getGetContactsCode = function (filter) {
    +    var preparedFilter = prepare(filter);
    +
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'var obj = new ContactFindOptions();\n' +
    +        'if (' + preparedFilter + ') {\n' +
    +        '    obj.filter = ' + preparedFilter + ';\n' +
    +        '}\n' +
    +        'obj.multiple = true;\n' +
    +        'navigator.contacts.find(["displayName", "name", "phoneNumbers", "emails", "urls", "note"], function(contacts) {\n' +
    +        '    var s = "";\n' +
    +        '    if (contacts.length === 0) {\n' +
    +        '        s = "No contacts found";\n' +
    +        '    } else {\n' +
    +        '        s = "Number of contacts: " + contacts.length + "<br><table width=100%><tr><th>Name</th><td>Phone</td><td>Email</td></tr>";\n' +
    +        '        for (var i = 0; i < contacts.length; i++) {\n' +
    +        '            var contact = contacts[i];\n' +
    +        '            var contactNameTag = contact.name ? "<tr><td>" + contact.name.formatted + "</td><td>" : "<tr><td>(No Name)</td><td>";\n' +
    +        '            s = s + contactNameTag;\n' +
    +        '            if (contact.phoneNumbers && contact.phoneNumbers.length > 0) {\n' +
    +        '                s = s + contact.phoneNumbers[0].value;\n' +
    +        '            }\n' +
    +        '            s = s + "</td><td>";\n' +
    +        '            if (contact.emails && contact.emails.length > 0) {\n' +
    +        '                s = s + contact.emails[0].value;\n' +
    +        '            }\n' +
    +        '            s = s + "</td></tr>";\n' +
    +        '    }\n' +
    +        '        s = s + "</table>";\n' +
    +        '    }\n' +
    +        '    results.innerHTML = s;\n' +
    +        '}, function(e) {\n' +
    +        '   results.innerHTML = "Search failed: error " + e.code;\n' +
    +        '}, obj);';
    +
    +    return result;
    +};
    +
    +module.exports.getPickContactCode = function () {
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'navigator.contacts.pickContact(\n' +
    +        '    function (contact) {\n' +
    +        '        results.innerHTML = contact ?\n' +
    +        '            "Picked contact: <pre>" + JSON.stringify(contact, null, 4) + "</pre>" :\n' +
    +        '            "No contacts found";\n' +
    +        '    },\n' +
    +        '    function (e) {\n' +
    +        '        results.innerHTML = e && e.code === ContactError.OPERATION_CANCELLED_ERROR ?\n' +
    +        '                "Pick cancelled" :\n' +
    +        '                "Pick failed: " + (e && e.code);\n' +
    +        '    }\n' +
    +        ');';
    +
    +    return result;
    +};
    +
    +module.exports.getRenameContactCode = function (oldDisplayName, newDisplayName, newName) {
    +    // these default values are copied from manual contacts tests
    +    if (!oldDisplayName) {
    +        oldDisplayName = 'Dooney Evans';
    +    }
    +    if (!newDisplayName) {
    +        newDisplayName = 'Urist McContact';
    +    }
    +    if (!newName) {
    +        newName = module.exports.getContactName('Urist', 'McContact');
    +    }
    +    var preparedOldDisplayName = prepare(oldDisplayName);
    +    var preparedNewDisplayName = prepare(newDisplayName);
    +    var preparedNewName = prepare(newName);
    +
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'var obj = new ContactFindOptions();\n' +
    +        'obj.filter = ' + preparedOldDisplayName + ';\n' +
    +        'obj.multiple = false;\n' +
    +
    +        'navigator.contacts.find(["displayName", "name"], function(contacts) {\n' +
    +        '    if (contacts.length === 0) {\n' +
    +        '        results.innerHTML = "No contacts to update.";\n' +
    +        '        return;\n' +
    +        '    }\n' +
    +        '    var contact = contacts[0];\n' +
    +        '    contact.displayName = ' + preparedNewDisplayName + ';\n' +
    +        '    contact.name = ' + preparedNewName + ';\n' +
    +        '    contact.save(function(updated) {\n' +
    +        '        results.innerHTML = "Contact updated.";\n' +
    +        '    },function(e) {\n' +
    +        '        results.innerHTML = "Update failed: error " + e.code;\n' +
    +        '    });\n' +
    +        '}, function(e) {\n' +
    +        '    results.innerHTML = "Search failed: error " + e.code;\n' +
    +        '}, obj);';
    +
    +    return result;
    +};
    +
    +module.exports.getRemoveTestContactsCode = function () {
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'results.innerHTML = "";\n' +
    +        'var obj = new ContactFindOptions();\n' +
    +        'obj.filter = "DeleteMe";\n' +
    +        'obj.multiple = true;\n' +
    +        'navigator.contacts.find(["note"], function(contacts) {\n' +
    +        '    var removes = [];\n' +
    +        '    contacts.forEach(function(contact) {\n' +
    +        '        removes.push(contact);\n' +
    +        '    });\n' +
    +        '    if (removes.length === 0) {\n' +
    +        '        results.innerHTML = "No contacts to remove";\n' +
    +        '        return;\n' +
    +        '    }\n' +
    +
    +        '   var nextToRemove;\n' +
    +        '   if (removes.length > 0) {\n' +
    +        '        nextToRemove = removes.shift();\n' +
    +        '    }\n' +
    +
    +        '    function removeNext(item) {\n' +
    +        '        if (typeof item === "undefined") {\n' +
    +        '            return;\n' +
    +        '        }\n' +
    +
    +        '        if (removes.length > 0) {\n' +
    +        '            nextToRemove = removes.shift();\n' +
    +        '        } else {\n' +
    +        '            nextToRemove = undefined;\n' +
    +        '        }\n' +
    +
    +        '        item.remove(function removeSucceeded() {\n' +
    +        '            results.innerHTML += "Removed a contact with ID " + item.id + "<br/>";\n' +
    +        '            removeNext(nextToRemove);\n' +
    +        '        }, function removeFailed() {\n' +
    +        '            results.innerHTML += "Failed to remove a contact with ID " + item.id + "<br/>";\n' +
    +        '            removeNext(nextToRemove);\n' +
    +        '        });\n' +
    +        '    }\n' +
    +        '    removeNext(nextToRemove);\n' +
    +        '}, function(e) {\n' +
    +        '   results.innerHTML = "Search failed: error " + e.code;\n' +
    +        '}, obj);';
    +
    +    return result;
    +};
    --- End diff --
    
    I'm very much against this pattern. Can you describe in more detail why this is necessary, and if there are other ways to implement these tests?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by nikhilkh <gi...@git.apache.org>.
Github user nikhilkh commented on a diff in the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#discussion_r57225224
  
    --- Diff: appium-tests/common/common.spec.js ---
    @@ -0,0 +1,321 @@
    +/*jshint node: true, jasmine: true, browser: true */
    +/*global ContactFindOptions, ContactName*/
    +
    +/*
    + *
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + *
    +*/
    +
    +// these tests are meant to be executed by Cordova Medic Appium runner
    +// you can find it here: https://github.com/apache/cordova-medic/
    +// it is not necessary to do a full CI setup to run these tests, just run:
    +// node cordova-medic/medic/medic.js appium --platform android --plugins cordova-plugin-contacts
    +
    +'use strict';
    +
    +var wdHelper = global.WD_HELPER;
    +var screenshotHelper = global.SCREENSHOT_HELPER;
    +var contactsHelper = require('../helpers/contactsHelper');
    +
    +var MINUTE = 60 * 1000;
    +var PLATFORM = global.PLATFORM;
    +var UNORM = global.UNORM;
    +
    +describe('Contacts Android', function () {
    +    var driver;
    +    var webviewContext;
    +    var callbackCount = 0;
    +
    +    function getNextCallbackId() {
    +        return 'appium_callback_' + callbackCount++;
    +    }
    +
    +    function saveScreenshotAndFail(error) {
    +        fail(error);
    +        return screenshotHelper
    +            .saveScreenshot(driver)
    +            .quit()
    +            .then(function () {
    +                return getDriver();
    +            });
    +    }
    +
    +    function getDriver() {
    +        var getWebviewContext = function () {
    +            return driver
    +                .contexts()
    +                .then(function (contexts) {
    +                    var found = false;
    +                    // take the last webview context
    +                    for (var i = 0; i < contexts.length ; i++) {
    +                        if (contexts[i].indexOf('WEBVIEW') >= 0) {
    +                            webviewContext = contexts[i];
    +                            found = true;
    +                        }
    +                    }
    +                    if (!found) {
    +                        // no webview context, the app is still loading
    +                        return driver
    +                            .sleep(10000)
    +                            .then(getWebviewContext);
    +                    }
    +                });
    +        };
    +        driver = wdHelper.getDriver(PLATFORM);
    +        return getWebviewContext();
    +    }
    +
    +    function addContact(firstName, lastName) {
    +        var contactName = contactsHelper.getContactName(firstName, lastName);
    +        return driver
    +            .context(webviewContext)
    +            .setAsyncScriptTimeout(MINUTE)
    +            .executeAsync(function(contactname, callback) {
    +                navigator.contacts
    +                    .create({ 'displayName': contactname.formatted, 'name': contactname, 'note': 'DeleteMe' })
    +                    .save(callback, callback);
    +            }, [contactName])
    +            .then(function(result) {
    +                if (result && result.hasOwnProperty('code')) {
    +                    throw result;
    +                }
    +                return result;
    +            });
    +    }
    +
    +    function pickContact(name) {
    +        var callbackId = getNextCallbackId();
    +        return driver
    +            .context(webviewContext)
    +            .execute(function (cbId) {
    +                var cbEl = document.createElement('div');
    +                cbEl.id = cbId;
    +                cbEl.style.display = 'none';
    +                navigator.contacts.pickContact(function (contact) {
    +                    cbEl.innerHTML = JSON.stringify(contact);
    +                    document.body.appendChild(cbEl);
    +                }, function (err) {
    +                    cbEl.innerHTML = 'ERROR: ' + err;
    +                    document.body.appendChild(cbEl);
    +                });
    +            }, [callbackId])
    +            .context('NATIVE_APP')
    +            .then(function () {
    +                switch (PLATFORM) {
    +                    case 'ios':
    +                        return driver.waitForElementByXPath(UNORM.nfd('//UIAStaticText[@label="' + name + '"]'), MINUTE);
    +                    case 'android':
    +                        return driver.waitForElementByXPath('//android.widget.TextView[@text="' + name + '"]', MINUTE);
    +                }
    +            })
    +            .click()
    +            .context(webviewContext)
    +            .waitForElementById(callbackId)
    +            .getAttribute('innerHTML')
    +            .then(function (result) {
    +                if (result && typeof result === 'string' && result.indexOf('ERROR: ') === 0) {
    +                    throw result.slice(7);
    +                }
    +                return JSON.parse(result);
    +            });
    +    }
    +
    +    function renameContact(oldName, newGivenName, newFamilyName) {
    +        return driver
    +            .context(webviewContext)
    +            .setAsyncScriptTimeout(MINUTE)
    +            .executeAsync(function (oldname, newgivenname, newfamilyname, callback) {
    +                var obj = new ContactFindOptions();
    +                obj.filter = oldname;
    +                obj.multiple = false;
    +
    +                navigator.contacts.find(['displayName', 'name'], function(contacts) {
    +                    if (contacts.length === 0) {
    +                        return;
    +                    }
    +                    var contact = contacts[0];
    +                    contact.displayName = newgivenname + ' ' + newfamilyname;
    +                    var name = new ContactName();
    +                    name.givenName = newgivenname;
    +                    name.familyName = newfamilyname;
    +                    contact.name = name;
    +                    contact.save(callback, callback);
    +                }, callback, obj);
    +            }, [oldName, newGivenName, newFamilyName])
    +            .then(function(result) {
    +                if (result && result.hasOwnProperty('code')) {
    +                    throw result;
    +                }
    +                return result;
    +            });
    +    }
    +
    +    function removeTestContacts() {
    +        return driver
    +            .context(webviewContext)
    +            .setAsyncScriptTimeout(MINUTE)
    +            .executeAsync(function (callback) {
    +                var obj = new ContactFindOptions();
    +                obj.filter = 'DeleteMe';
    +                obj.multiple = true;
    +                navigator.contacts.find(['note'], function(contacts) {
    +                    var removes = [];
    +                    contacts.forEach(function(contact) {
    +                        removes.push(contact);
    +                    });
    +                    if (removes.length === 0) {
    +                        return;
    +                    }
    +
    +                   var nextToRemove;
    +                   if (removes.length > 0) {
    +                        nextToRemove = removes.shift();
    +                    }
    +
    +                    function removeNext(item) {
    +                        if (typeof item === 'undefined') {
    +                            callback();
    +                            return;
    +                        }
    +
    +                        if (removes.length > 0) {
    +                            nextToRemove = removes.shift();
    +                        } else {
    +                            nextToRemove = undefined;
    +                        }
    +
    +                        item.remove(function removeSucceeded() {
    +                            removeNext(nextToRemove);
    +                        }, function removeFailed() {
    +                            removeNext(nextToRemove);
    +                        });
    +                    }
    +                    removeNext(nextToRemove);
    +                }, callback, obj);
    +            }, [])
    +            .then(function(result) {
    +                if (typeof result !== 'undefined') {
    +                    throw result;
    +                }
    +            });
    +    }
    +
    +    it('contacts.ui.util configuring driver and starting a session', function (done) {
    +        getDriver()
    +            .fail(fail)
    +            .finally(done);
    +    }, 5 * MINUTE);
    +
    +    describe('Picking contacts', function () {
    +        afterEach(function (done) {
    +            removeTestContacts()
    +                .finally(done);
    +        }, MINUTE);
    +
    +        it('contacts.ui.spec.1 Pick a contact', function (done) {
    +            driver
    +                .then(function () {
    +                    return addContact('Test', 'Contact');
    +                })
    +                .then(function () {
    +                    return pickContact('Test Contact');
    +                })
    +                .then(function (contact) {
    +                    expect(contact.name.givenName).toBe('Test');
    +                    expect(contact.name.familyName).toBe('Contact');
    +                })
    +                .fail(saveScreenshotAndFail)
    +                .finally(done);
    +        }, 5 * MINUTE);
    +
    +        it('contacts.ui.spec.2 Update an existing contact', function (done) {
    +            driver
    +                .then(function () {
    +                    return addContact('Dooney', 'Evans');
    +                })
    +                .then(function () {
    +                    return renameContact('Dooney Evans', 'Urist', 'McContact');
    +                })
    +                .then(function (contact) {
    +                    expect(contact.name.givenName).toBe('Urist');
    +                    expect(contact.name.familyName).toBe('McContact');
    +                })
    +                .then(function () {
    +                    return pickContact('Urist McContact');
    +                })
    +                .then(function (contact) {
    +                    expect(contact.name.givenName).toBe('Urist');
    +                    expect(contact.name.familyName).toBe('McContact');
    +                })
    +                .fail(saveScreenshotAndFail)
    --- End diff --
    
    Instead of doing this - you could add a jasmine thing to ensure that on every failure we get screenshot:
    
    https://github.com/webdriverio/webdriverio/issues/556


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by nikhilkh <gi...@git.apache.org>.
Github user nikhilkh commented on the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#issuecomment-200499861
  
    @riknoll @dblotsky Can you please review again? This seems to be converging to a good design now.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by alsorokin <gi...@git.apache.org>.
Github user alsorokin commented on a diff in the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#discussion_r57571624
  
    --- Diff: appium-tests/common/common.spec.js ---
    @@ -0,0 +1,321 @@
    +/*jshint node: true, jasmine: true, browser: true */
    +/*global ContactFindOptions, ContactName*/
    +
    +/*
    + *
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + *
    +*/
    +
    +// these tests are meant to be executed by Cordova Medic Appium runner
    +// you can find it here: https://github.com/apache/cordova-medic/
    +// it is not necessary to do a full CI setup to run these tests, just run:
    +// node cordova-medic/medic/medic.js appium --platform android --plugins cordova-plugin-contacts
    +
    +'use strict';
    +
    +var wdHelper = global.WD_HELPER;
    +var screenshotHelper = global.SCREENSHOT_HELPER;
    +var contactsHelper = require('../helpers/contactsHelper');
    +
    +var MINUTE = 60 * 1000;
    +var PLATFORM = global.PLATFORM;
    +var UNORM = global.UNORM;
    +
    +describe('Contacts Android', function () {
    +    var driver;
    +    var webviewContext;
    +    var callbackCount = 0;
    +
    +    function getNextCallbackId() {
    +        return 'appium_callback_' + callbackCount++;
    +    }
    +
    +    function saveScreenshotAndFail(error) {
    +        fail(error);
    +        return screenshotHelper
    +            .saveScreenshot(driver)
    +            .quit()
    +            .then(function () {
    +                return getDriver();
    +            });
    +    }
    +
    +    function getDriver() {
    +        var getWebviewContext = function () {
    +            return driver
    +                .contexts()
    +                .then(function (contexts) {
    +                    var found = false;
    +                    // take the last webview context
    +                    for (var i = 0; i < contexts.length ; i++) {
    +                        if (contexts[i].indexOf('WEBVIEW') >= 0) {
    +                            webviewContext = contexts[i];
    +                            found = true;
    +                        }
    +                    }
    +                    if (!found) {
    +                        // no webview context, the app is still loading
    +                        return driver
    +                            .sleep(10000)
    +                            .then(getWebviewContext);
    +                    }
    +                });
    +        };
    +        driver = wdHelper.getDriver(PLATFORM);
    +        return getWebviewContext();
    +    }
    +
    +    function addContact(firstName, lastName) {
    +        var contactName = contactsHelper.getContactName(firstName, lastName);
    +        return driver
    +            .context(webviewContext)
    +            .setAsyncScriptTimeout(MINUTE)
    +            .executeAsync(function(contactname, callback) {
    +                navigator.contacts
    +                    .create({ 'displayName': contactname.formatted, 'name': contactname, 'note': 'DeleteMe' })
    +                    .save(callback, callback);
    +            }, [contactName])
    +            .then(function(result) {
    +                if (result && result.hasOwnProperty('code')) {
    +                    throw result;
    +                }
    +                return result;
    +            });
    +    }
    +
    +    function pickContact(name) {
    +        var callbackId = getNextCallbackId();
    +        return driver
    +            .context(webviewContext)
    +            .execute(function (cbId) {
    +                var cbEl = document.createElement('div');
    +                cbEl.id = cbId;
    +                cbEl.style.display = 'none';
    +                navigator.contacts.pickContact(function (contact) {
    +                    cbEl.innerHTML = JSON.stringify(contact);
    +                    document.body.appendChild(cbEl);
    +                }, function (err) {
    +                    cbEl.innerHTML = 'ERROR: ' + err;
    +                    document.body.appendChild(cbEl);
    +                });
    +            }, [callbackId])
    +            .context('NATIVE_APP')
    +            .then(function () {
    +                switch (PLATFORM) {
    +                    case 'ios':
    +                        return driver.waitForElementByXPath(UNORM.nfd('//UIAStaticText[@label="' + name + '"]'), MINUTE);
    +                    case 'android':
    +                        return driver.waitForElementByXPath('//android.widget.TextView[@text="' + name + '"]', MINUTE);
    +                }
    +            })
    +            .click()
    +            .context(webviewContext)
    +            .waitForElementById(callbackId)
    +            .getAttribute('innerHTML')
    +            .then(function (result) {
    +                if (result && typeof result === 'string' && result.indexOf('ERROR: ') === 0) {
    +                    throw result.slice(7);
    +                }
    +                return JSON.parse(result);
    +            });
    +    }
    +
    +    function renameContact(oldName, newGivenName, newFamilyName) {
    +        return driver
    +            .context(webviewContext)
    +            .setAsyncScriptTimeout(MINUTE)
    +            .executeAsync(function (oldname, newgivenname, newfamilyname, callback) {
    +                var obj = new ContactFindOptions();
    +                obj.filter = oldname;
    +                obj.multiple = false;
    +
    +                navigator.contacts.find(['displayName', 'name'], function(contacts) {
    +                    if (contacts.length === 0) {
    +                        return;
    +                    }
    +                    var contact = contacts[0];
    +                    contact.displayName = newgivenname + ' ' + newfamilyname;
    +                    var name = new ContactName();
    +                    name.givenName = newgivenname;
    +                    name.familyName = newfamilyname;
    +                    contact.name = name;
    +                    contact.save(callback, callback);
    +                }, callback, obj);
    +            }, [oldName, newGivenName, newFamilyName])
    +            .then(function(result) {
    +                if (result && result.hasOwnProperty('code')) {
    +                    throw result;
    +                }
    +                return result;
    +            });
    +    }
    +
    +    function removeTestContacts() {
    +        return driver
    +            .context(webviewContext)
    +            .setAsyncScriptTimeout(MINUTE)
    +            .executeAsync(function (callback) {
    +                var obj = new ContactFindOptions();
    +                obj.filter = 'DeleteMe';
    +                obj.multiple = true;
    +                navigator.contacts.find(['note'], function(contacts) {
    +                    var removes = [];
    +                    contacts.forEach(function(contact) {
    +                        removes.push(contact);
    +                    });
    +                    if (removes.length === 0) {
    +                        return;
    +                    }
    +
    +                   var nextToRemove;
    +                   if (removes.length > 0) {
    +                        nextToRemove = removes.shift();
    +                    }
    +
    +                    function removeNext(item) {
    +                        if (typeof item === 'undefined') {
    +                            callback();
    +                            return;
    +                        }
    +
    +                        if (removes.length > 0) {
    +                            nextToRemove = removes.shift();
    +                        } else {
    +                            nextToRemove = undefined;
    +                        }
    +
    +                        item.remove(function removeSucceeded() {
    +                            removeNext(nextToRemove);
    +                        }, function removeFailed() {
    +                            removeNext(nextToRemove);
    +                        });
    +                    }
    +                    removeNext(nextToRemove);
    +                }, callback, obj);
    +            }, [])
    +            .then(function(result) {
    +                if (typeof result !== 'undefined') {
    +                    throw result;
    +                }
    +            });
    +    }
    +
    +    it('contacts.ui.util configuring driver and starting a session', function (done) {
    +        getDriver()
    +            .fail(fail)
    +            .finally(done);
    +    }, 5 * MINUTE);
    +
    +    describe('Picking contacts', function () {
    +        afterEach(function (done) {
    +            removeTestContacts()
    +                .finally(done);
    +        }, MINUTE);
    +
    +        it('contacts.ui.spec.1 Pick a contact', function (done) {
    +            driver
    +                .then(function () {
    +                    return addContact('Test', 'Contact');
    +                })
    +                .then(function () {
    +                    return pickContact('Test Contact');
    +                })
    +                .then(function (contact) {
    +                    expect(contact.name.givenName).toBe('Test');
    +                    expect(contact.name.familyName).toBe('Contact');
    +                })
    +                .fail(saveScreenshotAndFail)
    +                .finally(done);
    +        }, 5 * MINUTE);
    +
    +        it('contacts.ui.spec.2 Update an existing contact', function (done) {
    +            driver
    +                .then(function () {
    +                    return addContact('Dooney', 'Evans');
    +                })
    +                .then(function () {
    +                    return renameContact('Dooney Evans', 'Urist', 'McContact');
    +                })
    +                .then(function (contact) {
    +                    expect(contact.name.givenName).toBe('Urist');
    +                    expect(contact.name.familyName).toBe('McContact');
    +                })
    +                .then(function () {
    +                    return pickContact('Urist McContact');
    +                })
    +                .then(function (contact) {
    +                    expect(contact.name.givenName).toBe('Urist');
    +                    expect(contact.name.familyName).toBe('McContact');
    +                })
    +                .fail(saveScreenshotAndFail)
    --- End diff --
    
    Taking screenshot should be a part of a promise chain. In fact, some of our current failures (camera plugin) on the CI are there because in that old version of camera tests we take screenshots without respect to the promise chain:
    https://github.com/apache/cordova-plugin-camera/blob/master/appium-tests/android/android.spec.js#L62


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by alsorokin <gi...@git.apache.org>.
Github user alsorokin commented on a diff in the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#discussion_r55824201
  
    --- Diff: appium-tests/android/android.spec.js ---
    @@ -0,0 +1,338 @@
    +/*jshint node: true, jasmine: true */
    +/*
    + *
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + *
    +*/
    +
    +// these tests are meant to be executed by Cordova Medic Appium runner
    +// you can find it here: https://github.com/apache/cordova-medic/
    +// it is not necessary to do a full CI setup to run these tests
    +// just run "node cordova-medic/medic/medic.js appium --platform android --plugins cordova-plugin-contacts"
    +
    +'use strict';
    +
    +var wdHelper = require('../helpers/wdHelper');
    +var screenshotHelper = require('../helpers/screenshotHelper');
    +var contactsHelper = require('../helpers/contactsHelper');
    +
    +var STARTING_MESSAGE = 'Ready for action!';
    +var MINUTE = 60 * 1000;
    +var DEFAULT_WEBVIEW_CONTEXT = 'WEBVIEW';
    +
    +describe('Contacts Android', function () {
    +    var driver;
    +    // the name of webview context, it will be changed to match needed context if there are named ones:
    +    var webviewContext = DEFAULT_WEBVIEW_CONTEXT;
    +    // this indicates that there was a critical error and we should try to recover:
    +    var errorFlag = false;
    +    // this indicates that we couldn't restore Appium session and should fail fast:
    +    var stopFlag = false;
    +
    +    function win() {
    +        expect(true).toBe(true);
    +    }
    +
    +    function fail(error) {
    --- End diff --
    
    I was not aware that they did implement it. Such a nice function, gonna use it a lot.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by dblotsky <gi...@git.apache.org>.
Github user dblotsky commented on a diff in the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#discussion_r55780424
  
    --- Diff: appium-tests/android/android.spec.js ---
    @@ -0,0 +1,338 @@
    +/*jshint node: true, jasmine: true */
    +/*
    + *
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + *
    +*/
    +
    +// these tests are meant to be executed by Cordova Medic Appium runner
    +// you can find it here: https://github.com/apache/cordova-medic/
    +// it is not necessary to do a full CI setup to run these tests
    +// just run "node cordova-medic/medic/medic.js appium --platform android --plugins cordova-plugin-contacts"
    +
    +'use strict';
    +
    +var wdHelper = require('../helpers/wdHelper');
    +var screenshotHelper = require('../helpers/screenshotHelper');
    +var contactsHelper = require('../helpers/contactsHelper');
    +
    +var STARTING_MESSAGE = 'Ready for action!';
    +var MINUTE = 60 * 1000;
    +var DEFAULT_WEBVIEW_CONTEXT = 'WEBVIEW';
    +
    +describe('Contacts Android', function () {
    +    var driver;
    +    // the name of webview context, it will be changed to match needed context if there are named ones:
    +    var webviewContext = DEFAULT_WEBVIEW_CONTEXT;
    +    // this indicates that there was a critical error and we should try to recover:
    +    var errorFlag = false;
    +    // this indicates that we couldn't restore Appium session and should fail fast:
    +    var stopFlag = false;
    +
    +    function win() {
    +        expect(true).toBe(true);
    +    }
    +
    +    function fail(error) {
    --- End diff --
    
    Are we using a version of Jasmine that has a `fail()` function?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by alsorokin <gi...@git.apache.org>.
Github user alsorokin commented on a diff in the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#discussion_r55803719
  
    --- Diff: appium-tests/android/android.spec.js ---
    @@ -0,0 +1,338 @@
    +/*jshint node: true, jasmine: true */
    +/*
    + *
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + *
    +*/
    +
    +// these tests are meant to be executed by Cordova Medic Appium runner
    +// you can find it here: https://github.com/apache/cordova-medic/
    +// it is not necessary to do a full CI setup to run these tests
    +// just run "node cordova-medic/medic/medic.js appium --platform android --plugins cordova-plugin-contacts"
    +
    +'use strict';
    +
    +var wdHelper = require('../helpers/wdHelper');
    +var screenshotHelper = require('../helpers/screenshotHelper');
    +var contactsHelper = require('../helpers/contactsHelper');
    +
    +var STARTING_MESSAGE = 'Ready for action!';
    +var MINUTE = 60 * 1000;
    +var DEFAULT_WEBVIEW_CONTEXT = 'WEBVIEW';
    +
    +describe('Contacts Android', function () {
    +    var driver;
    +    // the name of webview context, it will be changed to match needed context if there are named ones:
    +    var webviewContext = DEFAULT_WEBVIEW_CONTEXT;
    +    // this indicates that there was a critical error and we should try to recover:
    +    var errorFlag = false;
    +    // this indicates that we couldn't restore Appium session and should fail fast:
    +    var stopFlag = false;
    +
    +    function win() {
    +        expect(true).toBe(true);
    +    }
    +
    +    function fail(error) {
    +        if (error === 'rethrow') {
    +            throw error;
    +        }
    +        if (error && error.message) {
    +            console.log('An error occured: ' + error.message);
    +            if (error.stack) {
    +                console.log(error.stack);
    +            }
    +            expect(true).toFailWithMessage(error.message);
    +        } else if (error && typeof error === 'string') {
    +            console.log('Failed expectation: ' + error);
    +            expect(true).toFailWithMessage(error);
    +        } else {
    +            // no message provided :(
    +            expect(true).toBe(false);
    +        }
    +        return screenshotHelper
    +            .saveScreenshot(driver)
    +            .finally(function() {
    +                throw 'rethrow';
    +            });
    +    }
    +
    +    function enterTest() {
    +        return driver
    +            // trying to determine where we are
    +            .context(webviewContext)
    +            .fail(function (error) {
    +                return fail(error);
    +            })
    +            .elementById('info')
    +            .then(function () {
    +                return driver; //we're already on the test screen
    +            }, function () {
    +                return driver
    +                    .elementById('middle')
    +                    .then(function () {
    +                        return driver
    +                            // we're on autotests page, we should go to start page
    +                            .execute('window.location = "../index.html"')
    +                            .sleep(5000)
    +                            .fail(function () {
    +                                errorFlag = true;
    +                                throw 'Couldn\'t find start page.';
    +                            });
    +                    }, function () {
    +                        return; // no-op
    +                    })
    +                    // unknown starting page: no 'info' div
    +                    // adding it manually
    +                    .execute('var info = document.createElement("div"); ' +
    +                             'info.id = "info"; ' +
    +                             'document.body.appendChild(info);');
    +            })
    +            .sleep(5000);
    +    }
    +
    +    function getDriver() {
    +        driver = wdHelper.getDriver('Android');
    +        return driver;
    +    }
    +
    +    function checkStopFlag() {
    +        if (stopFlag) {
    +            fail('Something went wrong: the stopFlag is on. Please see the log for more details.');
    +        }
    +        return stopFlag;
    +    }
    +
    +    beforeEach(function () {
    +        jasmine.addMatchers({
    +            toFailWithMessage: function () {
    +                return {
    +                    compare: function (actual, msg) {
    +                        console.log('Failing with message: ' + msg);
    +                        var result = {
    +                            pass: false,
    +                            message: msg
    +                        };
    +                        // status 6 means that we've lost the session
    +                        // status 7 means that Appium couldn't find an element
    +                        // both these statuses mean that the test has failed but
    +                        // we should try to recreate the session for the following tests
    +                        if (msg.indexOf('Error response status: 6') >= 0 ||
    +                            msg.indexOf('Error response status: 7') >= 0) {
    +                            errorFlag = true;
    +                        }
    +                        return result;
    +                    }
    +                };
    +            },
    +            toContain: function () {
    +                return {
    +                    compare: function (actual, expected) {
    +                        var result = {
    +                            pass: true,
    +                            message: ''
    +                        };
    +                        if (actual.indexOf(expected) < 0)  {
    +                            result.pass = false;
    +                            result.message = 'Expected ' + actual + ' to contain ' + expected;
    +                        }
    +                        return result;
    +                    }
    +                };
    +            }
    +        });
    +    });
    +
    +    it('camera.ui.util configuring driver and starting a session', function (done) {
    +        stopFlag = true; // just in case of timeout
    +        getDriver().then(function () {
    +            stopFlag = false;
    +        }, function (error) {
    +            return fail(error);
    +        })
    +        .finally(done);
    +    }, 5 * MINUTE);
    +
    +    it('camera.ui.util determine webview context name', function (done) {
    +        var i = 0;
    +        return driver
    +            .contexts(function (err, contexts) {
    +                if (err) {
    +                    console.log(err);
    +                }
    +                for (i = 0; i < contexts.length; i++) {
    +                    if (contexts[i].indexOf('mobilespec') >= 0) {
    +                        webviewContext = contexts[i];
    +                    }
    +                }
    +                done();
    +            });
    +    }, MINUTE);
    +
    +    describe("tests", function () {
    +        beforeEach(function (done) {
    +            // prepare the app for the test
    +            if (!stopFlag) {
    +                return driver
    +                    .context(webviewContext)
    +                    .then(function () {
    +                        return driver; // no-op
    +                    }, function (error) {
    +                        expect(true).toFailWithMessage(error);
    +                    })
    +                    .execute('document.getElementById("info").innerHTML = "' + STARTING_MESSAGE + '";')
    +                    .finally(done);
    +            }
    +            done();
    +        }, 3 * MINUTE);
    +
    +        afterEach(function (done) {
    +            if (!errorFlag || stopFlag) {
    +                // either there's no error or we've failed irrecoverably
    +                // nothing to worry about!
    +                done();
    +                return;
    +            }
    +            // recreate the session if there was a critical error in a previous spec
    +            stopFlag = true; // we're going to set this to false if we're able to restore the session
    +            return driver
    +                .quit()
    +                .then(function () {
    +                    return getDriver()
    +                        .then(function () {
    +                            errorFlag = false;
    +                            stopFlag = false;
    +                        }, function (error) {
    +                            return fail(error);
    +                            stopFlag = true;
    +                        });
    +                }, function (error) {
    +                    return fail(error);
    +                    stopFlag = true;
    +                })
    +                .finally(done);
    +        }, 3 * MINUTE);
    +
    +        afterEach(function (done) {
    +            // clean all created contacts
    +            driver
    +                .context(webviewContext)
    +                .execute(contactsHelper.getRemoveTestContactsCode())
    +                .sleep(5000)
    +                .then(win, fail)
    +                .finally(done);
    +        }, MINUTE);
    +
    +        it('contacts.ui.spec.1 Ensuring pick correctness', function (done) {
    +            var contactName = contactsHelper.getContactName('Test', 'Contact');
    +            enterTest()
    +                .execute(contactsHelper.getAddContactCode(contactName.formatted, contactName, "8 800 5553535"))
    +                .sleep(5000)
    +                .execute(contactsHelper.getGetContactsCode())
    +                .sleep(5000)
    +                .elementById('info')
    +                .getAttribute('innerHTML')
    +                .then(function (html) {
    +                    expect(html).toContain(contactName.formatted);
    +                })
    +                .execute(contactsHelper.getPickContactCode())
    +                .sleep(7000)
    +                .context('NATIVE_APP')
    +                .elementByXPath('//android.widget.TextView[@text="' + contactName.formatted + '"]')
    +                .click()
    +                .sleep(5000)
    +                .context(webviewContext)
    +                .elementById('info')
    +                .getAttribute('innerHTML')
    +                .then(function (html) {
    +                    expect(html).toContain('"formatted": "' + contactName.formatted + '"');
    +                })
    +                .then(win, fail)
    +                .finally(done);
    +        }, 5 * MINUTE);
    +
    +        it('contacts.ui.spec.2 Update an existing contact', function (done) {
    +            var oldContactName = contactsHelper.getContactName('Dooney', 'Evans');
    +            var newContactName = contactsHelper.getContactName('Urist', 'McContact');
    +            enterTest()
    +                .execute(contactsHelper.getAddContactCode(oldContactName.formatted, oldContactName, "8 800 5553535"))
    +                .sleep(5000)
    +                .execute(contactsHelper.getRenameContactCode(oldContactName.formatted, newContactName.formatted, newContactName))
    +                .sleep(5000)
    +                .execute(contactsHelper.getPickContactCode())
    +                .sleep(7000)
    +                .context('NATIVE_APP')
    +                .elementByXPath('//android.widget.TextView[@text="' + newContactName.formatted + '"]')
    +                .click()
    +                .sleep(5000)
    +                .context(webviewContext)
    +                .elementById('info')
    +                .getAttribute('innerHTML')
    +                .then(function (html) {
    +                    expect(html).toContain('"formatted": "' + newContactName.formatted + '"');
    +                })
    +                .then(win, fail)
    +                .finally(done);
    +        }, 5 * MINUTE);
    +
    +        it('contacts.ui.spec.3 Create a contact with no info', function (done) {
    +            var contactName = contactsHelper.getContactName();
    +            enterTest()
    +                .execute(contactsHelper.getAddContactCode())
    +                .sleep(5000)
    +                .execute(contactsHelper.getPickContactCode())
    +                .sleep(7000)
    +                .context('NATIVE_APP')
    +                .elementByXPath('//android.widget.TextView[@text="(No name)"]')
    +                .click()
    +                .sleep(5000)
    +                .context(webviewContext)
    +                .elementById('info')
    +                .getAttribute('innerHTML')
    +                .then(function (html) {
    +                    expect(html).toContain('"displayName": null');
    +                })
    +                .then(win, fail)
    +                .finally(done);
    +        }, 5* MINUTE);
    +
    +        it('contacts.ui.spec.4 Special characters and escape sequences', function (done) {
    +            var contactName = contactsHelper.getContactName('Н€йромонах', 'ФеофаЊ');
    +            enterTest()
    +                .execute(contactsHelper.getAddContactCode(contactName.formatted, contactName, '4 5 6789'))
    --- End diff --
    
    This is just a filler for the phone. it's not used anywhere else.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by dblotsky <gi...@git.apache.org>.
Github user dblotsky commented on a diff in the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#discussion_r57245776
  
    --- Diff: appium-tests/common/common.spec.js ---
    @@ -0,0 +1,321 @@
    +/*jshint node: true, jasmine: true, browser: true */
    +/*global ContactFindOptions, ContactName*/
    +
    +/*
    + *
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + *
    +*/
    +
    +// these tests are meant to be executed by Cordova Medic Appium runner
    +// you can find it here: https://github.com/apache/cordova-medic/
    +// it is not necessary to do a full CI setup to run these tests, just run:
    +// node cordova-medic/medic/medic.js appium --platform android --plugins cordova-plugin-contacts
    +
    +'use strict';
    +
    +var wdHelper = global.WD_HELPER;
    +var screenshotHelper = global.SCREENSHOT_HELPER;
    +var contactsHelper = require('../helpers/contactsHelper');
    +
    +var MINUTE = 60 * 1000;
    +var PLATFORM = global.PLATFORM;
    +var UNORM = global.UNORM;
    +
    +describe('Contacts Android', function () {
    +    var driver;
    +    var webviewContext;
    +    var callbackCount = 0;
    +
    +    function getNextCallbackId() {
    +        return 'appium_callback_' + callbackCount++;
    +    }
    +
    +    function saveScreenshotAndFail(error) {
    +        fail(error);
    +        return screenshotHelper
    +            .saveScreenshot(driver)
    +            .quit()
    +            .then(function () {
    +                return getDriver();
    +            });
    +    }
    +
    +    function getDriver() {
    +        var getWebviewContext = function () {
    +            return driver
    +                .contexts()
    +                .then(function (contexts) {
    +                    var found = false;
    +                    // take the last webview context
    +                    for (var i = 0; i < contexts.length ; i++) {
    +                        if (contexts[i].indexOf('WEBVIEW') >= 0) {
    +                            webviewContext = contexts[i];
    +                            found = true;
    +                        }
    +                    }
    +                    if (!found) {
    +                        // no webview context, the app is still loading
    +                        return driver
    +                            .sleep(10000)
    +                            .then(getWebviewContext);
    +                    }
    +                });
    +        };
    +        driver = wdHelper.getDriver(PLATFORM);
    +        return getWebviewContext();
    +    }
    +
    +    function addContact(firstName, lastName) {
    +        var contactName = contactsHelper.getContactName(firstName, lastName);
    +        return driver
    +            .context(webviewContext)
    +            .setAsyncScriptTimeout(MINUTE)
    +            .executeAsync(function(contactname, callback) {
    +                navigator.contacts
    +                    .create({ 'displayName': contactname.formatted, 'name': contactname, 'note': 'DeleteMe' })
    +                    .save(callback, callback);
    +            }, [contactName])
    +            .then(function(result) {
    +                if (result && result.hasOwnProperty('code')) {
    +                    throw result;
    +                }
    +                return result;
    +            });
    +    }
    +
    +    function pickContact(name) {
    +        var callbackId = getNextCallbackId();
    +        return driver
    +            .context(webviewContext)
    +            .execute(function (cbId) {
    +                var cbEl = document.createElement('div');
    +                cbEl.id = cbId;
    +                cbEl.style.display = 'none';
    +                navigator.contacts.pickContact(function (contact) {
    +                    cbEl.innerHTML = JSON.stringify(contact);
    +                    document.body.appendChild(cbEl);
    +                }, function (err) {
    +                    cbEl.innerHTML = 'ERROR: ' + err;
    +                    document.body.appendChild(cbEl);
    +                });
    --- End diff --
    
    @riknoll and I thought about this approach and realized that this can be done in a cleaner way by using promises. Instead of creating a DOM element to store the result, you can wrap the `pickContact` call in a promise and save the promise on the `navigator` object. Then you can just call `.done()` on it using `execAsync` instead of using `waitForElementById`.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by alsorokin <gi...@git.apache.org>.
Github user alsorokin commented on the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#issuecomment-196242692
  
    I'm going to merge it in soon. @dblotsky @riknoll @nikhilkh 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by dblotsky <gi...@git.apache.org>.
Github user dblotsky commented on a diff in the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#discussion_r55780482
  
    --- Diff: appium-tests/android/android.spec.js ---
    @@ -0,0 +1,338 @@
    +/*jshint node: true, jasmine: true */
    +/*
    + *
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + *
    +*/
    +
    +// these tests are meant to be executed by Cordova Medic Appium runner
    +// you can find it here: https://github.com/apache/cordova-medic/
    +// it is not necessary to do a full CI setup to run these tests
    +// just run "node cordova-medic/medic/medic.js appium --platform android --plugins cordova-plugin-contacts"
    +
    +'use strict';
    +
    +var wdHelper = require('../helpers/wdHelper');
    +var screenshotHelper = require('../helpers/screenshotHelper');
    +var contactsHelper = require('../helpers/contactsHelper');
    +
    +var STARTING_MESSAGE = 'Ready for action!';
    +var MINUTE = 60 * 1000;
    +var DEFAULT_WEBVIEW_CONTEXT = 'WEBVIEW';
    +
    +describe('Contacts Android', function () {
    +    var driver;
    +    // the name of webview context, it will be changed to match needed context if there are named ones:
    +    var webviewContext = DEFAULT_WEBVIEW_CONTEXT;
    +    // this indicates that there was a critical error and we should try to recover:
    +    var errorFlag = false;
    +    // this indicates that we couldn't restore Appium session and should fail fast:
    +    var stopFlag = false;
    +
    +    function win() {
    +        expect(true).toBe(true);
    +    }
    +
    +    function fail(error) {
    +        if (error === 'rethrow') {
    +            throw error;
    +        }
    +        if (error && error.message) {
    +            console.log('An error occured: ' + error.message);
    +            if (error.stack) {
    +                console.log(error.stack);
    +            }
    +            expect(true).toFailWithMessage(error.message);
    +        } else if (error && typeof error === 'string') {
    +            console.log('Failed expectation: ' + error);
    +            expect(true).toFailWithMessage(error);
    +        } else {
    +            // no message provided :(
    +            expect(true).toBe(false);
    +        }
    +        return screenshotHelper
    +            .saveScreenshot(driver)
    +            .finally(function() {
    +                throw 'rethrow';
    +            });
    +    }
    +
    +    function enterTest() {
    +        return driver
    +            // trying to determine where we are
    +            .context(webviewContext)
    +            .fail(function (error) {
    +                return fail(error);
    +            })
    +            .elementById('info')
    +            .then(function () {
    +                return driver; //we're already on the test screen
    +            }, function () {
    +                return driver
    +                    .elementById('middle')
    +                    .then(function () {
    +                        return driver
    +                            // we're on autotests page, we should go to start page
    +                            .execute('window.location = "../index.html"')
    +                            .sleep(5000)
    +                            .fail(function () {
    +                                errorFlag = true;
    +                                throw 'Couldn\'t find start page.';
    +                            });
    +                    }, function () {
    +                        return; // no-op
    +                    })
    +                    // unknown starting page: no 'info' div
    +                    // adding it manually
    +                    .execute('var info = document.createElement("div"); ' +
    +                             'info.id = "info"; ' +
    +                             'document.body.appendChild(info);');
    +            })
    +            .sleep(5000);
    +    }
    +
    +    function getDriver() {
    +        driver = wdHelper.getDriver('Android');
    +        return driver;
    +    }
    +
    +    function checkStopFlag() {
    +        if (stopFlag) {
    +            fail('Something went wrong: the stopFlag is on. Please see the log for more details.');
    +        }
    +        return stopFlag;
    +    }
    +
    +    beforeEach(function () {
    +        jasmine.addMatchers({
    +            toFailWithMessage: function () {
    --- End diff --
    
    This matcher is an antipattern. Use spies or the `fail` function.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by dblotsky <gi...@git.apache.org>.
Github user dblotsky commented on a diff in the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#discussion_r55780286
  
    --- Diff: appium-tests/ios/ios.spec.js ---
    @@ -0,0 +1,352 @@
    +/*jshint node: true, jasmine: true */
    +/*
    + *
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + *
    +*/
    +
    +// these tests are meant to be executed by Cordova Medic Appium runner
    +// you can find it here: https://github.com/apache/cordova-medic/
    +// it is not necessary to do a full CI setup to run these tests
    +// just run "node cordova-medic/medic/medic.js appium --platform ios --plugins cordova-plugin-contacts"
    +
    +'use strict';
    +
    +var wdHelper = require('../helpers/wdHelper');
    +var screenshotHelper = require('../helpers/screenshotHelper');
    +var contactsHelper = require('../helpers/contactsHelper');
    +var unorm = global.unorm || require("unorm");
    +
    +var STARTING_MESSAGE = 'Ready for action!';
    +var MINUTE = 60 * 1000;
    +var DEFAULT_WEBVIEW_CONTEXT = 'WEBVIEW_1';
    +
    +describe('contacts tests iOS', function () {
    +    var driver;
    +    // the name of webview context, it will be changed to match needed context if there are named ones:
    +    var webviewContext = DEFAULT_WEBVIEW_CONTEXT;
    +    // this indicates that there was a critical error and we should try to recover:
    +    var errorFlag = false;
    +    // this indicates that we couldn't restore Appium session and should fail fast:
    +    var stopFlag = false;
    +
    +    function win() {
    +        expect(true).toBe(true);
    +    }
    +
    +    function fail(error) {
    +        if (error === 'rethrow') {
    +            throw error;
    +        }
    +        if (error && error.message) {
    +            console.log('An error occured: ' + error.message);
    +            if (error.stack) {
    +                console.log(error.stack);
    +            }
    +            expect(true).toFailWithMessage(error.message);
    +        } else if (error && typeof error === 'string') {
    +            console.log('Failed expectation: ' + error);
    +            expect(true).toFailWithMessage(error);
    +        } else {
    +            // no message provided :(
    +            expect(true).toBe(false);
    +        }
    +        return screenshotHelper
    +            .saveScreenshot(driver)
    +            .finally(function() {
    +                throw 'rethrow';
    +            });
    +    }
    +
    +    function enterTest() {
    +        return driver
    +            // trying to determine where we are
    +            .context(webviewContext)
    +            .fail(function (error) {
    +                return fail(error);
    +            })
    +            .elementById('info')
    +            .then(function () {
    +                return driver; //we're already on the test screen
    +            }, function () {
    +                return driver
    +                    .elementById('middle')
    +                    .then(function () {
    +                        return driver
    +                            // we're on autotests page, we should go to start page
    +                            .execute('window.location = "../index.html"')
    +                            .sleep(5000)
    +                            .fail(function () {
    +                                errorFlag = true;
    +                                throw 'Couldn\'t find start page.';
    +                            });
    +                    }, function () {
    +                        return; // no-op
    +                    })
    +                    // unknown starting page: no 'info' div
    +                    // adding it manually
    +                    .execute('var info = document.createElement("div"); ' +
    +                             'info.id = "info"; ' +
    +                             'document.body.appendChild(info);');
    +            })
    +            .then(win, fail)
    +            .sleep(5000);
    +    }
    +
    +    function getDriver() {
    +        driver = wdHelper.getDriver('iOS');
    +        return driver;
    +    }
    +
    +    function checkStopFlag() {
    +        if (stopFlag) {
    +            fail('Something went wrong: the stopFlag is on. Please see the log for more details.');
    +        }
    +        return stopFlag;
    +    }
    +
    +    beforeEach(function () {
    +        jasmine.addMatchers({
    +            toFailWithMessage : function () {
    +                return {
    +                    compare: function (actual, msg) {
    +                        console.log('Failing with message: ' + msg);
    +                        var result = {
    +                            pass: false,
    +                            message: msg
    +                        };
    +                        // status 6 means that we've lost the session
    +                        // status 7 means that Appium couldn't find an element
    +                        // both these statuses mean that the test has failed but
    +                        // we should try to recreate the session for the following tests
    +                        if (msg.indexOf('Error response status: 6') >= 0 ||
    +                            msg.indexOf('Error response status: 7') >= 0) {
    +                            errorFlag = true;
    +                        }
    +                        return result;
    +                    }
    +                };
    +            },
    +            toContain: function () {
    +                return {
    +                    compare: function (actual, expected) {
    +                        var result = {
    +                            pass: true,
    +                            message: ''
    +                        };
    +                        if (actual.indexOf(expected) < 0)  {
    +                            result.pass = false;
    +                            result.message = 'Expected ' + actual + ' to contain ' + expected;
    +                        }
    +                        return result;
    +                    }
    +                };
    +            }
    +        });
    +    });
    +
    +    it('camera.ui.util configuring driver and starting a session', function (done) {
    +        stopFlag = true; // just in case of timeout
    +        getDriver().then(function () {
    +            stopFlag = false;
    +        }, function (error) {
    +            return fail(error);
    +        })
    +        .then(function() {
    +            return driver.contexts();
    +        })
    +        .finally(done);
    +    }, 5 * MINUTE);
    +
    +    it('camera.ui.util determine webview context name', function (done) {
    +        return driver
    +            .contexts()
    +            .then(function onSuccess (contexts) {
    +                var found = false;
    +                var i;
    +                // take the last named context
    +                for (i = 0; i < contexts.length; i++) {
    +                    if (contexts[i].indexOf('mobilespec') >= 0) {
    +                        webviewContext = contexts[i];
    +                        found = true;
    +                    }
    +                }
    +                // if no named context is found then take the last webview context
    +                if (!found) {
    +                    for (i = 0; i < contexts.length ; i++) {
    +                        if (contexts[i].indexOf('WEBVIEW') >= 0) {
    +                            webviewContext = contexts[i];
    +                        }
    +                    }
    +                }
    +                console.log('Webview context is ' + webviewContext);
    +                done();
    +            }, function onError (err) {
    +                console.log(err);
    +            })
    +            .finally(done);
    +    }, MINUTE);
    +
    +    describe('specs', function () {
    +        beforeEach(function (done) {
    +            // prepare the app for the test
    +            if (!stopFlag) {
    +                return driver
    +                    .context(webviewContext)
    +                    .then(function () {
    +                        return driver; // no-op
    +                    }, function (error) {
    +                        expect(true).toFailWithMessage(error);
    +                    })
    +                    .execute('document.getElementById("info").innerHTML = "' + STARTING_MESSAGE + '";')
    +                    .finally(done);
    +            }
    +            done();
    +        }, 3 * MINUTE);
    +
    +        afterEach(function (done) {
    +            if (!errorFlag || stopFlag) {
    +                // either there's no error or we've failed irrecoverably
    +                // nothing to worry about!
    --- End diff --
    
    Is there a way to loudly announce which of those two happened?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by dblotsky <gi...@git.apache.org>.
Github user dblotsky commented on a diff in the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#discussion_r55780673
  
    --- Diff: appium-tests/android/android.spec.js ---
    @@ -0,0 +1,338 @@
    +/*jshint node: true, jasmine: true */
    +/*
    + *
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + *
    +*/
    +
    +// these tests are meant to be executed by Cordova Medic Appium runner
    +// you can find it here: https://github.com/apache/cordova-medic/
    +// it is not necessary to do a full CI setup to run these tests
    +// just run "node cordova-medic/medic/medic.js appium --platform android --plugins cordova-plugin-contacts"
    +
    +'use strict';
    +
    +var wdHelper = require('../helpers/wdHelper');
    +var screenshotHelper = require('../helpers/screenshotHelper');
    +var contactsHelper = require('../helpers/contactsHelper');
    +
    +var STARTING_MESSAGE = 'Ready for action!';
    +var MINUTE = 60 * 1000;
    +var DEFAULT_WEBVIEW_CONTEXT = 'WEBVIEW';
    +
    +describe('Contacts Android', function () {
    +    var driver;
    +    // the name of webview context, it will be changed to match needed context if there are named ones:
    +    var webviewContext = DEFAULT_WEBVIEW_CONTEXT;
    +    // this indicates that there was a critical error and we should try to recover:
    +    var errorFlag = false;
    +    // this indicates that we couldn't restore Appium session and should fail fast:
    +    var stopFlag = false;
    +
    +    function win() {
    +        expect(true).toBe(true);
    +    }
    +
    +    function fail(error) {
    +        if (error === 'rethrow') {
    +            throw error;
    +        }
    +        if (error && error.message) {
    +            console.log('An error occured: ' + error.message);
    +            if (error.stack) {
    +                console.log(error.stack);
    +            }
    +            expect(true).toFailWithMessage(error.message);
    +        } else if (error && typeof error === 'string') {
    +            console.log('Failed expectation: ' + error);
    +            expect(true).toFailWithMessage(error);
    +        } else {
    +            // no message provided :(
    +            expect(true).toBe(false);
    +        }
    +        return screenshotHelper
    +            .saveScreenshot(driver)
    +            .finally(function() {
    +                throw 'rethrow';
    +            });
    +    }
    +
    +    function enterTest() {
    +        return driver
    +            // trying to determine where we are
    +            .context(webviewContext)
    +            .fail(function (error) {
    +                return fail(error);
    +            })
    +            .elementById('info')
    +            .then(function () {
    +                return driver; //we're already on the test screen
    +            }, function () {
    +                return driver
    +                    .elementById('middle')
    +                    .then(function () {
    +                        return driver
    +                            // we're on autotests page, we should go to start page
    +                            .execute('window.location = "../index.html"')
    +                            .sleep(5000)
    +                            .fail(function () {
    +                                errorFlag = true;
    +                                throw 'Couldn\'t find start page.';
    +                            });
    +                    }, function () {
    +                        return; // no-op
    +                    })
    +                    // unknown starting page: no 'info' div
    +                    // adding it manually
    +                    .execute('var info = document.createElement("div"); ' +
    +                             'info.id = "info"; ' +
    +                             'document.body.appendChild(info);');
    +            })
    +            .sleep(5000);
    +    }
    +
    +    function getDriver() {
    +        driver = wdHelper.getDriver('Android');
    +        return driver;
    +    }
    +
    +    function checkStopFlag() {
    +        if (stopFlag) {
    +            fail('Something went wrong: the stopFlag is on. Please see the log for more details.');
    +        }
    +        return stopFlag;
    +    }
    +
    +    beforeEach(function () {
    +        jasmine.addMatchers({
    +            toFailWithMessage: function () {
    +                return {
    +                    compare: function (actual, msg) {
    +                        console.log('Failing with message: ' + msg);
    +                        var result = {
    +                            pass: false,
    +                            message: msg
    +                        };
    +                        // status 6 means that we've lost the session
    +                        // status 7 means that Appium couldn't find an element
    +                        // both these statuses mean that the test has failed but
    +                        // we should try to recreate the session for the following tests
    +                        if (msg.indexOf('Error response status: 6') >= 0 ||
    +                            msg.indexOf('Error response status: 7') >= 0) {
    +                            errorFlag = true;
    +                        }
    +                        return result;
    +                    }
    +                };
    +            },
    +            toContain: function () {
    +                return {
    +                    compare: function (actual, expected) {
    +                        var result = {
    +                            pass: true,
    +                            message: ''
    +                        };
    +                        if (actual.indexOf(expected) < 0)  {
    +                            result.pass = false;
    +                            result.message = 'Expected ' + actual + ' to contain ' + expected;
    +                        }
    +                        return result;
    +                    }
    +                };
    +            }
    +        });
    +    });
    +
    +    it('camera.ui.util configuring driver and starting a session', function (done) {
    +        stopFlag = true; // just in case of timeout
    +        getDriver().then(function () {
    +            stopFlag = false;
    +        }, function (error) {
    +            return fail(error);
    +        })
    +        .finally(done);
    +    }, 5 * MINUTE);
    --- End diff --
    
    Is there an expect in this spec?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by alsorokin <gi...@git.apache.org>.
Github user alsorokin commented on the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#issuecomment-203324738
  
    Related PR to Medic: https://github.com/apache/cordova-medic/pull/85


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by dblotsky <gi...@git.apache.org>.
Github user dblotsky commented on the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#issuecomment-197586990
  
    @sgrebnov pure code tests that don't need UI interaction should not be in Appium tests. Pure code tests that need UI interaction (like taking a picture) should have a button for them. Option 1 is the path we should take: the app should be automatically and manually testable. Validation logic should follow what humans do, which is to say that it should live in Appium and should inspect output values on the UI.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by dblotsky <gi...@git.apache.org>.
Github user dblotsky commented on a diff in the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#discussion_r55780842
  
    --- Diff: appium-tests/android/android.spec.js ---
    @@ -0,0 +1,338 @@
    +/*jshint node: true, jasmine: true */
    +/*
    + *
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + *
    +*/
    +
    +// these tests are meant to be executed by Cordova Medic Appium runner
    +// you can find it here: https://github.com/apache/cordova-medic/
    +// it is not necessary to do a full CI setup to run these tests
    +// just run "node cordova-medic/medic/medic.js appium --platform android --plugins cordova-plugin-contacts"
    +
    +'use strict';
    +
    +var wdHelper = require('../helpers/wdHelper');
    +var screenshotHelper = require('../helpers/screenshotHelper');
    +var contactsHelper = require('../helpers/contactsHelper');
    +
    +var STARTING_MESSAGE = 'Ready for action!';
    +var MINUTE = 60 * 1000;
    +var DEFAULT_WEBVIEW_CONTEXT = 'WEBVIEW';
    +
    +describe('Contacts Android', function () {
    +    var driver;
    +    // the name of webview context, it will be changed to match needed context if there are named ones:
    +    var webviewContext = DEFAULT_WEBVIEW_CONTEXT;
    +    // this indicates that there was a critical error and we should try to recover:
    +    var errorFlag = false;
    +    // this indicates that we couldn't restore Appium session and should fail fast:
    +    var stopFlag = false;
    +
    +    function win() {
    +        expect(true).toBe(true);
    +    }
    +
    +    function fail(error) {
    +        if (error === 'rethrow') {
    +            throw error;
    +        }
    +        if (error && error.message) {
    +            console.log('An error occured: ' + error.message);
    +            if (error.stack) {
    +                console.log(error.stack);
    +            }
    +            expect(true).toFailWithMessage(error.message);
    +        } else if (error && typeof error === 'string') {
    +            console.log('Failed expectation: ' + error);
    +            expect(true).toFailWithMessage(error);
    +        } else {
    +            // no message provided :(
    +            expect(true).toBe(false);
    +        }
    +        return screenshotHelper
    +            .saveScreenshot(driver)
    +            .finally(function() {
    +                throw 'rethrow';
    +            });
    +    }
    +
    +    function enterTest() {
    +        return driver
    +            // trying to determine where we are
    +            .context(webviewContext)
    +            .fail(function (error) {
    +                return fail(error);
    +            })
    +            .elementById('info')
    +            .then(function () {
    +                return driver; //we're already on the test screen
    +            }, function () {
    +                return driver
    +                    .elementById('middle')
    +                    .then(function () {
    +                        return driver
    +                            // we're on autotests page, we should go to start page
    +                            .execute('window.location = "../index.html"')
    +                            .sleep(5000)
    +                            .fail(function () {
    +                                errorFlag = true;
    +                                throw 'Couldn\'t find start page.';
    +                            });
    +                    }, function () {
    +                        return; // no-op
    +                    })
    +                    // unknown starting page: no 'info' div
    +                    // adding it manually
    +                    .execute('var info = document.createElement("div"); ' +
    +                             'info.id = "info"; ' +
    +                             'document.body.appendChild(info);');
    +            })
    +            .sleep(5000);
    +    }
    +
    +    function getDriver() {
    +        driver = wdHelper.getDriver('Android');
    +        return driver;
    +    }
    +
    +    function checkStopFlag() {
    +        if (stopFlag) {
    +            fail('Something went wrong: the stopFlag is on. Please see the log for more details.');
    +        }
    +        return stopFlag;
    +    }
    +
    +    beforeEach(function () {
    +        jasmine.addMatchers({
    +            toFailWithMessage: function () {
    +                return {
    +                    compare: function (actual, msg) {
    +                        console.log('Failing with message: ' + msg);
    +                        var result = {
    +                            pass: false,
    +                            message: msg
    +                        };
    +                        // status 6 means that we've lost the session
    +                        // status 7 means that Appium couldn't find an element
    +                        // both these statuses mean that the test has failed but
    +                        // we should try to recreate the session for the following tests
    +                        if (msg.indexOf('Error response status: 6') >= 0 ||
    +                            msg.indexOf('Error response status: 7') >= 0) {
    +                            errorFlag = true;
    +                        }
    +                        return result;
    +                    }
    +                };
    +            },
    +            toContain: function () {
    +                return {
    +                    compare: function (actual, expected) {
    +                        var result = {
    +                            pass: true,
    +                            message: ''
    +                        };
    +                        if (actual.indexOf(expected) < 0)  {
    +                            result.pass = false;
    +                            result.message = 'Expected ' + actual + ' to contain ' + expected;
    +                        }
    +                        return result;
    +                    }
    +                };
    +            }
    +        });
    +    });
    +
    +    it('camera.ui.util configuring driver and starting a session', function (done) {
    +        stopFlag = true; // just in case of timeout
    +        getDriver().then(function () {
    +            stopFlag = false;
    +        }, function (error) {
    +            return fail(error);
    +        })
    +        .finally(done);
    +    }, 5 * MINUTE);
    +
    +    it('camera.ui.util determine webview context name', function (done) {
    +        var i = 0;
    +        return driver
    +            .contexts(function (err, contexts) {
    +                if (err) {
    +                    console.log(err);
    +                }
    +                for (i = 0; i < contexts.length; i++) {
    +                    if (contexts[i].indexOf('mobilespec') >= 0) {
    +                        webviewContext = contexts[i];
    +                    }
    +                }
    +                done();
    +            });
    +    }, MINUTE);
    +
    +    describe("tests", function () {
    +        beforeEach(function (done) {
    +            // prepare the app for the test
    +            if (!stopFlag) {
    +                return driver
    +                    .context(webviewContext)
    +                    .then(function () {
    +                        return driver; // no-op
    +                    }, function (error) {
    +                        expect(true).toFailWithMessage(error);
    +                    })
    +                    .execute('document.getElementById("info").innerHTML = "' + STARTING_MESSAGE + '";')
    +                    .finally(done);
    +            }
    +            done();
    +        }, 3 * MINUTE);
    +
    +        afterEach(function (done) {
    +            if (!errorFlag || stopFlag) {
    +                // either there's no error or we've failed irrecoverably
    +                // nothing to worry about!
    +                done();
    +                return;
    +            }
    +            // recreate the session if there was a critical error in a previous spec
    +            stopFlag = true; // we're going to set this to false if we're able to restore the session
    +            return driver
    +                .quit()
    +                .then(function () {
    +                    return getDriver()
    +                        .then(function () {
    +                            errorFlag = false;
    +                            stopFlag = false;
    +                        }, function (error) {
    +                            return fail(error);
    +                            stopFlag = true;
    +                        });
    +                }, function (error) {
    +                    return fail(error);
    +                    stopFlag = true;
    +                })
    +                .finally(done);
    +        }, 3 * MINUTE);
    +
    +        afterEach(function (done) {
    +            // clean all created contacts
    +            driver
    +                .context(webviewContext)
    +                .execute(contactsHelper.getRemoveTestContactsCode())
    +                .sleep(5000)
    +                .then(win, fail)
    +                .finally(done);
    +        }, MINUTE);
    +
    +        it('contacts.ui.spec.1 Ensuring pick correctness', function (done) {
    +            var contactName = contactsHelper.getContactName('Test', 'Contact');
    +            enterTest()
    +                .execute(contactsHelper.getAddContactCode(contactName.formatted, contactName, "8 800 5553535"))
    +                .sleep(5000)
    +                .execute(contactsHelper.getGetContactsCode())
    +                .sleep(5000)
    +                .elementById('info')
    +                .getAttribute('innerHTML')
    +                .then(function (html) {
    +                    expect(html).toContain(contactName.formatted);
    +                })
    +                .execute(contactsHelper.getPickContactCode())
    +                .sleep(7000)
    +                .context('NATIVE_APP')
    +                .elementByXPath('//android.widget.TextView[@text="' + contactName.formatted + '"]')
    +                .click()
    +                .sleep(5000)
    +                .context(webviewContext)
    +                .elementById('info')
    +                .getAttribute('innerHTML')
    +                .then(function (html) {
    +                    expect(html).toContain('"formatted": "' + contactName.formatted + '"');
    +                })
    +                .then(win, fail)
    +                .finally(done);
    +        }, 5 * MINUTE);
    +
    +        it('contacts.ui.spec.2 Update an existing contact', function (done) {
    +            var oldContactName = contactsHelper.getContactName('Dooney', 'Evans');
    +            var newContactName = contactsHelper.getContactName('Urist', 'McContact');
    +            enterTest()
    +                .execute(contactsHelper.getAddContactCode(oldContactName.formatted, oldContactName, "8 800 5553535"))
    +                .sleep(5000)
    +                .execute(contactsHelper.getRenameContactCode(oldContactName.formatted, newContactName.formatted, newContactName))
    +                .sleep(5000)
    +                .execute(contactsHelper.getPickContactCode())
    +                .sleep(7000)
    +                .context('NATIVE_APP')
    +                .elementByXPath('//android.widget.TextView[@text="' + newContactName.formatted + '"]')
    +                .click()
    +                .sleep(5000)
    +                .context(webviewContext)
    +                .elementById('info')
    +                .getAttribute('innerHTML')
    +                .then(function (html) {
    +                    expect(html).toContain('"formatted": "' + newContactName.formatted + '"');
    +                })
    +                .then(win, fail)
    +                .finally(done);
    +        }, 5 * MINUTE);
    +
    +        it('contacts.ui.spec.3 Create a contact with no info', function (done) {
    +            var contactName = contactsHelper.getContactName();
    +            enterTest()
    +                .execute(contactsHelper.getAddContactCode())
    +                .sleep(5000)
    +                .execute(contactsHelper.getPickContactCode())
    +                .sleep(7000)
    +                .context('NATIVE_APP')
    +                .elementByXPath('//android.widget.TextView[@text="(No name)"]')
    +                .click()
    +                .sleep(5000)
    +                .context(webviewContext)
    +                .elementById('info')
    +                .getAttribute('innerHTML')
    +                .then(function (html) {
    +                    expect(html).toContain('"displayName": null');
    +                })
    +                .then(win, fail)
    +                .finally(done);
    +        }, 5* MINUTE);
    +
    +        it('contacts.ui.spec.4 Special characters and escape sequences', function (done) {
    +            var contactName = contactsHelper.getContactName('Н€йромонах', 'ФеофаЊ');
    +            enterTest()
    +                .execute(contactsHelper.getAddContactCode(contactName.formatted, contactName, '4 5 6789'))
    --- End diff --
    
    I don't know if this string in particular occurs in other places, but please check if any literals like it can be factored out into constants.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by dblotsky <gi...@git.apache.org>.
Github user dblotsky commented on a diff in the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#discussion_r57226720
  
    --- Diff: appium-tests/common/common.spec.js ---
    @@ -0,0 +1,321 @@
    +/*jshint node: true, jasmine: true, browser: true */
    +/*global ContactFindOptions, ContactName*/
    +
    +/*
    + *
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + *
    +*/
    +
    +// these tests are meant to be executed by Cordova Medic Appium runner
    +// you can find it here: https://github.com/apache/cordova-medic/
    +// it is not necessary to do a full CI setup to run these tests, just run:
    +// node cordova-medic/medic/medic.js appium --platform android --plugins cordova-plugin-contacts
    +
    +'use strict';
    +
    +var wdHelper = global.WD_HELPER;
    +var screenshotHelper = global.SCREENSHOT_HELPER;
    +var contactsHelper = require('../helpers/contactsHelper');
    +
    +var MINUTE = 60 * 1000;
    +var PLATFORM = global.PLATFORM;
    +var UNORM = global.UNORM;
    +
    +describe('Contacts Android', function () {
    +    var driver;
    +    var webviewContext;
    +    var callbackCount = 0;
    +
    +    function getNextCallbackId() {
    +        return 'appium_callback_' + callbackCount++;
    +    }
    +
    +    function saveScreenshotAndFail(error) {
    +        fail(error);
    +        return screenshotHelper
    +            .saveScreenshot(driver)
    +            .quit()
    +            .then(function () {
    +                return getDriver();
    +            });
    +    }
    +
    +    function getDriver() {
    +        var getWebviewContext = function () {
    +            return driver
    +                .contexts()
    +                .then(function (contexts) {
    +                    var found = false;
    +                    // take the last webview context
    +                    for (var i = 0; i < contexts.length ; i++) {
    +                        if (contexts[i].indexOf('WEBVIEW') >= 0) {
    +                            webviewContext = contexts[i];
    +                            found = true;
    +                        }
    +                    }
    +                    if (!found) {
    +                        // no webview context, the app is still loading
    +                        return driver
    +                            .sleep(10000)
    --- End diff --
    
    Please make this a constant.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by nikhilkh <gi...@git.apache.org>.
Github user nikhilkh commented on the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#issuecomment-193442451
  
    @dblotsky @riknoll to review.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by sgrebnov <gi...@git.apache.org>.
Github user sgrebnov commented on the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#issuecomment-197526519
  
    @dblotsky  We don't have manual tests - we have buttons demonstrating api calls (for both api classes - with and without user interaction), there are no validation logic there.
    
    There are two options how we can proceed IMO (i'm fine with both of them):
    1. Made them as real tests (as you mentioned above so you can run them w/o appium). I actually support idea to be able to run tests manually if needed. Where do you think should be validation logic in this case (appium side or client app side)? Should we create separate button for each option/combination for Camera tests for example, or use switches/etc. Also manual api code writes  results to divs/dom elements so we will have to bring extra complexity to tests to find/parse results from dom elements before validation.
    2. Don't use those buttons at all (same reason why unit tests don't rely on calling buttons) - calling single cordova function from appium and getting callback result is simple. This may lead to more clean/readable code and tests definitions and simplify tests maintenance.
    
    Agree regarding `fn.toString()`, but there is a special function for this - you can execute function in browser context from appium.
    http://webdriver.io/api/protocol/execute.html


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org


[GitHub] cordova-plugin-contacts pull request: CB-10399 Added Appium tests

Posted by alsorokin <gi...@git.apache.org>.
Github user alsorokin commented on a diff in the pull request:

    https://github.com/apache/cordova-plugin-contacts/pull/101#discussion_r55976166
  
    --- Diff: appium-tests/helpers/contactsHelper.js ---
    @@ -0,0 +1,222 @@
    +/* jshint node: true */
    +/*
    + *
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *   http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + *
    +*/
    +
    +'use strict';
    +
    +function prepare(item) {
    +    if (typeof item === 'object') {
    +        return JSON.stringify(item);
    +    }
    +    if (typeof item === 'string') {
    +        return '"' + item + '"';
    +    }
    +    return undefined;
    +}
    +
    +module.exports.getContactName = function (firstName, lastName) {
    +    return {
    +        formatted: firstName == lastName === undefined ? null : firstName + ' ' + lastName,
    +        familyName: lastName,
    +        givenName: firstName,
    +        middleName: ''
    +    };
    +};
    +
    +module.exports.getAddContactCode = function (displayName, contactName, phoneNumber) {
    +    var preparedDisplayName = prepare(displayName);
    +    console.log('preparedDisplayName is ' + preparedDisplayName);
    +    var preparedContactName = prepare(contactName);
    +    var preparedPhoneNumber = prepare(phoneNumber);
    +
    +    var result =
    +        'try {\n' +
    +        '    var results = document.getElementById("info");\n' +
    +        '    var contact = navigator.contacts.create({ "displayName": ' + preparedDisplayName + ', "name": ' + preparedContactName + ', "note": "DeleteMe" });\n' +
    +
    +        '    var phoneNumbers = [1];\n' +
    +        '    phoneNumbers[0] = new ContactField("work", ' + preparedPhoneNumber + ', true);\n' +
    +        '    contact.phoneNumbers = phoneNumbers;\n' +
    +
    +        '    contact.save(function() {\n' +
    +        '        results.innerHTML = "' + (displayName || 'Nameless contact') + ' saved.";\n' +
    +        '    }, function(e) {\n' +
    +        '        if (e.code === ContactError.NOT_SUPPORTED_ERROR) {\n' +
    +        '            results.innerHTML = "Saving contacts not supported.";\n' +
    +        '        } else {\n' +
    +        '            results.innerHTML = "Contact save failed: error " + e.code;\n' +
    +        '        }\n' +
    +        '    });\n' +
    +        '} catch (e) {\n' +
    +        '    var results = document.getElementById("info");\n' +
    +        '    results.innerHTML = "ERROR: " + e.code;\n' +
    +        '}\n';
    +
    +    return result;
    +};
    +
    +module.exports.getGetContactsCode = function (filter) {
    +    var preparedFilter = prepare(filter);
    +
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'var obj = new ContactFindOptions();\n' +
    +        'if (' + preparedFilter + ') {\n' +
    +        '    obj.filter = ' + preparedFilter + ';\n' +
    +        '}\n' +
    +        'obj.multiple = true;\n' +
    +        'navigator.contacts.find(["displayName", "name", "phoneNumbers", "emails", "urls", "note"], function(contacts) {\n' +
    +        '    var s = "";\n' +
    +        '    if (contacts.length === 0) {\n' +
    +        '        s = "No contacts found";\n' +
    +        '    } else {\n' +
    +        '        s = "Number of contacts: " + contacts.length + "<br><table width=100%><tr><th>Name</th><td>Phone</td><td>Email</td></tr>";\n' +
    +        '        for (var i = 0; i < contacts.length; i++) {\n' +
    +        '            var contact = contacts[i];\n' +
    +        '            var contactNameTag = contact.name ? "<tr><td>" + contact.name.formatted + "</td><td>" : "<tr><td>(No Name)</td><td>";\n' +
    +        '            s = s + contactNameTag;\n' +
    +        '            if (contact.phoneNumbers && contact.phoneNumbers.length > 0) {\n' +
    +        '                s = s + contact.phoneNumbers[0].value;\n' +
    +        '            }\n' +
    +        '            s = s + "</td><td>";\n' +
    +        '            if (contact.emails && contact.emails.length > 0) {\n' +
    +        '                s = s + contact.emails[0].value;\n' +
    +        '            }\n' +
    +        '            s = s + "</td></tr>";\n' +
    +        '    }\n' +
    +        '        s = s + "</table>";\n' +
    +        '    }\n' +
    +        '    results.innerHTML = s;\n' +
    +        '}, function(e) {\n' +
    +        '   results.innerHTML = "Search failed: error " + e.code;\n' +
    +        '}, obj);';
    +
    +    return result;
    +};
    +
    +module.exports.getPickContactCode = function () {
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'navigator.contacts.pickContact(\n' +
    +        '    function (contact) {\n' +
    +        '        results.innerHTML = contact ?\n' +
    +        '            "Picked contact: <pre>" + JSON.stringify(contact, null, 4) + "</pre>" :\n' +
    +        '            "No contacts found";\n' +
    +        '    },\n' +
    +        '    function (e) {\n' +
    +        '        results.innerHTML = e && e.code === ContactError.OPERATION_CANCELLED_ERROR ?\n' +
    +        '                "Pick cancelled" :\n' +
    +        '                "Pick failed: " + (e && e.code);\n' +
    +        '    }\n' +
    +        ');';
    +
    +    return result;
    +};
    +
    +module.exports.getRenameContactCode = function (oldDisplayName, newDisplayName, newName) {
    +    // these default values are copied from manual contacts tests
    +    if (!oldDisplayName) {
    +        oldDisplayName = 'Dooney Evans';
    +    }
    +    if (!newDisplayName) {
    +        newDisplayName = 'Urist McContact';
    +    }
    +    if (!newName) {
    +        newName = module.exports.getContactName('Urist', 'McContact');
    +    }
    +    var preparedOldDisplayName = prepare(oldDisplayName);
    +    var preparedNewDisplayName = prepare(newDisplayName);
    +    var preparedNewName = prepare(newName);
    +
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'var obj = new ContactFindOptions();\n' +
    +        'obj.filter = ' + preparedOldDisplayName + ';\n' +
    +        'obj.multiple = false;\n' +
    +
    +        'navigator.contacts.find(["displayName", "name"], function(contacts) {\n' +
    +        '    if (contacts.length === 0) {\n' +
    +        '        results.innerHTML = "No contacts to update.";\n' +
    +        '        return;\n' +
    +        '    }\n' +
    +        '    var contact = contacts[0];\n' +
    +        '    contact.displayName = ' + preparedNewDisplayName + ';\n' +
    +        '    contact.name = ' + preparedNewName + ';\n' +
    +        '    contact.save(function(updated) {\n' +
    +        '        results.innerHTML = "Contact updated.";\n' +
    +        '    },function(e) {\n' +
    +        '        results.innerHTML = "Update failed: error " + e.code;\n' +
    +        '    });\n' +
    +        '}, function(e) {\n' +
    +        '    results.innerHTML = "Search failed: error " + e.code;\n' +
    +        '}, obj);';
    +
    +    return result;
    +};
    +
    +module.exports.getRemoveTestContactsCode = function () {
    +    var result =
    +        'var results = document.getElementById("info");\n' +
    +        'results.innerHTML = "";\n' +
    +        'var obj = new ContactFindOptions();\n' +
    +        'obj.filter = "DeleteMe";\n' +
    +        'obj.multiple = true;\n' +
    +        'navigator.contacts.find(["note"], function(contacts) {\n' +
    +        '    var removes = [];\n' +
    +        '    contacts.forEach(function(contact) {\n' +
    +        '        removes.push(contact);\n' +
    +        '    });\n' +
    +        '    if (removes.length === 0) {\n' +
    +        '        results.innerHTML = "No contacts to remove";\n' +
    +        '        return;\n' +
    +        '    }\n' +
    +
    +        '   var nextToRemove;\n' +
    +        '   if (removes.length > 0) {\n' +
    +        '        nextToRemove = removes.shift();\n' +
    +        '    }\n' +
    +
    +        '    function removeNext(item) {\n' +
    +        '        if (typeof item === "undefined") {\n' +
    +        '            return;\n' +
    +        '        }\n' +
    +
    +        '        if (removes.length > 0) {\n' +
    +        '            nextToRemove = removes.shift();\n' +
    +        '        } else {\n' +
    +        '            nextToRemove = undefined;\n' +
    +        '        }\n' +
    +
    +        '        item.remove(function removeSucceeded() {\n' +
    +        '            results.innerHTML += "Removed a contact with ID " + item.id + "<br/>";\n' +
    +        '            removeNext(nextToRemove);\n' +
    +        '        }, function removeFailed() {\n' +
    +        '            results.innerHTML += "Failed to remove a contact with ID " + item.id + "<br/>";\n' +
    +        '            removeNext(nextToRemove);\n' +
    +        '        });\n' +
    +        '    }\n' +
    +        '    removeNext(nextToRemove);\n' +
    +        '}, function(e) {\n' +
    +        '   results.innerHTML = "Search failed: error " + e.code;\n' +
    +        '}, obj);';
    +
    +    return result;
    +};
    --- End diff --
    
    There are other way: we could just click the buttons in the mobilespec app's manual tests.
    I've found a couple of downsides of such approach:
    - We are tightly tied to the mobilespec app and its implementation: should there be changes to it's markup/navigation, or to the manual tests, we're bound to change the appium tests too
    - Appium tests look more complicated. For example, to debug a failing Appium test which clicks a button in the manual test I need to look at the Appium code, see which button is clicked, like here: `elementByXPath('//a[text()="Add new nameless contact"]')`, go to the manual tests, find the code that creates this particular button and finally find a click handler function for this particular button. All this opposed to just having the executed code close at hand, in the helper function.
    - Clicking buttons can be difficult :) For example, Appium is having a huge problem scrolling the page to find a button which is out of view on iOS simulator.
    
    Could you please describe your thoughts about the current implementation and why are you against it?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@cordova.apache.org
For additional commands, e-mail: dev-help@cordova.apache.org