You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ag...@apache.org on 2014/07/07 20:08:11 UTC

[07/19] Move mobilespec into www/ so as to not include non-app files in the app

http://git-wip-us.apache.org/repos/asf/cordova-mobile-spec/blob/77ff9a37/www/autotest/tests/contacts.tests.js
----------------------------------------------------------------------
diff --git a/www/autotest/tests/contacts.tests.js b/www/autotest/tests/contacts.tests.js
new file mode 100644
index 0000000..73a605c
--- /dev/null
+++ b/www/autotest/tests/contacts.tests.js
@@ -0,0 +1,542 @@
+/*
+ *
+ * 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.
+ *
+*/
+
+// global to store a contact so it doesn't have to be created or retrieved multiple times
+// all of the setup/teardown test methods can reference the following variables to make sure to do the right cleanup
+var gContactObj = null,
+    gContactId = null,
+    isWindowsPhone = cordova.platformId == 'windowsphone';
+
+var removeContact = function(){
+    if (gContactObj) {
+        gContactObj.remove(function(){},function(){
+            console.log("[CONTACTS ERROR]: removeContact cleanup method failed to clean up test artifacts.");
+        });
+        gContactObj = null;
+    }
+};
+
+describe("Contacts (navigator.contacts)", function () {
+    it("contacts.spec.1 should exist", function() {
+        expect(navigator.contacts).toBeDefined();
+    });
+
+    it("contacts.spec.2 should contain a find function", function() {
+        expect(navigator.contacts.find).toBeDefined();
+        expect(typeof navigator.contacts.find).toBe('function');
+    });
+
+    describe("find method", function() {
+        it("contacts.spec.3 success callback should be called with an array", function() {
+            var win = jasmine.createSpy().andCallFake(function(result) {
+                    expect(result).toBeDefined();
+                    expect(result instanceof Array).toBe(true);
+                }),
+                fail = jasmine.createSpy(),
+                obj = new ContactFindOptions();
+
+            runs(function () {
+                obj.filter="";
+                obj.multiple=true;
+                navigator.contacts.find(["displayName", "name", "phoneNumbers", "emails"], win, fail, obj);
+            });
+
+            waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+            runs(function () {
+                expect(fail).not.toHaveBeenCalled();
+            });
+        });
+
+        it("success callback should be called with an array, even if partial ContactFindOptions specified", function () {
+            var win = jasmine.createSpy().andCallFake(function (result) {
+                expect(result).toBeDefined();
+                expect(result instanceof Array).toBe(true);
+            }),
+                fail = jasmine.createSpy();
+
+            runs(function () {
+                navigator.contacts.find(["displayName", "name", "phoneNumbers", "emails"], win, fail, {
+                    multiple: true
+                });
+            });
+
+            waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+            runs(function () {
+                expect(fail).not.toHaveBeenCalled();
+            });
+        });
+
+        it("contacts.spec.4 should throw an exception if success callback is empty", function() {
+            var fail = function() {};
+            var obj = new ContactFindOptions();
+            obj.filter="";
+            obj.multiple=true;
+
+            expect(function () {
+                navigator.contacts.find(["displayName", "name", "emails", "phoneNumbers"], null, fail, obj);
+            }).toThrow();
+        });
+
+        it("contacts.spec.5 error callback should be called when no fields are specified", function() {
+            var win = jasmine.createSpy(),
+                fail = jasmine.createSpy(function(result) {
+                    expect(result).toBeDefined();
+                    expect(result.code).toBe(ContactError.INVALID_ARGUMENT_ERROR);
+                }),
+                obj = new ContactFindOptions();
+
+            runs(function () {
+                obj.filter="";
+                obj.multiple=true;
+                navigator.contacts.find([], win, fail, obj);
+            });
+
+            waitsFor(function () { return fail.wasCalled; }, Tests.TEST_TIMEOUT);
+
+            runs(function () {
+                expect(win).not.toHaveBeenCalled();
+                expect(fail).toHaveBeenCalled();
+            });
+        });
+
+        describe("with newly-created contact", function () {
+
+            afterEach(removeContact);
+
+            it("contacts.spec.6 should be able to find a contact by name", function() {
+
+                // this api requires manual user confirmation on WP7/8 so skip it
+                if (isWindowsPhone) return;
+
+                var foundName = jasmine.createSpy().andCallFake(function(result) {
+                        var bFound = false;
+                        try {
+                            for (var i=0; i < result.length; i++) {
+                                if (result[i].name.familyName == "Delete") {
+                                    bFound = true;
+                                    break;
+                                }
+                            }
+                        } catch(e) {
+                            return false;
+                        }
+                        return bFound;
+                    }),
+                    fail = jasmine.createSpy(),
+                    test = jasmine.createSpy().andCallFake(function(savedContact) {
+                        console.log('in test');
+                        // update so contact will get removed
+                        gContactObj = savedContact;
+                        // ----
+                        // Find asserts
+                        // ---
+                        var findWin = jasmine.createSpy().andCallFake(function(object) {
+                                console.log('in findwin');
+                                expect(object instanceof Array).toBe(true);
+                                expect(object.length >= 1).toBe(true);
+                                expect(foundName(object)).toBe(true);
+                            }),
+                            findFail = jasmine.createSpy(),
+                            obj = new ContactFindOptions();
+
+                        obj.filter="Delete";
+                        obj.multiple=true;
+
+                        runs(function () {
+                            navigator.contacts.find(["displayName", "name", "phoneNumbers", "emails"], findWin, findFail, obj);
+                        });
+
+                        waitsFor(function () { return foundName.wasCalled; }, "foundName not done", Tests.TEST_TIMEOUT);
+
+                        runs(function () {
+                            expect(findFail).not.toHaveBeenCalled();
+                            expect(fail).not.toHaveBeenCalled();
+                        });
+                    });
+
+                runs(function () {
+                    gContactObj = new Contact();
+                    gContactObj.name = new ContactName();
+                    gContactObj.name.familyName = "Delete";
+                    gContactObj.save(test, fail);
+                });
+
+                waitsFor(function () { return test.wasCalled; }, "test not done", Tests.TEST_TIMEOUT);
+            });
+        });
+    });
+
+    describe('create method', function() {
+
+        it("contacts.spec.7 should exist", function() {
+            expect(navigator.contacts.create).toBeDefined();
+            expect(typeof navigator.contacts.create).toBe('function');
+        });
+
+        it("contacts.spec.8 should return a Contact object", function() {
+            var bDay = new Date(1976, 7,4);
+            var obj = navigator.contacts.create({"displayName": "test name", "gender": "male", "note": "my note", "name": {"formatted": "Mr. Test Name"}, "emails": [{"value": "here@there.com"}, {"value": "there@here.com"}], "birthday": bDay});
+
+            expect(obj).toBeDefined();
+            expect(obj.displayName).toBe('test name');
+            expect(obj.note).toBe('my note');
+            expect(obj.name.formatted).toBe('Mr. Test Name');
+            expect(obj.emails.length).toBe(2);
+            expect(obj.emails[0].value).toBe('here@there.com');
+            expect(obj.emails[1].value).toBe('there@here.com');
+            expect(obj.nickname).toBe(null);
+            expect(obj.birthday).toBe(bDay);
+        });
+    });
+
+    describe("Contact object", function () {
+        it("contacts.spec.9 should be able to create instance", function() {
+            var contact = new Contact("a", "b", new ContactName("a", "b", "c", "d", "e", "f"), "c", [], [], [], [], [], "f", "i",
+                [], [], []);
+            expect(contact).toBeDefined();
+            expect(contact.id).toBe("a");
+            expect(contact.displayName).toBe("b");
+            expect(contact.name.formatted).toBe("a");
+            expect(contact.nickname).toBe("c");
+            expect(contact.phoneNumbers).toBeDefined();
+            expect(contact.emails).toBeDefined();
+            expect(contact.addresses).toBeDefined();
+            expect(contact.ims).toBeDefined();
+            expect(contact.organizations).toBeDefined();
+            expect(contact.birthday).toBe("f");
+            expect(contact.note).toBe("i");
+            expect(contact.photos).toBeDefined();
+            expect(contact.categories).toBeDefined();
+            expect(contact.urls).toBeDefined();
+        });
+
+        it("contacts.spec.10 should be able to define a ContactName object", function() {
+            var contactName = new ContactName("Dr. First Last Jr.", "Last", "First", "Middle", "Dr.", "Jr.");
+            expect(contactName).toBeDefined();
+            expect(contactName.formatted).toBe("Dr. First Last Jr.");
+            expect(contactName.familyName).toBe("Last");
+            expect(contactName.givenName).toBe("First");
+            expect(contactName.middleName).toBe("Middle");
+            expect(contactName.honorificPrefix).toBe("Dr.");
+            expect(contactName.honorificSuffix).toBe("Jr.");
+        });
+
+        it("contacts.spec.11 should be able to define a ContactField object", function() {
+            var contactField = new ContactField("home", "8005551212", true);
+            expect(contactField).toBeDefined();
+            expect(contactField.type).toBe("home");
+            expect(contactField.value).toBe("8005551212");
+            expect(contactField.pref).toBe(true);
+        });
+
+        it("contacts.spec.12 ContactField object should coerce type and value properties to strings", function() {
+            var contactField = new ContactField(12345678, 12345678, true);
+            expect(contactField.type).toBe("12345678");
+            expect(contactField.value).toBe("12345678");
+        });
+
+        it("contacts.spec.13 should be able to define a ContactAddress object", function() {
+            var contactAddress = new ContactAddress(true, "home", "a","b","c","d","e","f");
+            expect(contactAddress).toBeDefined();
+            expect(contactAddress.pref).toBe(true);
+            expect(contactAddress.type).toBe("home");
+            expect(contactAddress.formatted).toBe("a");
+            expect(contactAddress.streetAddress).toBe("b");
+            expect(contactAddress.locality).toBe("c");
+            expect(contactAddress.region).toBe("d");
+            expect(contactAddress.postalCode).toBe("e");
+            expect(contactAddress.country).toBe("f");
+        });
+
+        it("contacts.spec.14 should be able to define a ContactOrganization object", function() {
+            var contactOrg = new ContactOrganization(true, "home", "a","b","c","d","e","f","g");
+            expect(contactOrg).toBeDefined();
+            expect(contactOrg.pref).toBe(true);
+            expect(contactOrg.type).toBe("home");
+            expect(contactOrg.name).toBe("a");
+            expect(contactOrg.department).toBe("b");
+            expect(contactOrg.title).toBe("c");
+        });
+
+        it("contacts.spec.15 should be able to define a ContactFindOptions object", function() {
+            var contactFindOptions = new ContactFindOptions("a", true, "b");
+            expect(contactFindOptions).toBeDefined();
+            expect(contactFindOptions.filter).toBe("a");
+            expect(contactFindOptions.multiple).toBe(true);
+        });
+
+        it("contacts.spec.16 should contain a clone function", function() {
+            var contact = new Contact();
+            expect(contact.clone).toBeDefined();
+            expect(typeof contact.clone).toBe('function');
+        });
+
+        it("contacts.spec.17 clone function should make deep copy of Contact Object", function() {
+            var contact = new Contact();
+            contact.id=1;
+            contact.displayName="Test Name";
+            contact.nickname="Testy";
+            contact.gender="male";
+            contact.note="note to be cloned";
+            contact.name = new ContactName("Mr. Test Name");
+
+            var clonedContact = contact.clone();
+
+            expect(contact.id).toBe(1);
+            expect(clonedContact.id).toBe(null);
+            expect(clonedContact.displayName).toBe(contact.displayName);
+            expect(clonedContact.nickname).toBe(contact.nickname);
+            expect(clonedContact.gender).toBe(contact.gender);
+            expect(clonedContact.note).toBe(contact.note);
+            expect(clonedContact.name.formatted).toBe(contact.name.formatted);
+            expect(clonedContact.connected).toBe(contact.connected);
+        });
+
+        it("contacts.spec.18 should contain a save function", function() {
+            var contact = new Contact();
+            expect(contact.save).toBeDefined();
+            expect(typeof contact.save).toBe('function');
+        });
+
+        it("contacts.spec.19 should contain a remove function", function() {
+            var contact = new Contact();
+            expect(contact.remove).toBeDefined();
+            expect(typeof contact.remove).toBe('function');
+        });
+    });
+
+    describe('save method', function () {
+        it("contacts.spec.20 should be able to save a contact", function() {
+
+            // this api requires manual user confirmation on WP7/8 so skip it
+            if (isWindowsPhone) return;
+
+            var bDay = new Date(1976, 6,4);
+            gContactObj = navigator.contacts.create({"gender": "male", "note": "my note", "name": {"familyName": "Delete", "givenName": "Test"}, "emails": [{"value": "here@there.com"}, {"value": "there@here.com"}], "birthday": bDay});
+
+            var saveSuccess = jasmine.createSpy().andCallFake(function(obj) {
+                    expect(obj).toBeDefined();
+                    if (cordova.platformId !== 'blackberry10') {
+                        expect(obj.note).toBe('my note');
+                    }
+                    expect(obj.name.familyName).toBe('Delete');
+                    expect(obj.name.givenName).toBe('Test');
+                    expect(obj.emails.length).toBe(2);
+                    expect(obj.emails[0].value).toBe('here@there.com');
+                    expect(obj.emails[1].value).toBe('there@here.com');
+                    expect(obj.birthday.toDateString()).toBe(bDay.toDateString());
+                    expect(obj.addresses).toBe(null);
+                    // must store returned object in order to have id for update test below
+                    gContactObj = obj;
+                }),
+                saveFail = jasmine.createSpy();
+
+            runs(function () {
+                gContactObj.save(saveSuccess, saveFail);
+            });
+
+            waitsFor(function () { return saveSuccess.wasCalled; }, "saveSuccess never called", Tests.TEST_TIMEOUT);
+
+            runs(function () {
+                expect(saveFail).not.toHaveBeenCalled();
+            });
+         });
+        // HACK: there is a reliance between the previous and next test. This is bad form.
+        it("contacts.spec.21 update a contact", function() {
+
+            // this api requires manual user confirmation on WP7/8 so skip it
+            if (isWindowsPhone) return;
+
+            expect(gContactObj).toBeDefined();
+
+            var bDay = new Date(1975, 5,4);
+            var noteText = "an UPDATED note";
+
+            var win = jasmine.createSpy().andCallFake(function(obj) {
+                    expect(obj).toBeDefined();
+                    expect(obj.id).toBe(gContactObj.id);
+                    if (cordova.platformId !== 'blackberry10') {
+                        expect(obj.note).toBe(noteText);
+                    }
+                    expect(obj.birthday.toDateString()).toBe(bDay.toDateString());
+                    expect(obj.emails.length).toBe(1);
+                    expect(obj.emails[0].value).toBe('here@there.com');
+                    removeContact();         // Clean up contact object
+                }), fail = jasmine.createSpy().andCallFake(removeContact);
+
+            runs(function () {
+                // remove an email
+                gContactObj.emails[1].value = "";
+                // change birthday
+                gContactObj.birthday = bDay;
+                // update note
+                gContactObj.note = noteText;
+                gContactObj.save(win, fail);
+            });
+
+            waitsFor(function () { return win.wasCalled; }, "saveSuccess never called", Tests.TEST_TIMEOUT);
+
+            runs(function () {
+                expect(fail).not.toHaveBeenCalled();
+            });
+        });
+    });
+
+    describe('Contact.remove method', function () {
+        afterEach(removeContact);
+
+        it("contacts.spec.22 calling remove on a contact has an id of null should return ContactError.UNKNOWN_ERROR", function() {
+            var win = jasmine.createSpy();
+            var fail = jasmine.createSpy().andCallFake(function(result) {
+                expect(result.code).toBe(ContactError.UNKNOWN_ERROR);
+            });
+
+            runs(function () {
+                var rmContact = new Contact();
+                rmContact.remove(win, fail);
+            });
+
+            waitsFor(function () { return fail.wasCalled; }, Tests.TEST_TIMEOUT);
+
+            runs(function () {
+                expect(win).not.toHaveBeenCalled();
+            });
+        });
+
+        it("contacts.spec.23 calling remove on a contact that does not exist should return ContactError.UNKNOWN_ERROR", function() {
+            var win = jasmine.createSpy();
+            var fail = jasmine.createSpy().andCallFake(function(result) {
+                expect(result.code).toBe(ContactError.UNKNOWN_ERROR);
+            });
+
+            runs(function () {
+                var rmContact = new Contact();
+                // this is a bit risky as some devices may have contact ids that large
+                var contact = new Contact("this string is supposed to be a unique identifier that will never show up on a device");
+                contact.remove(win, fail);
+            });
+
+            waitsFor(function () { return fail.wasCalled; }, Tests.TEST_TIMEOUT);
+
+            runs(function () {
+                expect(win).not.toHaveBeenCalled();
+            });
+        });
+    });
+
+    describe("Round trip Contact tests (creating + save + delete + find).", function () {
+        it("contacts.spec.24 Creating, saving, finding a contact should work, removing it should work, after which we should not be able to find it, and we should not be able to delete it again.", function() {
+
+            // this api requires manual user confirmation on WP7/8 so skip it
+            if (isWindowsPhone) return;
+
+            var done = false;
+            runs(function () {
+                gContactObj = new Contact();
+                gContactObj.name = new ContactName();
+                gContactObj.name.familyName = "DeleteMe";
+                gContactObj.save(function(c_obj) {
+                    var findWin = function(cs) {
+                        expect(cs.length).toBe(1);
+                        // update to have proper saved id
+                        gContactObj = cs[0];
+                        gContactObj.remove(function() {
+                            var findWinAgain = function(seas) {
+                                expect(seas.length).toBe(0);
+                                gContactObj.remove(function() {
+                                    throw("success callback called after non-existent Contact object called remove(). Test failed.");
+                                }, function(e) {
+                                    expect(e.code).toBe(ContactError.UNKNOWN_ERROR);
+                                    done = true;
+                                });
+                            };
+                            var findFailAgain = function(e) {
+                                throw("find error callback invoked after delete, test failed.");
+                            };
+                            var obj = new ContactFindOptions();
+                            obj.filter="DeleteMe";
+                            obj.multiple=true;
+                            navigator.contacts.find(["displayName", "name", "phoneNumbers", "emails"], findWinAgain, findFailAgain, obj);
+                        }, function(e) {
+                            throw("Newly created contact's remove function invoked error callback. Test failed.");
+                        });
+                    };
+                    var findFail = function(e) {
+                        throw("Failure callback invoked in navigator.contacts.find call, test failed.");
+                    };
+                    var obj = new ContactFindOptions();
+                    obj.filter="DeleteMe";
+                    obj.multiple=true;
+                    navigator.contacts.find(["displayName", "name", "phoneNumbers", "emails"], findWin, findFail, obj);
+                }, function(e) {
+                    throw("Contact creation failed, error callback was invoked.");
+                });
+            });
+
+            waitsFor(function () { return done; }, Tests.TEST_TIMEOUT);
+        });
+    });
+
+    describe('ContactError interface', function () {
+        it("contacts.spec.25 ContactError constants should be defined", function() {
+            expect(ContactError.UNKNOWN_ERROR).toBe(0);
+            expect(ContactError.INVALID_ARGUMENT_ERROR).toBe(1);
+            expect(ContactError.TIMEOUT_ERROR).toBe(2);
+            expect(ContactError.PENDING_OPERATION_ERROR).toBe(3);
+            expect(ContactError.IO_ERROR).toBe(4);
+            expect(ContactError.NOT_SUPPORTED_ERROR).toBe(5);
+            expect(ContactError.PERMISSION_DENIED_ERROR).toBe(20);
+        });
+    });
+
+    describe("Contacts autotests cleanup", function () {
+        it("contacts.spec.26 Cleanup any DeleteMe contacts from Contacts tests.", function() {
+            var done = false;
+            var obj = new ContactFindOptions();
+            obj.filter="DeleteMe";
+            obj.multiple=true;
+            runs(function () {
+                var findSuccess = function (cs) {
+                    var contactObj = new Contact();
+                    if (cs.length>0){
+                        contactObj = cs[0];
+                        contactObj.remove(function(){
+                            console.log("[CONTACTS CLEANUP] DeleteMe contact successfully removed");
+                            navigator.contacts.find(["displayName", "name", "phoneNumbers", "emails"], findSuccess, findFail, obj);
+                        },function(){
+                            console.log("[CONTACTS CLEANUP ERROR]: failed to remove DeleteMe contact");
+                        });
+                    } else {
+                        done = true;
+                    }
+                };
+                var findFail = function(e) {
+                    throw("Failure callback invoked in navigator.contacts.find call, test failed.");
+                };
+                navigator.contacts.find(["displayName", "name", "phoneNumbers", "emails"], findSuccess, findFail, obj);
+            });
+            waitsFor(function () { return done; }, Tests.TEST_TIMEOUT);
+        });
+    });
+
+});

