Bug 1436522 [wpt PR 9237] - WebAuthn WD-07 api tests, a=testonly
authorAdam Powers <apowers@ato.ms>
Tue, 06 Mar 2018 18:31:12 +0000
changeset 462367 21a741d38bb42d35adac765ecb90dee82a2d0ea6
parent 462366 3ea4f0746ad6c5817d91571ea2ed579f50c5cded
child 462368 c573bfc30e44b4e24d0fce97c453d919321d361e
push id1683
push usersfraser@mozilla.com
push dateThu, 26 Apr 2018 16:43:40 +0000
treeherdermozilla-release@5af6cb21869d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstestonly
bugs1436522
milestone60.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1436522 [wpt PR 9237] - WebAuthn WD-07 api tests, a=testonly Automatic update from web-platform-tests new tests based on Working Draft 7 <!-- Reviewable:start --> <!-- Reviewable:end --> wpt-commits: 025a5577b9a881d14783aec39d4c6963647d09a0 wpt-pr: 9237 reapplied-commits: 370e267e160568862f1fd9ec246ab5bb840f586e, fe4514c84e7ad28e46bad5da93381deb99b177f3, 7806af854343c043a2645a4034fdc7812f65daad, 9ddfd21554293dec5a4bf2e5375ae4f3c9f2ded0, 75f63c4d1ebc949647184fd60972fc7b9fd4affb, 1f3a5b496acd2288cc8cf0c32af86cb35157ea4e, 88b42bd5847abac58a62c4d6b33c1509bfce5f3d, 15c2e4c690700c6c115f8afe5e44ded10d943538, c8d461ef1437641ae7d4ea1d21e1e60cd62910b0, a6088a5f48ee299386a84d2f771902267d7355b1, 0634cd8f08ebe0905a9188fb1398c7b5f889c5dc, c8ee4a012dae506ae06bb5b2ad50942b04c1aaaa, c2c352456a4cf62dcc12f851138b04397675a445, b93a8879555d2fa7e7d4e00a275513a3a6338b35, b86e1331cb36634fd33677043b61fc0c1d8485bc, 44ddf14fd3346658c3223f13652073fafbfa48fa, a1a5840a6bb53e305ba02bcbeb215659342d0edb, 7465cb110ae5ec2e2ca73182caf5293f0efc8fd5, aad5349b3458bc3414e274b33fa86a1123901ff2, eca0907980d2769c449894a6277c60c1a306792f, 38626987c0cfd6e715cfcc6f4f1a1209191a03c5, e4a67f7ddcde6cd99348e9104bd7ed07074da44a, bb3c9990840a0fae2afc840b5952d7874785b112, 042d7adef0bdb9dc80e825c3997ace7519477c42, 99f1ea44fc7915b8b7b33bce4732fa8765fd3ac2, b81999f30c1516a70c153de51a0331d14c8faead
testing/web-platform/meta/MANIFEST.json
testing/web-platform/tests/lint.whitelist
testing/web-platform/tests/webauthn/createcredential-badargs-attestation.https.html
testing/web-platform/tests/webauthn/createcredential-badargs-authnrselection.https.html
testing/web-platform/tests/webauthn/createcredential-badargs-challenge.https.html
testing/web-platform/tests/webauthn/createcredential-badargs-rp.https.html
testing/web-platform/tests/webauthn/createcredential-badargs-user.https.html
testing/web-platform/tests/webauthn/createcredential-excludecredentials.https.html
testing/web-platform/tests/webauthn/createcredential-extensions.https.html
testing/web-platform/tests/webauthn/createcredential-passing.https.html
testing/web-platform/tests/webauthn/createcredential-pubkeycredparams.https.html
testing/web-platform/tests/webauthn/createcredential-timeout.https.html
testing/web-platform/tests/webauthn/getcredential-badargs-rpid.https.html
testing/web-platform/tests/webauthn/getcredential-badargs-userverification.https.html
testing/web-platform/tests/webauthn/getcredential-extensions.https.html
testing/web-platform/tests/webauthn/getcredential-passing.https.html
testing/web-platform/tests/webauthn/getcredential-timeout.https.html
testing/web-platform/tests/webauthn/helpers.js
testing/web-platform/tests/webauthn/securecontext.http.html
testing/web-platform/tests/webauthn/securecontext.https.html
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -359774,34 +359774,106 @@
     ]
    ],
    "webaudio/the-audio-api/the-waveshapernode-interface/waveshaper.html": [
     [
      "/webaudio/the-audio-api/the-waveshapernode-interface/waveshaper.html",
      {}
     ]
    ],
+   "webauthn/createcredential-badargs-attestation.https.html": [
+    [
+     "/webauthn/createcredential-badargs-attestation.https.html",
+     {}
+    ]
+   ],
+   "webauthn/createcredential-badargs-authnrselection.https.html": [
+    [
+     "/webauthn/createcredential-badargs-authnrselection.https.html",
+     {}
+    ]
+   ],
+   "webauthn/createcredential-badargs-challenge.https.html": [
+    [
+     "/webauthn/createcredential-badargs-challenge.https.html",
+     {}
+    ]
+   ],
    "webauthn/createcredential-badargs-rp.https.html": [
     [
      "/webauthn/createcredential-badargs-rp.https.html",
      {}
     ]
    ],
+   "webauthn/createcredential-badargs-user.https.html": [
+    [
+     "/webauthn/createcredential-badargs-user.https.html",
+     {}
+    ]
+   ],
+   "webauthn/createcredential-excludecredentials.https.html": [
+    [
+     "/webauthn/createcredential-excludecredentials.https.html",
+     {}
+    ]
+   ],
+   "webauthn/createcredential-extensions.https.html": [
+    [
+     "/webauthn/createcredential-extensions.https.html",
+     {}
+    ]
+   ],
    "webauthn/createcredential-passing.https.html": [
     [
      "/webauthn/createcredential-passing.https.html",
      {}
     ]
    ],
+   "webauthn/createcredential-pubkeycredparams.https.html": [
+    [
+     "/webauthn/createcredential-pubkeycredparams.https.html",
+     {}
+    ]
+   ],
+   "webauthn/createcredential-timeout.https.html": [
+    [
+     "/webauthn/createcredential-timeout.https.html",
+     {}
+    ]
+   ],
+   "webauthn/getcredential-badargs-rpid.https.html": [
+    [
+     "/webauthn/getcredential-badargs-rpid.https.html",
+     {}
+    ]
+   ],
+   "webauthn/getcredential-badargs-userverification.https.html": [
+    [
+     "/webauthn/getcredential-badargs-userverification.https.html",
+     {}
+    ]
+   ],
+   "webauthn/getcredential-extensions.https.html": [
+    [
+     "/webauthn/getcredential-extensions.https.html",
+     {}
+    ]
+   ],
    "webauthn/getcredential-passing.https.html": [
     [
      "/webauthn/getcredential-passing.https.html",
      {}
     ]
    ],
