+it('Allows selection of MOAC', function(done) {
+ var params = {
+ selectText: "MOAC - MOAC",
+ phrase: "ill clump only blind unit burden thing track silver cloth review awake useful craft whale all satisfy else trophy sunset walk vanish hope valve",
+ firstAddress: "0xa1350EA5707247e0092Ab780A0CDbeA9c8C7Acb5",
+ firstPubKey: "0x0376b024c6068c9fda7e91779e115dcd3a70584fd6984e6dd25da144c46ca259c6",
+ firstPrivKey: "0x2515f9db03c1e56de393648eabf35d288f730aadce5d30865c52e72b28e303c9",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Musicoin', function(done) {
+ var params = {
+ selectText: "MUSIC - Musicoin",
+ phrase: "abandon abandon ability",
+ firstAddress: "0xDc060e4A0b0313ea83Cf6B3A39B9db2D29004897",
+ firstPubKey: "0x02a17278d54548e7cf0c1e6120646174f42e380ae5a0080f1a0d09f118305d6f9f",
+ firstPrivKey: "0xaea8683b8bfd56b6fc68c19b88eee4ccd2f00430bc466741d0297aa65c7b56a5",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Poa', function(done) {
+ var params = {
+ selectText: "POA - Poa",
+ phrase: "abandon abandon ability",
+ firstAddress: "0x53aF28d754e106210C3d0467Dd581eaf7e3C5e60",
+ firstPubKey: "0x02cda40cf7f21f370afe0206cbf219f963369d7c7229dc7ba64137358489d96567",
+ firstPrivKey: "0xed0a44cff8e44fa978f339af3308ee439c30f4170671ad0e1ccd7e4bfff70ed9",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Expanse', function(done) {
+ var params = {
+ selectText: "EXP - Expanse",
+ phrase: "abandon abandon ability",
+ firstAddress: "0xf57FeAbf26582b6E3E666559d3B1Cc6fB2b2c5F6",
+ firstPubKey: "0x0232fa15f0971f93c182afea54cb28a3180f5a4c31759235ca6ceca47a5a777335",
+ firstPrivKey: "0x9f96418f9ec3672b52c2a6421272650b2d5992d524a48905a4ff0ed9ce347c9b",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Callisto', function(done) {
+ var params = {
+ selectText: "CLO - Callisto",
+ phrase: "abandon abandon ability",
+ firstAddress: "0x4f9364F7420B317266C51Dc8eB979717D4dE3f4E",
+ firstPubKey: "0x0313d9db8d77249c768630a5a8315e08e3a3284d7e18774476d15e073931ddc15e",
+ firstPrivKey: "0x02bbf00719f3730baf989f7392b8d55548dd349abd744c68242c69bd016ce28d",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of HUSH', function(done) {
+ var params = {
+ selectText: "HUSH - Hush (Legacy)",
+ phrase: "abandon abandon ability",
+ firstAddress: "t1g6rLXUnJaiJuu4q4zmJjoa9Gk4fwKpiuA",
+ firstPubKey: "038702683b2d7bbb5c35e18e01cd18483cda8485fb919f34c0186ae31a05007755",
+ firstPrivKey: "Kx99fhLCDHPsBsZAJDH7v8vgGDch4rNr9VjhAUMfVevJWnoGr8WD",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of HUSH3', function(done) {
+ var params = {
+ selectText: "HUSH - Hush3",
+ phrase: "abandon abandon ability",
+ firstAddress: "RXWSQhwvw5jHPGP8bjwJhWoRnMLBnuPDKD",
+ firstPubKey: "038702683b2d7bbb5c35e18e01cd18483cda8485fb919f34c0186ae31a05007755",
+ firstPrivKey: "UpvyyNxAiWN7evMFUkxhgabuCHfq9xeTv17Wjj9LxN91QegKs6RR",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of ExchangeCoin', function(done) {
+ var params = {
+ selectText: "EXCC - ExchangeCoin",
+ phrase: "abandon abandon ability",
+ firstAddress: "22txYKpFN5fwGwdSs2UBf7ywewbLM92YqK7E",
+ firstPubKey: "033f5aed5f6cfbafaf223188095b5980814897295f723815fea5d3f4b648d0d0b3",
+ firstPrivKey: "L26cVSpWFkJ6aQkPkKmTzLqTdLJ923e6CzrVh9cmx21QHsoUmrEE",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Artax', function(done) {
+ var params = {
+ selectText: "XAX - Artax",
+ phrase: "abandon abandon ability",
+ firstAddress: "AYxaQPY7XLidG31V7F3yNzwxPYpYzRqG4q",
+ firstPubKey: "02edef928ec3951112452119f9a63d9479741ea0fc497682bd13064cfc5d1cc4e3",
+ firstPrivKey: "PMcqFx52ipYy9gZynEi5LYVD3XUC8YbQr2Neg6e3LFnh4yTBQ9yJ",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of BitcoinGreen', function(done) {
+ var params = {
+ selectText: "BITG - Bitcoin Green",
+ phrase: "abandon abandon ability",
+ firstAddress: "GeNGm9SkEfwbsws3UrrUSE2sJeyWYjzraY",
+ firstPubKey: "02a8e34c2599a14ca861285b734750432a7ce10caf7f1ff5a366a94264c636a12b",
+ firstPrivKey: "7uf6WeVgBqKR1WyUcaz1TLSKabyov9SfQDghyvfaCy6VZPwLNeku",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of ANON', function(done) {
+ var params = {
+ selectText: "ANON - ANON",
+ phrase: "abandon abandon ability",
+ firstAddress: "AnU6pijpEeUZFWSTyM2qTqZQn996Zq1Xard",
+ firstPubKey: "032742ff4eaf9188d84d38dfb4a2fdbb541bfd3ca9ee533a7d1092940a1ea60bb4",
+ firstPrivKey: "L2w3aoZExc9eHh1KMnDzrzaSVmfgQMvBxxFbtcegKNvrHVa4r81m",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of ProjectCoin', function(done) {
+ var params = {
+ selectText: "PRJ - ProjectCoin",
+ phrase: "abandon abandon ability",
+ firstAddress: "PXZG97saRseSCftfe1mcFmfAA7pf6qBbaz",
+ firstPubKey: "025f84297a93a33bccb735c931140ddb4279fe9d55a571ee7731259e3e19d0c7fe",
+ firstPrivKey: "JRR5uB6daEtSCLNnv7hKSgZ5KmFdHMUcpTzJGtEAi9sWSiQd4hVQ",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Phore', function(done) {
+ var params = {
+ selectText: "PHR - Phore",
+ phrase: "abandon abandon ability",
+ firstAddress: "PJThxpoXAG6hqrmdeQQbVDX4TJtFTMMymC",
+ firstPubKey: "022ef3c4cbc0481fd925ecac51f09f2976ea024b0863b543b1b481181e1ef34265",
+ firstPrivKey: "YPzQxHMA2Pm5S2p8Xwhmhm2PnH6ooYHrWNXiAKCCA2CjMtHyNzuh",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Safecoin', function(done) {
+ var params = {
+ selectText: "SAFE - Safecoin",
+ phrase: "abandon abandon ability",
+ firstAddress: "RtxHpnhJz6RY8k9owP3ua5QWraunmewB1G",
+ firstPubKey: "0383956cd23c1124324c92ac69f4bcf71ad973892a83aceb4085041afb082f6db9",
+ firstPrivKey: "Uznk2AHWqpSGRw8dmG3t3Q3rJJwyn3TcjzWh9EgDCQ9jU34DWF6m",
+ };
+ testNetwork(done, params);
+ });
+it('Allows selection of Blocknode', function(done) {
+ var params = {
+ selectText: "BND - Blocknode",
+ phrase: "abandon abandon ability",
+ firstAddress: "BG8xZSAur2jYLG9VXt8dYfkKxxeR7w9bSe",
+ firstPubKey: "03e91c00dcfca87c80f57691e34e0e4c55a18eb79048dbdd5f6d9c83daefea6459",
+ firstPrivKey: "C6gySxND85cLnLgsjTfUxXmMzh8JrSR24vpQnUHqVMqGYy36k4ho",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Blocknode Testnet', function(done) {
+ var params = {
+ selectText: "tBND - Blocknode Testnet",
+ phrase: "abandon abandon ability",
+ firstAddress: "bSptsFyDktFSKpWveRywJsDoJA2TC6qfHv",
+ firstPubKey: "0382a5450765e2025bdb5f7d109c9254a11ef97a566228bf171d80ecb348763bb0",
+ firstPrivKey: "MPuJVFnTAhFFvtLqgYL32FBF1g7jPraowuN5tV9EF2AtkYXCfkE3",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of LitecoinZ', function(done) {
+ var params = {
+ selectText: "LTZ - LitecoinZ",
+ phrase: "abandon abandon ability",
+ firstAddress: "L1VTXju7hLgKV4T7fGXS9sKsnm2gmtRCmyw",
+ firstPubKey: "03ea84a1cc8b43ea8330bc2f363e706a9ff2d48858185c42c296d06ddcb94bc827",
+ firstPrivKey: "L1PktmLfTgVRQZsqs2ZoFBBqnVXi5hVAimJt8tmfT2ye95WH9zEd",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of BlockStamp', function(done) {
+ var params = {
+ selectText: "BST - BlockStamp",
+ phrase: "abandon abandon ability",
+ firstAddress: "15gypKtim4cVTj137ApfryG17RkvSbPazZ",
+ firstPubKey: "0277bc537f8354004f8a77e07fb78b38f291df7bc07819c2d7eab049b8d10b3f7f",
+ firstPrivKey: "L1NmycTQz17fXBMzK25aBTnN7v5U6rz3AURjL72xyKg21zmAmgt7",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of DEXON', function(done) {
+ var params = {
+ selectText: "DXN - DEXON",
+ phrase: "abandon abandon ability",
+ firstAddress: "0x136a58788033E028CCd740FbDec6734358DB56Ec",
+ firstPubKey: "0x028d7fa8c3417904cec37946db8d12bba51d85dde25156651f216260e0ff641cf4",
+ firstPrivKey: "0x8d7d8479dac38e786d4e493159dd655e116871d17ed803af6bb70207c60298ff",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Ellaism', function(done) {
+ var params = {
+ selectText: "ELLA - Ellaism",
+ phrase: "abandon abandon ability",
+ firstAddress: "0xa8B0BeA09eeBc41062308546a01d6E544277e2Ca",
+ firstPubKey: "0x03698fee21c52ad4b4772df3da92ddf0278da529da231c2ebfb167c9e3cc88f29f",
+ firstPrivKey: "0xe10bc99fcea6f5bca20c1b6e5386a18991b8d16d658b36881b7aca792e06bac2",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Ethersocial Network', function(done) {
+ var params = {
+ selectText: "ESN - Ethersocial Network",
+ phrase: "abandon abandon ability",
+ firstAddress: "0x6EE99Be2A0C7F887a71e21C8608ACF0aa0D2b767",
+ firstPubKey: "0x028df59c64daa4f1036fe0dc832c4e36d9df0692a7ed9a062d48a4662a01d2c7b3",
+ firstPrivKey: "0x44e0316578fd8168022039d5dfd5838e70826686a4b05dec9c88100c30049fce",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Stellar', function(done) {
+ var params = {
+ selectText: "XLM - Stellar",
+ phrase: "abandon abandon ability",
+ firstAddress: "GCUK3NYYUXA2QGN6KU5RR36WAKN3Y5EANZV65XNAWN4XM4CHQ3G4DMO2",
+ firstPubKey: "GCUK3NYYUXA2QGN6KU5RR36WAKN3Y5EANZV65XNAWN4XM4CHQ3G4DMO2",
+ firstPrivKey: "SA35HYGAHWYYLCW2P5EDHGWAYQW2C5F25KH4KFWEXLG5I4CPKPZTLRM5",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Wagerr', function(done) {
+ var params = {
+ selectText: "WGR - Wagerr",
+ phrase: "abandon abandon ability",
+ firstAddress: "WYiVgQU39VcQxcnacoCiaZHZZLjDCJoS95",
+ firstPubKey: "0343cfa1ed85e02fdc782c3c8b0b5febe7653c30a0c4319bef2e7d462e67245e46",
+ firstPrivKey: "WagfoYsRKgtBwBMgwYWuboY2DpGjJBpFcneqzSegZg4ppvYLWcry",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Groestlcoin', function(done) {
+ var params = {
+ selectText: "GRS - Groestlcoin",
+ phrase: "abandon abandon ability",
+ firstAddress: "FZycsFvZ1eH1hbtyjBpAgJSukVw1bN6PBN",
+ firstPubKey: "03c1d0c7b272a762b4b697bdb1b3b36e26add3215e69f7251db16c5a51c84b7b4c",
+ firstPrivKey: "KzQVqEsQrKjb4K6bViRqqQJc9nXrvEAxDy2AiPf6tfEkRW7rgNfg",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Groestlcoin Testnet', function(done) {
+ var params = {
+ selectText: "GRS - Groestlcoin Testnet",
+ phrase: "abandon abandon ability",
+ firstAddress: "mucaU5iiDaJDb69BHLeDv8JFfGiygRPne9",
+ firstPubKey: "0382a5450765e2025bdb5f7d109c9254a11ef97a566228bf171d80ecb348763bb0",
+ firstPrivKey: "cV3coiYD2NhHKfhC6Gb8DzpvPzcGYYExYxuNxpUtKq3VUJpRHpNq",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Elastos', function(done) {
+ var params = {
+ selectText: "ELA - Elastos",
+ phrase: "abandon abandon ability",
+ firstAddress: "EMccDcsn3SwPDcfeQMf3w7utqi8ioWYtkg",
+ firstPubKey: "02c936d5025b06acc283bf9562700279fd1ea3ce7ee204afca0c07be77bc3b4822",
+ firstPrivKey: "608f7e64b46a1df51ba6b5b38b0599196afd1f36572b1ec696d7aae65d05045d",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Energyweb', function(done) {
+ var params = {
+ selectText: "EWT - EnergyWeb",
+ phrase: "abandon abandon ability",
+ firstAddress: "0x22171474844Fc7E8E99A3A69CCf1eDb5574FdD4c",
+ firstPubKey: "0x03eee63d4d201168802b43f392e61f148a478935055cd990549452c741f4c34b84",
+ firstPrivKey: "0x325aa9e82d03b3773859d84bece81a598df8478d361cfbc59efc27385e0e3611",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Thought', function(done) {
+ var params = {
+ selectText: "THT - Thought",
+ phrase: "abandon abandon ability",
+ firstAddress: "4B1Bh9GibDarFQrhtYU8krpc7WSjgGfYvo",
+ firstPubKey: "0390e4598e7924f3b0369020394b133545db6bd37fa3aa4648aafbce46330c28cc",
+ firstPrivKey: "KCwL3y6VVrgzJFqtCkh2RV9M1zruX9NymKsWheb7by1dWLd2QkFx",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of EtherCore', function(done) {
+ var params = {
+ selectText: "ERE - EtherCore",
+ phrase: "abandon abandon ability",
+ firstAddress: "0x119e6EAC3Ce1b473D62d9fD847fb0ea222eF1D9e",
+ firstPubKey: "0x02cfeb9a4d8003b5c919c1eb67c91e06b3c08e602a336f74017fc7c756a2550ca9",
+ firstPrivKey: "0x6bb6e036aaf39326d3c74345ec34ef0c73b1608acb409306c9ba73d22de6abf0",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of RBTC - RSK', function(done) {
+ var params = {
+ selectText: "R-BTC - RSK",
+ phrase: "abandon abandon ability",
+ firstAddress: "0x37CA764c4b2fe819108448b80d2F35921b035931",
+ firstPubKey: "0x0219d9b5087ab68edc8a714969d8cb70e7159417b47a05932b227e6f417c7962b9",
+ firstPrivKey: "0x6e6f48cc422825f7fd68f2200d3dde757849f15342f252eeb0bc4ebc46089fe1",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of tRBTC - RSK Testnet', function(done) {
+ var params = {
+ selectText: "tR-BTC - RSK Testnet",
+ phrase: "abandon abandon ability",
+ firstAddress: "0x176484B5a155Fe802aCB26055eb1c193D5A576d5",
+ firstPubKey: "0x03f77eb7bd83e92ef47be1abddae7f71fb0bc8a7a1ee4b193662a86ed2705ffc5b",
+ firstPrivKey: "0x18c2400d2f818d28b80d0e31235873bfeef644fc45fd702f54ae0d422cff6ab3",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Argoneum', function(done) {
+ var params = {
+ selectText: "AGM - Argoneum",
+ phrase: "abandon abandon ability",
+ firstAddress: "MWgLPvJkaJwH6hrXFs1MimAC4FwC1kYRhe",
+ firstPubKey: "0348e5252045fee1d3b1e5bce25dbc16284d5b6c3bfff9c305d4ffa6078c16f3f8",
+ firstPrivKey: "VJXpuMEFnK8USLyo5tgF7M4cBXU44U8MUor1KRTQ6t9DVno9AAgg",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of CranePay', function(done) {
+ var params = {
+ selectText: "CRP - CranePay",
+ phrase: "abandon abandon ability",
+ firstAddress: "CcUHPqgmef1BmgWFa9g3YNc8scgVXVh8ip",
+ firstPubKey: "0392af9ea9dc78170c6f68c50bac926f960e50769295f539ac6382a3af2b928740",
+ firstPrivKey: "KHTCAvKHKg1WdLoDSg3VjjyZK5Wk1ihzJENpp2YMb1RmAxrCZrXX",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Scribe', function(done) {
+ var params = {
+ selectText: "SCRIBE - Scribe",
+ phrase: "abandon abandon ability",
+ firstAddress: "RYAnPeBLD8veZ9Tw8xugeTC2f9PeZonLHM",
+ firstPubKey: "02c912bc4759c8a209475502fb5352ff5be8a8f13eb72f1732ee25125cd53edc1e",
+ firstPrivKey: "HLZWvNCEUv4ghygjH9A2EYCa9HNRcxe5CS42kzUTmoxJYp3z96QE",
+ };
+ testNetwork(done, params);
+});
+
+// BIP39 seed is set from phrase
+it('Sets the bip39 seed from the prhase', function(done) {
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css('.seed'))
+ .getAttribute("value")
+ .then(function(seed) {
+ expect(seed).toBe("20da140d3dd1df8713cefcc4d54ce0e445b4151027a1ab567b832f6da5fcc5afc1c3a3f199ab78b8e0ab4652efd7f414ac2c9a3b81bceb879a70f377aa0a58f3");
+ done();
+ })
+ });
+});
+
+// BIP32 root key is set from phrase
+it('Sets the bip39 root key from the prhase', function(done) {
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css('.root-key'))
+ .getAttribute("value")
+ .then(function(seed) {
+ expect(seed).toBe("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi");
+ done();
+ })
+ });
+});
+
+// Tabs show correct addresses when changed
+it('Shows the correct address when tab is changed', function(done) {
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css('#bip32-tab a'))
+ .click();
+ driver.sleep(generateDelay).then(function() {
+ getFirstAddress(function(address) {
+ expect(address).toBe("17uQ7s2izWPwBmEVFikTmZUjbBKWYdJchz");
+ done();
+ });
+ });
+ });
+});
+
+// BIP44 derivation path is shown
+it('Shows the derivation path for bip44 tab', function(done) {
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css('#bip44 .path'))
+ .getAttribute("value")
+ .then(function(path) {
+ expect(path).toBe("m/44'/0'/0'/0");
+ done();
+ })
+ });
+});
+
+// BIP44 extended private key is shown
+it('Shows the extended private key for bip44 tab', function(done) {
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css('.extended-priv-key'))
+ .getAttribute("value")
+ .then(function(path) {
+ expect(path).toBe("xprvA2DxxvPZcyRvYgZMGS53nadR32mVDeCyqQYyFhrCVbJNjPoxMeVf7QT5g7mQASbTf9Kp4cryvcXnu2qurjWKcrdsr91jXymdCDNxKgLFKJG");
+ done();
+ })
+ });
+});
+
+// BIP44 extended public key is shown
+it('Shows the extended public key for bip44 tab', function(done) {
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css('.extended-pub-key'))
+ .getAttribute("value")
+ .then(function(path) {
+ expect(path).toBe("xpub6FDKNRvTTLzDmAdpNTc49ia9b4byd6vqCdUa46Fp3vqMcC96uBoufCmZXQLiN5AK3iSCJMhf9gT2sxkpyaPepRuA7W3MujV5tGmF5VfbueM");
+ done();
+ })
+ });
+});
+
+// BIP44 account field changes address list
+it('Changes the address list if bip44 account is changed', function(done) {
+ driver.findElement(By.css('#bip44 .account'))
+ .sendKeys('1');
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(generateDelay).then(function() {
+ getFirstAddress(function(address) {
+ expect(address).toBe("1Nq2Wmu726XHCuGhctEtGmhxo3wzk5wZ1H");
+ done();
+ });
+ });
+});
+
+// BIP44 change field changes address list
+it('Changes the address list if bip44 change is changed', function(done) {
+ driver.findElement(By.css('#bip44 .change'))
+ .sendKeys('1');
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(generateDelay).then(function() {
+ getFirstAddress(function(address) {
+ expect(address).toBe("1KAGfWgqfVbSSXY56fNQ7YnhyKuoskHtYo");
+ done();
+ });
+ });
+});
+
+// BIP32 derivation path can be set
+it('Can use a custom bip32 derivation path', function(done) {
+ driver.findElement(By.css('#bip32-tab a'))
+ .click();
+ driver.findElement(By.css('#bip32 .path'))
+ .clear();
+ driver.findElement(By.css('#bip32 .path'))
+ .sendKeys('m/1');
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(generateDelay).then(function() {
+ getFirstAddress(function(address) {
+ expect(address).toBe("16pYQQdLD1hH4hwTGLXBaZ9Teboi1AGL8L");
+ done();
+ });
+ });
+});
+
+// BIP32 can use hardened derivation paths
+it('Can use a hardened derivation paths', function(done) {
+ driver.findElement(By.css('#bip32-tab a'))
+ .click();
+ driver.findElement(By.css('#bip32 .path'))
+ .clear();
+ driver.findElement(By.css('#bip32 .path'))
+ .sendKeys("m/0'");
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(generateDelay).then(function() {
+ getFirstAddress(function(address) {
+ expect(address).toBe("14aXZeprXAE3UUKQc4ihvwBvww2LuEoHo4");
+ done();
+ });
+ });
+});
+
+// BIP32 extended private key is shown
+it('Shows the BIP32 extended private key', function(done) {
+ driver.findElement(By.css('#bip32-tab a'))
+ .click();
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css('.extended-priv-key'))
+ .getAttribute("value")
+ .then(function(privKey) {
+ expect(privKey).toBe("xprv9va99uTVE5aLiutUVLTyfxfe8v8aaXjSQ1XxZbK6SezYVuikA9MnjQVTA8rQHpNA5LKvyQBpLiHbBQiiccKiBDs7eRmBogsvq3THFeLHYbe");
+ done();
+ });
+ });
+});
+
+// BIP32 extended public key is shown
+it('Shows the BIP32 extended public key', function(done) {
+ driver.findElement(By.css('#bip32-tab a'))
+ .click();
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css('.extended-pub-key'))
+ .getAttribute("value")
+ .then(function(pubKey) {
+ expect(pubKey).toBe("xpub69ZVZQzP4T8dwPxwbMzz36cNgwy4yzTHmETZMyihzzXXNi3thgg3HCow1RtY252wdw5rS8369xKnraN5Q93y3FkFfJp2XEHWUrkyXsjS93P");
+ done();
+ });
+ });
+});
+
+// Derivation path is shown in table
+it('Shows the derivation path in the table', function(done) {
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(generateDelay).then(function() {
+ getFirstPath(function(path) {
+ expect(path).toBe("m/44'/0'/0'/0/0");
+ done();
+ });
+ });
+});
+
+// Derivation path for address can be hardened
+it('Can derive hardened addresses', function(done) {
+ driver.findElement(By.css('#bip32-tab a'))
+ .click();
+ driver.executeScript(function() {
+ $(".hardened-addresses").prop("checked", true);
+ });
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(generateDelay).then(function() {
+ getFirstAddress(function(address) {
+ expect(address).toBe("18exLzUv7kfpiXRzmCjFDoC9qwNLFyvwyd");
+ done();
+ });
+ });
+});
+
+// Derivation path visibility can be toggled
+it('Can toggle visibility of the derivation path column', function(done) {
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css('.index-toggle'))
+ .click();
+ testColumnValuesAreInvisible(done, "index");
+ });
+});
+
+// Address is shown
+it('Shows the address in the table', function(done) {
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(generateDelay).then(function() {
+ getFirstAddress(function(address) {
+ expect(address).toBe("1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug");
+ done();
+ });
+ });
+});
+
+// Addresses are shown in order of derivation path
+it('Shows the address in order of derivation path', function(done) {
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(generateDelay).then(function() {
+ testRowsAreInCorrectOrder(done);
+ });
+});
+
+// Address visibility can be toggled
+it('Can toggle visibility of the address column', function(done) {
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css('.address-toggle'))
+ .click();
+ testColumnValuesAreInvisible(done, "address");
+ });
+});
+
+// Public key is shown in table
+it('Shows the public key in the table', function(done) {
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(generateDelay).then(function() {
+ driver.findElements(By.css('.pubkey'))
+ .then(function(els) {
+ els[0].getText()
+ .then(function(pubkey) {
+ expect(pubkey).toBe("033f5aed5f6cfbafaf223188095b5980814897295f723815fea5d3f4b648d0d0b3");
+ done();
+ });
+ });
+ });
+});
+
+// Public key visibility can be toggled
+it('Can toggle visibility of the public key column', function(done) {
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css('.public-key-toggle'))
+ .click();
+ testColumnValuesAreInvisible(done, "pubkey");
+ });
+});
+
+// Private key is shown in table
+it('Shows the private key in the table', function(done) {
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(generateDelay).then(function() {
+ driver.findElements(By.css('.privkey'))
+ .then(function(els) {
+ els[0].getText()
+ .then(function(pubkey) {
+ expect(pubkey).toBe("L26cVSpWFkJ6aQkPkKmTzLqTdLJ923e6CzrVh9cmx21QHsoUmrEE");
+ done();
+ });
+ });
+ });
+});
+
+// Private key visibility can be toggled
+it('Can toggle visibility of the private key column', function(done) {
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css('.private-key-toggle'))
+ .click();
+ testColumnValuesAreInvisible(done, "privkey");
+ });
+});
+
+// More addresses can be generated
+it('Can generate more rows in the table', function(done) {
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css('.more'))
+ .click();
+ driver.sleep(generateDelay).then(function() {
+ driver.findElements(By.css('.address'))
+ .then(function(els) {
+ expect(els.length).toBe(40);
+ done();
+ });
+ });
+ });
+});
+
+// A custom number of additional addresses can be generated
+it('Can generate more rows in the table', function(done) {
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css('.rows-to-add'))
+ .clear();
+ driver.findElement(By.css('.rows-to-add'))
+ .sendKeys('1');
+ driver.findElement(By.css('.more'))
+ .click();
+ driver.sleep(generateDelay).then(function() {
+ driver.findElements(By.css('.address'))
+ .then(function(els) {
+ expect(els.length).toBe(21);
+ done();
+ });
+ });
+ });
+});
+
+// Additional addresses are shown in order of derivation path
+it('Shows additional addresses in order of derivation path', function(done) {
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css('.more'))
+ .click();
+ driver.sleep(generateDelay).then(function() {
+ testRowsAreInCorrectOrder(done);
+ });
+ });
+});
+
+// BIP32 root key can be set by the user
+it('Allows the user to set the BIP32 root key', function(done) {
+ driver.findElement(By.css('.root-key'))
+ .sendKeys('xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi');
+ driver.sleep(generateDelay).then(function() {
+ getFirstAddress(function(address) {
+ expect(address).toBe("1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug");
+ done();
+ });
+ });
+});
+
+// Setting BIP32 root key clears the existing phrase, passphrase and seed
+it('Confirms the existing phrase should be cleared', function(done) {
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('A non-blank but invalid value');
+ driver.findElement(By.css('.root-key'))
+ .sendKeys('xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi');
+ driver.switchTo().alert().accept();
+ driver.findElement(By.css('.phrase'))
+ .getAttribute("value").then(function(value) {
+ expect(value).toBe("");
+ done();
+ });
+});
+
+// Clearing of phrase, passphrase and seed can be cancelled by user
+it('Allows the clearing of the phrase to be cancelled', function(done) {
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css('.root-key'))
+ .clear();
+ driver.findElement(By.css('.root-key'))
+ .sendKeys('x');
+ driver.switchTo().alert().dismiss();
+ driver.findElement(By.css('.phrase'))
+ .getAttribute("value").then(function(value) {
+ expect(value).toBe("abandon abandon ability");
+ done();
+ });
+ });
+});
+
+// Custom BIP32 root key is used when changing the derivation path
+it('Can set derivation path for root key instead of phrase', function(done) {
+ driver.findElement(By.css('#bip44 .account'))
+ .sendKeys('1');
+ driver.findElement(By.css('.root-key'))
+ .sendKeys('xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi');
+ driver.sleep(generateDelay).then(function() {
+ getFirstAddress(function(address) {
+ expect(address).toBe("1Nq2Wmu726XHCuGhctEtGmhxo3wzk5wZ1H");
+ done();
+ });
+ });
+});
+
+// Incorrect mnemonic shows error
+it('Shows an error for incorrect mnemonic', function(done) {
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon abandon');
+ driver.sleep(feedbackDelay).then(function() {
+ driver.findElement(By.css('.feedback'))
+ .getText()
+ .then(function(feedback) {
+ expect(feedback).toBe("Invalid mnemonic");
+ done();
+ });
+ });
+});
+
+// Incorrect word shows suggested replacement
+it('Shows word suggestion for incorrect word', function(done) {
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon abiliti');
+ driver.sleep(feedbackDelay).then(function() {
+ driver.findElement(By.css('.feedback'))
+ .getText()
+ .then(function(feedback) {
+ var msg = "abiliti not in wordlist, did you mean ability?";
+ expect(feedback).toBe(msg);
+ done();
+ });
+ });
+});
+
+// Github pull request 48
+// First four letters of word shows that word, not closest
+// since first four letters gives unique word in BIP39 wordlist
+// eg ille should show illegal, not idle
+it('Shows word suggestion based on first four chars', function(done) {
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('ille');
+ driver.sleep(feedbackDelay).then(function() {
+ driver.findElement(By.css('.feedback'))
+ .getText()
+ .then(function(feedback) {
+ var msg = "ille not in wordlist, did you mean illegal?";
+ expect(feedback).toBe(msg);
+ done();
+ });
+ });
+});
+
+// Incorrect BIP32 root key shows error
+it('Shows error for incorrect root key', function(done) {
+ driver.findElement(By.css('.root-key'))
+ .sendKeys('xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpj');
+ driver.sleep(feedbackDelay).then(function() {
+ driver.findElement(By.css('.feedback'))
+ .getText()
+ .then(function(feedback) {
+ var msg = "Invalid root key";
+ expect(feedback).toBe(msg);
+ done();
+ });
+ });
+});
+
+// Derivation path not starting with m shows error
+it('Shows error for derivation path not starting with m', function(done) {
+ driver.findElement(By.css('#bip32-tab a'))
+ .click();
+ driver.findElement(By.css('#bip32 .path'))
+ .clear();
+ driver.findElement(By.css('#bip32 .path'))
+ .sendKeys('n/0');
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(feedbackDelay).then(function() {
+ driver.findElement(By.css('.feedback'))
+ .getText()
+ .then(function(feedback) {
+ var msg = "First character must be 'm'";
+ expect(feedback).toBe(msg);
+ done();
+ });
+ });
+});
+
+// Derivation path containing invalid characters shows useful error
+it('Shows error for derivation path not starting with m', function(done) {
+ driver.findElement(By.css('#bip32-tab a'))
+ .click();
+ driver.findElement(By.css('#bip32 .path'))
+ .clear();
+ driver.findElement(By.css('#bip32 .path'))
+ .sendKeys('m/1/0wrong1/1');
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abandon abandon ability');
+ driver.sleep(feedbackDelay).then(function() {
+ driver.findElement(By.css('.feedback'))
+ .getText()
+ .then(function(feedback) {
+ var msg = "Invalid characters 0wrong1 found at depth 2";
+ expect(feedback).toBe(msg);
+ done();
+ });
+ });
+});
+
+// Github Issue 11: Default word length is 15
+// https://github.com/iancoleman/bip39/issues/11
+it('Sets the default word length to 15', function(done) {
+ driver.findElement(By.css('.strength'))
+ .getAttribute("value")
+ .then(function(strength) {
+ expect(strength).toBe("15");
+ done();
+ });
+});
+
+// Github Issue 12: Generate more rows with private keys hidden
+// https://github.com/iancoleman/bip39/issues/12
+it('Sets the correct hidden column state on new rows', function(done) {
+ driver.findElement(By.css('.phrase'))
+ .sendKeys("abandon abandon ability");
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css('.private-key-toggle'))
+ .click();
+ driver.findElement(By.css('.more'))
+ .click();
+ driver.sleep(generateDelay).then(function() {
+ driver.findElements(By.css('.privkey'))
+ .then(function(els) {
+ expect(els.length).toBe(40);
+ });
+ testColumnValuesAreInvisible(done, "privkey");
+ });
+ });
+});
+
+// Github Issue 19: Mnemonic is not sensitive to whitespace
+// https://github.com/iancoleman/bip39/issues/19
+it('Ignores excess whitespace in the mnemonic', function(done) {
+ var doublespace = " ";
+ var mnemonic = "urge cat" + doublespace + "bid";
+ driver.findElement(By.css('.phrase'))
+ .sendKeys(mnemonic);
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css('.root-key'))
+ .getAttribute("value")
+ .then(function(seed) {
+ expect(seed).toBe("xprv9s21ZrQH143K3isaZsWbKVoTtbvd34Y1ZGRugGdMeBGbM3AgBVzTH159mj1cbbtYSJtQr65w6L5xy5L9SFC7c9VJZWHxgAzpj4mun5LhrbC");
+ done();
+ });
+ });
+});
+
+// Github Issue 23: Part 1: Use correct derivation path when changing tabs
+// https://github.com/iancoleman/bip39/issues/23
+// This test was failing for default timeout of 5000ms so changed it to +10s
+it('Uses the correct derivation path when changing tabs', function(done) {
+ // 1) and 2) set the phrase
+ driver.findElement(By.css('.phrase'))
+ .sendKeys("abandon abandon ability");
+ driver.sleep(generateDelay).then(function() {
+ // 3) select bip32 tab
+ driver.findElement(By.css('#bip32-tab a'))
+ .click();
+ driver.sleep(generateDelay).then(function() {
+ // 4) switch from bitcoin to litecoin
+ selectNetwork("LTC - Litecoin");
+ driver.sleep(generateDelay).then(function() {
+ // 5) Check address is displayed correctly
+ getFirstAddress(function(address) {
+ expect(address).toBe("LS8MP5LZ5AdzSZveRrjm3aYVoPgnfFh5T5");
+ // 5) Check derivation path is displayed correctly
+ getFirstPath(function(path) {
+ expect(path).toBe("m/0/0");
+ done();
+ });
+ });
+ });
+ });
+ });
+}, generateDelay + 10000);
+
+// Github Issue 23 Part 2: Coin selection in derivation path
+// https://github.com/iancoleman/bip39/issues/23#issuecomment-238011920
+it('Uses the correct derivation path when changing coins', function(done) {
+ // set the phrase
+ driver.findElement(By.css('.phrase'))
+ .sendKeys("abandon abandon ability");
+ driver.sleep(generateDelay).then(function() {
+ // switch from bitcoin to clam
+ selectNetwork("CLAM - Clams");
+ driver.sleep(generateDelay).then(function() {
+ // check derivation path is displayed correctly
+ getFirstPath(function(path) {
+ expect(path).toBe("m/44'/23'/0'/0/0");
+ done();
+ });
+ });
+ });
+});
+
+// Github Issue 26: When using a Root key derrived altcoins are incorrect
+// https://github.com/iancoleman/bip39/issues/26
+it('Uses the correct derivation for altcoins with root keys', function(done) {
+ // 1) 2) and 3) set the root key
+ driver.findElement(By.css('.root-key'))
+ .sendKeys("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi");
+ driver.sleep(generateDelay).then(function() {
+ // 4) switch from bitcoin to viacoin
+ selectNetwork("VIA - Viacoin");
+ driver.sleep(generateDelay).then(function() {
+ // 5) ensure the derived address is correct
+ getFirstAddress(function(address) {
+ expect(address).toBe("Vq9Eq4N5SQnjqZvxtxzo7hZPW5XnyJsmXT");
+ done();
+ });
+ });
+ });
+});
+
+// Selecting a language with no existing phrase should generate a phrase in
+// that language.
+it('Generate a random phrase when language is selected and no current phrase', function(done) {
+ driver.findElement(By.css("a[href='#japanese']"))
+ .click();
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css(".phrase"))
+ .getAttribute("value").then(function(phrase) {
+ expect(phrase.search(/[a-z]/)).toBe(-1);
+ expect(phrase.length).toBeGreaterThan(0);
+ done();
+ });
+ });
+});
+
+// Selecting a language with existing phrase should update the phrase to use
+// that language.
+it('Updates existing phrases when the language is changed', function(done) {
+ driver.findElement(By.css(".phrase"))
+ .sendKeys("abandon abandon ability");
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css("a[href='#italian']"))
+ .click();
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css(".phrase"))
+ .getAttribute("value").then(function(phrase) {
+ // Check only the language changes, not the phrase
+ expect(phrase).toBe("abaco abaco abbaglio");
+ getFirstAddress(function(address) {
+ // Check the address is correct
+ expect(address).toBe("1Dz5TgDhdki9spa6xbPFbBqv5sjMrx3xgV");
+ done();
+ });
+ });
+ });
+ });
+});
+
+// Suggested replacement for erroneous word in non-English language
+it('Shows word suggestion for incorrect word in non-English language', function(done) {
+ driver.findElement(By.css('.phrase'))
+ .sendKeys('abaco abaco zbbaglio');
+ driver.sleep(feedbackDelay).then(function() {
+ driver.findElement(By.css('.feedback'))
+ .getText()
+ .then(function(feedback) {
+ var msg = "zbbaglio not in wordlist, did you mean abbaglio?";
+ expect(feedback).toBe(msg);
+ done();
+ });
+ });
+});
+
+// Japanese word does not break across lines.
+// Point 2 from
+// https://github.com/bitcoin/bips/blob/master/bip-0039/bip-0039-wordlists.md#japanese
+it('Does not break Japanese words across lines', function(done) {
+ driver.findElement(By.css('.phrase'))
+ .getCssValue("word-break")
+ .then(function(value) {
+ expect(value).toBe("keep-all");
+ done();
+ });
+});
+
+// Language can be specified at page load using hash value in url
+it('Can set the language from the url hash', function(done) {
+ driver.get(url + "#japanese").then(function() {
+ driver.findElement(By.css('.generate')).click();
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css(".phrase"))
+ .getAttribute("value").then(function(phrase) {
+ expect(phrase.search(/[a-z]/)).toBe(-1);
+ expect(phrase.length).toBeGreaterThan(0);
+ done();
+ });
+ });
+ });
+});
+
+// Entropy can be entered by the user
+it('Allows entropy to be entered', function(done) {
+ driver.findElement(By.css('.use-entropy'))
+ .click();
+ driver.findElement(By.css('.entropy'))
+ .sendKeys('00000000 00000000 00000000 00000000');
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css(".phrase"))
+ .getAttribute("value").then(function(phrase) {
+ expect(phrase).toBe("abandon abandon ability");
+ getFirstAddress(function(address) {
+ expect(address).toBe("1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug");
+ done();
+ })
+ });
+ });
+});
+
+// A warning about entropy is shown to the user, with additional information
+it('Shows a warning about using entropy', function(done) {
+ driver.findElement(By.css('.use-entropy'))
+ .click();
+ driver.findElement(By.css('.entropy-container'))
+ .getText()
+ .then(function(containerText) {
+ var warning = "mnemonic may be insecure";
+ expect(containerText).toContain(warning);
+ driver.findElement(By.css('#entropy-notes'))
+ .findElement(By.xpath("parent::*"))
+ .getText()
+ .then(function(notesText) {
+ var detail = "flipping a fair coin, rolling a fair dice, noise measurements etc";
+ expect(notesText).toContain(detail);
+ done();
+ });
+ });
+});
+
+// The types of entropy available are described to the user
+it('Shows the types of entropy available', function(done) {
+ driver.findElement(By.css('.entropy'))
+ .getAttribute("placeholder")
+ .then(function(placeholderText) {
+ var options = [
+ "binary",
+ "base 6",
+ "dice",
+ "base 10",
+ "hexadecimal",
+ "cards",
+ ];
+ for (var i=0; i<options.length; i++) {
+ var option = options[i];
+ expect(placeholderText).toContain(option);
+ }
+ done();
+ });
+});
+
+// The actual entropy used is shown to the user
+it('Shows the actual entropy used', function(done) {
+ driver.findElement(By.css('.use-entropy'))
+ .click();
+ driver.findElement(By.css('.entropy'))
+ .sendKeys('Not A Very Good Entropy Source At All');
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css('.entropy-container'))
+ .getText()
+ .then(function(text) {
+ expect(text).toMatch(/Filtered Entropy\s+AedEceAA/);
+ done();
+ });
+ });
+});
+
+// Binary entropy can be entered
+it('Allows binary entropy to be entered', function(done) {
+ testEntropyType(done, "01", "binary");
+});
+
+// Base 6 entropy can be entered
+it('Allows base 6 entropy to be entered', function(done) {
+ testEntropyType(done, "012345", "base 6");
+});
+
+// Base 6 dice entropy can be entered
+it('Allows base 6 dice entropy to be entered', function(done) {
+ testEntropyType(done, "123456", "base 6 (dice)");
+});
+
+// Base 10 entropy can be entered
+it('Allows base 10 entropy to be entered', function(done) {
+ testEntropyType(done, "789", "base 10");
+});
+
+// Hexadecimal entropy can be entered
+it('Allows hexadecimal entropy to be entered', function(done) {
+ testEntropyType(done, "abcdef", "hexadecimal");
+});
+
+// Dice entropy value is shown as the converted base 6 value
+// ie 123456 is converted to 123450
+it('Shows dice entropy as base 6', function(done) {
+ driver.findElement(By.css('.use-entropy'))
+ .click();
+ driver.findElement(By.css('.entropy'))
+ .sendKeys("123456");
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css('.entropy-container'))
+ .getText()
+ .then(function(text) {
+ expect(text).toMatch(/Filtered Entropy\s+123450/);
+ done();
+ });
+ });
+});
+
+// The number of bits of entropy accumulated is shown
+it("Shows the number of bits of entropy for 20 bits of binary", function(done) {
+ testEntropyBits(done, "0000 0000 0000 0000 0000", "20");
+});
+it("Shows the number of bits of entropy for 1 bit of binary", function(done) {
+ testEntropyBits(done, "0", "1");
+});
+it("Shows the number of bits of entropy for 4 bits of binary", function(done) {
+ testEntropyBits(done, "0000", "4");
+});
+it("Shows the number of bits of entropy for 1 character of base 6 (dice)", function(done) {
+ // 6 in card is 0 in base 6, 0 is mapped to 00 by entropy.js
+ testEntropyBits(done, "6", "2");
+});
+it("Shows the number of bits of entropy for 1 character of base 10 with 3 bits", function(done) {
+ // 7 in base 10 is 111 in base 2, no leading zeros
+ testEntropyBits(done, "7", "3");
+});
+it("Shows the number of bits of entropy for 1 character of base 10 with 4 bis", function(done) {
+ // 8 in base 10 is mapped to 0 by entropy.js
+ testEntropyBits(done, "8", "1");
+});
+it("Shows the number of bits of entropy for 1 character of hex", function(done) {
+ testEntropyBits(done, "F", "4");
+});
+it("Shows the number of bits of entropy for 2 characters of base 10", function(done) {
+ // 2 as base 10 is binary 010, 9 is mapped to binary 1 by entropy.js
+ testEntropyBits(done, "29", "4");
+});
+it("Shows the number of bits of entropy for 2 characters of hex", function(done) {
+ testEntropyBits(done, "0A", "8");
+});
+it("Shows the number of bits of entropy for 2 characters of hex with 3 leading zeros", function(done) {
+ // hex is always multiple of 4 bits of entropy
+ testEntropyBits(done, "1A", "8");
+});
+it("Shows the number of bits of entropy for 2 characters of hex with 2 leading zeros", function(done) {
+ testEntropyBits(done, "2A", "8");
+});
+it("Shows the number of bits of entropy for 2 characters of hex with 1 leading zero", function(done) {
+ testEntropyBits(done, "4A", "8");
+});
+it("Shows the number of bits of entropy for 2 characters of hex with no leading zeros", function(done) {
+ testEntropyBits(done, "8A", "8");
+});
+it("Shows the number of bits of entropy for 2 characters of hex starting with F", function(done) {
+ testEntropyBits(done, "FA", "8");
+});
+it("Shows the number of bits of entropy for 4 characters of hex with leading zeros", function(done) {
+ testEntropyBits(done, "000A", "16");
+});
+it("Shows the number of bits of entropy for 4 characters of base 6", function(done) {
+ // 5 in base 6 is mapped to binary 1
+ testEntropyBits(done, "5555", "4");
+});
+it("Shows the number of bits of entropy for 4 characters of base 6 dice", function(done) {
+ // uses dice, so entropy is actually 0000 in base 6, which is 4 lots of
+ // binary 00
+ testEntropyBits(done, "6666", "8");
+});
+it("Shows the number of bits of entropy for 4 charactes of base 10", function(done) {
+ // 2 in base 10 is binary 010 and 7 is binary 111 so is 4 events of 3 bits
+ testEntropyBits(done, "2227", "12");
+});
+it("Shows the number of bits of entropy for 4 characters of hex with 2 leading zeros", function(done) {
+ testEntropyBits(done, "222F", "16");
+});
+it("Shows the number of bits of entropy for 4 characters of hex starting with F", function(done) {
+ testEntropyBits(done, "FFFF", "16");
+});
+it("Shows the number of bits of entropy for 10 characters of base 10", function(done) {
+ // 10 events with 3 bits for each event
+ testEntropyBits(done, "0000101017", "30");
+});
+it("Shows the number of bits of entropy for 10 characters of base 10 account for bias", function(done) {
+ // 9 events with 3 bits per event and 1 event with 1 bit per event
+ testEntropyBits(done, "0000101018", "28");
+});
+it("Shows the number of bits of entropy for a full deck of cards", function(done) {
+ // removing bias is 32*5 + 16*4 + 4*2
+ testEntropyBits(done, "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks", "232");
+});
+
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "A",
+ filtered: "A",
+ type: "hexadecimal",
+ events: "1",
+ bits: "4",
+ words: 0,
+ strength: "less than a second",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "AAAAAAAA",
+ filtered: "AAAAAAAA",
+ type: "hexadecimal",
+ events: "8",
+ bits: "32",
+ words: 3,
+ strength: "less than a second - Repeats like \"aaa\" are easy to guess",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "AAAAAAAA B",
+ filtered: "AAAAAAAAB",
+ type: "hexadecimal",
+ events: "9",
+ bits: "36",
+ words: 3,
+ strength: "less than a second - Repeats like \"aaa\" are easy to guess",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "AAAAAAAA BBBBBBBB",
+ filtered: "AAAAAAAABBBBBBBB",
+ type: "hexadecimal",
+ events: "16",
+ bits: "64",
+ words: 6,
+ strength: "less than a second - Repeats like \"aaa\" are easy to guess",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "AAAAAAAA BBBBBBBB CCCCCCCC",
+ filtered: "AAAAAAAABBBBBBBBCCCCCCCC",
+ type: "hexadecimal",
+ events: "24",
+ bits: "96",
+ words: 9,
+ strength: "less than a second",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD",
+ filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD",
+ type: "hexadecimal",
+ events: "32",
+ bits: "128",
+ words: 12,
+ strength: "2 minutes",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDA",
+ filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDA",
+ type: "hexadecimal",
+ events: "32",
+ bits: "128",
+ words: 12,
+ strength: "2 days",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDA EEEEEEEE",
+ filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDAEEEEEEEE",
+ type: "hexadecimal",
+ events: "40",
+ bits: "160",
+ words: 15,
+ strength: "3 years",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDA EEEEEEEE FFFFFFFF",
+ filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDAEEEEEEEEFFFFFFFF",
+ type: "hexadecimal",
+ events: "48",
+ bits: "192",
+ words: 18,
+ strength: "centuries",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "7d",
+ type: "card",
+ events: "1",
+ bits: "5",
+ words: 0,
+ strength: "less than a second",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
+ type: "card (full deck)",
+ events: "52",
+ bits: "232",
+ words: 21,
+ strength: "centuries",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks3d",
+ type: "card (full deck, 1 duplicate: 3d)",
+ events: "53",
+ bits: "237",
+ words: 21,
+ strength: "centuries",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqs3d4d",
+ type: "card (2 duplicates: 3d 4d, 1 missing: KS)",
+ events: "53",
+ bits: "240",
+ words: 21,
+ strength: "centuries",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqs3d4d5d6d",
+ type: "card (4 duplicates: 3d 4d 5d..., 1 missing: KS)",
+ events: "55",
+ bits: "250",
+ words: 21,
+ strength: "centuries",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ // Next test was throwing uncaught error in zxcvbn
+ {
+ entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsksac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
+ type: "card (full deck, 52 duplicates: ac 2c 3c...)",
+ events: "104",
+ bits: "464",
+ words: 42,
+ strength: "centuries",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ // Case insensitivity to duplicate cards
+ {
+ entropy: "asAS",
+ type: "card (1 duplicate: AS)",
+ events: "2",
+ bits: "8",
+ words: 0,
+ strength: "less than a second",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "ASas",
+ type: "card (1 duplicate: as)",
+ events: "2",
+ bits: "8",
+ words: 0,
+ strength: "less than a second",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ // Missing cards are detected
+ {
+ entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
+ type: "card (1 missing: 9C)",
+ events: "51",
+ bits: "227",
+ words: 21,
+ strength: "centuries",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
+ type: "card (2 missing: 9C 5D)",
+ events: "50",
+ bits: "222",
+ words: 18,
+ strength: "centuries",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d7d8d9dtdjd kdah2h3h 5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
+ type: "card (4 missing: 9C 5D QD...)",
+ events: "48",
+ bits: "212",
+ words: 18,
+ strength: "centuries",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ // More than six missing cards does not show message
+ {
+ entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d 8d9d jd kdah2h3h 5h6h7h8h9hthjhqhkh 2s3s4s5s6s7s8s9stsjsqsks",
+ type: "card",
+ events: "45",
+ bits: "198",
+ words: 18,
+ strength: "centuries",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ // multiple decks does not affect the bits per event
+ // since the bits are hardcoded in entropy.js
+ testEntropyFeedback(done,
+ {
+ entropy: "3d",
+ events: "1",
+ bits: "5",
+ bitsPerEvent: "4.46",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "3d3d",
+ events: "2",
+ bits: "10",
+ bitsPerEvent: "4.46",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "3d3d3d",
+ events: "3",
+ bits: "15",
+ bitsPerEvent: "4.46",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "3d3d3d3d",
+ events: "4",
+ bits: "20",
+ bitsPerEvent: "4.46",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "3d3d3d3d3d",
+ events: "5",
+ bits: "25",
+ bitsPerEvent: "4.46",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "3d3d3d3d3d3d",
+ events: "6",
+ bits: "30",
+ bitsPerEvent: "4.46",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d",
+ events: "33",
+ bits: "165",
+ bitsPerEvent: "4.46",
+ strength: 'less than a second - Repeats like "abcabcabc" are only slightly harder to guess than "abc"',
+ }
+ );
+});
+
+// Entropy is truncated from the left
+it('Truncates entropy from the left', function(done) {
+ // Truncate from left means 0000 is removed from the start
+ // which gives mnemonic 'avocado zoo zone'
+ // not 1111 removed from the end
+ // which gives the mnemonic 'abstract zoo zoo'
+ var entropy = "00000000 00000000 00000000 00000000";
+ entropy += "11111111 11111111 11111111 1111"; // Missing last byte
+ driver.findElement(By.css('.use-entropy'))
+ .click();
+ driver.findElement(By.css('.entropy'))
+ .sendKeys(entropy);
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css(".phrase"))
+ .getAttribute("value").then(function(phrase) {
+ expect(phrase).toBe("avocado zoo zone");
+ done();
+ });
+ });
+});
+
+// Very large entropy results in very long mnemonics
+it('Converts very long entropy to very long mnemonics', function(done) {
+ var entropy = "";
+ for (var i=0; i<33; i++) {
+ entropy += "AAAAAAAA"; // 3 words * 33 iterations = 99 words
+ }
+ driver.findElement(By.css('.use-entropy'))
+ .click();
+ driver.findElement(By.css('.entropy'))
+ .sendKeys(entropy);
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css(".phrase"))
+ .getAttribute("value").then(function(phrase) {
+ var wordCount = phrase.split(/\s+/g).length;
+ expect(wordCount).toBe(99);
+ done();
+ });
+ });
+});
+
+// Is compatible with bip32jp entropy
+// https://bip32jp.github.io/english/index.html
+// NOTES:
+// Is incompatible with:
+// base 6
+// base 20
+it('Is compatible with bip32jp.github.io', function(done) {
+ var entropy = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+ var expectedPhrase = "primary fetch primary fetch primary fetch primary fetch primary fetch primary fetch primary fetch primary fetch primary fetch primary fetch primary fetch primary foster";
+ driver.findElement(By.css('.use-entropy'))
+ .click();
+ driver.findElement(By.css('.entropy'))
+ .sendKeys(entropy);
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css(".phrase"))
+ .getAttribute("value").then(function(phrase) {
+ expect(phrase).toBe(expectedPhrase);
+ done();
+ });
+ });
+});
+
+// Blank entropy does not generate mnemonic or addresses
+it('Does not generate mnemonic for blank entropy', function(done) {
+ driver.findElement(By.css('.use-entropy'))
+ .click();
+ driver.findElement(By.css('.entropy'))
+ .clear();
+ // check there is no mnemonic
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css(".phrase"))
+ .getAttribute("value").then(function(phrase) {
+ expect(phrase).toBe("");
+ // check there is no mnemonic
+ driver.findElements(By.css(".address"))
+ .then(function(addresses) {
+ expect(addresses.length).toBe(0);
+ // Check the feedback says 'blank entropy'
+ driver.findElement(By.css(".feedback"))
+ .getText()
+ .then(function(feedbackText) {
+ expect(feedbackText).toBe("Blank entropy");
+ done();
+ });
+ })
+ });
+ });
+});
+
+// Mnemonic length can be selected even for weak entropy
+it('Allows selection of mnemonic length even for weak entropy', function(done) {
+ driver.findElement(By.css('.use-entropy'))
+ .click();
+ driver.executeScript(function() {
+ $(".mnemonic-length").val("18").trigger("change");
+ });
+ driver.findElement(By.css('.entropy'))
+ .sendKeys("012345");
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css(".phrase"))
+ .getAttribute("value").then(function(phrase) {
+ var wordCount = phrase.split(/\s+/g).length;
+ expect(wordCount).toBe(18);
+ done();
+ });
+ });
+});
+
+// Github issue 33
+// https://github.com/iancoleman/bip39/issues/33
+// Final cards should contribute entropy
+it('Uses as much entropy as possible for the mnemonic', function(done) {
+ driver.findElement(By.css('.use-entropy'))
+ .click();
+ driver.findElement(By.css('.entropy'))
+ .sendKeys("7S 9H 9S QH 8C KS AS 7D 7C QD 4S 4D TC 2D 5S JS 3D 8S 8H 4C 3C AC 3S QC 9C JC 7H AD TD JD 6D KH 5C QS 2S 6S 6H JH KD 9D-6C TS TH 4H KC 5H 2H AH 2C 8D 3H 5D");
+ driver.sleep(generateDelay).then(function() {
+ // Get mnemonic
+ driver.findElement(By.css(".phrase"))
+ .getAttribute("value").then(function(originalPhrase) {
+ // Set the last 12 cards to be AS
+ driver.findElement(By.css('.entropy'))
+ .clear();
+ driver.findElement(By.css('.entropy'))
+ .sendKeys("7S 9H 9S QH 8C KS AS 7D 7C QD 4S 4D TC 2D 5S JS 3D 8S 8H 4C 3C AC 3S QC 9C JC 7H AD TD JD 6D KH 5C QS 2S 6S 6H JH KD 9D-AS AS AS AS AS AS AS AS AS AS AS AS");
+ driver.sleep(generateDelay).then(function() {
+ // Get new mnemonic
+ driver.findElement(By.css(".phrase"))
+ .getAttribute("value").then(function(newPhrase) {
+ expect(originalPhrase).not.toEqual(newPhrase);
+ done();
+ });
+ });
+ });
+ });
+});
+
+// Github issue 35
+// https://github.com/iancoleman/bip39/issues/35
+// QR Code support
+// TODO this doesn't work in selenium with firefox
+// see https://stackoverflow.com/q/40360223
+it('Shows a qr code on hover for the phrase', function(done) {
+ if (browser == "firefox") {
+ pending("Selenium + Firefox bug for mouseMove, see https://stackoverflow.com/q/40360223");
+ }
+ // generate a random mnemonic
+ var generateEl = driver.findElement(By.css('.generate'));
+ generateEl.click();
+ // toggle qr to show (hidden by default)
+ var phraseEl = driver.findElement(By.css(".phrase"));
+ phraseEl.click();
+ var rootKeyEl = driver.findElement(By.css(".root-key"));
+ driver.sleep(generateDelay).then(function() {
+ // hover over the root key
+ driver.actions().mouseMove(rootKeyEl).perform().then(function() {
+ // check the qr code shows
+ driver.executeScript(function() {
+ return $(".qr-container").find("canvas").length > 0;
+ })
+ .then(function(qrShowing) {
+ expect(qrShowing).toBe(true);
+ // hover away from the phrase
+ driver.actions().mouseMove(generateEl).perform().then(function() {;
+ // check the qr code hides
+ driver.executeScript(function() {
+ return $(".qr-container").find("canvas").length == 0;
+ })
+ .then(function(qrHidden) {
+ expect(qrHidden).toBe(true);
+ done();
+ });
+ });
+ });
+ });
+ });
+});
+
+// BIP44 account extendend private key is shown
+// github issue 37 - compatibility with electrum
+it('Shows the bip44 account extended private key', function(done) {
+ driver.findElement(By.css(".phrase"))
+ .sendKeys("abandon abandon ability");
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css("#bip44 .account-xprv"))
+ .getAttribute("value")
+ .then(function(xprv) {
+ expect(xprv).toBe("xprv9yzrnt4zWVJUr1k2VxSPy9ettKz5PpeDMgaVG7UKedhqnw1tDkxP2UyYNhuNSumk2sLE5ctwKZs9vwjsq3e1vo9egCK6CzP87H2cVYXpfwQ");
+ done();
+ });
+ });
+});
+
+// BIP44 account extendend public key is shown
+// github issue 37 - compatibility with electrum
+it('Shows the bip44 account extended public key', function(done) {
+ driver.findElement(By.css(".phrase"))
+ .sendKeys("abandon abandon ability");
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css("#bip44 .account-xpub"))
+ .getAttribute("value")
+ .then(function(xprv) {
+ expect(xprv).toBe("xpub6CzDCPbtLrrn4VpVbyyQLHbdSMpZoHN4iuW64VswCyEpfjM2mJGdaHJ2DyuZwtst96E16VvcERb8BBeJdHSCVmAq9RhtRQg6eAZFrTKCNqf");
+ done();
+ });
+ });
+});
+
+// github issue 40
+// BIP32 root key can be set as an xpub
+it('Generates addresses from xpub as bip32 root key', function(done) {
+ driver.findElement(By.css('#bip32-tab a'))
+ .click();
+ // set xpub for account 0 of bip44 for 'abandon abandon ability'
+ driver.findElement(By.css("#root-key"))
+ .sendKeys("xpub6CzDCPbtLrrn4VpVbyyQLHbdSMpZoHN4iuW64VswCyEpfjM2mJGdaHJ2DyuZwtst96E16VvcERb8BBeJdHSCVmAq9RhtRQg6eAZFrTKCNqf");
+ driver.sleep(generateDelay).then(function() {
+ // check the addresses are generated
+ getFirstAddress(function(address) {
+ expect(address).toBe("1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug");
+ // check the xprv key is not set
+ driver.findElement(By.css(".extended-priv-key"))
+ .getAttribute("value")
+ .then(function(xprv) {
+ expect(xprv).toBe("NA");
+ // check the private key is not set
+ driver.findElements(By.css(".privkey"))
+ .then(function(els) {
+ els[0]
+ .getText()
+ .then(function(privkey) {
+ expect(xprv).toBe("NA");
+ done();
+ });
+ });
+ });
+ });
+ });
+});
+
+// github issue 40
+// xpub for bip32 root key will not work with hardened derivation paths
+it('Shows error for hardened derivation paths with xpub root key', function(done) {
+ // set xpub for account 0 of bip44 for 'abandon abandon ability'
+ driver.findElement(By.css("#root-key"))
+ .sendKeys("xpub6CzDCPbtLrrn4VpVbyyQLHbdSMpZoHN4iuW64VswCyEpfjM2mJGdaHJ2DyuZwtst96E16VvcERb8BBeJdHSCVmAq9RhtRQg6eAZFrTKCNqf");
+ driver.sleep(feedbackDelay).then(function() {
+ // Check feedback is correct
+ driver.findElement(By.css('.feedback'))
+ .getText()
+ .then(function(feedback) {
+ var msg = "Hardened derivation path is invalid with xpub key";
+ expect(feedback).toBe(msg);
+ // Check no addresses are shown
+ driver.findElements(By.css('.addresses tr'))
+ .then(function(rows) {
+ expect(rows.length).toBe(0);
+ done();
+ });
+ });
+ });
+});
+
+// github issue 39
+// no root key shows feedback
+it('Shows feedback for no root key', function(done) {
+ // set xpub for account 0 of bip44 for 'abandon abandon ability'
+ driver.findElement(By.css('#bip32-tab a'))
+ .click();
+ driver.sleep(feedbackDelay).then(function() {
+ // Check feedback is correct
+ driver.findElement(By.css('.feedback'))
+ .getText()
+ .then(function(feedback) {
+ expect(feedback).toBe("Invalid root key");
+ done();
+ });
+ });
+});
+
+// Github issue 44
+// display error switching tabs while addresses are generating
+it('Can change details while old addresses are still being generated', function(done) {
+ // Set to generate 199 more addresses.
+ // This will take a long time allowing a new set of addresses to be
+ // generated midway through this lot.
+ // The newly generated addresses should not include any from the old set.
+ // Any more than 199 will show an alert which needs to be accepted.
+ driver.findElement(By.css('.rows-to-add'))
+ .clear();
+ driver.findElement(By.css('.rows-to-add'))
+ .sendKeys('199');
+ // set the prhase
+ driver.findElement(By.css('.phrase'))
+ .sendKeys("abandon abandon ability");
+ driver.sleep(generateDelay).then(function() {
+ // change tabs which should cancel the previous generating
+ driver.findElement(By.css('.rows-to-add'))
+ .clear();
+ driver.findElement(By.css('.rows-to-add'))
+ .sendKeys('20');
+ driver.findElement(By.css('#bip32-tab a'))
+ .click()
+ driver.sleep(generateDelay).then(function() {
+ driver.findElements(By.css('.index'))
+ .then(function(els) {
+ // check the derivation paths have the right quantity
+ expect(els.length).toBe(20);
+ // check the derivation paths are in order
+ testRowsAreInCorrectOrder(done);
+ });
+ });
+ });
+}, generateDelay + 10000);
+
+// Github issue 49
+// padding for binary should give length with multiple of 256
+// hashed entropy 1111 is length 252, so requires 4 leading zeros
+// prior to issue 49 it would only generate 2 leading zeros, ie missing 2
+it('Pads hashed entropy with leading zeros', function(done) {
+ driver.findElement(By.css('.use-entropy'))
+ .click();
+ driver.executeScript(function() {
+ $(".mnemonic-length").val("15").trigger("change");
+ });
+ driver.findElement(By.css('.entropy'))
+ .sendKeys("1111");
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css('.phrase'))
+ .getAttribute("value")
+ .then(function(phrase) {
+ expect(phrase).toBe("avocado valid quantum cross link predict excuse edit street able flame large galaxy ginger nuclear");
+ done();
+ });
+ });
+});
+
+// Github pull request 55
+// https://github.com/iancoleman/bip39/pull/55
+// Client select
+it('Can set the derivation path on bip32 tab for bitcoincore', function(done) {
+ testClientSelect(done, {
+ selectValue: "0",
+ bip32path: "m/0'/0'",
+ useHardenedAddresses: "true",
+ });
+});
+it('Can set the derivation path on bip32 tab for multibit', function(done) {
+ testClientSelect(done, {
+ selectValue: "2",
+ bip32path: "m/0'/0",
+ useHardenedAddresses: null,
+ });
+});
+it('Can set the derivation path on bip32 tab for coinomi/ledger', function(done) {
+ testClientSelect(done, {
+ selectValue: "3",
+ bip32path: "m/44'/0'/0'",
+ useHardenedAddresses: null,
+ });
+});
+
+// github issue 58
+// https://github.com/iancoleman/bip39/issues/58
+// bip32 derivation is correct, does not drop leading zeros
+// see also
+// https://medium.com/@alexberegszaszi/why-do-my-bip32-wallets-disagree-6f3254cc5846
+it('Retains leading zeros for bip32 derivation', function(done) {
+ driver.findElement(By.css(".phrase"))
+ .sendKeys("fruit wave dwarf banana earth journey tattoo true farm silk olive fence");
+ driver.findElement(By.css(".passphrase"))
+ .sendKeys("banana");
+ driver.sleep(generateDelay).then(function() {
+ getFirstAddress(function(address) {
+ // Note that bitcore generates an incorrect address
+ // 13EuKhffWkBE2KUwcbkbELZb1MpzbimJ3Y
+ // see the medium.com link above for more details
+ expect(address).toBe("17rxURoF96VhmkcEGCj5LNQkmN9HVhWb7F");
+ done();
+ });
+ });
+});
+
+// github issue 60
+// Japanese mnemonics generate incorrect bip32 seed
+// BIP39 seed is set from phrase
+it('Generates correct seed for Japanese mnemonics', function(done) {
+ driver.findElement(By.css(".phrase"))
+ .sendKeys("あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あおぞら");
+ driver.findElement(By.css(".passphrase"))
+ .sendKeys("メートルガバヴァぱばぐゞちぢ十人十色");
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css(".seed"))
+ .getAttribute("value")
+ .then(function(seed) {
+ expect(seed).toBe("a262d6fb6122ecf45be09c50492b31f92e9beb7d9a845987a02cefda57a15f9c467a17872029a9e92299b5cbdf306e3a0ee620245cbd508959b6cb7ca637bd55");
+ done();
+ });
+ });
+});
+
+// BIP49 official test vectors
+// https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki#test-vectors
+it('Generates BIP49 addresses matching the official test vectors', function(done) {
+ driver.findElement(By.css('#bip49-tab a'))
+ .click();
+ selectNetwork("BTC - Bitcoin Testnet");
+ driver.findElement(By.css(".phrase"))
+ .sendKeys("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about");
+ driver.sleep(generateDelay).then(function() {
+ getFirstAddress(function(address) {
+ expect(address).toBe("2Mww8dCYPUpKHofjgcXcBCEGmniw9CoaiD2");
+ done();
+ });
+ });
+});
+
+// BIP49 derivation path is shown
+it('Shows the bip49 derivation path', function(done) {
+ driver.findElement(By.css('#bip49-tab a'))
+ .click();
+ driver.findElement(By.css(".phrase"))
+ .sendKeys("abandon abandon ability");
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css('#bip49 .path'))
+ .getAttribute("value")
+ .then(function(path) {
+ expect(path).toBe("m/49'/0'/0'/0");
+ done();
+ });
+ });
+});
+
+// BIP49 extended private key is shown
+it('Shows the bip49 extended private key', function(done) {
+ driver.findElement(By.css('#bip49-tab a'))
+ .click();
+ driver.findElement(By.css(".phrase"))
+ .sendKeys("abandon abandon ability");
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css('.extended-priv-key'))
+ .getAttribute("value")
+ .then(function(xprv) {
+ expect(xprv).toBe("yprvALYB4DYRG6CzzVgzQZwwqjAA2wjBGC3iEd7KYYScpoDdmf75qMRWZWxoFcRXBJjgEXdFqJ9vDRGRLJQsrL22Su5jMbNFeM9vetaGVqy9Qy2");
+ done();
+ });
+ });
+});
+
+// BIP49 extended public key is shown
+it('Shows the bip49 extended public key', function(done) {
+ driver.findElement(By.css('#bip49-tab a'))
+ .click();
+ driver.findElement(By.css(".phrase"))
+ .sendKeys("abandon abandon ability");
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css('.extended-pub-key'))
+ .getAttribute("value")
+ .then(function(xprv) {
+ expect(xprv).toBe("ypub6ZXXTj5K6TmJCymTWbUxCs6tayZffemZbr2vLvrEP8kceTSENtjm7KHH6thvAKxVar9fGe8rgsPEX369zURLZ68b4f7Vexz7RuXsjQ69YDt");
+ done();
+ });
+ });
+});
+
+// BIP49 account field changes address list
+it('Can set the bip49 account field', function(done) {
+ driver.findElement(By.css('#bip49-tab a'))
+ .click();
+ driver.findElement(By.css('#bip49 .account'))
+ .clear();
+ driver.findElement(By.css('#bip49 .account'))
+ .sendKeys("1");
+ driver.findElement(By.css(".phrase"))
+ .sendKeys("abandon abandon ability");
+ driver.sleep(generateDelay).then(function() {
+ getFirstAddress(function(address) {
+ expect(address).toBe("381wg1GGN4rP88rNC9v7QWsiww63yLVPsn");
+ done();
+ });
+ });
+});
+
+// BIP49 change field changes address list
+it('Can set the bip49 change field', function(done) {
+ driver.findElement(By.css('#bip49-tab a'))
+ .click();
+ driver.findElement(By.css('#bip49 .change'))
+ .clear();
+ driver.findElement(By.css('#bip49 .change'))
+ .sendKeys("1");
+ driver.findElement(By.css(".phrase"))
+ .sendKeys("abandon abandon ability");
+ driver.sleep(generateDelay).then(function() {
+ getFirstAddress(function(address) {
+ expect(address).toBe("3PEM7MiKed5konBoN66PQhK8r3hjGhy9dT");
+ done();
+ });
+ });
+});
+
+// BIP49 account extendend private key is shown
+it('Shows the bip49 account extended private key', function(done) {
+ driver.findElement(By.css('#bip49-tab a'))
+ .click();
+ driver.findElement(By.css(".phrase"))
+ .sendKeys("abandon abandon ability");
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css('#bip49 .account-xprv'))
+ .getAttribute("value")
+ .then(function(xprv) {
+ expect(xprv).toBe("yprvAHtB1M5Wp675aLzFy9TJYK2mSsLkg6mcBRh5DZTR7L4EnYSmYPaL63KFA4ycg1PngW5LfkmejxzosCs17TKZMpRFKc3z5SJar6QAKaFcaZL");
+ done();
+ });
+ });
+});
+
+// BIP49 account extendend public key is shown
+it('Shows the bip49 account extended public key', function(done) {
+ driver.findElement(By.css('#bip49-tab a'))
+ .click();
+ driver.findElement(By.css(".phrase"))
+ .sendKeys("abandon abandon ability");
+ driver.sleep(generateDelay).then(function() {
+ driver.findElement(By.css('#bip49 .account-xpub'))
+ .getAttribute("value")
+ .then(function(xprv) {
+ expect(xprv).toBe("ypub6WsXQrcQeTfNnq4j5AzJuSyVzuBF5ZVTYecg1ws2ffbDfLmv5vtadqdj1NgR6C6gufMpMfJpHxvb6JEQKvETVNWCRanNedfJtnTchZiJtsL");
+ done();
+ });
+ });
+});
+
+// Test selecting coin where bip49 is unavailable (eg CLAM)
+it('Shows an error on bip49 tab for coins without bip49', function(done) {
+ driver.findElement(By.css('#bip49-tab a'))
+ .click();
+ driver.findElement(By.css(".phrase"))
+ .sendKeys("abandon abandon ability");
+ driver.sleep(generateDelay).then(function() {
+ selectNetwork("CLAM - Clams");
+ // bip49 available is hidden
+ driver.findElement(By.css('#bip49 .available'))
+ .getAttribute("class")
+ .then(function(classes) {
+ expect(classes).toContain("hidden");
+ // bip49 unavailable is shown
+ driver.findElement(By.css('#bip49 .unavailable'))
+ .getAttribute("class")
+ .then(function(classes) {
+ expect(classes).not.toContain("hidden");
+ // check there are no addresses shown
+ driver.findElements(By.css('.addresses tr'))
+ .then(function(rows) {
+ expect(rows.length).toBe(0);
+ // check the derived private key is blank
+ driver.findElement(By.css('.extended-priv-key'))
+ .getAttribute("value")
+ .then(function(xprv) {
+ expect(xprv).toBe('');
+ // check the derived public key is blank
+ driver.findElement(By.css('.extended-pub-key'))
+ .getAttribute("value")
+ .then(function(xpub) {
+ expect(xpub).toBe('');
+ done();
+ });
+ });
+ })
+ });
+ });
+ });
+});
+
+// github issue 43
+// Cleared mnemonic and root key still allows addresses to be generated
+// https://github.com/iancoleman/bip39/issues/43
+it('Clears old root keys from memory when mnemonic is cleared', function(done) {
+ // set the phrase
+ driver.findElement(By.css(".phrase"))
+ .sendKeys("abandon abandon ability");
+ driver.sleep(generateDelay).then(function() {
+ // clear the mnemonic and root key
+ // using selenium .clear() doesn't seem to trigger the 'input' event
+ // so clear it using keys instead
+ driver.findElement(By.css('.phrase'))
+ .sendKeys(Key.CONTROL,"a");
+ driver.findElement(By.css('.phrase'))
+ .sendKeys(Key.DELETE);
+ driver.findElement(By.css('.root-key'))
+ .sendKeys(Key.CONTROL,"a");
+ driver.findElement(By.css('.root-key'))
+ .sendKeys(Key.DELETE);
+ driver.sleep(generateDelay).then(function() {
+ // try to generate more addresses
+ driver.findElement(By.css('.more'))
+ .click();
+ driver.sleep(generateDelay).then(function() {
+ driver.findElements(By.css(".addresses tr"))
+ .then(function(els) {
+ // check there are no addresses shown
+ expect(els.length).toBe(0);
+ done();
+ });
+ });