http://git-wip-us.apache.org/repos/asf/cordova-mobile-spec/blob/77ff9a37/www/autotest/tests/datauri.tests.js
----------------------------------------------------------------------
diff --git a/www/autotest/tests/datauri.tests.js b/www/autotest/tests/datauri.tests.js
new file mode 100644
index 0000000..08ebbbc
--- /dev/null
+++ b/www/autotest/tests/datauri.tests.js
@@ -0,0 +1,60 @@
+/*
+ * 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.
+*/
+var isWindowsPhone = cordova.platformId == 'windowsphone';
+
+describe('data uris', function () {
+    it("datauri.spec.1 should work with iframes", function() {
+        // IE on WP7/8 considers 'data:' in frame.src string as protocol type
+        // so asks user to look for appropriating application in the market;
+        // temporary skipped since requires user interaction
+        if (isWindowsPhone) return;
+        var gotFoo = false,
+            frame = document.createElement('iframe');
+        function onMessage(msg) {
+            gotFoo = gotFoo || msg.data == 'foo';
+        };
+
+        this.after(function() {
+            document.body.removeChild(frame);
+            window.removeEventListener('message', onMessage, false);
+        });
+
+        window.addEventListener('message', onMessage, false);
+        frame.src = 'data:text/html;charset=utf-8,%3Chtml%3E%3Cscript%3Eparent.postMessage%28%27foo%27%2C%27%2A%27%29%3C%2Fscript%3E%3C%2Fhtml%3E'
+        document.body.appendChild(frame);
+        waitsFor(function() {
+            return gotFoo;
+        }, 'iframe did not load.', 1000);
+        runs(function() {
+            expect(gotFoo).toBe(true);
+        });
+    });
+    it("datauri.spec.2 should work with images", function() {
+        var img = new Image();
+        img.onload = jasmine.createSpy('onLoad');
+        img.onerror = jasmine.createSpy('onError');
+        img.src = 'data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7'
+        waitsFor(function() {
+            return img.onload.wasCalled || img.onerror.wasCalled;
+        }, 'image did not load or error', 1000);
+        runs(function() {
+            expect(img.onload).toHaveBeenCalled();
+        });
+    });
+});