+   "webauthn/getcredential-timeout.https.html": [
+    [
+     "/webauthn/getcredential-timeout.https.html",
+     {}
+    ]
+   ],
    "webauthn/interfaces.https.html": [
     [
      "/webauthn/interfaces.https.html",
      {}
     ]
    ],
    "webauthn/securecontext.http.html": [
     [
@@ -385850,17 +385922,17 @@
    "f8af4287f3b0f6925a2a6c5c75b3788e24de1680",
    "support"
   ],
   "./config.default.json": [
    "403d365196f6fe2c631d27fe6042e3114d204016",
    "support"
   ],
   "./lint.whitelist": [
-   "2292c83ea0bd1432a7ba43e86a6b9f9fa8836e23",
+   "67c693358b77f86e338e779ec808d00caeb5a253",
    "support"
   ],
   "./serve.py": [
    "0efa39b1f26f86d73f2fce4f9e46003d62057b41",
    "support"
   ],
   "./server-side.md": [
    "c51b17fbac2a2e3121dc74f7badbd2873ce92f61",
@@ -593037,46 +593109,94 @@
   "webaudio/the-audio-api/the-waveshapernode-interface/waveshaper.html": [
    "84975ca29be6d977ed238a46ff6597959ab05047",
    "testharness"
   ],
   "webauthn/OWNERS": [
    "368ab4153a7f6843ce65ce924a3b4af92f3488ee",
    "support"
   ],
+  "webauthn/createcredential-badargs-attestation.https.html": [
+   "397a6f0b95e75cf2b743eb208f6c79c767ec648a",
+   "testharness"
+  ],
+  "webauthn/createcredential-badargs-authnrselection.https.html": [
+   "f5f5c8316551a921823bfe000031d42d91d9baa1",
+   "testharness"
+  ],
+  "webauthn/createcredential-badargs-challenge.https.html": [
+   "741efba3e4c583d5983a5005803f718bdaa435b0",
+   "testharness"
+  ],
   "webauthn/createcredential-badargs-rp.https.html": [
-   "941a9bda02e22b7d54855e3a4714a49d8392fa9d",
+   "8ab678da79853a5c41ff142704bb4732b026e06c",
+   "testharness"
+  ],
+  "webauthn/createcredential-badargs-user.https.html": [
+   "37f734eed5ecd34f6feb90bb96154e16a763140a",
+   "testharness"
+  ],
+  "webauthn/createcredential-excludecredentials.https.html": [
+   "387387626892215c1552ef5e742fd32d800df4ad",
+   "testharness"
+  ],
+  "webauthn/createcredential-extensions.https.html": [
+   "9642dafa7ed7ce75d5812328fcd3ac2239e33ebd",
    "testharness"
   ],
   "webauthn/createcredential-passing.https.html": [
-   "32a6ac38f91ec6b887e9e57519eb1603b4abcdbb",
+   "e89da85133f56cf0b5b78f6d6f39b43926ed9fda",
+   "testharness"
+  ],
+  "webauthn/createcredential-pubkeycredparams.https.html": [
+   "009193df4404190c820618840104da8db380eaa8",
+   "testharness"
+  ],
+  "webauthn/createcredential-timeout.https.html": [
+   "c0e639f8a32a1bc3553fd437a4fcf694a63960c2",
+   "testharness"
+  ],
+  "webauthn/getcredential-badargs-rpid.https.html": [
+   "275511dbafc9a536f92e74ef4c0531a7d8b7a437",
+   "testharness"
+  ],
+  "webauthn/getcredential-badargs-userverification.https.html": [
+   "5ac7b919d473bfc126c3e57df70c2f0defc60671",
+   "testharness"
+  ],
+  "webauthn/getcredential-extensions.https.html": [
+   "ea4d0533a5939927dd9eaa5d81116dbcc2f3ccbe",
    "testharness"
   ],
   "webauthn/getcredential-passing.https.html": [
-   "6272128ea3af65ecb4fc40055b062a678bfbb2fd",
+   "1b0f77b533a4e528b3abc484ba4d74b56833131f",
+   "testharness"
+  ],
+  "webauthn/getcredential-timeout.https.html": [
+   "b8c71a3fccdf39c2e35bd34a3cd42561cac5836b",
    "testharness"
   ],
   "webauthn/helpers.js": [
-   "e6224e8e2be8657e2e312f4197cbe0225c819cea",
+   "9ce729fb89ba1863fb14dfc4d567e6b544a5238d",
    "support"
   ],
   "webauthn/interfaces.https.html": [
    "5a30981934a38e09328a946352b21a8abc90851f",
    "testharness"
   ],
   "webauthn/interfaces.idl": [
    "77076f0828383c0f48f36131a81b25186622b3a3",
    "support"
   ],
   "webauthn/securecontext.http.html": [
-   "afc1492723d140e34027a3bdbf0d1e09843ef5d6",
+   "7abf48e74debed79578e39934d1b84655731a3ea",
    "testharness"
   ],
   "webauthn/securecontext.https.html": [
-   "7f7a7aba32b9e049c618203121fae0884936643a",
+   "9bdd7e09c7f468b9b0c106d4764d61e77b32131f",
    "testharness"
   ],
   "webdriver/OWNERS": [
    "752d7099018be8b67e4ca16628bbecfa08da8e82",
    "support"
   ],
   "webdriver/README.md": [
    "185acb69e9516e0564e16bf7d7f8dc2a4c48d3c7",
--- a/testing/web-platform/tests/lint.whitelist
+++ b/testing/web-platform/tests/lint.whitelist
@@ -221,16 +221,17 @@ SET TIMEOUT: streams/piping/error-propag
 SET TIMEOUT: streams/piping/error-propagation-forward.js
 SET TIMEOUT: streams/piping/general.js
 SET TIMEOUT: streams/readable-streams/cancel.js
 SET TIMEOUT: streams/resources/rs-utils.js
 SET TIMEOUT: streams/writable-streams/byte-length-queuing-strategy.js
 SET TIMEOUT: user-timing/*
 SET TIMEOUT: webaudio/js/lodash.js
 SET TIMEOUT: webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSourceToScriptProcessorTest.html
+SET TIMEOUT: webauthn/*timeout.https.html
 SET TIMEOUT: webdriver/*
 SET TIMEOUT: webmessaging/*
 SET TIMEOUT: websockets/*
 SET TIMEOUT: webstorage/eventTestHarness.js
 SET TIMEOUT: webvtt/*
 SET TIMEOUT: workers/*
 SET TIMEOUT: xhr/resources/init.htm
 SET TIMEOUT: xhr/resources/xmlhttprequest-timeout.js
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/webauthn/createcredential-badargs-attestation.https.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.create() attestation parameter Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+    "use strict";
+
+    // attestation bad values
+    new CreateCredentialsTest("options.publicKey.attestation", {}).runTest("Bad attestation parameter: attestation is empty object", new TypeError());
+    new CreateCredentialsTest("options.publicKey.attestation", []).runTest("Bad attestation parameter: attestation is empty array", new TypeError());
+    new CreateCredentialsTest("options.publicKey.attestation", null).runTest("Bad attestation parameter: attestation is null", new TypeError());
+    new CreateCredentialsTest("options.publicKey.attestation", "noneofyourbusiness").runTest("Bad attestation parameter: attestation is \"noneofyourbusiness\"", new TypeError());
+    new CreateCredentialsTest("options.publicKey.attestation", "").runTest("Bad attestation parameter: attestation is empty string", new TypeError());
+});
+
+/* JSHINT */
+/* globals standardSetup, CreateCredentialsTest */
+</script>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/webauthn/createcredential-badargs-authnrselection.https.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.create() authenticator selection Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+    "use strict";
+
+    var defaultAuthnrSel = {
+        authenticatorAttachment: "cross-platform",
+        requireResidentKey: false,
+        userVerification: "preferred"
+    };
+    // attachment
+    var authnrSelAttachPlatform = cloneObject(defaultAuthnrSel);
+    authnrSelAttachPlatform.authenticatorAttachment = "platform";
+    var authnrSelBadAttachEmptyStr = cloneObject(defaultAuthnrSel);
+    authnrSelBadAttachEmptyStr.authenticatorAttachment = "";
+    var authnrSelBadAttachEmptyObj = cloneObject(defaultAuthnrSel);
+    authnrSelBadAttachEmptyObj.authenticatorAttachment = {};
+    var authnrSelBadAttachNull = cloneObject(defaultAuthnrSel);
+    authnrSelBadAttachNull.authenticatorAttachment = null;
+    // resident key
+    var authnrSelRkTrue = cloneObject(defaultAuthnrSel);
+    authnrSelRkTrue.requireResidentKey = true;
+    var authnrSelRkBadString = cloneObject(defaultAuthnrSel);
+    authnrSelRkBadString.requireResidentKey = "foo";
+    // user verification
+    var authnrSelUvRequired = cloneObject(defaultAuthnrSel);
+    authnrSelUvRequired.userVerification = "required";
+    var authnrSelBadUvEmptyStr = cloneObject(defaultAuthnrSel);
+    authnrSelBadUvEmptyStr.userVerification = "";
+    var authnrSelBadUvEmptyObj = cloneObject(defaultAuthnrSel);
+    authnrSelBadUvEmptyObj.userVerification = {};
+    var authnrSelBadUvStr = cloneObject(defaultAuthnrSel);
+    authnrSelBadUvStr.userVerification = "requiredshirtshoestshirt";
+    var authnrSelBadUvNull = cloneObject(defaultAuthnrSel);
+    authnrSelBadUvNull.userVerification = null;
+
+    // authenticatorSelection bad values
+    new CreateCredentialsTest("options.publicKey.authenticatorSelection", []).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection is empty array", new TypeError());
+    new CreateCredentialsTest("options.publicKey.authenticatorSelection", null).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection is null", new TypeError());
+    new CreateCredentialsTest("options.publicKey.authenticatorSelection", "").runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection is empty string", new TypeError());
+    new CreateCredentialsTest("options.publicKey.authenticatorSelection", "none").runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection is string", new TypeError());
+
+    // authenticatorSelection bad attachment values
+    new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadAttachEmptyStr).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection attachment is empty string", new TypeError());
+    new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadAttachEmptyObj).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection attachment is empty object", new TypeError());
+    new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadAttachNull).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection attachment is null", new TypeError());
+    // XXX: assumes authnr is behaving like most U2F authnrs; really depends on the authnr or mock configuration
+    new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelAttachPlatform).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection attachment platform", "NotAllowedError");
+
+    // authenticatorSelection bad requireResidentKey values
+   // XXX: assumes authnr is behaving like most U2F authnrs; really depends on the authnr or mock configuration
+    new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelRkTrue).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection residentKey true", "NotAllowedError");
+    new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelRkBadString).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection residentKey is string", new TypeError());
+    // TODO: not sure if rk is "boolean" or "truthy"; add test cases if it should only accept boolean values
+
+    // authenticatorSelection bad userVerification values
+    new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadUvEmptyStr).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection userVerification empty string", new TypeError());
+    new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadUvEmptyObj).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection userVerification empty object", new TypeError());
+    new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadUvStr).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection userVerification bad value", new TypeError());
+    new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadUvNull).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection userVerification null", new TypeError());
+    // XXX: assumes this is a mock authenticator the properly reports that it is not doing userVerfication
+    new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelUvRequired).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection userVerification required", "NotAllowedError");
+});
+
+/* JSHINT */
+/* globals standardSetup, CreateCredentialsTest, cloneObject */
+</script>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/webauthn/createcredential-badargs-challenge.https.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.create() challenge Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+    "use strict";
+
+    // bad challenge values
+    new CreateCredentialsTest({path: "options.publicKey.challenge", value: undefined}).runTest("Bad challenge: challenge missing", new TypeError());
+    new CreateCredentialsTest("options.publicKey.challenge", "hi mom").runTest("Bad challenge: challenge is string", new TypeError());
+    new CreateCredentialsTest("options.publicKey.challenge", null).runTest("Bad challenge: challenge is null", new TypeError());
+    new CreateCredentialsTest("options.publicKey.challenge", {}).runTest("Bad challenge: challenge is empty object", new TypeError());
+    new CreateCredentialsTest("options.publicKey.challenge", new Array()).runTest("Bad challenge: challenge is empty Array", new TypeError());
+    new CreateCredentialsTest("options.publicKey.challenge", new ArrayBuffer(0)).runTest("Bad challenge: challenge is empty ArrayBuffer", new TypeError());
+});
+
+/* JSHINT */
+/* globals standardSetup, CreateCredentialsTest */
+</script>
\ No newline at end of file
--- a/testing/web-platform/tests/webauthn/createcredential-badargs-rp.https.html
+++ b/testing/web-platform/tests/webauthn/createcredential-badargs-rp.https.html
@@ -7,36 +7,36 @@
 <script src="/resources/testharnessreport.js"></script>
 <script src=helpers.js></script>
 <body></body>
 <script>
 standardSetup(function() {
     "use strict";
 
     // rp bad values
-    new CreateCredentialsTest({path: "options.publicKey.rp", value: undefined}).testBadArgs("rp missing");
-    new CreateCredentialsTest("options.publicKey.rp", "hi mom").testBadArgs("rp is string");
-    // new CreateCredentialsTest("options.publicKey.rp", {}).testBadArgs("rp is empty object");
+    new CreateCredentialsTest({path: "options.publicKey.rp", value: undefined}).runTest("Bad rp: rp missing", new TypeError());
+    new CreateCredentialsTest("options.publicKey.rp", "hi mom").runTest("Bad rp: rp is string", new TypeError());
+    new CreateCredentialsTest("options.publicKey.rp", {}).runTest("Bad rp: rp is empty object", new TypeError());
 
-    // rp.id
-    // new CreateCredentialsTest({path: "options.publicKey.rp.id", value: undefined}).testBadArgs("rp missing id");
-    new CreateCredentialsTest("options.publicKey.rp.id", {}).testBadArgs("Bad rp: id is object");
-    new CreateCredentialsTest("options.publicKey.rp.id", null).testBadArgs("Bad rp: id is null");
-    new CreateCredentialsTest("options.publicKey.rp.id", "").testBadArgs("Bad rp: id is empty String");
+    // // rp.id
+    new CreateCredentialsTest("options.publicKey.rp.id", {}).runTest("Bad rp: id is object", new TypeError());
+    new CreateCredentialsTest("options.publicKey.rp.id", null).runTest("Bad rp: id is null", "SecurityError");
+    new CreateCredentialsTest("options.publicKey.rp.id", "").runTest("Bad rp: id is empty String", "SecurityError");
+    new CreateCredentialsTest("options.publicKey.rp.id", "invalid domain.com").runTest("Bad rp: id is invalid domain (has space)", "SecurityError");
+    new CreateCredentialsTest("options.publicKey.rp.id", "-invaliddomain.com").runTest("Bad rp: id is invalid domain (starts with dash)", "SecurityError");
+    new CreateCredentialsTest("options.publicKey.rp.id", "0invaliddomain.com").runTest("Bad rp: id is invalid domain (starts with number)", "SecurityError");
 
-    // rp.name
-    // new CreateCredentialsTest({path: "options.publicKey.rp.name", value: undefined}).testBadArgs("rp missing name");
-    new CreateCredentialsTest("options.publicKey.rp.name", {}).testBadArgs("Bad rp: name is object");
-    new CreateCredentialsTest("options.publicKey.rp.name", null).testBadArgs("Bad rp: name is null");
-    new CreateCredentialsTest("options.publicKey.rp.name", "").testBadArgs("Bad rp: name is empty String");
+    // // rp.name
+    new CreateCredentialsTest({path: "options.publicKey.rp.name", value: undefined}).runTest("rp missing name", new TypeError());
+    new CreateCredentialsTest("options.publicKey.rp.name", {}).runTest("Bad rp: name is object", new TypeError());
+    new CreateCredentialsTest("options.publicKey.rp.name", null).runTest("Bad rp: name is null", new TypeError());
+    new CreateCredentialsTest("options.publicKey.rp.name", "").runTest("Bad rp: name is empty String", new TypeError());
 
-    // rp.icon
-    // new CreateCredentialsTest({path: "options.publicKey.rp.icon", value: undefined}).testBadArgs("rp missing icon");
-    new CreateCredentialsTest("options.publicKey.rp.icon", {}).testBadArgs("Bad rp: icon is object");
-    new CreateCredentialsTest("options.publicKey.rp.icon", null).testBadArgs("Bad rp: icon is null");
-    new CreateCredentialsTest("options.publicKey.rp.icon", "").testBadArgs("Bad rp: icon is empty String");
-    // TODO: see https://github.com/w3c/webauthn/issues/587 for the 'undefined' tests that are commented out above
-    // TODO: unicode tests for icon URL (see also: USVString)
+    // // rp.icon
+    new CreateCredentialsTest("options.publicKey.rp.icon", {}).runTest("Bad rp: icon is object", new TypeError());
+    new CreateCredentialsTest("options.publicKey.rp.icon", null).runTest("Bad rp: icon is null", new TypeError());
+    new CreateCredentialsTest("options.publicKey.rp.icon", "").runTest("Bad rp: icon is empty String", new TypeError());
+    // // TODO: unicode tests for icon URL (see also: USVString)
 });
 
 /* JSHINT */
 /* globals standardSetup, CreateCredentialsTest */
 </script>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/webauthn/createcredential-badargs-user.https.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.create() user Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+    "use strict";
