+it('Allows selection of Monkey Project', function(done) {
+ var params = {
+ selectText: "MONK - Monkey Project",
+ firstAddress: "MnLrcnnUzKnf7TzufjRe5DLZqQJz18oYyu",
+ };
+ testNetwork(done, params);
+});
+
+it('Allows selection of Musicoin', function(done) {
+ var params = {
+ selectText: "MUSIC - Musicoin",
+ firstAddress: "0xDc060e4A0b0313ea83Cf6B3A39B9db2D29004897",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Poa', function(done) {
+ var params = {
+ selectText: "POA - Poa",
+ firstAddress: "0x53aF28d754e106210C3d0467Dd581eaf7e3C5e60",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Expanse', function(done) {
+ var params = {
+ selectText: "EXP - Expanse",
+ firstAddress: "0xf57FeAbf26582b6E3E666559d3B1Cc6fB2b2c5F6",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Callisto', function(done) {
+ var params = {
+ selectText: "CLO - Callisto",
+ firstAddress: "0x4f9364F7420B317266C51Dc8eB979717D4dE3f4E",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of HUSH', function(done) {
+ var params = {
+ selectText: "HUSH - Hush (Legacy)",
+ firstAddress: "t1g6rLXUnJaiJuu4q4zmJjoa9Gk4fwKpiuA",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of HUSH3', function(done) {
+ var params = {
+ selectText: "HUSH - Hush3",
+ firstAddress: "RXWSQhwvw5jHPGP8bjwJhWoRnMLBnuPDKD",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of ExchangeCoin', function(done) {
+ var params = {
+ selectText: "EXCC - ExchangeCoin",
+ firstAddress: "22txYKpFN5fwGwdSs2UBf7ywewbLM92YqK7E",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Artax', function(done) {
+ var params = {
+ selectText: "XAX - Artax",
+ firstAddress: "AYxaQPY7XLidG31V7F3yNzwxPYpYzRqG4q",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of BitcoinGreen', function(done) {
+ var params = {
+ selectText: "BITG - Bitcoin Green",
+ firstAddress: "GeNGm9SkEfwbsws3UrrUSE2sJeyWYjzraY",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of ANON', function(done) {
+ var params = {
+ selectText: "ANON - ANON",
+ firstAddress: "AnU6pijpEeUZFWSTyM2qTqZQn996Zq1Xard",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of ProjectCoin', function(done) {
+ var params = {
+ selectText: "PRJ - ProjectCoin",
+ firstAddress: "PXZG97saRseSCftfe1mcFmfAA7pf6qBbaz",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Phore', function(done) {
+ var params = {
+ selectText: "PHR - Phore",
+ firstAddress: "PJThxpoXAG6hqrmdeQQbVDX4TJtFTMMymC",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Safecoin', function(done) {
+ var params = {
+ selectText: "SAFE - Safecoin",
+ firstAddress: "RtxHpnhJz6RY8k9owP3ua5QWraunmewB1G",
+ };
+ testNetwork(done, params);
+ });
+it('Allows selection of Blocknode', function(done) {
+ var params = {
+ selectText: "BND - Blocknode",
+ firstAddress: "BG8xZSAur2jYLG9VXt8dYfkKxxeR7w9bSe",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Blocknode Testnet', function(done) {
+ var params = {
+ selectText: "tBND - Blocknode Testnet",
+ firstAddress: "bSptsFyDktFSKpWveRywJsDoJA2TC6qfHv",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of LitecoinZ', function(done) {
+ var params = {
+ selectText: "LTZ - LitecoinZ",
+ firstAddress: "L1VTXju7hLgKV4T7fGXS9sKsnm2gmtRCmyw",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of BlockStamp', function(done) {
+ var params = {
+ selectText: "BST - BlockStamp",
+ firstAddress: "15gypKtim4cVTj137ApfryG17RkvSbPazZ",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of DEXON', function(done) {
+ var params = {
+ selectText: "DXN - DEXON",
+ firstAddress: "0x136a58788033E028CCd740FbDec6734358DB56Ec",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Ellaism', function(done) {
+ var params = {
+ selectText: "ELLA - Ellaism",
+ firstAddress: "0xa8B0BeA09eeBc41062308546a01d6E544277e2Ca",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Ethersocial Network', function(done) {
+ var params = {
+ selectText: "ESN - Ethersocial Network",
+ firstAddress: "0x6EE99Be2A0C7F887a71e21C8608ACF0aa0D2b767",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Stellar', function(done) {
+ var params = {
+ selectText: "XLM - Stellar",
+ firstAddress: "GCUK3NYYUXA2QGN6KU5RR36WAKN3Y5EANZV65XNAWN4XM4CHQ3G4DMO2",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Wagerr', function(done) {
+ var params = {
+ selectText: "WGR - Wagerr",
+ firstAddress: "WYiVgQU39VcQxcnacoCiaZHZZLjDCJoS95",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Groestlcoin', function(done) {
+ var params = {
+ selectText: "GRS - Groestlcoin",
+ firstAddress: "FZycsFvZ1eH1hbtyjBpAgJSukVw1bN6PBN",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Groestlcoin Testnet', function(done) {
+ var params = {
+ selectText: "GRS - Groestlcoin Testnet",
+ firstAddress: "mucaU5iiDaJDb69BHLeDv8JFfGiygRPne9",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Elastos', function(done) {
+ var params = {
+ selectText: "ELA - Elastos",
+ firstAddress: "EMccDcsn3SwPDcfeQMf3w7utqi8ioWYtkg",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Energyweb', function(done) {
+ var params = {
+ selectText: "EWT - EnergyWeb",
+ firstAddress: "0x22171474844Fc7E8E99A3A69CCf1eDb5574FdD4c",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of Thought', function(done) {
+ var params = {
+ selectText: "THT - Thought",
+ firstAddress: "4B1Bh9GibDarFQrhtYU8krpc7WSjgGfYvo",
+ };
+ testNetwork(done, params);
+});
+it('Allows selection of EtherCore', function(done) {
+ var params = {
+ selectText: "ERE - EtherCore",
+ firstAddress: "0xDeeAD0297F06dfe6c7Ad0C1D0CF5B06D6047bEEe",
+ };
+ 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 in base 6 is 2.6 bits (rounded down to 2 bits)
+ 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) {
+ testEntropyBits(done, "8", "4");
+});
+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) {
+ testEntropyBits(done, "29", "6");
+});
+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) {
+ testEntropyBits(done, "5555", "11");
+});
+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
+ // 2.58 bits, which is 10.32 bits (rounded down to 10 bits)
+ testEntropyBits(done, "6666", "10");
+});
+it("Shows the number of bits of entropy for 4 charactes of base 10", function(done) {
+ // Uses base 10, which is 4 lots of 3.32 bits, which is 13.3 bits (rounded
+ // down to 13)
+ testEntropyBits(done, "2227", "13");
+});
+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 at 3.32 bits per event
+ testEntropyBits(done, "0000101017", "33");
+});
+it("Shows the number of bits of entropy for a full deck of cards", function(done) {
+ // cards are not replaced, so a full deck is not 52^52 entropy which is 296
+ // bits, it's 52!, which is 225 bits
+ testEntropyBits(done, "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks", "225");
+});
+
+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: "4",
+ 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: "225",
+ 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: "254",
+ 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: "254",
+ 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: "264",
+ words: 24,
+ strength: "centuries",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ // Next test was throwing uncaught error in zxcvbn
+ // Also tests 451 bits, ie Math.log2(52!)*2 = 225.58 * 2
+ {
+ entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsksac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
+ type: "card (full deck, 52 duplicates: ac 2c 3c...)",
+ events: "104",
+ bits: "499",
+ words: 45,
+ 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: "9",
+ 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: "9",
+ 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: "221",
+ words: 18,
+ 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: "216",
+ 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: "208",
+ 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: "195",
+ words: 18,
+ strength: "centuries",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ // Multiple decks of cards increases bits per event
+ {
+ entropy: "3d",
+ events: "1",
+ bits: "4",
+ bitsPerEvent: "4.34",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "3d3d",
+ events: "2",
+ bits: "9",
+ bitsPerEvent: "4.80",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "3d3d3d",
+ events: "3",
+ bits: "15",
+ bitsPerEvent: "5.01",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "3d3d3d3d",
+ events: "4",
+ bits: "20",
+ bitsPerEvent: "5.14",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "3d3d3d3d3d",
+ events: "5",
+ bits: "26",
+ bitsPerEvent: "5.22",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "3d3d3d3d3d3d",
+ events: "6",
+ bits: "31",
+ bitsPerEvent: "5.28",
+ }
+ );
+});
+it("Shows details about the entered entropy", function(done) {
+ testEntropyFeedback(done,
+ {
+ entropy: "3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d",
+ events: "33",
+ bits: "184",
+ bitsPerEvent: "5.59",
+ strength: 'less than a second - Repeats like "abcabcabc" are only slightly harder to guess than "abc"',
+ }
+ );
+});
+
+// Entropy is truncated from the left