X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=tests.js;h=ebdf9ec78d89231c13e7aad26991ba6e1118f276;hb=92b46ab44fb7fe7aef1cef3d843d1e3d19c1d7cb;hp=cef6e138828af369827332194fcb5a354f476527;hpb=61ed16a9cefec8a9a9b7d7c41141e6ef10c3e3e1;p=perso%2FImmae%2FProjets%2FCryptomonnaies%2FBIP39.git diff --git a/tests.js b/tests.js index cef6e13..ebdf9ec 100644 --- a/tests.js +++ b/tests.js @@ -44,6 +44,37 @@ function waitForGenerate(fn, maxTime) { wait(); } +function waitForFeedback(fn, maxTime) { + if (!maxTime) { + maxTime = testMaxTime; + } + var start = new Date().getTime(); + var wait = function keepWaiting() { + var now = new Date().getTime(); + var hasTimedOut = now - start > maxTime; + if (hasTimedOut) { + console.log("Test timed out"); + fn(); + return; + } + var feedback = page.evaluate(function() { + var feedback = $(".feedback"); + if (feedback.css("display") == "none") { + return ""; + } + return feedback.text(); + }); + var hasFinished = feedback.length > 0 && feedback != "Calculating..."; + if (hasFinished) { + fn(); + } + else { + setTimeout(keepWaiting, 100); + } + } + wait(); +} + function next() { if (tests.length > 0) { var testsStr = tests.length == 1 ? "test" : "tests"; @@ -1303,7 +1334,7 @@ page.open(url, function(status) { return $(".address:first").text(); }); if (actual != expected) { - console.log("Passphrase results in wrong address"); + console.log("Setting BIP32 root key results in wrong address"); console.log("Expected: " + expected); console.log("Actual: " + actual); fail(); @@ -1314,29 +1345,601 @@ page.open(url, function(status) { }, // Setting BIP32 root key clears the existing phrase, passphrase and seed +function() { +page.open(url, function(status) { + var expected = ""; + // set a mnemonic + page.evaluate(function() { + $(".phrase").val("A non-blank but invalid value"); + }); + // Accept any confirm dialogs + page.onConfirm = function() { + return true; + }; + // set the root key + page.evaluate(function() { + $(".root-key").val("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi").trigger("input"); + }); + waitForGenerate(function() { + var actual = page.evaluate(function() { + return $(".phrase").val(); + }); + if (actual != expected) { + console.log("Phrase not cleared when setting BIP32 root key"); + console.log("Expected: " + expected); + console.log("Actual: " + actual); + fail(); + } + next(); + }); +}); +}, + // Clearing of phrase, passphrase and seed can be cancelled by user +function() { +page.open(url, function(status) { + var expected = "abandon abandon ability"; + // set a mnemonic + page.evaluate(function() { + $(".phrase").val("abandon abandon ability"); + }); + // Cancel any confirm dialogs + page.onConfirm = function() { + return false; + }; + // set the root key + page.evaluate(function() { + $(".root-key").val("xprv9s21ZrQH143K3d3vzEDD3KpSKmxsZ3y7CqhAL1tinwtP6wqK4TKEKjpBuo6P2hUhB6ZENo7TTSRytiP857hBZVpBdk8PooFuRspE1eywwNZ").trigger("input"); + }); + var actual = page.evaluate(function() { + return $(".phrase").val(); + }); + if (actual != expected) { + console.log("Phrase not retained when cancelling changes to BIP32 root key"); + console.log("Expected: " + expected); + console.log("Actual: " + actual); + fail(); + } + next(); +}); +}, + // Custom BIP32 root key is used when changing the derivation path +function() { +page.open(url, function(status) { + var expected = "1Nq2Wmu726XHCuGhctEtGmhxo3wzk5wZ1H"; + // set the root key + page.evaluate(function() { + $(".root-key").val("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi").trigger("input"); + }); + waitForGenerate(function() { + // change the derivation path + page.evaluate(function() { + $("#account").val("1").trigger("input"); + }); + // check the bip32 root key is used for derivation, not the blank phrase + waitForGenerate(function() { + var actual = page.evaluate(function() { + return $(".address:first").text(); + }); + if (actual != expected) { + console.log("Changing the derivation path does not use BIP32 root key"); + console.log("Expected: " + expected); + console.log("Actual: " + actual); + fail(); + } + next(); + }); + }); +}); +}, // Incorrect mnemonic shows error +function() { +page.open(url, function(status) { + // set the root key + page.evaluate(function() { + $(".phrase").val("abandon abandon abandon").trigger("input"); + }); + waitForFeedback(function() { + // check there is an error shown + var feedback = page.evaluate(function() { + return $(".feedback").text(); + }); + if (feedback.length <= 0) { + console.log("Invalid mnemonic does not show error"); + fail(); + } + next(); + }); +}); +}, + // Incorrect word shows suggested replacement +function() { +page.open(url, function(status) { + // set the root key + page.evaluate(function() { + $(".phrase").val("abandon abandon abiliti").trigger("input"); + }); + // check there is a suggestion shown + waitForFeedback(function() { + var feedback = page.evaluate(function() { + return $(".feedback").text(); + }); + if (feedback.indexOf("did you mean ability?") < 0) { + console.log("Incorrect word does not show suggested replacement"); + console.log("Error: " + error); + fail(); + } + next(); + }); +}); +}, + // Incorrect BIP32 root key shows error +function() { +page.open(url, function(status) { + // set the root key + page.evaluate(function() { + $(".root-key").val("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpj").trigger("input"); + }); + // check there is an error shown + waitForFeedback(function() { + var feedback = page.evaluate(function() { + return $(".feedback").text(); + }); + if (feedback != "Invalid root key") { + console.log("Invalid root key does not show error"); + console.log("Error: " + error); + fail(); + } + next(); + }); +}); +}, + // Derivation path not starting with m shows error +function() { +page.open(url, function(status) { + // set the mnemonic phrase + page.evaluate(function() { + $(".phrase").val("abandon abandon ability").trigger("input"); + }); + waitForGenerate(function() { + // select the bip32 tab so custom derivation path can be set + page.evaluate(function() { + $("#bip32-tab a").click(); + }); + waitForGenerate(function() { + // set the incorrect derivation path + page.evaluate(function() { + $("#bip32 .path").val("n/0").trigger("input"); + }); + waitForFeedback(function() { + var feedback = page.evaluate(function() { + return $(".feedback").text(); + }); + if (feedback != "First character must be 'm'") { + console.log("Derivation path not starting with m should show error"); + console.log("Error: " + error); + fail(); + } + next(); + }); + }); + }); +}); +}, + // Derivation path containing invalid characters shows useful error +function() { +page.open(url, function(status) { + // set the mnemonic phrase + page.evaluate(function() { + $(".phrase").val("abandon abandon ability").trigger("input"); + }); + waitForGenerate(function() { + // select the bip32 tab so custom derivation path can be set + page.evaluate(function() { + $("#bip32-tab a").click(); + }); + waitForGenerate(function() { + // set the incorrect derivation path + page.evaluate(function() { + $("#bip32 .path").val("m/1/0wrong1/1").trigger("input"); + }); + waitForFeedback(function() { + var feedback = page.evaluate(function() { + return $(".feedback").text(); + }); + if (feedback != "Invalid characters 0wrong1 found at depth 2") { + console.log("Derivation path with invalid characters should show error"); + console.log("Error: " + error); + fail(); + } + next(); + }); + }); + }); +}); +}, // Github Issue 11: Default word length is 15 -// https://github.com/dcpos/bip39/issues/11 +// https://github.com/iancoleman/bip39/issues/11 +function() { +page.open(url, function(status) { + // get the word length + var defaultLength = page.evaluate(function() { + return $(".strength").val(); + }); + if (defaultLength != 15) { + console.log("Default word length is not 15"); + fail(); + } + next(); +}); +}, + // Github Issue 12: Generate more rows with private keys hidden -// https://github.com/dcpos/bip39/issues/12 +// https://github.com/iancoleman/bip39/issues/12 +function() { +page.open(url, function(status) { + // set the phrase + page.evaluate(function() { + $(".phrase").val("abandon abandon ability"); + $(".phrase").trigger("input"); + }); + waitForGenerate(function() { + // toggle private keys hidden, then generate more addresses + page.evaluate(function() { + $(".private-key-toggle").click(); + $(".more").click(); + }); + waitForGenerate(function() { + // check more have been generated + var expected = 40; + var numPrivKeys = page.evaluate(function() { + return $(".privkey").length; + }); + if (numPrivKeys != expected) { + console.log("Wrong number of addresses when clicking 'more' with hidden privkeys"); + console.log("Expected: " + expected); + console.log("Actual: " + numPrivKeys); + fail(); + } + // check no private keys are shown + var numHiddenPrivKeys = page.evaluate(function() { + return $(".privkey span[class=invisible]").length; + }); + if (numHiddenPrivKeys != expected) { + console.log("Generating more does not retain hidden state of privkeys"); + console.log("Expected: " + expected); + console.log("Actual: " + numHiddenPrivKeys); + fail(); + } + next(); + }); + }); +}); +}, // Github Issue 19: Mnemonic is not sensitive to whitespace -// https://github.com/dcpos/bip39/issues/19 +// https://github.com/iancoleman/bip39/issues/19 +function() { +page.open(url, function(status) { + // set the phrase + var expected = "xprv9s21ZrQH143K3isaZsWbKVoTtbvd34Y1ZGRugGdMeBGbM3AgBVzTH159mj1cbbtYSJtQr65w6L5xy5L9SFC7c9VJZWHxgAzpj4mun5LhrbC"; + page.evaluate(function() { + var doubleSpace = " "; + $(".phrase").val("urge cat" + doubleSpace + "bid"); + $(".phrase").trigger("input"); + }); + waitForGenerate(function() { + // Check the bip32 root key is correct + var actual = page.evaluate(function() { + return $(".root-key").val(); + }); + if (actual != expected) { + console.log("Mnemonic is sensitive to whitespace"); + console.log("Expected: " + expected); + console.log("Actual: " + actual); + fail(); + } + next(); + }); +}); +}, -// Github Issue 23: Use correct derivation path when changing tabs -// https://github.com/dcpos/bip39/issues/23 +// Github Issue 23: Part 1: Use correct derivation path when changing tabs +// https://github.com/iancoleman/bip39/issues/23 +function() { +page.open(url, function(status) { + // 1) and 2) set the phrase + page.evaluate(function() { + $(".phrase").val("abandon abandon ability").trigger("input"); + }); + waitForGenerate(function() { + // 3) select bip32 tab + page.evaluate(function() { + $("#bip32-tab a").click(); + }); + waitForGenerate(function() { + // 4) switch from bitcoin to litecoin + page.evaluate(function() { + $(".network").val("2").trigger("change"); + }); + waitForGenerate(function() { + // 5) Check derivation path is displayed correctly + var expected = "m/0/0"; + var actual = page.evaluate(function() { + return $(".index:first").text(); + }); + if (actual != expected) { + console.log("Github Issue 23 Part 1: derivation path display error"); + console.log("Expected: " + expected); + console.log("Actual: " + actual); + fail(); + } + // 5) Check address is displayed correctly + var expected = "LS8MP5LZ5AdzSZveRrjm3aYVoPgnfFh5T5"; + var actual = page.evaluate(function() { + return $(".address:first").text(); + }); + if (actual != expected) { + console.log("Github Issue 23 Part 1: address display error"); + console.log("Expected: " + expected); + console.log("Actual: " + actual); + fail(); + } + next(); + }); + }); + }); +}); +}, + +// Github Issue 23 Part 2: Coin selection in derivation path +// https://github.com/iancoleman/bip39/issues/23#issuecomment-238011920 +function() { +page.open(url, function(status) { + // set the phrase + page.evaluate(function() { + $(".phrase").val("abandon abandon ability").trigger("input"); + }); + waitForGenerate(function() { + // switch from bitcoin to clam + page.evaluate(function() { + $(".network").val("9").trigger("change"); + }); + waitForGenerate(function() { + // check derivation path is displayed correctly + var expected = "m/44'/23'/0'/0/0"; + var actual = page.evaluate(function() { + return $(".index:first").text(); + }); + if (actual != expected) { + console.log("Github Issue 23 Part 2: Coin in BIP44 derivation path is incorrect"); + console.log("Expected: " + expected); + console.log("Actual: " + actual); + fail(); + } + next(); + }); + }); +}); +}, // Github Issue 26: When using a Root key derrived altcoins are incorrect -// https://github.com/dcpos/bip39/issues/26 +// https://github.com/iancoleman/bip39/issues/26 +function() { +page.open(url, function(status) { + // 1) 2) and 3) set the root key + page.evaluate(function() { + $(".root-key").val("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi").trigger("input"); + }); + waitForGenerate(function() { + // 4) switch from bitcoin to viacoin + page.evaluate(function() { + $(".network").val("6").trigger("change"); + }); + waitForGenerate(function() { + // 5) ensure the derived address is correct + var expected = "Vq9Eq4N5SQnjqZvxtxzo7hZPW5XnyJsmXT"; + var actual = page.evaluate(function() { + return $(".address:first").text(); + }); + if (actual != expected) { + console.log("Github Issue 26: address is incorrect when changing networks and using root-key to derive"); + console.log("Expected: " + expected); + console.log("Actual: " + actual); + fail(); + } + next(); + }); + }); +}); +}, + +// Selecting a language with no existing phrase should generate a phrase in +// that language. +function() { +page.open(url, function(status) { + // Select a language + // Need to manually simulate hash being set due to quirk between + // 'click' event triggered by javascript vs triggered by mouse. + // Perhaps look into page.sendEvent + // http://phantomjs.org/api/webpage/method/send-event.html + page.evaluate(function() { + window.location.hash = "#japanese"; + $("a[href='#japanese']").trigger("click"); + }); + waitForGenerate(function() { + // Check the mnemonic is in Japanese + var phrase = page.evaluate(function() { + return $(".phrase").val(); + }); + if (phrase.length <= 0) { + console.log("No Japanese phrase generated"); + fail(); + } + if (phrase.charCodeAt(0) < 128) { + console.log("First character of Japanese phrase is ascii"); + console.log("Phrase: " + phrase); + fail(); + } + next(); + }); +}); +}, + +// Selecting a language with existing phrase should update the phrase to use +// that language. +function() { +page.open(url, function(status) { + // Set the phrase to an English phrase. + page.evaluate(function() { + $(".phrase").val("abandon abandon ability").trigger("input"); + }); + waitForGenerate(function() { + // Change to Italian + // Need to manually simulate hash being set due to quirk between + // 'click' event triggered by javascript vs triggered by mouse. + // Perhaps look into page.sendEvent + // http://phantomjs.org/api/webpage/method/send-event.html + page.evaluate(function() { + window.location.hash = "#italian"; + $("a[href='#italian']").trigger("click"); + }); + waitForGenerate(function() { + // Check only the language changes, not the phrase + var expected = "abaco abaco abbaglio"; + var actual = page.evaluate(function() { + return $(".phrase").val(); + }); + if (actual != expected) { + console.log("Changing language with existing phrase"); + console.log("Expected: " + expected); + console.log("Actual: " + actual); + fail(); + } + // Check the address is correct + var expected = "1Dz5TgDhdki9spa6xbPFbBqv5sjMrx3xgV"; + var actual = page.evaluate(function() { + return $(".address:first").text(); + }); + if (actual != expected) { + console.log("Changing language generates incorrect address"); + console.log("Expected: " + expected); + console.log("Actual: " + actual); + fail(); + } + next(); + }); + }); +}); +}, + +// Suggested replacement for erroneous word in non-English language +function() { +page.open(url, function(status) { + // Set an incorrect phrase in Italian + page.evaluate(function() { + $(".phrase").val("abaco abaco zbbaglio").trigger("input"); + }); + waitForFeedback(function() { + // Check the suggestion is correct + var feedback = page.evaluate(function() { + return $(".feedback").text(); + }); + if (feedback.indexOf("did you mean abbaglio?") < 0) { + console.log("Incorrect Italian word does not show suggested replacement"); + console.log("Error: " + error); + fail(); + } + next(); + }); +}); +}, + + +// Japanese word does not break across lines. +// Point 2 from +// https://github.com/bitcoin/bips/blob/master/bip-0039/bip-0039-wordlists.md#japanese +function() { +page.open(url, function(status) { + hasWordBreakCss = page.content.indexOf("word-break: keep-all;") > -1; + if (!hasWordBreakCss) { + console.log("Japanese words can break across lines mid-word"); + console.log("Check CSS for '.phrase { word-break: keep-all; }'"); + fail(); + } + // Run the next test + next(); +}); +}, + +// Language can be specified at page load using hash value in url +function() { +page.open(url, function(status) { + // Set the page hash as if it were on a fresh page load + page.evaluate(function() { + window.location.hash = "#japanese"; + }); + // Generate a random phrase + page.evaluate(function() { + $(".generate").trigger("click"); + }); + waitForGenerate(function() { + // Check the phrase is in Japanese + var phrase = page.evaluate(function() { + return $(".phrase").val(); + }); + if (phrase.length <= 0) { + console.log("No phrase generated using url hash"); + fail(); + } + if (phrase.charCodeAt(0) < 128) { + console.log("Language not detected from url hash on page load."); + console.log("Phrase: " + phrase); + fail(); + } + next(); + }); +}); +}, + +// If you wish to add more tests, do so here... + +// Here is a blank test template +/* + +function() { +page.open(url, function(status) { + // Do something on the page + page.evaluate(function() { + $(".phrase").val("abandon abandon ability").trigger("input"); + }); + waitForGenerate(function() { + // Check the result of doing the thing + var expected = "1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug"; + var actual = page.evaluate(function() { + return $(".address:first").text(); + }); + if (actual != expected) { + console.log("A specific message about what failed"); + console.log("Expected: " + expected); + console.log("Actual: " + actual); + fail(); + } + // Run the next test + next(); + }); +}); +}, + +*/ ];