+
+    // user bad values
+    new CreateCredentialsTest({path: "options.publicKey.user", value: undefined}).runTest("Bad user: user missing", new TypeError());
+    new CreateCredentialsTest("options.publicKey.user", "hi mom").runTest("Bad user: user is string", new TypeError());
+    new CreateCredentialsTest("options.publicKey.user", {}).runTest("Bad user: user is empty object", new TypeError());
+
+    // // user.id
+    new CreateCredentialsTest({path: "options.publicKey.user.id", value: undefined}).runTest("Bad user: id is undefined", new TypeError());
+    new CreateCredentialsTest("options.publicKey.user.id", {}).runTest("Bad user: id is object", new TypeError());
+    new CreateCredentialsTest("options.publicKey.user.id", null).runTest("Bad user: id is null", new TypeError());
+    new CreateCredentialsTest("options.publicKey.user.id", "").runTest("Bad user: id is empty String", new TypeError());
+    new CreateCredentialsTest("options.publicKey.user.id", new Array()).runTest("Bad user: id is empty Array", new TypeError());
+    new CreateCredentialsTest("options.publicKey.user.id", new ArrayBuffer(0)).runTest("Bad user: id is empty ArrayBuffer", new TypeError());
+    new CreateCredentialsTest("options.publicKey.user.id", new ArrayBuffer(65)).runTest("Bad user: ArrayBuffer id is too long (65 bytes)", new TypeError());
+    new CreateCredentialsTest("options.publicKey.user.id", new Int16Array(33)).runTest("Bad user: Int16Array id is too long (66 bytes)", new TypeError());
+    new CreateCredentialsTest("options.publicKey.user.id", new Int32Array(17)).runTest("Bad user: Int32Array id is too long (68 bytes)", new TypeError());
+    new CreateCredentialsTest("options.publicKey.user.id", new Float32Array(17)).runTest("Bad user: Float32Array id is too long (68 bytes)", new TypeError());
+    new CreateCredentialsTest("options.publicKey.user.id", new Float64Array(9)).runTest("Bad user: Float64Array id is too long (72 bytes)", new TypeError());
+    var buf = new ArrayBuffer(65);
+    new CreateCredentialsTest("options.publicKey.user.id", new DataView(buf)).runTest("Bad user: id is too long (65 bytes)", new TypeError());
+
+    // // user.name
+    new CreateCredentialsTest({path: "options.publicKey.user.name", value: undefined}).runTest("user missing name", new TypeError());
+    new CreateCredentialsTest("options.publicKey.user.name", {}).runTest("Bad user: name is object", new TypeError());
+    new CreateCredentialsTest("options.publicKey.user.name", null).runTest("Bad user: name is null", new TypeError());
+    new CreateCredentialsTest("options.publicKey.user.name", "").runTest("Bad user: name is empty String", new TypeError());
+
+    // // user.icon
+    new CreateCredentialsTest("options.publicKey.user.icon", {}).runTest("Bad user: icon is object", new TypeError());
+    new CreateCredentialsTest("options.publicKey.user.icon", null).runTest("Bad user: icon is null", new TypeError());
+    new CreateCredentialsTest("options.publicKey.user.icon", "").runTest("Bad user: icon is empty String", new TypeError());
+    // // TODO: unicode tests for icon URL (see also: USVString)
+
+    // // user.displayName
+    new CreateCredentialsTest({path: "options.publicKey.user.displayName", value: undefined}).runTest("Bad user: displayName is undefined", new TypeError());
+    new CreateCredentialsTest("options.publicKey.user.displayName", {}).runTest("Bad user: displayName is object", new TypeError());
+    new CreateCredentialsTest("options.publicKey.user.displayName", null).runTest("Bad user: displayName is null", new TypeError());
+    new CreateCredentialsTest("options.publicKey.user.displayName", "").runTest("Bad user: displayName is empty String", new TypeError());
+});
+
+/* JSHINT */
+/* globals standardSetup, CreateCredentialsTest */
+</script>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/webauthn/createcredential-excludecredentials.https.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.create() excludeCredentials Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+    "use strict";
+
+    // bad excludeCredentials values
+    new CreateCredentialsTest("options.publicKey.excludeCredentials", "hi mom").runTest("Bad excludeCredentials: string", new TypeError());
+    new CreateCredentialsTest("options.publicKey.excludeCredentials", {}).runTest("Bad excludeCredentials: empty object", new TypeError());
+    // TODO: bad excludeCredentials with [{.type}] or [{.id}] or [{.transports}] wrong
+
+    // good excludeCredentials values
+    new CreateCredentialsTest({path: "options.publicKey.excludeCredentials", value: undefined}).runTest("excludeCredentials missing");
+    new CreateCredentialsTest("options.publicKey.excludeCredentials", []).runTest("excludeCredentials empty array");
+
+    // proper excludeCredentials behavior
+    // should error on excluding existing credential
+    promise_test((t) => {
+        var cred1;
+        return Promise.resolve()
+            .then(() => {
+                return createCredential();
+            })
+            .then((cred) => {
+                cred1 = cred;
+                var excludeCred = {
+                    id: cred.rawId,
+                    type: "public-key"
+                };
+                var args = {
+                    options: {
+                        publicKey: {
+                            excludeCredentials: [excludeCred]
+                        }
+                    }
+                };
+                var p = createCredential(args);
+                return promise_rejects (t, "NotAllowedError", p, "expected to fail on excluded credenetial");
+            });
+    }, "exclude existing credential");
+
+    // should not error on excluding random credential
+    promise_test(() => {
+        return Promise.resolve()
+            .then(() => {
+                return createCredential();
+            })
+            .then(() => {
+                var randomCredId = new Uint8Array(162);
+                window.crypto.getRandomValues(randomCredId);
+
+                var excludeCred = {
+                    id: randomCredId,
+                    type: "public-key"
+                };
+                var args = {
+                    options: {
+                        publicKey: {
+                            excludeCredentials: [excludeCred]
+                        }
+                    }
+                };
+                return createCredential(args);
+            });
+    }, "exclude random (non-existing) credential");
+
+    // TODO: exclude including transport type (USB, BLE, NFC)
+});
+
+/* JSHINT */
+/* globals standardSetup, CreateCredentialsTest, createCredential, promise_test, promise_rejects */
+</script>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/webauthn/createcredential-extensions.https.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.create() extensions Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+    "use strict";
+
+    var dummyExtension = {
+        foo: true,
+        bar: "yup"
+    };
+
+    // bad extension values
+    new CreateCredentialsTest("options.publicKey.extensions", "hi mom").runTest("Bad extensions: extensions is string", new TypeError());
+    new CreateCredentialsTest("options.publicKey.extensions", null).runTest("Bad extensions: extensions is null", new TypeError());
+    new CreateCredentialsTest("options.publicKey.extensions", []).runTest("Bad extensions: extensions is empty Array", new TypeError());
+    new CreateCredentialsTest("options.publicKey.extensions", new ArrayBuffer(0)).runTest("Bad extensions: extensions is empty ArrayBuffer", new TypeError());
+    var badJson = '{"foo": true, "bar: "yup"}'; // missing quote after "bar"
+    new CreateCredentialsTest("options.publicKey.extensions", {foo: badJson}).runTest("Bad extensions: malformatted JSON", new TypeError());
+    new CreateCredentialsTest("options.publicKey.extensions", {foo: dummyExtension}).runTest("Bad extensions: JavaScript object", new TypeError());
+    var badExtId = {};
+    badExtId[createRandomString(65)] = dummyExtension;
+    new CreateCredentialsTest("options.publicKey.extensions", {badExtId: dummyExtension}).runTest("Bad extensions: extension ID too long", new TypeError());
+
+    // phony extensions
+    // TODO: not sure if this should pass or fail
+    // should be clarified as part of https://github.com/w3c/webauthn/pull/765
+    var randomExtId = {};
+    randomExtId[createRandomString(64)] = dummyExtension;
+    new CreateCredentialsTest("options.publicKey.extensions", {foo: JSON.stringify(randomExtId)}).runTest("extensions is a nonsensical JSON string");
+
+    // TODO
+    // defined extensions:
+    // * appid
+    // * txAuthSimple
+    // * txAuthGeneric
+    // * authnSel
+    // * exts
+    // * uvi
+    // * loc
+    // * uvm
+});
+
+/* JSHINT */
+/* globals standardSetup, CreateCredentialsTest, createRandomString */
+</script>
\ No newline at end of file
--- a/testing/web-platform/tests/webauthn/createcredential-passing.https.html
+++ b/testing/web-platform/tests/webauthn/createcredential-passing.https.html
@@ -7,14 +7,113 @@
 <script src="/resources/testharnessreport.js"></script>
 <script src=helpers.js></script>
 <body></body>
 <script>
 standardSetup(function() {
     "use strict";
 
     // CreateCredentialTest passing tests
-    new CreateCredentialsTest().test();
+
+    // default arguments
+    new CreateCredentialsTest().runTest("passing credentials.create() with default arguments");
+
+    // rp
+    new CreateCredentialsTest({path: "options.publicKey.rp.id", value: window.location.host}).runTest("passing credentials.create() with rpId (host and port)");
+    new CreateCredentialsTest({path: "options.publicKey.rp.id", value: window.location.hostname}).runTest("passing credentials.create() with rpId (hostname)");
+    new CreateCredentialsTest({path: "options.publicKey.rp.icon", value: undefined}).runTest("passing credentials.create() without rp.icon");
+
+    // user
+    new CreateCredentialsTest("options.publicKey.user.id", new ArrayBuffer(1)).runTest("very short user id");
+    new CreateCredentialsTest("options.publicKey.user.id", new ArrayBuffer(64)).runTest("max length user id");
+    new CreateCredentialsTest("options.publicKey.user.id", new Uint8Array(64)).runTest("Uint8Array user id");
+    new CreateCredentialsTest("options.publicKey.user.id", new Int8Array(64)).runTest("Int8Array user id");
+    new CreateCredentialsTest("options.publicKey.user.id", new Int16Array(32)).runTest("Int16Array user id");
+    new CreateCredentialsTest("options.publicKey.user.id", new Int32Array(16)).runTest("Int32Array user id");
+    new CreateCredentialsTest("options.publicKey.user.id", new Float32Array(16)).runTest("Float32Array user id");
+    var dvBuf1 = new ArrayBuffer(16);
+    new CreateCredentialsTest("options.publicKey.user.id", new DataView(dvBuf1)).runTest("DataView user id");
+    new CreateCredentialsTest({path: "options.publicKey.user.icon", value: undefined}).runTest("passing credentials.create() without user.icon");
+
+    // good challenge values
+    // all these challenges are zero-filled buffers... think anyone will complain?
+    new CreateCredentialsTest("options.publicKey.challenge", new Int16Array(33)).runTest("Int16Array challenge");
+    new CreateCredentialsTest("options.publicKey.challenge", new Int32Array(17)).runTest("Int32Array challenge");
+    new CreateCredentialsTest("options.publicKey.challenge", new Float32Array(17)).runTest("Float32Array challenge");
+    new CreateCredentialsTest("options.publicKey.challenge", new Float64Array(9)).runTest("Float64Array challenge");
+    var dvBuf2 = new ArrayBuffer(65);
+    new CreateCredentialsTest("options.publicKey.challenge", new DataView(dvBuf2)).runTest("DataView challenge");
+    new CreateCredentialsTest("options.publicKey.challenge", new ArrayBuffer(8192)).runTest("Absurdly large challenge");
+
+    // good pubKeyCredParams values
+    new CreateCredentialsTest("options.publicKey.pubKeyCredParams", []).runTest("Bad pubKeyCredParams: pubKeyCredParams is empty Array");
+    const pkParamEC256 = {
+        type: "public-key",
+        alg: cose_alg_ECDSA_w_SHA256
+    };
+    const pkParamEC512 = {
+        type: "public-key",
+        alg: cose_alg_ECDSA_w_SHA512
+    };
+    // XXX: presumes all mock authenticators support EC256
+    new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [pkParamEC256]).runTest("EC256 pubKeyCredParams");
+    new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [pkParamEC512, pkParamEC256])
+        .runTest("SelectEC256 pubKeyCredParams from a list");
+    // TODO: currently most browsers are mocking FIDO U2F, which is EC256 only
+    // new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [pkParamEC512]).runTest("EC512 pubKeyCredParams");
+
+    // NOTE: excludeCredentials parameter -- see also: createcredential-excludecredentials.https.html
+
+    // timeout
+    new CreateCredentialsTest({path: "options.publicKey.timeout", value: undefined}).runTest("passing credentials.create() with no timeout");
+
+    // valid authenticatorSelection values
+    var defaultAuthnrSel = {
+        authenticatorAttachment: "cross-platform",
+        requireResidentKey: false,
+        userVerification: "preferred"
+    };
+    // attachment
+    var authnrSelAttachUndef = cloneObject(defaultAuthnrSel);
+    authnrSelAttachUndef.authenticatorAttachment = undefined;
+    // resident key
+    var authnrSelRkUndef = cloneObject(defaultAuthnrSel);
+    authnrSelRkUndef.requireResidentKey = undefined;
+    var authnrSelRkFalse = cloneObject(defaultAuthnrSel);
+    authnrSelRkFalse.requireResidentKey = false;
+    // user verification
+    var authnrSelUvUndef = cloneObject(defaultAuthnrSel);
+    authnrSelUvUndef.userVerification = undefined;
+    var authnrSelUvDiscouraged = cloneObject(defaultAuthnrSel);
+    authnrSelUvDiscouraged.userVerification = "discouraged";
+    new CreateCredentialsTest({path: "options.publicKey.authenticatorSelection", value: undefined}).runTest("authenticatorSelection is undefined");
+    new CreateCredentialsTest("options.publicKey.authenticatorSelection", {}).runTest("authenticatorSelection is empty object");
+    new CreateCredentialsTest("options.publicKey.authenticatorSelection", cloneObject(defaultAuthnrSel)).runTest("authenticatorSelection default values");
+
+    // authnr selection attachment
+    new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelAttachUndef).runTest("authenticatorSelection attachment undefined");
+
+    // authnr selection resident key
+    new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelRkUndef).runTest("authenticatorSelection residentKey undefined");
+    // XXX: assumes authnr is behaving like most U2F authnrs; really depends on the authnr or mock configuration
+    new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelRkFalse).runTest("authenticatorSelection residentKey false");
+
+    // authnr selection user verification
+    new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelUvUndef).runTest("authenticatorSelection userVerification undefined");
+    new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelUvDiscouraged).runTest("authenticatorSelection userVerification discouraged");
+
+
+    // good attestation values
+    new CreateCredentialsTest("options.publicKey.attestation", "none").runTest("attestation parameter: attestation is \"none\"");
+    new CreateCredentialsTest("options.publicKey.attestation", "indirect").runTest("attestation parameter: attestation is \"indirect\"");
+    new CreateCredentialsTest("options.publicKey.attestation", "direct").runTest("attestation parameter: attestation is \"direct\"");
+    new CreateCredentialsTest({path: "options.publicKey.attestation", value: undefined}).runTest("attestation parameter: attestation is undefined");
+    // TODO: test this with multiple mock authenticators to make sure that the right options are chosen when available?
+
+    // good extension values
+    new CreateCredentialsTest({path: "options.publicKey.extensions", value: undefined}).runTest("extensions undefined");
+    new CreateCredentialsTest("options.publicKey.extensions", {}).runTest("extensions are empty object");
+    new CreateCredentialsTest("options.publicKey.extensions", {foo: "", bar: "", bat: ""}).runTest("extensions are dict of empty strings");
 });
 
 /* JSHINT */