http://git-wip-us.apache.org/repos/asf/cordova-mobile-spec/blob/77ff9a37/www/autotest/tests/device.tests.js
----------------------------------------------------------------------
diff --git a/www/autotest/tests/device.tests.js b/www/autotest/tests/device.tests.js
new file mode 100644
index 0000000..0bcd0d9
--- /dev/null
+++ b/www/autotest/tests/device.tests.js
@@ -0,0 +1,64 @@
+/*
+ *
+ * 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.
+ *
+*/
+
+describe('Device Information (window.device)', function () {
+	it("should exist", function() {
+        expect(window.device).toBeDefined();
+	});
+
+	it("should contain a platform specification that is a string", function() {
+        expect(window.device.platform).toBeDefined();
+		expect((new String(window.device.platform)).length > 0).toBe(true);
+	});
+
+	it("should contain a version specification that is a string", function() {
+        expect(window.device.version).toBeDefined();
+		expect((new String(window.device.version)).length > 0).toBe(true);
+	});
+
+	it("should contain a UUID specification that is a string or a number", function() {
+        expect(window.device.uuid).toBeDefined();
+		if (typeof window.device.uuid == 'string' || typeof window.device.uuid == 'object') {
+		    expect((new String(window.device.uuid)).length > 0).toBe(true);
+		} else {
+			expect(window.device.uuid > 0).toBe(true);
+		}
+	});
+
+	it("should contain a cordova specification that is a string", function() {
+        expect(window.device.cordova).toBeDefined();
+		expect((new String(window.device.cordova)).length > 0).toBe(true);
+	});
+
+    it("should depend on the precense of cordova.version string", function() {
+            expect(window.cordova.version).toBeDefined();
+            expect((new String(window.cordova.version)).length > 0).toBe(true);
+    });
+
+    it("should contain device.cordova equal to cordova.version", function() {
+             expect(window.device.cordova).toBe(window.cordova.version);
+    });
+
+	it("should contain a model specification that is a string", function() {
+        expect(window.device.model).toBeDefined();
+		expect((new String(window.device.model)).length > 0).toBe(true);
+	});
+});