-/* globals standardSetup, CreateCredentialsTest */
+/* globals standardSetup, CreateCredentialsTest, cose_alg_ECDSA_w_SHA256, cose_alg_ECDSA_w_SHA512, cloneObject */
 </script>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/webauthn/createcredential-pubkeycredparams.https.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.create() pubKeyCredParams Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+    "use strict";
+
+    var badType = {
+        type: "something-else",
+        alg: cose_alg_ECDSA_w_SHA512
+    };
+    var badTypeEmptyString = cloneObject(badType);
+    badTypeEmptyString.type = "";
+    var badTypeNull = cloneObject(badType);
+    badTypeNull.type = null;
+    var badTypeEmptyObj = cloneObject(badType);
+    badTypeEmptyObj.type = {};
+
+    var badAlg = {
+        type: "public-key",
+        alg: 42
+    };
+    var badAlgZero = cloneObject(badAlg);
+    badAlgZero.alg = 0;
+
+    // bad pubKeyCredParams values
+    new CreateCredentialsTest({path: "options.publicKey.pubKeyCredParams", value: undefined}).runTest("Bad pubKeyCredParams: pubKeyCredParams is undefined", new TypeError());
+    new CreateCredentialsTest("options.publicKey.pubKeyCredParams", "hi mom").runTest("Bad pubKeyCredParams: pubKeyCredParams is string", new TypeError());
+    new CreateCredentialsTest("options.publicKey.pubKeyCredParams", null).runTest("Bad pubKeyCredParams: pubKeyCredParams is null", new TypeError());
+    new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [badType]).runTest("Bad pubKeyCredParams: first param has bad type (\"something-else\")", new TypeError());
+    new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [badTypeEmptyString]).runTest("Bad pubKeyCredParams: first param has bad type (\"\")", new TypeError());
+    new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [badTypeNull]).runTest("Bad pubKeyCredParams: first param has bad type (null)", new TypeError());
+    new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [badTypeEmptyObj]).runTest("Bad pubKeyCredParams: first param has bad type (empty object)", new TypeError());
+    new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [badAlg]).runTest("Bad pubKeyCredParams: first param has bad alg (42)", "NotSupportedError");
+    new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [badAlgZero]).runTest("Bad pubKeyCredParams: first param has bad alg (0)", "NotSupportedError");
+
+    // TODO: come back to this when mock authenticators support multiple cryptos so that we can test the preference ranking
+    // function verifyEC256(res) {
+    //     debug ("verifyEC256 got", res);
+    //     debug ("client data JSON", ab2str(res.response.clientDataJSON));
+    //     parseAuthenticatorData(res.response.attestationObject);
+    // }
+    // new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [pkParamEC256, pkParamEC512])
+    //     .afterTest(verifyEC256)
+    //     .runTest("EC256, EC512 pubKeyCredParams");
+    // function verifyEC512(res) {
+    //     debug ("verifyEC512 got", res);
+    //     debug ("client data JSON", ab2str(res.response.clientDataJSON));
+    //     // parseAuthenticatorData(res.response.attestationObject);
+    //     printHex ("clientDataJSON", res.response.clientDataJSON);
+    //     printHex ("attestationObject", res.response.attestationObject);
+    // }
+    // new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [pkParamEC512, pkParamEC256])
+    //     .afterTest(verifyEC512)
+    //     .runTest("EC512, EC256 pubKeyCredParams");
+});
+
+/* JSHINT */
+/* globals standardSetup, CreateCredentialsTest, cose_alg_ECDSA_w_SHA512, cloneObject */
+</script>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/webauthn/createcredential-timeout.https.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.create() timeout Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+    "use strict";
+
+    // bad timeout values
+    // TODO: there is some debate as to whether MAX_UNSIGNED_LONG + 1 and / or -1 should be disallowed since they get converted to valid values internally
+    // new CreateCredentialsTest({path: "options.publicKey.timeout", value: -1}).runTest("Bad timeout: negative", new TypeError());
+    // new CreateCredentialsTest({path: "options.publicKey.timeout", value: 4294967295 + 1}).runTest("Bad timeout: too big", new TypeError());
+
+    // timeout test
+    // XXX: this probably always passes with most mock authenticators unless
+    // some setup happens right here to make sure they don't return a credential
+    // right away. So... uhh... I guess test this with a real authenticator if you
+    // want to see if it really works.
+    promise_test(() => {
+        return new Promise((resolve, reject) => {
+            var args = {
+                options: {
+                    publicKey: {
+                        timeout: 1
+                    }
+                }
+            };
+
+            setTimeout(() => {
+                reject(new Error ("timed out"));
+            }, 1000);
+
+            createCredential(args).then((res) => {
+                resolve(res);
+            });
+        });
+    }, "ensure create credential times out");
+    // TODO: createCredential.timeout > 1s && setTimeout < 1s
+    // TODO: createCredential.timeout < 5s && setTimeout > 5s
+});
+
+/* JSHINT */
+/* globals standardSetup, CreateCredentialsTest, createCredential, promise_test */
+</script>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/webauthn/getcredential-badargs-rpid.https.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn credential.get() rpId Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+    "use strict";
+
+    var credPromise = createCredential();
+
+    new GetCredentialsTest("options.publicKey.rpId", "")
+        .addCredential(credPromise)
+        .runTest("Bad rpId: empty string", "SecurityError");
+    new GetCredentialsTest("options.publicKey.rpId", null)
+        .addCredential(credPromise)
+        .runTest("Bad rpId: null", "SecurityError");
+    new GetCredentialsTest("options.publicKey.rpId", "invalid domain.com")
+        .addCredential(credPromise)
+        .runTest("Bad rpId: invalid domain (has space)", "SecurityError");
+    new GetCredentialsTest("options.publicKey.rpId", "-invaliddomain.com")
+        .addCredential(credPromise)
+        .runTest("Bad rpId: invalid domain (starts with dash)", "SecurityError");
+    new GetCredentialsTest("options.publicKey.rpId", "0invaliddomain.com")
+        .addCredential(credPromise)
+        .runTest("Bad rpId: invalid domain (starts with number)", "SecurityError");
+});
+
+/* JSHINT */
+/* globals standardSetup, GetCredentialsTest, createCredential */
+</script>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/webauthn/getcredential-badargs-userverification.https.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.get() user verification Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+    "use strict";
+
+    var credPromise = createCredential();
+
+    // authenticatorSelection bad userVerification values
+    new GetCredentialsTest("options.publicKey.userVerification", "")
+        .addCredential(credPromise)
+        .runTest("Bad userVerification: empty string", new TypeError());
+    new GetCredentialsTest("options.publicKey.userVerification", {})
+        .addCredential(credPromise)
+        .runTest("Bad userVerification: empty object", new TypeError());
+    new GetCredentialsTest("options.publicKey.userVerification", "requiredshirtshoestshirt")
+        .addCredential(credPromise)
+        .runTest("Bad userVerification: bad value", new TypeError());
+    new GetCredentialsTest("options.publicKey.userVerification", null)
+        .addCredential(credPromise)
+        .runTest("Bad userVerification: null", new TypeError());
+    // XXX: assumes this is a mock authenticator the properly reports that it is not doing userVerfication
+    new GetCredentialsTest("options.publicKey.userVerification", "required")
+        .addCredential(credPromise)
+        .runTest("Bad userVerification: \"required\"", "NotAllowedError");
+});
+
+/* JSHINT */
+/* globals standardSetup, GetCredentialsTest, createCredential */
+</script>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/webauthn/getcredential-extensions.https.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.get() extensions Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+    "use strict";
+
+    var dummyExtension = {
+        foo: true,
+        bar: "yup"
+    };
+    var credPromise = createCredential();
+
+    // bad extension values
+    new GetCredentialsTest("options.publicKey.extensions", "hi mom")
+        .addCredential(credPromise)
+        .runTest("Bad extensions: extensions is string", new TypeError());
+    new GetCredentialsTest("options.publicKey.extensions", null)
+        .addCredential(credPromise)
+        .runTest("Bad extensions: extensions is null", new TypeError());
+    new GetCredentialsTest("options.publicKey.extensions", [])
+        .addCredential(credPromise)
+        .runTest("Bad extensions: extensions is empty Array", new TypeError());
+    new GetCredentialsTest("options.publicKey.extensions", new ArrayBuffer(0))
+        .addCredential(credPromise)
+        .runTest("Bad extensions: extensions is empty ArrayBuffer", new TypeError());
+    var badJson = '{"foo": true, "bar: "yup"}'; // missing quote after "bar"
+    new GetCredentialsTest("options.publicKey.extensions", {foo: badJson})
+        .addCredential(credPromise)
+        .runTest("Bad extensions: malformatted JSON", new TypeError());
+    new GetCredentialsTest("options.publicKey.extensions", {foo: dummyExtension})
+        .addCredential(credPromise)
+        .runTest("Bad extensions: JavaScript object", new TypeError());
+    var badExtId = {};
+    badExtId[createRandomString(65)] = dummyExtension;
+    new GetCredentialsTest("options.publicKey.extensions", {badExtId: dummyExtension})
+        .addCredential(credPromise)
+        .runTest("Bad extensions: extension ID too long", new TypeError());
+
+    // phony extensions
+    // TODO: not sure if this should pass or fail
+    // should be clarified as part of https://github.com/w3c/webauthn/pull/765
+    var randomExtId = {};
+    randomExtId[createRandomString(64)] = dummyExtension;
+    new GetCredentialsTest("options.publicKey.extensions", {foo: JSON.stringify(randomExtId)})
+        .addCredential(credPromise)
+        .runTest("extensions is a nonsensical JSON string");
+
+    // TODO
+    // defined extensions:
+    // * appid
+    // * txAuthSimple
+    // * txAuthGeneric
+    // * authnSel
+    // * exts
+    // * uvi
+    // * loc
+    // * uvm
+});
+
+/* JSHINT */
+/* globals standardSetup, GetCredentialsTest, createRandomString, createCredential */
+</script>
\ No newline at end of file
--- a/testing/web-platform/tests/webauthn/getcredential-passing.https.html
+++ b/testing/web-platform/tests/webauthn/getcredential-passing.https.html
@@ -6,16 +6,61 @@
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src=helpers.js></script>
 <body></body>
 <script>
 standardSetup(function() {
     "use strict";
 
-    // GetCredentialsTest passing tests
-    // new GetCredentialsTest().addCredential();
-    new GetCredentialsTest().addCredential().test();
+    var credPromise = createCredential();
+
+    // GetCredentialsTest with default args
+    new GetCredentialsTest()
+        .addCredential(credPromise)
+        .runTest("passing credentials.get() with default args");
+
+    // timeout
+    new GetCredentialsTest({path: "options.publicKey.timeout", value: undefined})
+        .addCredential(credPromise)
+        .runTest("passing credentials.create() with no timeout");
+
+    // rpId
+    new GetCredentialsTest({path: "options.publicKey.rpId", value: undefined})
+        .addCredential(credPromise)
+        .runTest("rpId undefined");
+    new GetCredentialsTest({path: "options.publicKey.rpId", value: window.location.host})
+        .addCredential(credPromise)
+        .runTest("passing credentials.get() with rpId (host and port)");
+    new GetCredentialsTest({path: "options.publicKey.rpId", value: window.location.hostname})
+        .addCredential(credPromise)
+        .runTest("passing credentials.get() with rpId (hostname)");
+
+    // allowCredentials
+    new GetCredentialsTest({path: "options.publicKey.allowCredentials", value: undefined})
+        .runTest("no credential specified");
+
+    // authnr selection user verification
+    new GetCredentialsTest({path: "options.publicKey.userVerification", value: undefined})
+        .addCredential(credPromise)
+        .runTest("authenticatorSelection userVerification undefined");
+    new GetCredentialsTest("options.publicKey.userVerification", "preferred")
+        .addCredential(credPromise)
+        .runTest("authenticatorSelection userVerification preferred");
+    new GetCredentialsTest("options.publicKey.userVerification", "discouraged")
+        .addCredential(credPromise)
+        .runTest("authenticatorSelection userVerification discouraged");
+
+    // good extension values
+    new GetCredentialsTest({path: "options.publicKey.extensions", value: undefined})
+        .addCredential(credPromise)
+        .runTest("extensions undefined");
+    new GetCredentialsTest("options.publicKey.extensions", {})
+        .addCredential(credPromise)
+        .runTest("extensions are empty object");
+    new GetCredentialsTest("options.publicKey.extensions", {foo: "", bar: "", bat: ""})
+        .addCredential(credPromise)
+        .runTest("extensions are dict of empty strings");
 });
 
 /* JSHINT */
-/* globals standardSetup, GetCredentialsTest */
+/* globals standardSetup, GetCredentialsTest, createCredential */
 </script>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/webauthn/getcredential-timeout.https.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebAuthn navigator.credentials.get() timeout Tests</title>
+<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
+<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src=helpers.js></script>
+<body></body>
+<script>
+standardSetup(function() {
+    "use strict";
+
+    var credPromise = createCredential();
+
+    // bad timeout values
+    // TODO: there is some debate as to whether MAX_UNSIGNED_LONG + 1 and / or -1 should be disallowed since they get converted to valid values internally
+    // new GetCredentialsTest({path: "options.publicKey.timeout", value: -1})
+    //     .addCredential(credPromise)
+    //     .runTest("Bad timeout: negative", new TypeError());
+    // new GetCredentialsTest({path: "options.publicKey.timeout", value: 4294967295 + 1})
+    //     .addCredential(credPromise)
+    //     .runTest("Bad timeout: too big", new TypeError());
+
+    // timeout test
+    // XXX: this probably always passes with most mock authenticators unless
+    // some setup happens right here to make sure they don't return a credential
+    // right away. So... uhh... I guess test this with a real authenticator if you
+    // want to see if it really works.
+    var timer;
+    function startTimer() {
+        timer = setTimeout(() => {
+            throw new Error("Timer went off before timeout");
+        }, 1000);
+    }
+    function stopTimer() {
+        clearTimeout(timer);
+    }
+    new GetCredentialsTest({path: "options.publicKey.timeout", value: 1})
+        .addCredential(credPromise)
+        .beforeTest(startTimer)
+        .afterTest(stopTimer)
+        .runTest("ensure create credential times out");
+    // TODO: createCredential.timeout > 1s && setTimeout < 1s
+    // TODO: createCredential.timeout < 5s && setTimeout > 5s
+});
+
+/* JSHINT */
+/* globals standardSetup, GetCredentialsTest, createCredential */
+</script>
\ No newline at end of file
--- a/testing/web-platform/tests/webauthn/helpers.js
+++ b/testing/web-platform/tests/webauthn/helpers.js
@@ -1,21 +1,131 @@
-
-/* Useful constants for working with COSE key objects */
+// Useful constants for working with COSE key objects
 const cose_kty = 1;
 const cose_kty_ec2 = 2;
 const cose_alg = 3;
 const cose_alg_ECDSA_w_SHA256 = -7;
 const cose_alg_ECDSA_w_SHA512 = -36;
 const cose_crv = -1;
 const cose_crv_P256 = 1;
 const cose_crv_x = -2;
 const cose_crv_y = -3;
 
 /**
+ * These are the default arguments that will be passed to navigator.credentials.create()
+ * unless modified by a specific test case
+ */
+var createCredentialDefaultArgs = {
+    options: {
+        publicKey: {
+            // Relying Party:
+            rp: {
+                name: "Acme",
+                icon: "https://www.w3.org/StyleSheets/TR/2016/logos/W3C"
+            },
+
+            // User:
+            user: {
+                id: new Uint8Array(16), // Won't survive the copy, must be rebuilt
+                name: "john.p.smith@example.com",
+                displayName: "John P. Smith",
+                icon: "https://pics.acme.com/00/p/aBjjjpqPb.png"
+            },
+
+            pubKeyCredParams: [{
+                type: "public-key",
+                alg: cose_alg_ECDSA_w_SHA256,
+            }],
+
+            timeout: 60000, // 1 minute
+            excludeCredentials: [] // No excludeList
+        }
+    }
+};
+
+/**
+ * These are the default arguments that will be passed to navigator.credentials.get()
+ * unless modified by a specific test case
+ */
+var getCredentialDefaultArgs = {
+    options: {
+        publicKey: {
+            timeout: 60000
+            // allowCredentials: [newCredential]
+        }
+    }
+};
+
+function createCredential(opts) {
+    opts = opts || {};
+
+    // set the default options
+    var createArgs = cloneObject(createCredentialDefaultArgs);
+    let challengeBytes = new Uint8Array(16);
+    window.crypto.getRandomValues(challengeBytes);
+    createArgs.options.publicKey.challenge = challengeBytes;
+    createArgs.options.publicKey.user.id = new Uint8Array(16);
+
+    // change the defaults with any options that were passed in
+    extendObject (createArgs, opts);
+
+    // create the credential, return the Promise
+    return navigator.credentials.create(createArgs.options);
+}
+
+function createRandomString(len) {
+    var text = "";
+    var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+    for(var i = 0; i < len; i++) {
+        text += possible.charAt(Math.floor(Math.random() * possible.length));
+    }
+    return text;
+}
+
+
+function ab2str(buf) {
+    return String.fromCharCode.apply(null, new Uint8Array(buf));
+}
+
+// Useful constants for working with attestation data
+const authenticator_data_user_present = 0x01;
+const authenticator_data_user_verified = 0x04;
+const authenticator_data_attested_cred_data = 0x40;
+const authenticator_data_extension_data = 0x80;
+
+function parseAuthenticatorData(buf) {
+    if (buf.byteLength < 37) {
+        throw new TypeError ("parseAuthenticatorData: buffer must be at least 37 bytes");
+    }
+
+    printHex ("authnrData", buf);
+
+    var authnrData = new DataView(buf);
+    var authnrDataObj = {};
+    authnrDataObj.length = buf.byteLength;
+
+    authnrDataObj.rpIdHash = new Uint8Array (buf.slice (0,32));
+    authnrDataObj.rawFlags = authnrData.getUint8(32);
+    authnrDataObj.counter = authnrData.getUint32(33, false);
+    authnrDataObj.rawCounter = [];
+    authnrDataObj.rawCounter[0] = authnrData.getUint8(33);
+    authnrDataObj.rawCounter[1] = authnrData.getUint8(34);
+    authnrDataObj.rawCounter[2] = authnrData.getUint8(35);
+    authnrDataObj.rawCounter[3] = authnrData.getUint8(36);
+    authnrDataObj.flags = {};
+
+    authnrDataObj.flags.userPresent = (authnrDataObj.rawFlags&authenticator_data_user_present)?true:false;
+    authnrDataObj.flags.userVerified = (authnrDataObj.rawFlags&authenticator_data_user_verified)?true:false;
+    authnrDataObj.flags.attestedCredentialData = (authnrDataObj.rawFlags&authenticator_data_attested_cred_data)?true:false;
+    authnrDataObj.flags.extensionData = (authnrDataObj.rawFlags&authenticator_data_extension_data)?true:false;
+
+    return authnrDataObj;
+}
+
+/**
  * TestCase
  *
  * A generic template for test cases
  * Is intended to be overloaded with subclasses that override testObject, testFunction and argOrder
  * The testObject is the default arguments for the testFunction
  * The default testObject can be modified with the modify() method, making it easy to create new tests based on the default
  * The testFunction is the target of the test and is called by the doIt() method. doIt() applies the testObject as arguments via toArgs()
  * toArgs() uses argOrder to make sure the resulting array is in the right order of the arguments for the testFunction
@@ -113,76 +223,137 @@ class TestCase {
             throw new Error("Test function not found");
         }
 
         return this.testFunction.call(this.ctx, ...this.toArgs());
     }
 
     /**
      * run the test function with the top-level properties of the test object applied as arguments
+     * expects the test to pass, and then validates the results
      */
-    test(desc) {
-        promise_test(() => {
-            return this.doIt()
-                .then((ret) => {
-                    // check the result
-                    this.validateRet(ret);
-                    return ret;
-                });
-        }, desc);
+    testPasses(desc) {
+        return this.doIt()
+            .then((ret) => {
+                // check the result
+                this.validateRet(ret);
+                return ret;
+            });
+    }
+
+    /**
+     * run the test function with the top-level properties of the test object applied as arguments
+     * expects the test to fail
+     */
+    testFails(t, testDesc, expectedErr) {
+        return promise_rejects(t, expectedErr, this.doIt(), "Expected bad parameters to fail");
+    }
+
+    /**
+     * Runs the test that's implemented by the class by calling the doIt() function
+     * @param  {String} desc                A description of the test being run
+     * @param  [Error|String] expectedErr   A string matching an error type, such as "SecurityError" or an object with a .name value that is an error type string
+     */
+    runTest(desc, expectedErr) {
+        promise_test((t) => {
+            return Promise.resolve().then(() => {
+                return this.testSetup();
+            }).then(() => {
+                if (expectedErr === undefined) {
+                    return this.testPasses(desc);
+                } else {
+                    return this.testFails(t, desc, expectedErr);
+                }
+            }).then((res) => {
+                return this.testTeardown(res);
+            })
+        }, desc)
+    }
+
+    /**
+     * called before runTest
+     * virtual method expected to be overridden by child class if needed
+     */
+    testSetup() {
+        if (this.beforeTestFn) {
+            this.beforeTestFn.call(this);
+        }
+
+        return Promise.resolve();
+    }
+
+    /**
+     * Adds a callback function that gets called in the TestCase context
+     * and within the testing process.
+     */
+    beforeTest(fn) {
+        if (typeof fn !== "function") {
+            throw new Error ("Tried to call non-function before test");
+        }
+
+        this.beforeTestFn = fn;
+
+        return this;
+    }
+
+    /**
+     * called after runTest
+     * virtual method expected to be overridden by child class if needed
+     */
+    testTeardown(res) {
+        if (this.afterTestFn) {
+            this.afterTestFn.call(this, res);
+        }
+
+        return Promise.resolve();
+    }
+
+    /**
+     * Adds a callback function that gets called in the TestCase context
+     * and within the testing process. Good for validating results.
+     */
+    afterTest(fn) {
+        if (typeof fn !== "function") {
+            throw new Error ("Tried to call non-function after test");
+        }
+
+        this.afterTestFn = fn;
+
+        return this;
     }
 
     /**
      * validates the value returned from the test function
+     * virtual method expected to be overridden by child class
      */
     validateRet() {
         throw new Error("Not implemented");
     }
-
-    /**
-     * calls doIt() with testObject() and expects it to fail with a TypeError()
-     */
-    testBadArgs(testDesc) {
-        promise_test(function(t) {
-            return promise_rejects(t, new TypeError(), this.doIt(), "Expected bad parameters to fail");
-        }.bind(this), testDesc);
-    }
 }
 
-var createCredentialDefaultArgs = {
-    options: {
-        publicKey: {
-            // Relying Party:
-            rp: {
-                name: "Acme"
-            },
-
-            // User:
-            user: {
-                id: new Uint8Array(), // Won't survive the copy, must be rebuilt
-                name: "john.p.smith@example.com",
-                displayName: "John P. Smith",
-                icon: "https://pics.acme.com/00/p/aBjjjpqPb.png"
-            },
-
-            pubKeyCredParams: [{
-                type: "public-key",
-                alg: cose_alg_ECDSA_w_SHA256,
-            }],
-
-            timeout: 60000, // 1 minute
-            excludeCredentials: [] // No excludeList
-        }
-    }
-};
-
 function cloneObject(o) {
     return JSON.parse(JSON.stringify(o));
 }
 
+function extendObject(dst, src) {
+    Object.keys(src).forEach(function(key) {
+        if (isSimpleObject(src[key])) {
+            extendObject (dst[key], src[key]);
+        } else {
+            dst[key] = src[key];
+        }
+    });
+}
+
+function isSimpleObject(o) {
+    return (typeof o === "object" &&
+        !Array.isArray(o) &&
+        !(o instanceof ArrayBuffer));
+}
+
 /**
  * CreateCredentialTest
  *
  * tests the WebAuthn navigator.credentials.create() interface
  */
 class CreateCredentialsTest extends TestCase {
     constructor() {
         // initialize the parent class
@@ -193,17 +364,17 @@ class CreateCredentialsTest extends Test
         // the context to call the test function with (i.e. - the 'this' object for the function)
         this.ctx = navigator.credentials;
 
         // the default object to pass to makeCredential, to be modified with modify() for various tests
         let challengeBytes = new Uint8Array(16);
         window.crypto.getRandomValues(challengeBytes);
         this.testObject = cloneObject(createCredentialDefaultArgs);
         // cloneObject can't clone the BufferSource in user.id, so let's recreate it.
-        this.testObject.options.publicKey.user.id = new Uint8Array();
+        this.testObject.options.publicKey.user.id = new Uint8Array(16);
         this.testObject.options.publicKey.challenge = challengeBytes;
 
         // how to order the properties of testObject when passing them to makeCredential
         this.argOrder = [
             "options"
         ];
 
         // enable the constructor to modify the default testObject
@@ -230,25 +401,18 @@ class GetCredentialsTest extends TestCas
         // the function to be tested
         this.testFunction = navigator.credentials.get;
         // the context to call the test function with (i.e. - the 'this' object for the function)
         this.ctx = navigator.credentials;
 
         // default arguments
         let challengeBytes = new Uint8Array(16);
         window.crypto.getRandomValues(challengeBytes);
-        this.testObject = {
-            options: {
-                publicKey: {
-                    challenge: challengeBytes,
-                    // timeout: 60000,
-                    // allowCredentials: [newCredential]
-                }
-            }
-        };
+        this.testObject = cloneObject(getCredentialDefaultArgs);
+        this.testObject.options.publicKey.challenge = challengeBytes;
 
         // how to order the properties of testObject when passing them to makeCredential
         this.argOrder = [
             "options"
         ];
 
         this.credentialPromiseList = [];
 
@@ -261,58 +425,56 @@ class GetCredentialsTest extends TestCas
             this.modify(...arguments);
         }
     }
 
     addCredential(arg) {
         // if a Promise was passed in, add it to the list
         if (arg instanceof Promise) {
             this.credentialPromiseList.push(arg);
-            return;
+            return this;
         }
 
         // if a credential object was passed in, convert it to a Promise for consistency
         if (typeof arg === "object") {
             this.credentialPromiseList.push(Promise.resolve(arg));
-            return;
+            return this;
         }
 
-        // if a credential wasn't passed in, create one
-        let challengeBytes = new Uint8Array(16);
-        window.crypto.getRandomValues(challengeBytes);
-        var createArgs = cloneObject(createCredentialDefaultArgs);
-        createArgs.options.publicKey.challenge = challengeBytes;
-        createArgs.options.publicKey.user.id = new Uint8Array();
-        var p = navigator.credentials.create(createArgs.options);
+        // if no credential specified then create one
+        var p = createCredential();
         this.credentialPromiseList.push(p);
 
         return this;
     }
 
-    test() {
+    testSetup(desc) {
         if (!this.credentialPromiseList.length) {
             throw new Error("Attempting list without defining credential to test");
         }
 
-        Promise.all(this.credentialPromiseList)
+        return Promise.all(this.credentialPromiseList)
             .then((credList) => {
                 var idList = credList.map((cred) => {
                     return {
                         id: cred.rawId,
                         transports: ["usb", "nfc", "ble"],
                         type: "public-key"
                     };
                 });
                 this.testObject.options.publicKey.allowCredentials = idList;
-                return super.test();
+                // return super.test(desc);
+            })
+            .catch((err) => {
+                throw Error(err);
             });
     }
 
     validateRet(ret) {
-        validatePublicKeyCredential (ret);
+        validatePublicKeyCredential(ret);
         validateAuthenticatorAssertionResponse(ret.response);
     }
 }
 
 /**
  * runs assertions against a PublicKeyCredential object to ensure it is properly formatted
  */
 function validatePublicKeyCredential(cred) {
@@ -330,53 +492,62 @@ function validatePublicKeyCredential(cre
 }
 
 /**
  * runs assertions against a AuthenticatorAttestationResponse object to ensure it is properly formatted
  */
 function validateAuthenticatorAttestationResponse(attr) {
     // class
     assert_class_string(attr, "AuthenticatorAttestationResponse", "Expected credentials.create() to return instance of 'AuthenticatorAttestationResponse' class");
+
     // clientDataJSON
     assert_idl_attribute(attr, "clientDataJSON", "credentials.create() should return AuthenticatorAttestationResponse with clientDataJSON attribute");
     assert_readonly(attr, "clientDataJSON", "credentials.create() should return AuthenticatorAttestationResponse with readonly clientDataJSON attribute");
+    // TODO: clientDataJSON() and make sure fields are correct
+
     // attestationObject
     assert_idl_attribute(attr, "attestationObject", "credentials.create() should return AuthenticatorAttestationResponse with attestationObject attribute");
     assert_readonly(attr, "attestationObject", "credentials.create() should return AuthenticatorAttestationResponse with readonly attestationObject attribute");
+    // TODO: parseAuthenticatorData() and make sure flags are correct
 }
 
 /**
  * runs assertions against a AuthenticatorAssertionResponse object to ensure it is properly formatted
  */
 function validateAuthenticatorAssertionResponse(assert) {
     // class
     assert_class_string(assert, "AuthenticatorAssertionResponse", "Expected credentials.create() to return instance of 'AuthenticatorAssertionResponse' class");
+
     // clientDataJSON
     assert_idl_attribute(assert, "clientDataJSON", "credentials.get() should return AuthenticatorAssertionResponse with clientDataJSON attribute");
     assert_readonly(assert, "clientDataJSON", "credentials.get() should return AuthenticatorAssertionResponse with readonly clientDataJSON attribute");
+    // TODO: clientDataJSON() and make sure fields are correct
+
     // signature
     assert_idl_attribute(assert, "signature", "credentials.get() should return AuthenticatorAssertionResponse with signature attribute");
     assert_readonly(assert, "signature", "credentials.get() should return AuthenticatorAssertionResponse with readonly signature attribute");
+
     // authenticatorData
     assert_idl_attribute(assert, "authenticatorData", "credentials.get() should return AuthenticatorAssertionResponse with authenticatorData attribute");
     assert_readonly(assert, "authenticatorData", "credentials.get() should return AuthenticatorAssertionResponse with readonly authenticatorData attribute");
+    // TODO: parseAuthenticatorData() and make sure flags are correct
 }
 
 //************* BEGIN DELETE AFTER 1/1/2018 *************** //
 // XXX for development mode only!!
 // debug() for debugging purposes... we can drop this later if it is considered ugly
 // note that debug is currently an empty function (i.e. - prints no output)
 // and debug only prints output if the polyfill is loaded
 var debug = function() {};
 // if the WebAuthn API doesn't exist load a polyfill for testing
 // note that the polyfill only gets loaded if navigator.credentials create doesn't exist
 // AND if the polyfill script is found at the right path (i.e. - the polyfill is opt-in)
 function ensureInterface() {
-    if (typeof navigator.credentials.create !== "function") {
-        debug = console.log;
+    if (typeof navigator.credentials === "object" && typeof navigator.credentials.create !== "function") {
+        // debug = onsole.log;
 
         return loadJavaScript("/webauthn/webauthn-polyfill/webauthn-polyfill.js")
             .then(() => {
                 return loadJavaScript("/webauthn/webauthn-soft-authn/soft-authn.js");
             });
     } else {
         return Promise.resolve();
     }
--- a/testing/web-platform/tests/webauthn/securecontext.http.html
+++ b/testing/web-platform/tests/webauthn/securecontext.http.html
@@ -12,17 +12,17 @@ standardSetup(function() {
     "use strict";
 
     // See https://www.w3.org/TR/secure-contexts/
     // Section 1.1 - 1.4 for list of examples referenced below
 
     // Example 1
     // http://example.com/ opened in a top-level browsing context is not a secure context, as it was not delivered over an authenticated and encrypted channel.
     test (() => {
-        assert_false (typeof navigator.credentials.create === "function");
+        assert_false (typeof navigator.credentials === "object" && typeof navigator.credentials.create === "function");
     }, "no navigator.credentials.create in non-secure context");
 
     // Example 4: TODO
     // If a non-secure context opens https://example.com/ in a new window, then things are more complicated. The new window’s status depends on how it was opened. If the non-secure context can obtain a reference to the secure context, or vice-versa, then the new window is not a secure context.
     //
     // This means that the following will both produce non-secure contexts:
     //<a href="https://example.com/" target="_blank">Link!</a>
     // <script>
--- a/testing/web-platform/tests/webauthn/securecontext.https.html
+++ b/testing/web-platform/tests/webauthn/securecontext.https.html
@@ -12,17 +12,17 @@ standardSetup(function() {
     "use strict";
 
     // See https://www.w3.org/TR/secure-contexts/
     // Section 1.1 - 1.4 for list of examples referenced below
 
     // Example 2
     // https://example.com/ opened in a top-level browsing context is a secure context, as it was delivered over an authenticated and encrypted channel.
     test (() => {
-        assert_true (typeof navigator.credentials.create === "function");
+        assert_true (typeof navigator.credentials === "object" && typeof navigator.credentials.create === "function");
     }, "navigator.credentials.create exists in secure context");
 
     // Example 3: TODO
     // Example 5: TODO
     // Example 8: TODO
     // Example 10: TODO
     // Example 11: TODO