2 // cd /path/to/repo/tests
3 // jasmine spec/tests.js
9 // see https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode#Automated_testing_with_headless_mode
11 // USER SPECIFIED OPTIONS
12 var browser
= process
.env
.BROWSER
; //"firefox"; // or "chrome"
14 console
.log("Browser can be set via environment variable, eg");
15 console
.log("BROWSER=firefox jasmine spec/tests.js");
16 console
.log("Options for BROWSER are firefox chrome");
17 console
.log("Using default browser: chrome");
21 console
.log("Using browser: " + browser
);
26 var webdriver
= require('selenium-webdriver');
27 var By
= webdriver
.By
;
28 var Key
= webdriver
.Key
;
29 var until
= webdriver
.until
;
33 var generateDelay
= 1500;
34 var feedbackDelay
= 500;
35 var entropyFeedbackDelay
= 500;
36 var bip38delay
= 15000;
38 // url uses file:// scheme
39 var path
= require('path')
40 var parentDir
= path
.resolve(process
.cwd(), '..', 'src', 'index.html');
41 var url
= "file://" + parentDir
;
42 if (browser
== "firefox") {
43 // TODO loading local html in firefox is broken
44 console
.log("Loading local html in firefox is broken, see https://stackoverflow.com/q/46367054");
45 console
.log("You must run a server in this case, ie do this:");
46 console
.log("$ cd /path/to/bip39/src");
47 console
.log("$ python -m http.server");
48 url
= "http://localhost:8000";
51 // Variables dependent on specific browser selection
53 if (browser
== "firefox") {
54 var firefox
= require('selenium-webdriver/firefox');
55 var binary
= new firefox
.Binary(firefox
.Channel
.NIGHTLY
);
56 binary
.addArguments("-headless");
57 newDriver = function() {
58 return new webdriver
.Builder()
59 .forBrowser('firefox')
60 .setFirefoxOptions(new firefox
.Options().setBinary(binary
))
64 else if (browser
== "chrome") {
65 var chrome
= require('selenium-webdriver/chrome');
66 newDriver = function() {
67 return new webdriver
.Builder()
69 .setChromeOptions(new chrome
.Options().addArguments("headless"))
76 function testNetwork(done
, params
, comparePub
= false) {
77 var phrase
= params
.phrase
|| 'abandon abandon ability';
78 driver
.findElement(By
.css('.phrase'))
80 selectNetwork(params
.selectText
);
81 driver
.sleep(generateDelay
).then(function() {
83 getFirstAddress(function(address
) {
84 expect(address
).toBe(params
.firstAddress
);
88 getFirstPublicKey(function(pubkey
) {
89 expect(pubkey
).toBe(params
.firstPubKey
);
96 function getFirstRowValue(handler
, selector
) {
97 driver
.findElements(By
.css(selector
))
104 function getFirstAddress(handler
) {
105 getFirstRowValue(handler
, ".address");
108 function getFirstPublicKey(handler
) {
109 getFirstRowValue(handler
, ".pubkey");
112 function getFirstPath(handler
) {
113 getFirstRowValue(handler
, ".index");
116 function testColumnValuesAreInvisible(done
, columnClassName
) {
117 var selector
= "." + columnClassName
+ " span";
118 driver
.findElements(By
.css(selector
))
119 .then(function(els
) {
120 els
[0].getAttribute("class")
121 .then(function(classes
) {
122 expect(classes
).toContain("invisible");
128 function testRowsAreInCorrectOrder(done
) {
129 driver
.findElements(By
.css('.index'))
130 .then(function(els
) {
131 var testRowAtIndex = function(i
) {
132 if (i
>= els
.length
) {
137 .then(function(actualPath
) {
138 var noHardened
= actualPath
.replace(/'/g, "");
139 var pathBits = noHardened.split("/")
140 var lastBit = pathBits[pathBits.length-1];
141 var actualIndex = parseInt(lastBit);
142 expect(actualIndex).toBe(i);
151 function selectNetwork(name) {
152 driver.executeScript(function() {
153 var selectText = arguments[0];
154 $(".network option[selected]").removeAttr("selected");
155 $(".network option").filter(function(i,e) {
156 return $(e).html() == selectText;
157 }).prop("selected", true);
158 $(".network").trigger("change");
162 function testEntropyType(done, entropyText, entropyTypeUnsafe) {
163 // entropy type is compiled into regexp so needs escaping
164 // see https://stackoverflow.com/a/2593661
165 var entropyType = (entropyTypeUnsafe+'').replace(/[.?*+^$[\]\\(){}|-]/g, "\\$&");
166 driver.findElement(By.css('.use-entropy
'))
168 driver.findElement(By.css('.entropy
'))
169 .sendKeys(entropyText);
170 driver.sleep(generateDelay).then(function() {
171 driver.findElement(By.css('.entropy
-container
'))
173 .then(function(text) {
174 var re = new RegExp("Entropy Type\\s+" + entropyType);
175 expect(text).toMatch(re);
181 function testEntropyBits(done, entropyText, entropyBits) {
182 driver.findElement(By.css('.use-entropy
'))
184 driver.findElement(By.css('.entropy
'))
185 .sendKeys(entropyText);
186 driver.sleep(generateDelay).then(function() {
187 driver.findElement(By.css('.entropy
-container
'))
189 .then(function(text) {
190 var re = new RegExp("Total Bits\\s+" + entropyBits);
191 expect(text).toMatch(re);
197 function testEntropyFeedback(done, entropyDetail) {
198 // entropy type is compiled into regexp so needs escaping
199 // see https://stackoverflow.com/a/2593661
200 if ("type" in entropyDetail) {
201 entropyDetail.type = (entropyDetail.type+'').replace(/[.?*+^$[\]\\(){}|-]/g, "\\$&");
203 driver.findElement(By.css('.use-entropy
'))
205 driver.findElement(By.css('.entropy
'))
206 .sendKeys(entropyDetail.entropy);
207 driver.sleep(entropyFeedbackDelay).then(function() {
208 driver.findElement(By.css('.entropy
-container
'))
210 .then(function(text) {
211 driver.findElement(By.css('.phrase
'))
212 .getAttribute("value")
213 .then(function(phrase) {
214 if ("filtered" in entropyDetail) {
215 var key = "Filtered Entropy";
216 var value = entropyDetail.filtered;
217 var reText = key + "\\s+" + value;
218 var re = new RegExp(reText);
219 expect(text).toMatch(re);
221 if ("type" in entropyDetail) {
222 var key = "Entropy Type";
223 var value = entropyDetail.type;
224 var reText = key + "\\s+" + value;
225 var re = new RegExp(reText);
226 expect(text).toMatch(re);
228 if ("events" in entropyDetail) {
229 var key = "Event Count";
230 var value = entropyDetail.events;
231 var reText = key + "\\s+" + value;
232 var re = new RegExp(reText);
233 expect(text).toMatch(re);
235 if ("bits" in entropyDetail) {
236 var key = "Total Bits";
237 var value = entropyDetail.bits;
238 var reText = key + "\\s+" + value;
239 var re = new RegExp(reText);
240 expect(text).toMatch(re);
242 if ("bitsPerEvent" in entropyDetail) {
243 var key = "Bits Per Event";
244 var value = entropyDetail.bitsPerEvent;
245 var reText = key + "\\s+" + value;
246 var re = new RegExp(reText);
247 expect(text).toMatch(re);
249 if ("words" in entropyDetail) {
250 var actualWords = phrase.split(/\s+/)
251 .filter(function(w) { return w.length > 0 })
253 expect(actualWords).toBe(entropyDetail.words);
255 if ("strength" in entropyDetail) {
256 var key = "Time To Crack";
257 var value = entropyDetail.strength;
258 var reText = key + "\\s+" + value;
259 var re = new RegExp(reText);
260 expect(text).toMatch(re);
268 function testClientSelect(done, params) {
269 // set mnemonic and select bip32 tab
270 driver.findElement(By.css('#bip32
-tab a
'))
272 driver.findElement(By.css('.phrase
'))
273 .sendKeys("abandon abandon ability");
274 driver.sleep(generateDelay).then(function() {
276 // set bip32 client to bitcoin core
277 driver.executeScript(function() {
278 $("#bip32-client").val(arguments[0]).trigger("change");
279 }, params.selectValue);
280 driver.sleep(generateDelay).then(function() {
281 // check the derivation path is correct
282 driver.findElement(By.css("#bip32-path"))
283 .getAttribute("value")
284 .then(function(path) {
285 expect(path).toBe(params.bip32path);
286 // check hardened addresses is selected
287 driver.findElement(By.css(".hardened-addresses"))
288 .getAttribute("checked")
289 .then(function(isChecked) {
290 expect(isChecked).toBe(params.useHardenedAddresses);
291 // check input is readonly
292 driver.findElement(By.css("#bip32-path"))
293 .getAttribute("readonly")
294 .then(function(isReadonly) {
295 expect(isReadonly).toBe("true");
306 describe('BIP39 Tool Tests
', function() {
308 beforeEach(function(done) {
309 driver = newDriver();
310 driver.get(url).then(done);
313 // Close the website after each test is run (so that it is opened fresh each time)
314 afterEach(function(done) {
315 driver.quit().then(done);
320 // Page initially loads with blank phrase
321 it('Should load the page
', function(done) {
322 driver.findElement(By.css('.phrase
'))
323 .getAttribute('value
').then(function(value) {
324 expect(value).toBe('');
330 it('Should have text on the page
', function(done) {
331 driver.findElement(By.css('body
'))
333 .then(function(text) {
334 var textToFind = "You can enter an existing BIP39 mnemonic";
335 expect(text).toContain(textToFind);
340 // Entering mnemonic generates addresses
341 it('Should have a list
of addresses
', function(done) {
342 driver.findElement(By.css('.phrase
'))
343 .sendKeys('abandon abandon ability
');
344 driver.sleep(generateDelay).then(function() {
345 driver.findElements(By.css('.address
'))
346 .then(function(els) {
347 expect(els.length).toBe(20);
353 // Generate button generates random mnemonic
354 it('Should be able to generate a random mnemonic
', function(done) {
355 // initial phrase is blank
356 driver.findElement(By.css('.phrase
'))
357 .getAttribute("value")
358 .then(function(phrase) {
359 expect(phrase.length).toBe(0);
361 driver.findElement(By.css('.generate
')).click();
362 driver.sleep(generateDelay).then(function() {
363 // new phrase is not blank
364 driver.findElement(By.css('.phrase
'))
365 .getAttribute("value")
366 .then(function(phrase) {
367 expect(phrase.length).toBeGreaterThan(0);
374 // Mnemonic length can be customized
375 it('Should allow custom length mnemonics
', function(done) {
377 driver.executeScript(function() {
378 $(".strength option[selected]").removeAttr("selected");
379 $(".strength option[value=6]").prop("selected", true);
381 driver.findElement(By.css('.generate
')).click();
382 driver.sleep(generateDelay).then(function() {
383 driver.findElement(By.css('.phrase
'))
384 .getAttribute("value")
385 .then(function(phrase) {
386 var words = phrase.split(" ");
387 expect(words.length).toBe(6);
393 // Passphrase can be set
394 it('Allows a passphrase to be
set', function(done) {
395 driver.findElement(By.css('.phrase
'))
396 .sendKeys('abandon abandon ability
');
397 driver.findElement(By.css('.passphrase
'))
398 .sendKeys('secure_passphrase
');
399 driver.sleep(generateDelay).then(function() {
400 getFirstAddress(function(address) {
401 expect(address).toBe("15pJzUWPGzR7avffV9nY5by4PSgSKG9rba");
407 // Network can be set to networks other than bitcoin
408 it('Allows selection
of bitcoin testnet
', function(done) {
410 selectText: "BTC - Bitcoin Testnet",
411 firstAddress: "mucaU5iiDaJDb69BHLeDv8JFfGiyg2nJKi",
413 testNetwork(done, params);
415 it('Allows selection
of bitcoin regtest
', function(done) {
417 selectText: "BTC - Bitcoin RegTest",
418 firstAddress: "mucaU5iiDaJDb69BHLeDv8JFfGiyg2nJKi",
420 testNetwork(done, params);
422 it('Allows selection
of litecoin
', function(done) {
424 selectText: "LTC - Litecoin",
425 firstAddress: "LQ4XU8RX2ULPmPq9FcUHdVmPVchP9nwXdn",
427 testNetwork(done, params);
429 it('Allows selection
of litecoin testnet
', function(done) {
431 selectText: "LTCt - Litecoin Testnet",
432 firstAddress: "mucaU5iiDaJDb69BHLeDv8JFfGiyg2nJKi",
434 testNetwork(done, params);
436 it('Allows selection
of ripple
', function(done) {
438 selectText: "XRP - Ripple",
439 firstAddress: "rLTFnqbmCVPGx6VfaygdtuKWJgcN4v1zRS",
440 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",
442 testNetwork(done, params);
444 it('Allows selection
of casinocoin
', function(done) {
446 selectText: "CSC - CasinoCoin",
447 firstAddress: "c3P5EUb27Pzk9dcGt4s7zQDQj4sC6Y81mT",
448 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",
450 testNetwork(done, params);
452 it('Allows selection
of dogecoin
', function(done) {
454 selectText: "DOGE - Dogecoin",
455 firstAddress: "DPQH2AtuzkVSG6ovjKk4jbUmZ6iXLpgbJA",
457 testNetwork(done, params);
459 it('Allows selection
of dogecoin testnet
', function(done) {
461 selectText: "DOGEt - Dogecoin Testnet",
462 firstAddress: "niHnSJKHdwDyDxRMLBJrtNqpvHEsAFWe6B",
464 testNetwork(done, params);
466 it('Allows selection
of denarius
', function(done) {
468 selectText: "DNR - Denarius",
469 firstAddress: "DFdFMVUMzU9xX88EywXvAGwjiwpxyh9vKb",
471 testNetwork(done, params);
473 it('Allows selection
of shadowcash
', function(done) {
475 selectText: "SDC - ShadowCash",
476 firstAddress: "SiSZtfYAXEFvMm3XM8hmtkGDyViRwErtCG",
478 testNetwork(done, params);
480 it('Allows selection
of shadowcash testnet
', function(done) {
482 selectText: "SDC - ShadowCash Testnet",
483 firstAddress: "tM2EDpVKaTiEg2NZg3yKg8eqjLr55BErHe",
485 testNetwork(done, params);
487 it('Allows selection
of viacoin
', function(done) {
489 selectText: "VIA - Viacoin",
490 firstAddress: "Vq9Eq4N5SQnjqZvxtxzo7hZPW5XnyJsmXT",
492 testNetwork(done, params);
494 it('Allows selection
of viacoin testnet
', function(done) {
496 selectText: "VIA - Viacoin Testnet",
497 firstAddress: "tM2EDpVKaTiEg2NZg3yKg8eqjLr55BErHe",
499 testNetwork(done, params);
501 it('Allows selection
of jumbucks
', function(done) {
503 selectText: "JBS - Jumbucks",
504 firstAddress: "JLEXccwDXADK4RxBPkRez7mqsHVoJBEUew",
506 testNetwork(done, params);
508 it('Allows selection
of clam
', function(done) {
510 selectText: "CLAM - Clams",
511 firstAddress: "xCp4sakjVx4pUAZ6cBCtuin8Ddb6U1sk9y",
513 testNetwork(done, params);
515 it('Allows selection
of crown
', function(done) {
517 selectText: "CRW - Crown (Legacy)",
518 firstAddress: "18pWSwSUAQdiwMHUfFZB1fM2xue9X1FqE5",
520 testNetwork(done, params);
522 it('Allows selection
of crown
', function(done) {
524 selectText: "CRW - Crown",
525 firstAddress: "CRWKnVmVhvH1KWTYe6sq8xV4dFGcFpBEEkPQ",
527 testNetwork(done, params);
529 it('Allows selection
of dash
', function(done) {
531 selectText: "DASH - Dash",
532 firstAddress: "XdbhtMuGsPSkE6bPdNTHoFSszQKmK4S5LT",
534 testNetwork(done, params);
536 it('Allows selection
of dash testnet
', function(done) {
538 selectText: "DASH - Dash Testnet",
539 firstAddress: "yaR52EN4oojdJfBgzWJTymC4uuCLPT29Gw",
541 testNetwork(done, params);
543 it('Allows selection
of game
', function(done) {
545 selectText: "GAME - GameCredits",
546 firstAddress: "GSMY9bAp36cMR4zyT4uGVS7GFjpdXbao5Q",
548 testNetwork(done, params);
550 it('Allows selection
of komodo
', function(done) {
552 selectText: "KMD - Komodo",
553 firstAddress: "RMPPzJwAjPVZZAwJvXivHJGGjdCx6WBD2t",
555 testNetwork(done, params);
557 it('Allows selection
of namecoin
', function(done) {
559 selectText: "NMC - Namecoin",
560 firstAddress: "Mw2vK2Bvex1yYtYF6sfbEg2YGoUc98YUD2",
562 testNetwork(done, params);
564 it('Allows selection
of onixcoin
', function(done) {
566 selectText: "ONX - Onixcoin",
567 firstAddress: "XGwMqddeKjT3ddgX73QokjVbCL3aK6Yxfk",
569 testNetwork(done, params);
571 it('Allows selection
of lkrcoin
', function(done) {
573 selectText: "LKR - Lkrcoin",
574 firstAddress: "LfbT296e7AEEnn4bYDbL535Nd8P9g98CdJ",
576 testNetwork(done, params);
578 it('Allows selection
of bolivarcoin
', function(done) {
580 selectText: "BOLI - Bolivarcoin",
581 firstAddress: "bbKzCAUR7hZ3nqfffy7VgrSz8LmAP3S5mK",
583 testNetwork(done, params);
585 it('Allows selection
of peercoin
', function(done) {
587 selectText: "PPC - Peercoin",
588 firstAddress: "PVAiioTaK2eDHSEo3tppT9AVdBYqxRTBAm",
590 testNetwork(done, params);
592 it('Allows selection
of ethereum
', function(done) {
594 selectText: "ETH - Ethereum",
595 firstAddress: "0xe5815d5902Ad612d49283DEdEc02100Bd44C2772",
597 testNetwork(done, params);
599 it('Allows selection
of slimcoin
', function(done) {
601 selectText: "SLM - Slimcoin",
602 firstAddress: "SNzPi1CafHFm3WWjRo43aMgiaEEj3ogjww",
604 testNetwork(done, params);
606 it('Allows selection
of slimcoin testnet
', function(done) {
608 selectText: "SLM - Slimcoin Testnet",
609 firstAddress: "n3nMgWufTek5QQAr6uwMhg5xbzj8xqc4Dq",
611 testNetwork(done, params);
613 it('Allows selection
of bitcoin cash
', function(done) {
615 selectText: "BCH - Bitcoin Cash",
616 firstAddress: "bitcoincash:qzlquk7w4hkudxypl4fgv8x279r754dkvur7jpcsps",
618 testNetwork(done, params);
621 it('Allows selection
of simpleledger(SLP
)', function(done) {
623 selectText: "SLP - Simple Ledger Protocol",
624 firstAddress: "simpleledger:qrtffz6ajfsn74gpur7y3epjquz42pvww5acewqmre",
626 testNetwork(done, params);
629 it('Allows selection
of myriadcoin
', function(done) {
631 selectText: "XMY - Myriadcoin",
632 firstAddress: "MJEswvRR46wh9BoiVj9DzKYMBkCramhoBV",
634 testNetwork(done, params);
636 it('Allows selection
of pivx
', function(done) {
638 selectText: "PIVX - PIVX",
639 firstAddress: "DBxgT7faCuno7jmtKuu6KWCiwqsVPqh1tS",
641 testNetwork(done, params);
643 it('Allows selection
of pivx testnet
', function(done) {
645 selectText: "PIVX - PIVX Testnet",
646 firstAddress: "yB5U384n6dGkVE3by5y9VdvHHPwPg68fQj",
648 testNetwork(done, params);
650 it('Allows selection
of maza
', function(done) {
652 selectText: "MAZA - Maza",
653 firstAddress: "MGW4Bmi2NEm4PxSjgeFwhP9vg18JHoRnfw",
655 testNetwork(done, params);
657 it('Allows selection
of FIX
', function(done) {
659 selectText: "FIX - FIX",
660 firstAddress: "FS5MEU8fs5dUvsaSCSusV8RQtC8j2h3JEh",
662 testNetwork(done, params);
664 it('Allows selection
of FIX testnet
', function(done) {
666 selectText: "FIX - FIX Testnet",
667 firstAddress: "XpnU1HHdNG5YxvG9Rez4wjmidchxqnZaNa",
669 testNetwork(done, params);
671 it('Allows selection
of fujicoin
', function(done) {
673 selectText: "FJC - Fujicoin",
674 firstAddress: "FgiaLpG7C99DyR4WnPxXedRVHXSfKzUDhF",
676 testNetwork(done, params);
678 it('Allows selection
of nubits
', function(done) {
680 selectText: "USNBT - NuBits",
681 firstAddress: "BLxkabXuZSJSdesLD7KxZdqovd4YwyBTU6",
683 testNetwork(done, params);
685 it('Allows selection
of bitcoin gold
', function(done) {
687 selectText: "BTG - Bitcoin Gold",
688 firstAddress: "GdDqug4WUsn5syNbSTHatNn4XnuwZtzedx",
690 testNetwork(done, params);
692 it('Allows selection
of monacoin
', function(done) {
694 selectText: "MONA - Monacoin",
695 firstAddress: "MKMiMr7MyjDKjJbCBzgF6u4ByqTS4NkRB1",
697 testNetwork(done, params);
699 it('Allows selection
of AXE
', function(done) {
701 selectText: "AXE - Axe",
702 firstAddress: "PScwtLUyPiGrqtKXrHF37DGETLXLZdw4up",
704 testNetwork(done, params);
706 it('Allows selection
of BlackCoin
', function(done) {
708 selectText: "BLK - BlackCoin",
709 firstAddress: "B5MznAKwj7uQ42vDz3w4onhBXPcqhTwJ9z",
711 testNetwork(done, params);
713 it('Allows selection
of Neblio
', function(done) {
715 selectText: "NEBL - Neblio",
716 firstAddress: "NefkeEEvhusbHMmTRrxx7H9wFnUXd8qQsE",
718 testNetwork(done, params);
720 it('Allows selection
of Beetlecoin
', function(done) {
722 selectText: "BEET - Beetlecoin",
723 firstAddress: "BVmtbEsGrjpknprmpHFq26z4kYHJUFHE71",
725 testNetwork(done, params);
727 it('Allows selection
of Adcoin
', function(done) {
729 selectText: "ACC - Adcoin",
730 firstAddress: "AcEDM6V5sF4kFHC76MJjjfProtS5Sw2qcd",
732 testNetwork(done, params);
734 it('Allows selection
of Asiacoin
', function(done) {
736 selectText: "AC - Asiacoin",
737 firstAddress: "ALupuEEz7kJjQTAvmtcBMBVuEjPa7GqZzE",
739 testNetwork(done, params);
741 it('Allows selection
of Aryacoin
', function(done) {
743 selectText: "ARYA - Aryacoin",
744 firstAddress: "Abr6gX25KaU9BpwD34UfsL3A4n89NvYYSf",
746 testNetwork(done, params);
748 it('Allows selection
of Auroracoin
', function(done) {
750 selectText: "AUR - Auroracoin",
751 firstAddress: "ANuraS6F4Jpi413FEnavjYkKYJJRHkgYCm",
753 testNetwork(done, params);
755 it('Allows selection
of Bata
', function(done) {
757 selectText: "BTA - Bata",
758 firstAddress: "BGxBdNeYPtF3GCuTtZBPQdFxCkdBYSF3fj",
760 testNetwork(done, params);
762 it('Allows selection
of Belacoin
', function(done) {
764 selectText: "BELA - Belacoin",
765 firstAddress: "BEeetqpNffdzeknSpNmQp5KAFh2KK1Qx7S",
767 testNetwork(done, params);
769 it('Allows selection
of Bitcoin Atom
', function(done) {
771 selectText: "BCA - Bitcoin Atom",
772 firstAddress: "AMy6qMbJeC4zsGRL6iWszmeCdQH65fgfih",
774 testNetwork(done, params);
776 it('Allows selection
of Bitcoinplus
', function(done) {
778 selectText: "XBC - Bitcoinplus",
779 firstAddress: "B7FSynZoDbEwTCSgsXq9nJ5ue8owYLVL8r",
781 testNetwork(done, params);
783 it('Allows selection
of Bitcoin Private
', function(done) {
785 selectText: "BTCP - Bitcoin Private",
786 firstAddress: "b1M3PbiXXyN6Hdivdw5rJv5VKpLjPzhm4jM",
788 testNetwork(done, params);
790 it('Allows selection
of Bitcoin SV
', function(done) {
792 selectText: "BSV - BitcoinSV",
793 firstAddress: "1N4mgtE5yxifch9jWs7Sds6oVqxdy2t576",
795 testNetwork(done, params);
797 it('Allows selection
of Bitcoinz
', function(done) {
799 selectText: "BTCZ - Bitcoinz",
800 firstAddress: "t1X2YQoxs8cYRo2oaBYgVEwW5QNjCC59NYc",
802 testNetwork(done, params);
804 it('Allows selection
of BitCloud
', function(done) {
806 selectText: "BTDX - BitCloud",
807 firstAddress: "BHbWitXCNgTf1BhsRDNMP186EeibuzmrBi",
809 testNetwork(done, params);
811 it('Allows selection
of Bitcore
', function(done) {
813 selectText: "BTX - Bitcore",
814 firstAddress: "2Rgp5Znhpy34TK4QmPkfCiYs9r4KovfTH9",
816 testNetwork(done, params);
818 it('Allows selection
of Bitsend
', function(done) {
820 selectText: "BSD - Bitsend",
821 firstAddress: "iBPk7LYjDun3EPk7CRR8UUmnPoceVc1bp2",
823 testNetwork(done, params);
825 it('Allows selection
of Britcoin
', function(done) {
827 selectText: "BRIT - Britcoin",
828 firstAddress: "B6Aue4J2XLs1f1dtD4H1SHYFfh4XrmEbrw",
830 testNetwork(done, params);
832 it('Allows selection
of Canadaecoin
', function(done) {
834 selectText: "CDN - Canadaecoin",
835 firstAddress: "CanAyCfd5Rj2CQVfaoAmvDUZunPM5W1AEQ",
837 testNetwork(done, params);
839 it('Allows selection
of Cannacoin
', function(done) {
841 selectText: "CCN - Cannacoin",
842 firstAddress: "CYjW8xWB43g6krLJTmmrPk1PonoQX7h9Qd",
844 testNetwork(done, params);
846 it('Allows selection
of Clubcoin
', function(done) {
848 selectText: "CLUB - Clubcoin",
849 firstAddress: "CHMDEXN4sihpSVX4GyAa2hZ62shnby7uyN",
851 testNetwork(done, params);
853 it('Allows selection
of Compcoin
', function(done) {
855 selectText: "CMP - Compcoin",
856 firstAddress: "CLshtw3zhxkseBJS46UF12v3AFy9Dx7JVv",
858 testNetwork(done, params);
860 it('Allows selection
of CPUchain
', function(done) {
862 selectText: "CPU - CPUchain",
863 firstAddress: "CWSpLpW7jS4mBHJnkz3mmL5s3yQMg93zK8",
865 testNetwork(done, params);
867 it('Allows selection
of Crave
', function(done) {
869 selectText: "CRAVE - Crave",
870 firstAddress: "VCYJeti6uKMNBFKCL7eP96UwuFWYHM7c85",
872 testNetwork(done, params);
874 it('Allows selection
of Defcoin
', function(done) {
876 selectText: "DFC - Defcoin",
877 firstAddress: "D8swcgyaaFUrXZU3ATwbgy16buCpWqbG1M",
879 testNetwork(done, params);
881 it('Allows selection
of Diamond
', function(done) {
883 selectText: "DMD - Diamond",
884 firstAddress: "dJnrVbLL9UPjdaVRz2C8VpqHZknqAqjLek",
886 testNetwork(done, params);
888 it('Allows selection
of Digibyte
', function(done) {
890 selectText: "DGB - Digibyte",
891 firstAddress: "D85Rp9jwLtMdmP6wGjTiqHBdVQLST3YCEq",
893 testNetwork(done, params);
895 it('Allows selection
of Digitalcoin
', function(done) {
897 selectText: "DGC - Digitalcoin",
898 firstAddress: "DKw4UGKEAZWweDNEbBFNQx4EM8x1mpUdia",
900 testNetwork(done, params);
902 it('Allows selection
of Ecoin
', function(done) {
904 selectText: "ECN - Ecoin",
905 firstAddress: "e6WFPLG5gcXyF7cESFteH1hE2XSmowW5yB",
907 testNetwork(done, params);
909 it('Allows selection
of Edrcoin
', function(done) {
911 selectText: "EDRC - Edrcoin",
912 firstAddress: "eh1nUJsvgKPFv6ebMBfcwJ299GMCpjeZUG",
914 testNetwork(done, params);
916 it('Allows selection
of Egulden
', function(done) {
918 selectText: "EFL - Egulden",
919 firstAddress: "Lg66yt55R7edRM58cDhKzXik2kFme3viX7",
921 testNetwork(done, params);
923 it('Allows selection
of Einsteinium
', function(done) {
925 selectText: "EMC2 - Einsteinium",
926 firstAddress: "EVAABm9hXKHk2MpVMbwNakRubFnNha5m8m",
928 testNetwork(done, params);
930 it('Allows selection
of EOSIO
', function(done) {
932 selectText: "EOS - EOSIO",
933 firstPubKey: "EOS692VJTBK3Rmw93onNnpnZ8ZtmE9PdxjDStArvbyzoe11QUTNoy",
935 testNetwork(done, params, true);
937 it('Allows selection
of Europecoin
', function(done) {
939 selectText: "ERC - Europecoin",
940 firstAddress: "ESA2YwPYntAoaPrE8Fm5qkKRtkcwLcwD6R",
942 testNetwork(done, params);
944 it('Allows selection
of Exclusivecoin
', function(done) {
946 selectText: "EXCL - Exclusivecoin",
947 firstAddress: "EbUa6m8UZW6nTxsYZD2FsDjkadKbp5M6JT",
949 testNetwork(done, params);
951 it('Allows selection
of Feathercoin
', function(done) {
953 selectText: "FTC - Feathercoin",
954 firstAddress: "6gDdjAMoSgQaW8UhqK3oboHs6ftGAroKkM",
956 testNetwork(done, params);
958 it('Allows selection
of Firstcoin
', function(done) {
960 selectText: "FRST - Firstcoin",
961 firstAddress: "FJN9GzfMm7Q8R4DJwK1H9F6A1GTghvFiMJ",
963 testNetwork(done, params);
965 it('Allows selection
of Flashcoin
', function(done) {
967 selectText: "FLASH - Flashcoin",
968 firstAddress: "UWfpf5LfMmLxZYooEb2EyvWhZ8NG7EZDRt",
970 testNetwork(done, params);
972 it('Allows selection
of GCRCoin
', function(done) {
974 selectText: "GCR - GCRCoin",
975 firstAddress: "GJjF5cLwyXLacpuvXAVksxGxKvHDjx58d6",
977 testNetwork(done, params);
979 it('Allows selection
of Gobyte
', function(done) {
981 selectText: "GBX - Gobyte",
982 firstAddress: "GS813Ys2brkmvSUw1rUqGPm2HqQVDHJRyA",
984 testNetwork(done, params);
986 it('Allows selection
of Gridcoin
', function(done) {
988 selectText: "GRC - Gridcoin",
989 firstAddress: "SGrWbBPvobgqKRF8td1Kdc9vbRY7MJ78Y9",
991 testNetwork(done, params);
993 it('Allows selection
of Gulden
', function(done) {
995 selectText: "NLG - Gulden",
996 firstAddress: "GcDP7cNEc33MPPdTFNJ8pZc6VMZJ2CbKxY",
998 testNetwork(done, params);
1000 it('Allows selection
of Helleniccoin
', function(done) {
1002 selectText: "HNC - Helleniccoin",
1003 firstAddress: "LbHEKe5H72zp9G1fuWNiiNePTUfJb88915",
1005 testNetwork(done, params);
1007 it('Allows selection
of Hempcoin
', function(done) {
1009 selectText: "THC - Hempcoin",
1010 firstAddress: "H8sdWbZyJV4gyXyHtLXDaNnAuUDhK5mfTV",
1012 testNetwork(done, params);
1014 it('Allows selection
of Insane
', function(done) {
1016 selectText: "INSN - Insane",
1017 firstAddress: "iMPqEJMiXWuxC9U2NVinCCMr4t72h58EWx",
1019 testNetwork(done, params);
1021 it('Allows selection
of Iop
', function(done) {
1023 selectText: "IOP - Iop",
1024 firstAddress: "pGKQmcaPf95Ur5o6oHK4qdiZ52p1yaTvq1",
1026 testNetwork(done, params);
1028 it('Allows selection
of Ixcoin
', function(done) {
1030 selectText: "IXC - Ixcoin",
1031 firstAddress: "xgE9bTZ6YypT3E6ByzkTt31Hq68E9BqywH",
1033 testNetwork(done, params);
1035 it('Allows selection
of Kobocoin
', function(done) {
1037 selectText: "KOBO - Kobocoin",
1038 firstAddress: "FTVoNJETXDAM8x7MnmdE8RwWndSr9PQWhy",
1040 testNetwork(done, params);
1042 it('Allows selection
of Landcoin
', function(done) {
1044 selectText: "LDCN - Landcoin",
1045 firstAddress: "LLvLwNjG1aJcn1RS4W4GJUbv8fNaRATG7c",
1047 testNetwork(done, params);
1049 it('Allows selection
of Library Credits
', function(done) {
1051 selectText: "LBC - Library Credits",
1052 firstAddress: "bQJEQrHDJyHdqycB32uysh1SWn8Ln8LMdg",
1054 testNetwork(done, params);
1056 it('Allows selection
of Linx
', function(done) {
1058 selectText: "LINX - Linx",
1059 firstAddress: "XGWQ3cb3LGUB3VnHmj6xYSMgnokNbf6dyk",
1061 testNetwork(done, params);
1063 it('Allows selection
of Litecoincash
', function(done) {
1065 selectText: "LCC - Litecoincash",
1066 firstAddress: "Ce5n7fjUuQPLutJ4W5nCCfQLKdKLE1mv9A",
1068 testNetwork(done, params);
1070 it('Allows selection
of Lynx
', function(done) {
1072 selectText: "LYNX - Lynx",
1073 firstAddress: "KUeY3ZdZkg96p4W98pj1JjygCFU1XqWdw3",
1075 testNetwork(done, params);
1077 it('Allows selection
of Megacoin
', function(done) {
1079 selectText: "MEC - Megacoin",
1080 firstAddress: "MDfAj9CzkC1HpcUiVGnHp8yKTa7WXgu8AY",
1082 testNetwork(done, params);
1084 it('Allows selection
of Minexcoin
', function(done) {
1086 selectText: "MNX - Minexcoin",
1087 firstAddress: "XC1VnyJVfiMDwWgFtAHDp41cgY3AHk3dJT",
1089 testNetwork(done, params);
1091 it('Allows selection
of Navcoin
', function(done) {
1093 selectText: "NAV - Navcoin",
1094 firstAddress: "NTQVTPK3NWSQLKoffkiQw99T8PifkF1Y2U",
1096 testNetwork(done, params);
1098 it('Allows selection
of Nebulas
', function(done) {
1100 selectText: "NAS - Nebulas",
1101 firstAddress: "n1PbK61DGBfDoDusLw621G6sVSMfLLHdfnm",
1103 testNetwork(done, params);
1105 it('Allows selection
of Neoscoin
', function(done) {
1107 selectText: "NEOS - Neoscoin",
1108 firstAddress: "NgATz6QbQNXvayHQ4CpZayugb9HeaPDdby",
1110 testNetwork(done, params);
1112 it('Allows selection
of Nix
', function(done) {
1114 selectText: "NIX - NIX Platform",
1115 firstAddress: "GgcNW2SQQXB4LWHRQTHKkQF3GzXNSLqS8u",
1117 testNetwork(done, params);
1119 it('Allows selection
of Neurocoin
', function(done) {
1121 selectText: "NRO - Neurocoin",
1122 firstAddress: "NVdYErQ3mFpDuF5DquW9WMiT7sLc8ufFTn",
1124 testNetwork(done, params);
1126 it('Allows selection
of Newyorkc
', function(done) {
1128 selectText: "NYC - Newyorkc",
1129 firstAddress: "RSVMfyH1fKfy3puADJEhut2vfkRyon6imm",
1131 testNetwork(done, params);
1133 it('Allows selection
of Novacoin
', function(done) {
1135 selectText: "NVC - Novacoin",
1136 firstAddress: "4JRvUmxcKCJmaMXZyvRoSS1cmG2XvnZfHN",
1138 testNetwork(done, params);
1140 it('Allows selection
of Nushares
', function(done) {
1142 selectText: "NSR - Nushares",
1143 firstAddress: "SecjXzU3c7EecdT7EbC4vvmbdtBBokWh6J",
1145 testNetwork(done, params);
1147 it('Allows selection
of Okcash
', function(done) {
1149 selectText: "OK - Okcash",
1150 firstAddress: "PV4Qp1TUYuGv4TqVtLZtqvrsWWRycfx1Yi",
1152 testNetwork(done, params);
1154 it('Allows selection
of Omnicore
', function(done) {
1156 selectText: "OMNI - Omnicore",
1157 firstAddress: "1Q1t3gonjCT3rW38TsTsCvgSc3hh7zBGbi",
1159 testNetwork(done, params);
1161 it('Allows selection
of DeepOnion
', function(done) {
1163 selectText: "ONION - DeepOnion",
1164 firstAddress: "DYREY7XCFXVqJ3x5UuN43k2JwD2s1kif48",
1166 testNetwork(done, params);
1168 it('Allows selection
of Pesobit
', function(done) {
1170 selectText: "PSB - Pesobit",
1171 firstAddress: "PDePsF7ALyXP7JaywokdYiRTDtKa14MAr1",
1173 testNetwork(done, params);
1175 it('Allows selection
of Pinkcoin
', function(done) {
1177 selectText: "PINK - Pinkcoin",
1178 firstAddress: "2TgjYQffjbzUHJghNaVbdsjHbRwruC3yzC",
1180 testNetwork(done, params);
1182 it('Allows selection
of POSWcoin
', function(done) {
1184 selectText: "POSW - POSWcoin",
1185 firstAddress: "PNxewmZoPnGBvoEbH6hgQZCK1igDiBCdgC",
1187 testNetwork(done, params);
1189 it('Allows selection
of Potcoin
', function(done) {
1191 selectText: "POT - Potcoin",
1192 firstAddress: "PEo7Vg2ctXgpP4vuLPeY9aGJtZotyrmiHc",
1194 testNetwork(done, params);
1196 it('Allows selection
of Putincoin
', function(done) {
1198 selectText: "PUT - Putincoin",
1199 firstAddress: "PViWnfr2uFtovd6e7joM49C94CsGSnqJis",
1201 testNetwork(done, params);
1203 it('Allows selection
of Rapids
', function(done) {
1205 selectText: "RPD - Rapids",
1206 firstAddress: "Ri8XxUdZaXS5LqxmFJcFEjFinkaMbmhSUp",
1208 testNetwork(done, params);
1210 it('Allows selection
of Ravencoin
', function(done) {
1212 selectText: "RVN - Ravencoin",
1213 firstAddress: "RBuDoVNnzvFsEcX8XKPm8ic4mgiCzjUCNk",
1215 testNetwork(done, params);
1217 it('Allows selection
of Reddcoin
', function(done) {
1219 selectText: "RDD - Reddcoin",
1220 firstAddress: "RtgRvXMBng1y51ftteveFqwNfyRG18HpxQ",
1222 testNetwork(done, params);
1224 it('Allows selection
of RevolutionVR
', function(done) {
1226 selectText: "RVR - RevolutionVR",
1227 firstAddress: "VXeeoP2jkzZnMFxtc66ZBZK1NHN5QJnnjL",
1229 testNetwork(done, params);
1231 it('Allows selection
of Rubycoin
', function(done) {
1233 selectText: "RBY - Rubycoin",
1234 firstAddress: "RV76JDtjTs11JdMDRToYn6CHecMRPLnKS6",
1236 testNetwork(done, params);
1238 it('Allows selection
of Salus
', function(done) {
1240 selectText: "SLS - Salus",
1241 firstAddress: "SNzPi1CafHFm3WWjRo43aMgiaEEj3ogjww",
1243 testNetwork(done, params);
1245 it('Allows selection
of Smileycoin
', function(done) {
1247 selectText: "SMLY - Smileycoin",
1248 firstAddress: "BEZVnEBCAyFByrgKpwAgYgtvP4rKAd9Sj2",
1250 testNetwork(done, params);
1252 it('Allows selection
of Solarcoin
', function(done) {
1254 selectText: "SLR - Solarcoin",
1255 firstAddress: "8LZ13HbnjtaMJWSvvVFNTLf71zFfDrhwLu",
1257 testNetwork(done, params);
1259 it('Allows selection
of stash
', function(done) {
1261 selectText: "STASH - Stash",
1262 firstAddress: "XxwAsWB7REDKmAvHA85SbEZQQtpxeUDxS3",
1264 testNetwork(done, params);
1266 it('Allows selection
of stash testnet
', function(done) {
1268 selectText: "STASH - Stash Testnet",
1269 firstAddress: "yWQCTSkUst7ddYuebKsqa1kSoXEjpCkGKR",
1271 testNetwork(done, params);
1273 it('Allows selection
of Stratis
', function(done) {
1275 selectText: "STRAT - Stratis",
1276 firstAddress: "ScfJnq3QDhKgDMEds6sqUE1ot6ShfhmXXq",
1278 testNetwork(done, params);
1280 it('Allows selection
of Stratis Test
', function(done) {
1282 selectText: "TSTRAT - Stratis Testnet",
1283 firstAddress: "TRLWm3dye4FRrDWouwYUSUZP96xb76mBE3",
1285 testNetwork(done, params);
1287 it('Allows selection
of Syscoin
', function(done) {
1289 selectText: "SYS - Syscoin",
1290 firstAddress: "SZwJi42Pst3VAMomyK5DG4157WM5ofRmSj",
1292 testNetwork(done, params);
1294 it('Allows selection
of Toa
', function(done) {
1296 selectText: "TOA - Toa",
1297 firstAddress: "TSe1QAnUwQzUfbBusDzRJ9URttrRGKoNKF",
1299 testNetwork(done, params);
1301 it('Allows selection
of TWINS
', function(done) {
1303 selectText: "TWINS - TWINS",
1304 firstAddress: "WPpJnfLLubNmF7HLNxg8d8zH5haxn4wri8",
1306 testNetwork(done, params);
1308 it('Allows selection
of TWINS testnet
', function(done) {
1310 selectText: "TWINS - TWINS Testnet",
1311 firstAddress: "XpnU1HHdNG5YxvG9Rez4wjmidchxqnZaNa",
1313 testNetwork(done, params);
1315 it('Allows selection
of Ultimatesecurecash
', function(done) {
1317 selectText: "USC - Ultimatesecurecash",
1318 firstAddress: "UPyLAZU2Che5fiy7Ed8xVJFmXAUhitA4ug",
1320 testNetwork(done, params);
1322 it('Allows selection
of Unobtanium
', function(done) {
1324 selectText: "UNO - Unobtanium",
1325 firstAddress: "uUBMPVMXrR6qhqornJqKTWgr8L69vihSL9",
1327 testNetwork(done, params);
1329 it('Allows selection
of Vcash
', function(done) {
1331 selectText: "XVC - Vcash",
1332 firstAddress: "VuL53MSY6KjvAjKSeRkh3NDnKykacDVeps",
1334 testNetwork(done, params);
1336 it('Allows selection
of Verge
', function(done) {
1338 selectText: "XVG - Verge",
1339 firstAddress: "DCrVuGkMjLJpTGgwAgv9AcMdeb1nkWbjZA",
1341 testNetwork(done, params);
1343 it('Allows selection
of Vertcoin
', function(done) {
1345 selectText: "VTC - Vertcoin",
1346 firstAddress: "Vf6koGuiWdXQfx8tNqxoNeEDxh4xh5cxsG",
1348 testNetwork(done, params);
1350 it('Allows selection
of Vivo
', function(done) {
1352 selectText: "VIVO - Vivo",
1353 firstAddress: "VFmBwuXXGhJe7MarQG2GfzHMFebRHgfSpB",
1355 testNetwork(done, params);
1357 it('Allows selection
of Vpncoin
', function(done) {
1359 selectText: "VASH - Vpncoin",
1360 firstAddress: "VoEmH1qXC4TsSgBAStR21QYetwnFqbqCx9",
1362 testNetwork(done, params);
1364 it('Allows selection
of VeChain
', function(done) {
1366 selectText: "VET - VeChain",
1367 firstAddress: "0xdba55B1B6070f3a733D5eDFf35F0da4A00E455F2",
1369 testNetwork(done, params);
1371 it('Allows selection
of Whitecoin
', function(done) {
1373 selectText: "XWC - Whitecoin",
1374 firstAddress: "WcSwCAUqrSgeSYbsaS3SSWWhsx8KRYTFDR",
1376 testNetwork(done, params);
1378 it('Allows selection
of Wincoin
', function(done) {
1380 selectText: "WC - Wincoin",
1381 firstAddress: "WaDVCESMGgyKgNESdn3u43NnwmGSkZED3Z",
1383 testNetwork(done, params);
1385 it('Allows selection
of Zcoin
', function(done) {
1387 selectText: "XZC - Zcoin",
1388 firstAddress: "a6VcMdP4XgAA9Tr7xNszmPG5FZpfRf17Cq",
1390 testNetwork(done, params);
1392 it('Allows selection
of Zcash
', function(done) {
1394 selectText: "ZEC - Zcash",
1395 firstAddress: "t1Sz8AneMcVuzUg3tPJ8et5AS5LFJ7K2EF9",
1397 testNetwork(done, params);
1399 it('Allows selection
of Zclassic
', function(done) {
1401 selectText: "ZCL - Zclassic",
1402 firstAddress: "t1TBMxTvVJRybUbMLGWq8H4A8F4VUL7czEc",
1404 testNetwork(done, params);
1406 it('Allows selection
of Horizen
', function(done) {
1408 selectText: "ZEN - Horizen",
1409 firstAddress: "znWh9XASyW2dZq5tck84wFjiwuqVysi7q3p",
1411 testNetwork(done, params);
1413 it('Allows selection
of Energi
', function(done) {
1415 selectText: "NRG - Energi",
1416 firstAddress: "EejRy4t4nidzhGGzkJUgFP3z4HYBjhTsRt",
1418 testNetwork(done, params);
1420 it('Allows selection
of Ethereum Classic
', function(done) {
1422 selectText: "ETC - Ethereum Classic",
1423 firstAddress: "0x3c05e5556693808367afB62eF3b63e35d6eD249A",
1425 testNetwork(done, params);
1427 it('Allows selection
of Pirl
', function(done) {
1429 selectText: "PIRL - Pirl",
1430 firstAddress: "0xe77FC0723dA122B5025CA79193c28563eB47e776",
1432 testNetwork(done, params);
1434 it('Allows selection
of MIX
', function(done) {
1436 selectText: "MIX - MIX",
1437 firstAddress: "0x98BC5e63aeb6A4e82d72850d20710F07E29A29F1",
1439 testNetwork(done, params);
1441 it('Allows selection
of Monkey Project
', function(done) {
1443 selectText: "MONK - Monkey Project",
1444 firstAddress: "MnLrcnnUzKnf7TzufjRe5DLZqQJz18oYyu",
1446 testNetwork(done, params);
1449 it('Allows selection
of Musicoin
', function(done) {
1451 selectText: "MUSIC - Musicoin",
1452 firstAddress: "0xDc060e4A0b0313ea83Cf6B3A39B9db2D29004897",
1454 testNetwork(done, params);
1456 it('Allows selection
of Poa
', function(done) {
1458 selectText: "POA - Poa",
1459 firstAddress: "0x53aF28d754e106210C3d0467Dd581eaf7e3C5e60",
1461 testNetwork(done, params);
1463 it('Allows selection
of Expanse
', function(done) {
1465 selectText: "EXP - Expanse",
1466 firstAddress: "0xf57FeAbf26582b6E3E666559d3B1Cc6fB2b2c5F6",
1468 testNetwork(done, params);
1470 it('Allows selection
of Callisto
', function(done) {
1472 selectText: "CLO - Callisto",
1473 firstAddress: "0x4f9364F7420B317266C51Dc8eB979717D4dE3f4E",
1475 testNetwork(done, params);
1477 it('Allows selection
of HUSH
', function(done) {
1479 selectText: "HUSH - Hush (Legacy)",
1480 firstAddress: "t1g6rLXUnJaiJuu4q4zmJjoa9Gk4fwKpiuA",
1482 testNetwork(done, params);
1484 it('Allows selection
of HUSH3
', function(done) {
1486 selectText: "HUSH - Hush3",
1487 firstAddress: "RXWSQhwvw5jHPGP8bjwJhWoRnMLBnuPDKD",
1489 testNetwork(done, params);
1491 it('Allows selection
of ExchangeCoin
', function(done) {
1493 selectText: "EXCC - ExchangeCoin",
1494 firstAddress: "22txYKpFN5fwGwdSs2UBf7ywewbLM92YqK7E",
1496 testNetwork(done, params);
1498 it('Allows selection
of Artax
', function(done) {
1500 selectText: "XAX - Artax",
1501 firstAddress: "AYxaQPY7XLidG31V7F3yNzwxPYpYzRqG4q",
1503 testNetwork(done, params);
1505 it('Allows selection
of BitcoinGreen
', function(done) {
1507 selectText: "BITG - Bitcoin Green",
1508 firstAddress: "GeNGm9SkEfwbsws3UrrUSE2sJeyWYjzraY",
1510 testNetwork(done, params);
1512 it('Allows selection
of ANON
', function(done) {
1514 selectText: "ANON - ANON",
1515 firstAddress: "AnU6pijpEeUZFWSTyM2qTqZQn996Zq1Xard",
1517 testNetwork(done, params);
1519 it('Allows selection
of ProjectCoin
', function(done) {
1521 selectText: "PRJ - ProjectCoin",
1522 firstAddress: "PXZG97saRseSCftfe1mcFmfAA7pf6qBbaz",
1524 testNetwork(done, params);
1526 it('Allows selection
of Phore
', function(done) {
1528 selectText: "PHR - Phore",
1529 firstAddress: "PJThxpoXAG6hqrmdeQQbVDX4TJtFTMMymC",
1531 testNetwork(done, params);
1533 it('Allows selection
of Safecoin
', function(done) {
1535 selectText: "SAFE - Safecoin",
1536 firstAddress: "RtxHpnhJz6RY8k9owP3ua5QWraunmewB1G",
1538 testNetwork(done, params);
1540 it('Allows selection
of Blocknode
', function(done) {
1542 selectText: "BND - Blocknode",
1543 firstAddress: "BG8xZSAur2jYLG9VXt8dYfkKxxeR7w9bSe",
1545 testNetwork(done, params);
1547 it('Allows selection
of Blocknode Testnet
', function(done) {
1549 selectText: "tBND - Blocknode Testnet",
1550 firstAddress: "bSptsFyDktFSKpWveRywJsDoJA2TC6qfHv",
1552 testNetwork(done, params);
1554 it('Allows selection
of LitecoinZ
', function(done) {
1556 selectText: "LTZ - LitecoinZ",
1557 firstAddress: "L1VTXju7hLgKV4T7fGXS9sKsnm2gmtRCmyw",
1559 testNetwork(done, params);
1561 it('Allows selection
of BlockStamp
', function(done) {
1563 selectText: "BST - BlockStamp",
1564 firstAddress: "15gypKtim4cVTj137ApfryG17RkvSbPazZ",
1566 testNetwork(done, params);
1568 it('Allows selection
of DEXON
', function(done) {
1570 selectText: "DXN - DEXON",
1571 firstAddress: "0x136a58788033E028CCd740FbDec6734358DB56Ec",
1573 testNetwork(done, params);
1575 it('Allows selection
of Ellaism
', function(done) {
1577 selectText: "ELLA - Ellaism",
1578 firstAddress: "0xa8B0BeA09eeBc41062308546a01d6E544277e2Ca",
1580 testNetwork(done, params);
1582 it('Allows selection
of Ethersocial Network
', function(done) {
1584 selectText: "ESN - Ethersocial Network",
1585 firstAddress: "0x6EE99Be2A0C7F887a71e21C8608ACF0aa0D2b767",
1587 testNetwork(done, params);
1589 it('Allows selection
of Stellar
', function(done) {
1591 selectText: "XLM - Stellar",
1592 firstAddress: "GCUK3NYYUXA2QGN6KU5RR36WAKN3Y5EANZV65XNAWN4XM4CHQ3G4DMO2",
1594 testNetwork(done, params);
1596 it('Allows selection
of Wagerr
', function(done) {
1598 selectText: "WGR - Wagerr",
1599 firstAddress: "WYiVgQU39VcQxcnacoCiaZHZZLjDCJoS95",
1601 testNetwork(done, params);
1603 it('Allows selection
of Groestlcoin
', function(done) {
1605 selectText: "GRS - Groestlcoin",
1606 firstAddress: "FZycsFvZ1eH1hbtyjBpAgJSukVw1bN6PBN",
1608 testNetwork(done, params);
1610 it('Allows selection
of Groestlcoin Testnet
', function(done) {
1612 selectText: "GRS - Groestlcoin Testnet",
1613 firstAddress: "mucaU5iiDaJDb69BHLeDv8JFfGiygRPne9",
1615 testNetwork(done, params);
1617 it('Allows selection
of Elastos
', function(done) {
1619 selectText: "ELA - Elastos",
1620 firstAddress: "EMccDcsn3SwPDcfeQMf3w7utqi8ioWYtkg",
1622 testNetwork(done, params);
1624 it('Allows selection
of Energyweb
', function(done) {
1626 selectText: "EWT - EnergyWeb",
1627 firstAddress: "0x22171474844Fc7E8E99A3A69CCf1eDb5574FdD4c",
1629 testNetwork(done, params);
1631 it('Allows selection
of Thought
', function(done) {
1633 selectText: "THT - Thought",
1634 firstAddress: "4B1Bh9GibDarFQrhtYU8krpc7WSjgGfYvo",
1636 testNetwork(done, params);
1638 it('Allows selection
of EtherCore
', function(done) {
1640 selectText: "ERE - EtherCore",
1641 firstAddress: "0x119e6EAC3Ce1b473D62d9fD847fb0ea222eF1D9e",
1643 testNetwork(done, params);
1645 it('Allows selection
of RBTC
- RSK
', function(done) {
1647 selectText: "RBTC - RSK",
1648 firstAddress: "RGtz5TDdtviAZ9haz1YAUNQzcGVFm5bQrP",
1650 testNetwork(done, params);
1652 it('Allows selection
of tRBTC
- RSK Testnet
', function(done) {
1654 selectText: "tRBTC - RSK Testnet",
1655 firstAddress: "RHkrWgnSdJHxQAqEsMErhUUa4icXY6xUUC",
1657 testNetwork(done, params);
1660 // BIP39 seed is set from phrase
1661 it('Sets the bip39 seed
from the prhase
', function(done) {
1662 driver.findElement(By.css('.phrase
'))
1663 .sendKeys('abandon abandon ability
');
1664 driver.sleep(generateDelay).then(function() {
1665 driver.findElement(By.css('.seed
'))
1666 .getAttribute("value")
1667 .then(function(seed) {
1668 expect(seed).toBe("20da140d3dd1df8713cefcc4d54ce0e445b4151027a1ab567b832f6da5fcc5afc1c3a3f199ab78b8e0ab4652efd7f414ac2c9a3b81bceb879a70f377aa0a58f3");
1674 // BIP32 root key is set from phrase
1675 it('Sets the bip39 root key
from the prhase
', function(done) {
1676 driver.findElement(By.css('.phrase
'))
1677 .sendKeys('abandon abandon ability
');
1678 driver.sleep(generateDelay).then(function() {
1679 driver.findElement(By.css('.root
-key
'))
1680 .getAttribute("value")
1681 .then(function(seed) {
1682 expect(seed).toBe("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi");
1688 // Tabs show correct addresses when changed
1689 it('Shows the correct address when tab is changed
', function(done) {
1690 driver.findElement(By.css('.phrase
'))
1691 .sendKeys('abandon abandon ability
');
1692 driver.sleep(generateDelay).then(function() {
1693 driver.findElement(By.css('#bip32
-tab a
'))
1695 driver.sleep(generateDelay).then(function() {
1696 getFirstAddress(function(address) {
1697 expect(address).toBe("17uQ7s2izWPwBmEVFikTmZUjbBKWYdJchz");
1704 // BIP44 derivation path is shown
1705 it('Shows the derivation path
for bip44 tab
', function(done) {
1706 driver.findElement(By.css('.phrase
'))
1707 .sendKeys('abandon abandon ability
');
1708 driver.sleep(generateDelay).then(function() {
1709 driver.findElement(By.css('#bip44
.path
'))
1710 .getAttribute("value")
1711 .then(function(path) {
1712 expect(path).toBe("m/44'/0'/0'/0");
1718 // BIP44 extended private key is shown
1719 it('Shows the extended private key for bip44 tab', function(done) {
1720 driver.findElement(By.css('.phrase'))
1721 .sendKeys('abandon abandon ability');
1722 driver.sleep(generateDelay).then(function() {
1723 driver.findElement(By.css('.extended-priv-key'))
1724 .getAttribute("value
")
1725 .then(function(path) {
1726 expect(path).toBe("xprvA2DxxvPZcyRvYgZMGS53nadR32mVDeCyqQYyFhrCVbJNjPoxMeVf7QT5g7mQASbTf9Kp4cryvcXnu2qurjWKcrdsr91jXymdCDNxKgLFKJG
");
1732 // BIP44 extended public key is shown
1733 it('Shows the extended public key for bip44 tab', function(done) {
1734 driver.findElement(By.css('.phrase'))
1735 .sendKeys('abandon abandon ability');
1736 driver.sleep(generateDelay).then(function() {
1737 driver.findElement(By.css('.extended-pub-key'))
1738 .getAttribute("value
")
1739 .then(function(path) {
1740 expect(path).toBe("xpub6FDKNRvTTLzDmAdpNTc49ia9b4byd6vqCdUa46Fp3vqMcC96uBoufCmZXQLiN5AK3iSCJMhf9gT2sxkpyaPepRuA7W3MujV5tGmF5VfbueM
");
1746 // BIP44 account field changes address list
1747 it('Changes the address list if bip44 account is changed', function(done) {
1748 driver.findElement(By.css('#bip44 .account'))
1750 driver.findElement(By.css('.phrase'))
1751 .sendKeys('abandon abandon ability');
1752 driver.sleep(generateDelay).then(function() {
1753 getFirstAddress(function(address) {
1754 expect(address).toBe("1Nq2Wmu726XHCuGhctEtGmhxo3wzk5wZ1H
");
1760 // BIP44 change field changes address list
1761 it('Changes the address list if bip44 change is changed', function(done) {
1762 driver.findElement(By.css('#bip44 .change'))
1764 driver.findElement(By.css('.phrase'))
1765 .sendKeys('abandon abandon ability');
1766 driver.sleep(generateDelay).then(function() {
1767 getFirstAddress(function(address) {
1768 expect(address).toBe("1KAGfWgqfVbSSXY56fNQ7YnhyKuoskHtYo
");
1774 // BIP32 derivation path can be set
1775 it('Can use a custom bip32 derivation path', function(done) {
1776 driver.findElement(By.css('#bip32-tab a'))
1778 driver.findElement(By.css('#bip32 .path'))
1780 driver.findElement(By.css('#bip32 .path'))
1782 driver.findElement(By.css('.phrase'))
1783 .sendKeys('abandon abandon ability');
1784 driver.sleep(generateDelay).then(function() {
1785 getFirstAddress(function(address) {
1786 expect(address).toBe("16pYQQdLD1hH4hwTGLXBaZ9Teboi1AGL8L
");
1792 // BIP32 can use hardened derivation paths
1793 it('Can use a hardened derivation paths', function(done) {
1794 driver.findElement(By.css('#bip32-tab a'))
1796 driver.findElement(By.css('#bip32 .path'))
1798 driver.findElement(By.css('#bip32 .path'))
1800 driver.findElement(By.css('.phrase
'))
1801 .sendKeys('abandon abandon ability
');
1802 driver.sleep(generateDelay).then(function() {
1803 getFirstAddress(function(address) {
1804 expect(address).toBe("14aXZeprXAE3UUKQc4ihvwBvww2LuEoHo4");
1810 // BIP32 extended private key is shown
1811 it('Shows the BIP32 extended
private key
', function(done) {
1812 driver.findElement(By.css('#bip32
-tab a
'))
1814 driver.findElement(By.css('.phrase
'))
1815 .sendKeys('abandon abandon ability
');
1816 driver.sleep(generateDelay).then(function() {
1817 driver.findElement(By.css('.extended
-priv
-key
'))
1818 .getAttribute("value")
1819 .then(function(privKey) {
1820 expect(privKey).toBe("xprv9va99uTVE5aLiutUVLTyfxfe8v8aaXjSQ1XxZbK6SezYVuikA9MnjQVTA8rQHpNA5LKvyQBpLiHbBQiiccKiBDs7eRmBogsvq3THFeLHYbe");
1826 // BIP32 extended public key is shown
1827 it('Shows the BIP32 extended
public key
', function(done) {
1828 driver.findElement(By.css('#bip32
-tab a
'))
1830 driver.findElement(By.css('.phrase
'))
1831 .sendKeys('abandon abandon ability
');
1832 driver.sleep(generateDelay).then(function() {
1833 driver.findElement(By.css('.extended
-pub
-key
'))
1834 .getAttribute("value")
1835 .then(function(pubKey) {
1836 expect(pubKey).toBe("xpub69ZVZQzP4T8dwPxwbMzz36cNgwy4yzTHmETZMyihzzXXNi3thgg3HCow1RtY252wdw5rS8369xKnraN5Q93y3FkFfJp2XEHWUrkyXsjS93P");
1842 // Derivation path is shown in table
1843 it('Shows the derivation path
in the table
', function(done) {
1844 driver.findElement(By.css('.phrase
'))
1845 .sendKeys('abandon abandon ability
');
1846 driver.sleep(generateDelay).then(function() {
1847 getFirstPath(function(path) {
1848 expect(path).toBe("m/44'/0'/0'/0/0");
1854 // Derivation path for address can be hardened
1855 it('Can derive hardened addresses', function(done) {
1856 driver.findElement(By.css('#bip32-tab a'))
1858 driver.executeScript(function() {
1859 $(".hardened
-addresses
").prop("checked
", true);
1861 driver.findElement(By.css('.phrase'))
1862 .sendKeys('abandon abandon ability');
1863 driver.sleep(generateDelay).then(function() {
1864 getFirstAddress(function(address) {
1865 expect(address).toBe("18exLzUv7kfpiXRzmCjFDoC9qwNLFyvwyd
");
1871 // Derivation path visibility can be toggled
1872 it('Can toggle visibility of the derivation path column', function(done) {
1873 driver.findElement(By.css('.phrase'))
1874 .sendKeys('abandon abandon ability');
1875 driver.sleep(generateDelay).then(function() {
1876 driver.findElement(By.css('.index-toggle'))
1878 testColumnValuesAreInvisible(done, "index
");
1883 it('Shows the address in the table', function(done) {
1884 driver.findElement(By.css('.phrase'))
1885 .sendKeys('abandon abandon ability');
1886 driver.sleep(generateDelay).then(function() {
1887 getFirstAddress(function(address) {
1888 expect(address).toBe("1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug
");
1894 // Addresses are shown in order of derivation path
1895 it('Shows the address in order of derivation path', function(done) {
1896 driver.findElement(By.css('.phrase'))
1897 .sendKeys('abandon abandon ability');
1898 driver.sleep(generateDelay).then(function() {
1899 testRowsAreInCorrectOrder(done);
1903 // Address visibility can be toggled
1904 it('Can toggle visibility of the address column', function(done) {
1905 driver.findElement(By.css('.phrase'))
1906 .sendKeys('abandon abandon ability');
1907 driver.sleep(generateDelay).then(function() {
1908 driver.findElement(By.css('.address-toggle'))
1910 testColumnValuesAreInvisible(done, "address
");
1914 // Public key is shown in table
1915 it('Shows the public key in the table', function(done) {
1916 driver.findElement(By.css('.phrase'))
1917 .sendKeys('abandon abandon ability');
1918 driver.sleep(generateDelay).then(function() {
1919 driver.findElements(By.css('.pubkey'))
1920 .then(function(els) {
1922 .then(function(pubkey) {
1923 expect(pubkey).toBe("033f5aed5f6cfbafaf223188095b5980814897295f723815fea5d3f4b648d0d0b3
");
1930 // Public key visibility can be toggled
1931 it('Can toggle visibility of the public key column', function(done) {
1932 driver.findElement(By.css('.phrase'))
1933 .sendKeys('abandon abandon ability');
1934 driver.sleep(generateDelay).then(function() {
1935 driver.findElement(By.css('.public-key-toggle'))
1937 testColumnValuesAreInvisible(done, "pubkey
");
1941 // Private key is shown in table
1942 it('Shows the private key in the table', function(done) {
1943 driver.findElement(By.css('.phrase'))
1944 .sendKeys('abandon abandon ability');
1945 driver.sleep(generateDelay).then(function() {
1946 driver.findElements(By.css('.privkey'))
1947 .then(function(els) {
1949 .then(function(pubkey) {
1950 expect(pubkey).toBe("L26cVSpWFkJ6aQkPkKmTzLqTdLJ923e6CzrVh9cmx21QHsoUmrEE
");
1957 // Private key visibility can be toggled
1958 it('Can toggle visibility of the private key column', function(done) {
1959 driver.findElement(By.css('.phrase'))
1960 .sendKeys('abandon abandon ability');
1961 driver.sleep(generateDelay).then(function() {
1962 driver.findElement(By.css('.private-key-toggle'))
1964 testColumnValuesAreInvisible(done, "privkey
");
1968 // More addresses can be generated
1969 it('Can generate more rows in the table', function(done) {
1970 driver.findElement(By.css('.phrase'))
1971 .sendKeys('abandon abandon ability');
1972 driver.sleep(generateDelay).then(function() {
1973 driver.findElement(By.css('.more'))
1975 driver.sleep(generateDelay).then(function() {
1976 driver.findElements(By.css('.address'))
1977 .then(function(els) {
1978 expect(els.length).toBe(40);
1985 // A custom number of additional addresses can be generated
1986 it('Can generate more rows in the table', function(done) {
1987 driver.findElement(By.css('.phrase'))
1988 .sendKeys('abandon abandon ability');
1989 driver.sleep(generateDelay).then(function() {
1990 driver.findElement(By.css('.rows-to-add'))
1992 driver.findElement(By.css('.rows-to-add'))
1994 driver.findElement(By.css('.more'))
1996 driver.sleep(generateDelay).then(function() {
1997 driver.findElements(By.css('.address'))
1998 .then(function(els) {
1999 expect(els.length).toBe(21);
2006 // Additional addresses are shown in order of derivation path
2007 it('Shows additional addresses in order of derivation path', function(done) {
2008 driver.findElement(By.css('.phrase'))
2009 .sendKeys('abandon abandon ability');
2010 driver.sleep(generateDelay).then(function() {
2011 driver.findElement(By.css('.more'))
2013 driver.sleep(generateDelay).then(function() {
2014 testRowsAreInCorrectOrder(done);
2019 // BIP32 root key can be set by the user
2020 it('Allows the user to set the BIP32 root key', function(done) {
2021 driver.findElement(By.css('.root-key'))
2022 .sendKeys('xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi');
2023 driver.sleep(generateDelay).then(function() {
2024 getFirstAddress(function(address) {
2025 expect(address).toBe("1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug
");
2031 // Setting BIP32 root key clears the existing phrase, passphrase and seed
2032 it('Confirms the existing phrase should be cleared', function(done) {
2033 driver.findElement(By.css('.phrase'))
2034 .sendKeys('A non-blank but invalid value');
2035 driver.findElement(By.css('.root-key'))
2036 .sendKeys('xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi');
2037 driver.switchTo().alert().accept();
2038 driver.findElement(By.css('.phrase'))
2039 .getAttribute("value
").then(function(value) {
2040 expect(value).toBe("");
2045 // Clearing of phrase, passphrase and seed can be cancelled by user
2046 it('Allows the clearing of the phrase to be cancelled', function(done) {
2047 driver.findElement(By.css('.phrase'))
2048 .sendKeys('abandon abandon ability');
2049 driver.sleep(generateDelay).then(function() {
2050 driver.findElement(By.css('.root-key'))
2052 driver.findElement(By.css('.root-key'))
2054 driver.switchTo().alert().dismiss();
2055 driver.findElement(By.css('.phrase'))
2056 .getAttribute("value
").then(function(value) {
2057 expect(value).toBe("abandon abandon ability
");
2063 // Custom BIP32 root key is used when changing the derivation path
2064 it('Can set derivation path for root key instead of phrase', function(done) {
2065 driver.findElement(By.css('#bip44 .account'))
2067 driver.findElement(By.css('.root-key'))
2068 .sendKeys('xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi');
2069 driver.sleep(generateDelay).then(function() {
2070 getFirstAddress(function(address) {
2071 expect(address).toBe("1Nq2Wmu726XHCuGhctEtGmhxo3wzk5wZ1H
");
2077 // Incorrect mnemonic shows error
2078 it('Shows an error for incorrect mnemonic', function(done) {
2079 driver.findElement(By.css('.phrase'))
2080 .sendKeys('abandon abandon abandon');
2081 driver.sleep(feedbackDelay).then(function() {
2082 driver.findElement(By.css('.feedback'))
2084 .then(function(feedback) {
2085 expect(feedback).toBe("Invalid mnemonic
");
2091 // Incorrect word shows suggested replacement
2092 it('Shows word suggestion for incorrect word', function(done) {
2093 driver.findElement(By.css('.phrase'))
2094 .sendKeys('abandon abandon abiliti');
2095 driver.sleep(feedbackDelay).then(function() {
2096 driver.findElement(By.css('.feedback'))
2098 .then(function(feedback) {
2099 var msg = "abiliti not
in wordlist
, did you mean ability
?";
2100 expect(feedback).toBe(msg);
2106 // Github pull request 48
2107 // First four letters of word shows that word, not closest
2108 // since first four letters gives unique word in BIP39 wordlist
2109 // eg ille should show illegal, not idle
2110 it('Shows word suggestion based on first four chars', function(done) {
2111 driver.findElement(By.css('.phrase'))
2113 driver.sleep(feedbackDelay).then(function() {
2114 driver.findElement(By.css('.feedback'))
2116 .then(function(feedback) {
2117 var msg = "ille not
in wordlist
, did you mean illegal
?";
2118 expect(feedback).toBe(msg);
2124 // Incorrect BIP32 root key shows error
2125 it('Shows error for incorrect root key', function(done) {
2126 driver.findElement(By.css('.root-key'))
2127 .sendKeys('xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpj');
2128 driver.sleep(feedbackDelay).then(function() {
2129 driver.findElement(By.css('.feedback'))
2131 .then(function(feedback) {
2132 var msg = "Invalid root key
";
2133 expect(feedback).toBe(msg);
2139 // Derivation path not starting with m shows error
2140 it('Shows error for derivation path not starting with m', function(done) {
2141 driver.findElement(By.css('#bip32-tab a'))
2143 driver.findElement(By.css('#bip32 .path'))
2145 driver.findElement(By.css('#bip32 .path'))
2147 driver.findElement(By.css('.phrase'))
2148 .sendKeys('abandon abandon ability');
2149 driver.sleep(feedbackDelay).then(function() {
2150 driver.findElement(By.css('.feedback'))
2152 .then(function(feedback) {
2153 var msg = "First character must be
'm'";
2154 expect(feedback).toBe(msg);
2160 // Derivation path containing invalid characters shows useful error
2161 it('Shows error for derivation path not starting with m', function(done) {
2162 driver.findElement(By.css('#bip32-tab a'))
2164 driver.findElement(By.css('#bip32 .path'))
2166 driver.findElement(By.css('#bip32 .path'))
2167 .sendKeys('m/1/0wrong1/1');
2168 driver.findElement(By.css('.phrase'))
2169 .sendKeys('abandon abandon ability');
2170 driver.sleep(feedbackDelay).then(function() {
2171 driver.findElement(By.css('.feedback'))
2173 .then(function(feedback) {
2174 var msg = "Invalid characters
0wrong1 found at depth
2";
2175 expect(feedback).toBe(msg);
2181 // Github Issue 11: Default word length is 15
2182 // https://github.com/iancoleman/bip39/issues/11
2183 it('Sets the default word length to 15', function(done) {
2184 driver.findElement(By.css('.strength'))
2185 .getAttribute("value
")
2186 .then(function(strength) {
2187 expect(strength).toBe("15");
2192 // Github Issue 12: Generate more rows with private keys hidden
2193 // https://github.com/iancoleman/bip39/issues/12
2194 it('Sets the correct hidden column state on new rows', function(done) {
2195 driver.findElement(By.css('.phrase'))
2196 .sendKeys("abandon abandon ability
");
2197 driver.sleep(generateDelay).then(function() {
2198 driver.findElement(By.css('.private-key-toggle'))
2200 driver.findElement(By.css('.more'))
2202 driver.sleep(generateDelay).then(function() {
2203 driver.findElements(By.css('.privkey'))
2204 .then(function(els) {
2205 expect(els.length).toBe(40);
2207 testColumnValuesAreInvisible(done, "privkey
");
2212 // Github Issue 19: Mnemonic is not sensitive to whitespace
2213 // https://github.com/iancoleman/bip39/issues/19
2214 it('Ignores excess whitespace in the mnemonic', function(done) {
2215 var doublespace = " ";
2216 var mnemonic = "urge cat
" + doublespace + "bid
";
2217 driver.findElement(By.css('.phrase'))
2218 .sendKeys(mnemonic);
2219 driver.sleep(generateDelay).then(function() {
2220 driver.findElement(By.css('.root-key'))
2221 .getAttribute("value
")
2222 .then(function(seed) {
2223 expect(seed).toBe("xprv9s21ZrQH143K3isaZsWbKVoTtbvd34Y1ZGRugGdMeBGbM3AgBVzTH159mj1cbbtYSJtQr65w6L5xy5L9SFC7c9VJZWHxgAzpj4mun5LhrbC
");
2229 // Github Issue 23: Part 1: Use correct derivation path when changing tabs
2230 // https://github.com/iancoleman/bip39/issues/23
2231 // This test was failing for default timeout of 5000ms so changed it to +10s
2232 it('Uses the correct derivation path when changing tabs', function(done) {
2233 // 1) and 2) set the phrase
2234 driver.findElement(By.css('.phrase'))
2235 .sendKeys("abandon abandon ability
");
2236 driver.sleep(generateDelay).then(function() {
2237 // 3) select bip32 tab
2238 driver.findElement(By.css('#bip32-tab a'))
2240 driver.sleep(generateDelay).then(function() {
2241 // 4) switch from bitcoin to litecoin
2242 selectNetwork("LTC
- Litecoin
");
2243 driver.sleep(generateDelay).then(function() {
2244 // 5) Check address is displayed correctly
2245 getFirstAddress(function(address) {
2246 expect(address).toBe("LS8MP5LZ5AdzSZveRrjm3aYVoPgnfFh5T5
");
2247 // 5) Check derivation path is displayed correctly
2248 getFirstPath(function(path) {
2249 expect(path).toBe("m
/0/0");
2256 }, generateDelay + 10000);
2258 // Github Issue 23 Part 2: Coin selection in derivation path
2259 // https://github.com/iancoleman/bip39/issues/23#issuecomment-238011920
2260 it('Uses the correct derivation path when changing coins', function(done) {
2262 driver.findElement(By.css('.phrase'))
2263 .sendKeys("abandon abandon ability
");
2264 driver.sleep(generateDelay).then(function() {
2265 // switch from bitcoin to clam
2266 selectNetwork("CLAM
- Clams
");
2267 driver.sleep(generateDelay).then(function() {
2268 // check derivation path is displayed correctly
2269 getFirstPath(function(path) {
2270 expect(path).toBe("m
/44'/23'/0'/0/0");
2277 // Github Issue 26: When using a Root key derrived altcoins are incorrect
2278 // https://github.com/iancoleman/bip39/issues/26
2279 it('Uses the correct derivation for altcoins with root keys', function(done) {
2280 // 1) 2) and 3) set the root key
2281 driver.findElement(By.css('.root-key'))
2282 .sendKeys("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi
");
2283 driver.sleep(generateDelay).then(function() {
2284 // 4) switch from bitcoin to viacoin
2285 selectNetwork("VIA
- Viacoin
");
2286 driver.sleep(generateDelay).then(function() {
2287 // 5) ensure the derived address is correct
2288 getFirstAddress(function(address) {
2289 expect(address).toBe("Vq9Eq4N5SQnjqZvxtxzo7hZPW5XnyJsmXT
");
2296 // Selecting a language with no existing phrase should generate a phrase in
2298 it('Generate a random phrase when language is selected and no current phrase', function(done) {
2299 driver.findElement(By.css("a
[href
='#japanese']"))
2301 driver.sleep(generateDelay).then(function() {
2302 driver.findElement(By.css(".phrase
"))
2303 .getAttribute("value
").then(function(phrase) {
2304 expect(phrase.search(/[a-z]/)).toBe(-1);
2305 expect(phrase.length).toBeGreaterThan(0);
2311 // Selecting a language with existing phrase should update the phrase to use
2313 it('Updates existing phrases when the language is changed', function(done) {
2314 driver.findElement(By.css(".phrase
"))
2315 .sendKeys("abandon abandon ability
");
2316 driver.sleep(generateDelay).then(function() {
2317 driver.findElement(By.css("a
[href
='#italian']"))
2319 driver.sleep(generateDelay).then(function() {
2320 driver.findElement(By.css(".phrase
"))
2321 .getAttribute("value
").then(function(phrase) {
2322 // Check only the language changes, not the phrase
2323 expect(phrase).toBe("abaco abaco abbaglio
");
2324 getFirstAddress(function(address) {
2325 // Check the address is correct
2326 expect(address).toBe("1Dz5TgDhdki9spa6xbPFbBqv5sjMrx3xgV
");
2334 // Suggested replacement for erroneous word in non-English language
2335 it('Shows word suggestion for incorrect word in non-English language', function(done) {
2336 driver.findElement(By.css('.phrase'))
2337 .sendKeys('abaco abaco zbbaglio');
2338 driver.sleep(feedbackDelay).then(function() {
2339 driver.findElement(By.css('.feedback'))
2341 .then(function(feedback) {
2342 var msg = "zbbaglio not
in wordlist
, did you mean abbaglio
?";
2343 expect(feedback).toBe(msg);
2349 // Japanese word does not break across lines.
2351 // https://github.com/bitcoin/bips/blob/master/bip-0039/bip-0039-wordlists.md#japanese
2352 it('Does not break Japanese words across lines', function(done) {
2353 driver.findElement(By.css('.phrase'))
2354 .getCssValue("word
-break")
2355 .then(function(value) {
2356 expect(value).toBe("keep
-all
");
2361 // Language can be specified at page load using hash value in url
2362 it('Can set the language from the url hash', function(done) {
2363 driver.get(url + "#japanese
").then(function() {
2364 driver.findElement(By.css('.generate')).click();
2365 driver.sleep(generateDelay).then(function() {
2366 driver.findElement(By.css(".phrase
"))
2367 .getAttribute("value
").then(function(phrase) {
2368 expect(phrase.search(/[a-z]/)).toBe(-1);
2369 expect(phrase.length).toBeGreaterThan(0);
2376 // Entropy can be entered by the user
2377 it('Allows entropy to be entered', function(done) {
2378 driver.findElement(By.css('.use-entropy'))
2380 driver.findElement(By.css('.entropy'))
2381 .sendKeys('00000000 00000000 00000000 00000000');
2382 driver.sleep(generateDelay).then(function() {
2383 driver.findElement(By.css(".phrase
"))
2384 .getAttribute("value
").then(function(phrase) {
2385 expect(phrase).toBe("abandon abandon ability
");
2386 getFirstAddress(function(address) {
2387 expect(address).toBe("1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug
");
2394 // A warning about entropy is shown to the user, with additional information
2395 it('Shows a warning about using entropy', function(done) {
2396 driver.findElement(By.css('.use-entropy'))
2398 driver.findElement(By.css('.entropy-container'))
2400 .then(function(containerText) {
2401 var warning = "mnemonic may be insecure
";
2402 expect(containerText).toContain(warning);
2403 driver.findElement(By.css('#entropy-notes'))
2404 .findElement(By.xpath("parent::*"))
2406 .then(function(notesText) {
2407 var detail = "flipping a fair coin
, rolling a fair dice
, noise measurements etc
";
2408 expect(notesText).toContain(detail);
2414 // The types of entropy available are described to the user
2415 it('Shows the types of entropy available', function(done) {
2416 driver.findElement(By.css('.entropy'))
2417 .getAttribute("placeholder
")
2418 .then(function(placeholderText) {
2427 for (var i=0; i<options.length; i++) {
2428 var option = options[i];
2429 expect(placeholderText).toContain(option);
2435 // The actual entropy used is shown to the user
2436 it('Shows the actual entropy used', function(done) {
2437 driver.findElement(By.css('.use-entropy'))
2439 driver.findElement(By.css('.entropy'))
2440 .sendKeys('Not A Very Good Entropy Source At All');
2441 driver.sleep(generateDelay).then(function() {
2442 driver.findElement(By.css('.entropy-container'))
2444 .then(function(text) {
2445 expect(text).toMatch(/Filtered Entropy\s+AedEceAA/);
2451 // Binary entropy can be entered
2452 it('Allows binary entropy to be entered', function(done) {
2453 testEntropyType(done, "01", "binary
");
2456 // Base 6 entropy can be entered
2457 it('Allows base 6 entropy to be entered', function(done) {
2458 testEntropyType(done, "012345", "base
6");
2461 // Base 6 dice entropy can be entered
2462 it('Allows base 6 dice entropy to be entered', function(done) {
2463 testEntropyType(done, "123456", "base
6 (dice
)");
2466 // Base 10 entropy can be entered
2467 it('Allows base 10 entropy to be entered', function(done) {
2468 testEntropyType(done, "789", "base
10");
2471 // Hexadecimal entropy can be entered
2472 it('Allows hexadecimal entropy to be entered', function(done) {
2473 testEntropyType(done, "abcdef
", "hexadecimal
");
2476 // Dice entropy value is shown as the converted base 6 value
2477 // ie 123456 is converted to 123450
2478 it('Shows dice entropy as base 6', function(done) {
2479 driver.findElement(By.css('.use-entropy'))
2481 driver.findElement(By.css('.entropy'))
2482 .sendKeys("123456");
2483 driver.sleep(generateDelay).then(function() {
2484 driver.findElement(By.css('.entropy-container'))
2486 .then(function(text) {
2487 expect(text).toMatch(/Filtered Entropy\s+123450/);
2493 // The number of bits of entropy accumulated is shown
2494 it("Shows the number
of bits
of entropy
for 20 bits
of binary
", function(done) {
2495 testEntropyBits(done, "0000 0000 0000 0000 0000", "20");
2497 it("Shows the number
of bits
of entropy
for 1 bit
of binary
", function(done) {
2498 testEntropyBits(done, "0", "1");
2500 it("Shows the number
of bits
of entropy
for 4 bits
of binary
", function(done) {
2501 testEntropyBits(done, "0000", "4");
2503 it("Shows the number
of bits
of entropy
for 1 character
of base
6 (dice
)", function(done) {
2504 // 6 in card is 0 in base 6, 0 in base 6 is 2.6 bits (rounded down to 2 bits)
2505 testEntropyBits(done, "6", "2");
2507 it("Shows the number
of bits
of entropy
for 1 character
of base
10 with 3 bits
", function(done) {
2508 // 7 in base 10 is 111 in base 2, no leading zeros
2509 testEntropyBits(done, "7", "3");
2511 it("Shows the number
of bits
of entropy
for 1 character
of base
10 with 4 bis
", function(done) {
2512 testEntropyBits(done, "8", "4");
2514 it("Shows the number
of bits
of entropy
for 1 character
of hex
", function(done) {
2515 testEntropyBits(done, "F
", "4");
2517 it("Shows the number
of bits
of entropy
for 2 characters
of base
10", function(done) {
2518 testEntropyBits(done, "29", "6");
2520 it("Shows the number
of bits
of entropy
for 2 characters
of hex
", function(done) {
2521 testEntropyBits(done, "0A
", "8");
2523 it("Shows the number
of bits
of entropy
for 2 characters
of hex
with 3 leading zeros
", function(done) {
2524 // hex is always multiple of 4 bits of entropy
2525 testEntropyBits(done, "1A
", "8");
2527 it("Shows the number
of bits
of entropy
for 2 characters
of hex
with 2 leading zeros
", function(done) {
2528 testEntropyBits(done, "2A
", "8");
2530 it("Shows the number
of bits
of entropy
for 2 characters
of hex
with 1 leading zero
", function(done) {
2531 testEntropyBits(done, "4A
", "8");
2533 it("Shows the number
of bits
of entropy
for 2 characters
of hex
with no leading zeros
", function(done) {
2534 testEntropyBits(done, "8A
", "8");
2536 it("Shows the number
of bits
of entropy
for 2 characters
of hex starting
with F
", function(done) {
2537 testEntropyBits(done, "FA
", "8");
2539 it("Shows the number
of bits
of entropy
for 4 characters
of hex
with leading zeros
", function(done) {
2540 testEntropyBits(done, "000A
", "16");
2542 it("Shows the number
of bits
of entropy
for 4 characters
of base
6", function(done) {
2543 testEntropyBits(done, "5555", "11");
2545 it("Shows the number
of bits
of entropy
for 4 characters
of base
6 dice
", function(done) {
2546 // uses dice, so entropy is actually 0000 in base 6, which is 4 lots of
2547 // 2.58 bits, which is 10.32 bits (rounded down to 10 bits)
2548 testEntropyBits(done, "6666", "10");
2550 it("Shows the number
of bits
of entropy
for 4 charactes
of base
10", function(done) {
2551 // Uses base 10, which is 4 lots of 3.32 bits, which is 13.3 bits (rounded
2553 testEntropyBits(done, "2227", "13");
2555 it("Shows the number
of bits
of entropy
for 4 characters
of hex
with 2 leading zeros
", function(done) {
2556 testEntropyBits(done, "222F
", "16");
2558 it("Shows the number
of bits
of entropy
for 4 characters
of hex starting
with F
", function(done) {
2559 testEntropyBits(done, "FFFF
", "16");
2561 it("Shows the number
of bits
of entropy
for 10 characters
of base
10", function(done) {
2562 // 10 events at 3.32 bits per event
2563 testEntropyBits(done, "0000101017", "33");
2565 it("Shows the number
of bits
of entropy
for a full deck
of cards
", function(done) {
2566 // cards are not replaced, so a full deck is not 52^52 entropy which is 296
2567 // bits, it's 52!, which is 225 bits
2568 testEntropyBits(done, "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks
", "225");
2571 it("Shows details about the entered entropy
", function(done) {
2572 testEntropyFeedback(done,
2576 type: "hexadecimal
",
2580 strength: "less than a second
",
2584 it("Shows details about the entered entropy
", function(done) {
2585 testEntropyFeedback(done,
2587 entropy: "AAAAAAAA
",
2588 filtered: "AAAAAAAA
",
2589 type: "hexadecimal
",
2593 strength: "less than a second
- Repeats like
\"aaa
\" are easy to guess
",
2597 it("Shows details about the entered entropy
", function(done) {
2598 testEntropyFeedback(done,
2600 entropy: "AAAAAAAA B
",
2601 filtered: "AAAAAAAAB
",
2602 type: "hexadecimal
",
2606 strength: "less than a second
- Repeats like
\"aaa
\" are easy to guess
",
2610 it("Shows details about the entered entropy
", function(done) {
2611 testEntropyFeedback(done,
2613 entropy: "AAAAAAAA BBBBBBBB
",
2614 filtered: "AAAAAAAABBBBBBBB
",
2615 type: "hexadecimal
",
2619 strength: "less than a second
- Repeats like
\"aaa
\" are easy to guess
",
2623 it("Shows details about the entered entropy
", function(done) {
2624 testEntropyFeedback(done,
2626 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC
",
2627 filtered: "AAAAAAAABBBBBBBBCCCCCCCC
",
2628 type: "hexadecimal
",
2632 strength: "less than a second
",
2636 it("Shows details about the entered entropy
", function(done) {
2637 testEntropyFeedback(done,
2639 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD
",
2640 filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD
",
2641 type: "hexadecimal
",
2645 strength: "2 minutes
",
2649 it("Shows details about the entered entropy
", function(done) {
2650 testEntropyFeedback(done,
2652 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDA
",
2653 filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDA
",
2654 type: "hexadecimal
",
2662 it("Shows details about the entered entropy
", function(done) {
2663 testEntropyFeedback(done,
2665 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDA EEEEEEEE
",
2666 filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDAEEEEEEEE
",
2667 type: "hexadecimal
",
2671 strength: "3 years
",
2675 it("Shows details about the entered entropy
", function(done) {
2676 testEntropyFeedback(done,
2678 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDA EEEEEEEE FFFFFFFF
",
2679 filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDAEEEEEEEEFFFFFFFF
",
2680 type: "hexadecimal
",
2684 strength: "centuries
",
2688 it("Shows details about the entered entropy
", function(done) {
2689 testEntropyFeedback(done,
2696 strength: "less than a second
",
2700 it("Shows details about the entered entropy
", function(done) {
2701 testEntropyFeedback(done,
2703 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks
",
2704 type: "card (full deck
)",
2708 strength: "centuries
",
2712 it("Shows details about the entered entropy
", function(done) {
2713 testEntropyFeedback(done,
2715 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks3d
",
2716 type: "card (full deck
, 1 duplicate: 3d
)",
2720 strength: "centuries
",
2724 it("Shows details about the entered entropy
", function(done) {
2725 testEntropyFeedback(done,
2727 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqs3d4d
",
2728 type: "card (2 duplicates: 3d
4d
, 1 missing: KS
)",
2732 strength: "centuries
",
2736 it("Shows details about the entered entropy
", function(done) {
2737 testEntropyFeedback(done,
2739 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqs3d4d5d6d
",
2740 type: "card (4 duplicates: 3d
4d
5d
..., 1 missing: KS
)",
2744 strength: "centuries
",
2748 it("Shows details about the entered entropy
", function(done) {
2749 testEntropyFeedback(done,
2750 // Next test was throwing uncaught error in zxcvbn
2751 // Also tests 451 bits, ie Math.log2(52!)*2 = 225.58 * 2
2753 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsksac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks
",
2754 type: "card (full deck
, 52 duplicates: ac
2c
3c
...)",
2758 strength: "centuries
",
2762 it("Shows details about the entered entropy
", function(done) {
2763 testEntropyFeedback(done,
2764 // Case insensitivity to duplicate cards
2767 type: "card (1 duplicate: AS
)",
2771 strength: "less than a second
",
2775 it("Shows details about the entered entropy
", function(done) {
2776 testEntropyFeedback(done,
2779 type: "card (1 duplicate: as
)",
2783 strength: "less than a second
",
2787 it("Shows details about the entered entropy
", function(done) {
2788 testEntropyFeedback(done,
2789 // Missing cards are detected
2791 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks
",
2792 type: "card (1 missing: 9C
)",
2796 strength: "centuries
",
2800 it("Shows details about the entered entropy
", function(done) {
2801 testEntropyFeedback(done,
2803 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d
6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks
",
2804 type: "card (2 missing: 9C
5D
)",
2808 strength: "centuries
",
2812 it("Shows details about the entered entropy
", function(done) {
2813 testEntropyFeedback(done,
2815 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d
6d7d8d9dtdjd kdah2h3h
5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks
",
2816 type: "card (4 missing: 9C
5D QD
...)",
2820 strength: "centuries
",
2824 it("Shows details about the entered entropy
", function(done) {
2825 testEntropyFeedback(done,
2826 // More than six missing cards does not show message
2828 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d
6d
8d9d jd kdah2h3h
5h6h7h8h9hthjhqhkh
2s3s4s5s6s7s8s9stsjsqsks
",
2833 strength: "centuries
",
2837 it("Shows details about the entered entropy
", function(done) {
2838 testEntropyFeedback(done,
2839 // Multiple decks of cards increases bits per event
2844 bitsPerEvent: "4.34",
2848 it("Shows details about the entered entropy
", function(done) {
2849 testEntropyFeedback(done,
2854 bitsPerEvent: "4.80",
2858 it("Shows details about the entered entropy
", function(done) {
2859 testEntropyFeedback(done,
2864 bitsPerEvent: "5.01",
2868 it("Shows details about the entered entropy
", function(done) {
2869 testEntropyFeedback(done,
2871 entropy: "3d3d3d3d
",
2874 bitsPerEvent: "5.14",
2878 it("Shows details about the entered entropy
", function(done) {
2879 testEntropyFeedback(done,
2881 entropy: "3d3d3d3d3d
",
2884 bitsPerEvent: "5.22",
2888 it("Shows details about the entered entropy
", function(done) {
2889 testEntropyFeedback(done,
2891 entropy: "3d3d3d3d3d3d
",
2894 bitsPerEvent: "5.28",
2898 it("Shows details about the entered entropy
", function(done) {
2899 testEntropyFeedback(done,
2901 entropy: "3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d
",
2904 bitsPerEvent: "5.59",
2905 strength: 'less than a second - Repeats like "abcabcabc
" are only slightly harder to guess than "abc
"',
2910 // Entropy is truncated from the left
2911 it('Truncates entropy from the left', function(done) {
2912 // Truncate from left means 0000 is removed from the start
2913 // which gives mnemonic 'avocado zoo zone'
2914 // not 1111 removed from the end
2915 // which gives the mnemonic 'abstract zoo zoo'
2916 var entropy = "00000000 00000000 00000000 00000000";
2917 entropy += "11111111 11111111 11111111 1111"; // Missing last byte
2918 driver.findElement(By.css('.use-entropy'))
2920 driver.findElement(By.css('.entropy'))
2922 driver.sleep(generateDelay).then(function() {
2923 driver.findElement(By.css(".phrase
"))
2924 .getAttribute("value
").then(function(phrase) {
2925 expect(phrase).toBe("avocado zoo zone
");
2931 // Very large entropy results in very long mnemonics
2932 it('Converts very long entropy to very long mnemonics', function(done) {
2934 for (var i=0; i<33; i++) {
2935 entropy += "AAAAAAAA
"; // 3 words * 33 iterations = 99 words
2937 driver.findElement(By.css('.use-entropy'))
2939 driver.findElement(By.css('.entropy'))
2941 driver.sleep(generateDelay).then(function() {
2942 driver.findElement(By.css(".phrase
"))
2943 .getAttribute("value
").then(function(phrase) {
2944 var wordCount = phrase.split(/\s+/g).length;
2945 expect(wordCount).toBe(99);
2951 // Is compatible with bip32jp entropy
2952 // https://bip32jp.github.io/english/index.html
2954 // Is incompatible with:
2956 it('Is compatible with bip32jp.github.io', function(done) {
2957 var entropy = "543210543210543210543210543210543210543210543210543210543210543210543210543210543210543210543210543";
2958 var expectedPhrase = "train then jungle barely whip fiber purpose puppy eagle cloud clump hospital robot brave balcony utility detect estate old green desk skill multiply virus
";
2959 driver.findElement(By.css('.use-entropy'))
2961 driver.findElement(By.css('.entropy'))
2963 driver.sleep(generateDelay).then(function() {
2964 driver.findElement(By.css(".phrase
"))
2965 .getAttribute("value
").then(function(phrase) {
2966 expect(phrase).toBe(expectedPhrase);
2972 // Blank entropy does not generate mnemonic or addresses
2973 it('Does not generate mnemonic for blank entropy', function(done) {
2974 driver.findElement(By.css('.use-entropy'))
2976 driver.findElement(By.css('.entropy'))
2978 // check there is no mnemonic
2979 driver.sleep(generateDelay).then(function() {
2980 driver.findElement(By.css(".phrase
"))
2981 .getAttribute("value
").then(function(phrase) {
2982 expect(phrase).toBe("");
2983 // check there is no mnemonic
2984 driver.findElements(By.css(".address
"))
2985 .then(function(addresses) {
2986 expect(addresses.length).toBe(0);
2987 // Check the feedback says 'blank entropy'
2988 driver.findElement(By.css(".feedback
"))
2990 .then(function(feedbackText) {
2991 expect(feedbackText).toBe("Blank entropy
");
2999 // Mnemonic length can be selected even for weak entropy
3000 it('Allows selection of mnemonic length even for weak entropy', function(done) {
3001 driver.findElement(By.css('.use-entropy'))
3003 driver.executeScript(function() {
3004 $(".mnemonic
-length
").val("18").trigger("change
");
3006 driver.findElement(By.css('.entropy'))
3007 .sendKeys("012345");
3008 driver.sleep(generateDelay).then(function() {
3009 driver.findElement(By.css(".phrase
"))
3010 .getAttribute("value
").then(function(phrase) {
3011 var wordCount = phrase.split(/\s+/g).length;
3012 expect(wordCount).toBe(18);
3019 // https://github.com/iancoleman/bip39/issues/33
3020 // Final cards should contribute entropy
3021 it('Uses as much entropy as possible for the mnemonic', function(done) {
3022 driver.findElement(By.css('.use-entropy'))
3024 driver.findElement(By.css('.entropy'))
3025 .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
");
3026 driver.sleep(generateDelay).then(function() {
3028 driver.findElement(By.css(".phrase
"))
3029 .getAttribute("value
").then(function(originalPhrase) {
3030 // Set the last 12 cards to be AS
3031 driver.findElement(By.css('.entropy'))
3033 driver.findElement(By.css('.entropy'))
3034 .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
");
3035 driver.sleep(generateDelay).then(function() {
3037 driver.findElement(By.css(".phrase
"))
3038 .getAttribute("value
").then(function(newPhrase) {
3039 expect(originalPhrase).not.toEqual(newPhrase);
3048 // https://github.com/iancoleman/bip39/issues/35
3050 // TODO this doesn't work in selenium with firefox
3051 // see https://stackoverflow.com/q/40360223
3052 it('Shows a qr code on hover for the phrase', function(done) {
3053 if (browser == "firefox
") {
3054 pending("Selenium
+ Firefox bug
for mouseMove
, see
https://stackoverflow.com/q/40360223");
3056 // generate a random mnemonic
3057 var generateEl
= driver
.findElement(By
.css('.generate'));
3059 // toggle qr to show (hidden by default)
3060 var phraseEl
= driver
.findElement(By
.css(".phrase"));
3062 var rootKeyEl
= driver
.findElement(By
.css(".root-key"));
3063 driver
.sleep(generateDelay
).then(function() {
3064 // hover over the root key
3065 driver
.actions().mouseMove(rootKeyEl
).perform().then(function() {
3066 // check the qr code shows
3067 driver
.executeScript(function() {
3068 return $(".qr-container").find("canvas").length
> 0;
3070 .then(function(qrShowing
) {
3071 expect(qrShowing
).toBe(true);
3072 // hover away from the phrase
3073 driver
.actions().mouseMove(generateEl
).perform().then(function() {;
3074 // check the qr code hides
3075 driver
.executeScript(function() {
3076 return $(".qr-container").find("canvas").length
== 0;
3078 .then(function(qrHidden
) {
3079 expect(qrHidden
).toBe(true);
3088 // BIP44 account extendend private key is shown
3089 // github issue 37 - compatibility with electrum
3090 it('Shows the bip44 account extended private key', function(done
) {
3091 driver
.findElement(By
.css(".phrase"))
3092 .sendKeys("abandon abandon ability");
3093 driver
.sleep(generateDelay
).then(function() {
3094 driver
.findElement(By
.css("#bip44 .account-xprv"))
3095 .getAttribute("value")
3096 .then(function(xprv
) {
3097 expect(xprv
).toBe("xprv9yzrnt4zWVJUr1k2VxSPy9ettKz5PpeDMgaVG7UKedhqnw1tDkxP2UyYNhuNSumk2sLE5ctwKZs9vwjsq3e1vo9egCK6CzP87H2cVYXpfwQ");
3103 // BIP44 account extendend public key is shown
3104 // github issue 37 - compatibility with electrum
3105 it('Shows the bip44 account extended public key', function(done
) {
3106 driver
.findElement(By
.css(".phrase"))
3107 .sendKeys("abandon abandon ability");
3108 driver
.sleep(generateDelay
).then(function() {
3109 driver
.findElement(By
.css("#bip44 .account-xpub"))
3110 .getAttribute("value")
3111 .then(function(xprv
) {
3112 expect(xprv
).toBe("xpub6CzDCPbtLrrn4VpVbyyQLHbdSMpZoHN4iuW64VswCyEpfjM2mJGdaHJ2DyuZwtst96E16VvcERb8BBeJdHSCVmAq9RhtRQg6eAZFrTKCNqf");
3119 // BIP32 root key can be set as an xpub
3120 it('Generates addresses from xpub as bip32 root key', function(done
) {
3121 driver
.findElement(By
.css('#bip32-tab a'))
3123 // set xpub for account 0 of bip44 for 'abandon abandon ability'
3124 driver
.findElement(By
.css("#root-key"))
3125 .sendKeys("xpub6CzDCPbtLrrn4VpVbyyQLHbdSMpZoHN4iuW64VswCyEpfjM2mJGdaHJ2DyuZwtst96E16VvcERb8BBeJdHSCVmAq9RhtRQg6eAZFrTKCNqf");
3126 driver
.sleep(generateDelay
).then(function() {
3127 // check the addresses are generated
3128 getFirstAddress(function(address
) {
3129 expect(address
).toBe("1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug");
3130 // check the xprv key is not set
3131 driver
.findElement(By
.css(".extended-priv-key"))
3132 .getAttribute("value")
3133 .then(function(xprv
) {
3134 expect(xprv
).toBe("NA");
3135 // check the private key is not set
3136 driver
.findElements(By
.css(".privkey"))
3137 .then(function(els
) {
3140 .then(function(privkey
) {
3141 expect(xprv
).toBe("NA");
3151 // xpub for bip32 root key will not work with hardened derivation paths
3152 it('Shows error for hardened derivation paths with xpub root key', function(done
) {
3153 // set xpub for account 0 of bip44 for 'abandon abandon ability'
3154 driver
.findElement(By
.css("#root-key"))
3155 .sendKeys("xpub6CzDCPbtLrrn4VpVbyyQLHbdSMpZoHN4iuW64VswCyEpfjM2mJGdaHJ2DyuZwtst96E16VvcERb8BBeJdHSCVmAq9RhtRQg6eAZFrTKCNqf");
3156 driver
.sleep(feedbackDelay
).then(function() {
3157 // Check feedback is correct
3158 driver
.findElement(By
.css('.feedback'))
3160 .then(function(feedback
) {
3161 var msg
= "Hardened derivation path is invalid with xpub key";
3162 expect(feedback
).toBe(msg
);
3163 // Check no addresses are shown
3164 driver
.findElements(By
.css('.addresses tr'))
3165 .then(function(rows
) {
3166 expect(rows
.length
).toBe(0);
3174 // no root key shows feedback
3175 it('Shows feedback for no root key', function(done
) {
3176 // set xpub for account 0 of bip44 for 'abandon abandon ability'
3177 driver
.findElement(By
.css('#bip32-tab a'))
3179 driver
.sleep(feedbackDelay
).then(function() {
3180 // Check feedback is correct
3181 driver
.findElement(By
.css('.feedback'))
3183 .then(function(feedback
) {
3184 expect(feedback
).toBe("Invalid root key");
3191 // display error switching tabs while addresses are generating
3192 it('Can change details while old addresses are still being generated', function(done
) {
3193 // Set to generate 199 more addresses.
3194 // This will take a long time allowing a new set of addresses to be
3195 // generated midway through this lot.
3196 // The newly generated addresses should not include any from the old set.
3197 // Any more than 199 will show an alert which needs to be accepted.
3198 driver
.findElement(By
.css('.rows-to-add'))
3200 driver
.findElement(By
.css('.rows-to-add'))
3203 driver
.findElement(By
.css('.phrase'))
3204 .sendKeys("abandon abandon ability");
3205 driver
.sleep(generateDelay
).then(function() {
3206 // change tabs which should cancel the previous generating
3207 driver
.findElement(By
.css('.rows-to-add'))
3209 driver
.findElement(By
.css('.rows-to-add'))
3211 driver
.findElement(By
.css('#bip32-tab a'))
3213 driver
.sleep(generateDelay
).then(function() {
3214 driver
.findElements(By
.css('.index'))
3215 .then(function(els
) {
3216 // check the derivation paths have the right quantity
3217 expect(els
.length
).toBe(20);
3218 // check the derivation paths are in order
3219 testRowsAreInCorrectOrder(done
);
3223 }, generateDelay
+ 10000);
3226 // padding for binary should give length with multiple of 256
3227 // hashed entropy 1111 is length 252, so requires 4 leading zeros
3228 // prior to issue 49 it would only generate 2 leading zeros, ie missing 2
3229 it('Pads hashed entropy with leading zeros', function(done
) {
3230 driver
.findElement(By
.css('.use-entropy'))
3232 driver
.executeScript(function() {
3233 $(".mnemonic-length").val("15").trigger("change");
3235 driver
.findElement(By
.css('.entropy'))
3237 driver
.sleep(generateDelay
).then(function() {
3238 driver
.findElement(By
.css('.phrase'))
3239 .getAttribute("value")
3240 .then(function(phrase
) {
3241 expect(phrase
).toBe("avocado valid quantum cross link predict excuse edit street able flame large galaxy ginger nuclear");
3247 // Github pull request 55
3248 // https://github.com/iancoleman/bip39/pull/55
3250 it('Can set the derivation path on bip32 tab for bitcoincore', function(done
) {
3251 testClientSelect(done
, {
3253 bip32path: "m/0'/0'",
3254 useHardenedAddresses: "true",
3257 it('Can set the derivation path on bip32 tab for multibit', function(done
) {
3258 testClientSelect(done
, {
3260 bip32path: "m/0'/0",
3261 useHardenedAddresses: null,
3264 it('Can set the derivation path on bip32 tab for coinomi/ledger', function(done
) {
3265 testClientSelect(done
, {
3267 bip32path: "m/44'/0'/0'",
3268 useHardenedAddresses: null,
3273 // https://github.com/iancoleman/bip39/issues/58
3274 // bip32 derivation is correct, does not drop leading zeros
3276 // https://medium.com/@alexberegszaszi/why-do-my-bip32-wallets-disagree-6f3254cc5846
3277 it('Retains leading zeros for bip32 derivation', function(done
) {
3278 driver
.findElement(By
.css(".phrase"))
3279 .sendKeys("fruit wave dwarf banana earth journey tattoo true farm silk olive fence");
3280 driver
.findElement(By
.css(".passphrase"))
3281 .sendKeys("banana");
3282 driver
.sleep(generateDelay
).then(function() {
3283 getFirstAddress(function(address
) {
3284 // Note that bitcore generates an incorrect address
3285 // 13EuKhffWkBE2KUwcbkbELZb1MpzbimJ3Y
3286 // see the medium.com link above for more details
3287 expect(address
).toBe("17rxURoF96VhmkcEGCj5LNQkmN9HVhWb7F");
3294 // Japanese mnemonics generate incorrect bip32 seed
3295 // BIP39 seed is set from phrase
3296 it('Generates correct seed for Japanese mnemonics', function(done
) {
3297 driver
.findElement(By
.css(".phrase"))
3298 .sendKeys("あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あおぞら");
3299 driver
.findElement(By
.css(".passphrase"))
3300 .sendKeys("メートルガバヴァぱばぐゞちぢ十人十色");
3301 driver
.sleep(generateDelay
).then(function() {
3302 driver
.findElement(By
.css(".seed"))
3303 .getAttribute("value")
3304 .then(function(seed
) {
3305 expect(seed
).toBe("a262d6fb6122ecf45be09c50492b31f92e9beb7d9a845987a02cefda57a15f9c467a17872029a9e92299b5cbdf306e3a0ee620245cbd508959b6cb7ca637bd55");
3311 // BIP49 official test vectors
3312 // https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki#test-vectors
3313 it('Generates BIP49 addresses matching the official test vectors', function(done
) {
3314 driver
.findElement(By
.css('#bip49-tab a'))
3316 selectNetwork("BTC - Bitcoin Testnet");
3317 driver
.findElement(By
.css(".phrase"))
3318 .sendKeys("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about");
3319 driver
.sleep(generateDelay
).then(function() {
3320 getFirstAddress(function(address
) {
3321 expect(address
).toBe("2Mww8dCYPUpKHofjgcXcBCEGmniw9CoaiD2");
3327 // BIP49 derivation path is shown
3328 it('Shows the bip49 derivation path', function(done
) {
3329 driver
.findElement(By
.css('#bip49-tab a'))
3331 driver
.findElement(By
.css(".phrase"))
3332 .sendKeys("abandon abandon ability");
3333 driver
.sleep(generateDelay
).then(function() {
3334 driver
.findElement(By
.css('#bip49 .path'))
3335 .getAttribute("value")
3336 .then(function(path
) {
3337 expect(path
).toBe("m/49'/0'/0'/0");
3343 // BIP49 extended private key is shown
3344 it('Shows the bip49 extended private key', function(done
) {
3345 driver
.findElement(By
.css('#bip49-tab a'))
3347 driver
.findElement(By
.css(".phrase"))
3348 .sendKeys("abandon abandon ability");
3349 driver
.sleep(generateDelay
).then(function() {
3350 driver
.findElement(By
.css('.extended-priv-key'))
3351 .getAttribute("value")
3352 .then(function(xprv
) {
3353 expect(xprv
).toBe("yprvALYB4DYRG6CzzVgzQZwwqjAA2wjBGC3iEd7KYYScpoDdmf75qMRWZWxoFcRXBJjgEXdFqJ9vDRGRLJQsrL22Su5jMbNFeM9vetaGVqy9Qy2");
3359 // BIP49 extended public key is shown
3360 it('Shows the bip49 extended public key', function(done
) {
3361 driver
.findElement(By
.css('#bip49-tab a'))
3363 driver
.findElement(By
.css(".phrase"))
3364 .sendKeys("abandon abandon ability");
3365 driver
.sleep(generateDelay
).then(function() {
3366 driver
.findElement(By
.css('.extended-pub-key'))
3367 .getAttribute("value")
3368 .then(function(xprv
) {
3369 expect(xprv
).toBe("ypub6ZXXTj5K6TmJCymTWbUxCs6tayZffemZbr2vLvrEP8kceTSENtjm7KHH6thvAKxVar9fGe8rgsPEX369zURLZ68b4f7Vexz7RuXsjQ69YDt");
3375 // BIP49 account field changes address list
3376 it('Can set the bip49 account field', function(done
) {
3377 driver
.findElement(By
.css('#bip49-tab a'))
3379 driver
.findElement(By
.css('#bip49 .account'))
3381 driver
.findElement(By
.css('#bip49 .account'))
3383 driver
.findElement(By
.css(".phrase"))
3384 .sendKeys("abandon abandon ability");
3385 driver
.sleep(generateDelay
).then(function() {
3386 getFirstAddress(function(address
) {
3387 expect(address
).toBe("381wg1GGN4rP88rNC9v7QWsiww63yLVPsn");
3393 // BIP49 change field changes address list
3394 it('Can set the bip49 change field', function(done
) {
3395 driver
.findElement(By
.css('#bip49-tab a'))
3397 driver
.findElement(By
.css('#bip49 .change'))
3399 driver
.findElement(By
.css('#bip49 .change'))
3401 driver
.findElement(By
.css(".phrase"))
3402 .sendKeys("abandon abandon ability");
3403 driver
.sleep(generateDelay
).then(function() {
3404 getFirstAddress(function(address
) {
3405 expect(address
).toBe("3PEM7MiKed5konBoN66PQhK8r3hjGhy9dT");
3411 // BIP49 account extendend private key is shown
3412 it('Shows the bip49 account extended private key', function(done
) {
3413 driver
.findElement(By
.css('#bip49-tab a'))
3415 driver
.findElement(By
.css(".phrase"))
3416 .sendKeys("abandon abandon ability");
3417 driver
.sleep(generateDelay
).then(function() {
3418 driver
.findElement(By
.css('#bip49 .account-xprv'))
3419 .getAttribute("value")
3420 .then(function(xprv
) {
3421 expect(xprv
).toBe("yprvAHtB1M5Wp675aLzFy9TJYK2mSsLkg6mcBRh5DZTR7L4EnYSmYPaL63KFA4ycg1PngW5LfkmejxzosCs17TKZMpRFKc3z5SJar6QAKaFcaZL");
3427 // BIP49 account extendend public key is shown
3428 it('Shows the bip49 account extended public key', function(done
) {
3429 driver
.findElement(By
.css('#bip49-tab a'))
3431 driver
.findElement(By
.css(".phrase"))
3432 .sendKeys("abandon abandon ability");
3433 driver
.sleep(generateDelay
).then(function() {
3434 driver
.findElement(By
.css('#bip49 .account-xpub'))
3435 .getAttribute("value")
3436 .then(function(xprv
) {
3437 expect(xprv
).toBe("ypub6WsXQrcQeTfNnq4j5AzJuSyVzuBF5ZVTYecg1ws2ffbDfLmv5vtadqdj1NgR6C6gufMpMfJpHxvb6JEQKvETVNWCRanNedfJtnTchZiJtsL");
3443 // Test selecting coin where bip49 is unavailable (eg CLAM)
3444 it('Shows an error on bip49 tab for coins without bip49', function(done
) {
3445 driver
.findElement(By
.css('#bip49-tab a'))
3447 driver
.findElement(By
.css(".phrase"))
3448 .sendKeys("abandon abandon ability");
3449 driver
.sleep(generateDelay
).then(function() {
3450 selectNetwork("CLAM - Clams");
3451 // bip49 available is hidden
3452 driver
.findElement(By
.css('#bip49 .available'))
3453 .getAttribute("class")
3454 .then(function(classes
) {
3455 expect(classes
).toContain("hidden");
3456 // bip49 unavailable is shown
3457 driver
.findElement(By
.css('#bip49 .unavailable'))
3458 .getAttribute("class")
3459 .then(function(classes
) {
3460 expect(classes
).not
.toContain("hidden");
3461 // check there are no addresses shown
3462 driver
.findElements(By
.css('.addresses tr'))
3463 .then(function(rows
) {
3464 expect(rows
.length
).toBe(0);
3465 // check the derived private key is blank
3466 driver
.findElement(By
.css('.extended-priv-key'))
3467 .getAttribute("value")
3468 .then(function(xprv
) {
3469 expect(xprv
).toBe('');
3470 // check the derived public key is blank
3471 driver
.findElement(By
.css('.extended-pub-key'))
3472 .getAttribute("value")
3473 .then(function(xpub
) {
3474 expect(xpub
).toBe('');
3485 // Cleared mnemonic and root key still allows addresses to be generated
3486 // https://github.com/iancoleman/bip39/issues/43
3487 it('Clears old root keys from memory when mnemonic is cleared', function(done
) {
3489 driver
.findElement(By
.css(".phrase"))
3490 .sendKeys("abandon abandon ability");
3491 driver
.sleep(generateDelay
).then(function() {
3492 // clear the mnemonic and root key
3493 // using selenium .clear() doesn't seem to trigger the 'input' event
3494 // so clear it using keys instead
3495 driver
.findElement(By
.css('.phrase'))
3496 .sendKeys(Key
.CONTROL
,"a");
3497 driver
.findElement(By
.css('.phrase'))
3498 .sendKeys(Key
.DELETE
);
3499 driver
.findElement(By
.css('.root-key'))
3500 .sendKeys(Key
.CONTROL
,"a");
3501 driver
.findElement(By
.css('.root-key'))
3502 .sendKeys(Key
.DELETE
);
3503 driver
.sleep(generateDelay
).then(function() {
3504 // try to generate more addresses
3505 driver
.findElement(By
.css('.more'))
3507 driver
.sleep(generateDelay
).then(function() {
3508 driver
.findElements(By
.css(".addresses tr"))
3509 .then(function(els
) {
3510 // check there are no addresses shown
3511 expect(els
.length
).toBe(0);
3520 // error trying to generate addresses from xpub with hardened derivation
3521 it('Shows error for hardened addresses with xpub root key', function(done
) {
3522 driver
.findElement(By
.css('#bip32-tab a'))
3524 driver
.executeScript(function() {
3525 $(".hardened-addresses").prop("checked", true);
3527 // set xpub for account 0 of bip44 for 'abandon abandon ability'
3528 driver
.findElement(By
.css("#root-key"))
3529 .sendKeys("xpub6CzDCPbtLrrn4VpVbyyQLHbdSMpZoHN4iuW64VswCyEpfjM2mJGdaHJ2DyuZwtst96E16VvcERb8BBeJdHSCVmAq9RhtRQg6eAZFrTKCNqf");
3530 driver
.sleep(feedbackDelay
).then(function() {
3531 // Check feedback is correct
3532 driver
.findElement(By
.css('.feedback'))
3534 .then(function(feedback
) {
3535 var msg
= "Hardened derivation path is invalid with xpub key";
3536 expect(feedback
).toBe(msg
);
3542 // Litecoin uses ltub by default, and can optionally be set to xprv
3544 // https://github.com/iancoleman/bip39/issues/96
3545 // Issue with extended keys on Litecoin
3546 it('Uses ltub by default for litecoin, but can be set to xprv', function(done
) {
3547 driver
.findElement(By
.css('.phrase'))
3548 .sendKeys("abandon abandon ability");
3549 selectNetwork("LTC - Litecoin");
3550 driver
.sleep(generateDelay
).then(function() {
3551 // check the extended key is generated correctly
3552 driver
.findElement(By
.css('.root-key'))
3553 .getAttribute("value")
3554 .then(function(rootKey
) {
3555 expect(rootKey
).toBe("Ltpv71G8qDifUiNesiPqf6h5V6eQ8ic77oxQiYtawiACjBEx3sTXNR2HGDGnHETYxESjqkMLFBkKhWVq67ey1B2MKQXannUqNy1RZVHbmrEjnEU");
3556 // set litecoin to use ltub
3557 driver
.executeScript(function() {
3558 $(".litecoin-use-ltub").prop("checked", false);
3559 $(".litecoin-use-ltub").trigger("change");
3561 driver
.sleep(generateDelay
).then(function() {
3562 driver
.findElement(By
.css('.root-key'))
3563 .getAttribute("value")
3564 .then(function(rootKey
) {
3565 expect(rootKey
).toBe("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi");
3574 // https://github.com/iancoleman/bip39/issues/99#issuecomment-327094159
3575 // "warn me emphatically when they have detected invalid input" to the entropy field
3576 // A warning is shown when entropy is filtered and discarded
3577 it('Warns when entropy is filtered and discarded', function(done
) {
3578 driver
.findElement(By
.css('.use-entropy'))
3580 // set entropy to have no filtered content
3581 driver
.findElement(By
.css('.entropy'))
3582 .sendKeys("00000000 00000000 00000000 00000000");
3583 driver
.sleep(generateDelay
).then(function() {
3584 // check the filter warning does not show
3585 driver
.findElement(By
.css('.entropy-container .filter-warning'))
3586 .getAttribute("class")
3587 .then(function(classes
) {
3588 expect(classes
).toContain("hidden");
3589 // set entropy to have some filtered content
3590 driver
.findElement(By
.css('.entropy'))
3591 .sendKeys("10000000 zxcvbn 00000000 00000000 00000000");
3592 driver
.sleep(entropyFeedbackDelay
).then(function() {
3593 // check the filter warning shows
3594 driver
.findElement(By
.css('.entropy-container .filter-warning'))
3595 .getAttribute("class")
3596 .then(function(classes
) {
3597 expect(classes
).not
.toContain("hidden");
3605 // Bitcoin Cash address can be set to use cashaddr format
3606 it('Can use cashaddr format for bitcoin cash addresses', function(done
) {
3607 driver
.executeScript(function() {
3608 $(".use-bch-cashaddr-addresses").prop("checked", true);
3610 driver
.findElement(By
.css('.phrase'))
3611 .sendKeys("abandon abandon ability");
3612 selectNetwork("BCH - Bitcoin Cash");
3613 driver
.sleep(generateDelay
).then(function() {
3614 getFirstAddress(function(address
) {
3615 expect(address
).toBe("bitcoincash:qzlquk7w4hkudxypl4fgv8x279r754dkvur7jpcsps");
3621 // Bitcoin Cash address can be set to use bitpay format
3622 it('Can use bitpay format for bitcoin cash addresses', function(done
) {
3623 driver
.executeScript(function() {
3624 $(".use-bch-bitpay-addresses").prop("checked", true);
3626 driver
.findElement(By
.css('.phrase'))
3627 .sendKeys("abandon abandon ability");
3628 selectNetwork("BCH - Bitcoin Cash");
3629 driver
.sleep(generateDelay
).then(function() {
3630 getFirstAddress(function(address
) {
3631 expect(address
).toBe("CZnpA9HPmvhuhLLPWJP8rNDpLUYXy1LXFk");
3637 // Bitcoin Cash address can be set to use legacy format
3638 it('Can use legacy format for bitcoin cash addresses', function(done
) {
3639 driver
.executeScript(function() {
3640 $(".use-bch-legacy-addresses").prop("checked", true);
3642 driver
.findElement(By
.css('.phrase'))
3643 .sendKeys("abandon abandon ability");
3644 selectNetwork("BCH - Bitcoin Cash");
3645 driver
.sleep(generateDelay
).then(function() {
3646 getFirstAddress(function(address
) {
3647 expect(address
).toBe("1JKvb6wKtsjNoCRxpZ4DGrbniML7z5U16A");
3653 // End of tests ported from old suit, so no more comments above each test now
3655 it('Can generate more addresses from a custom index', function(done
) {
3656 var expectedIndexes
= [
3657 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,
3658 40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59
3660 driver
.findElement(By
.css('.phrase'))
3661 .sendKeys("abandon abandon ability");
3662 driver
.sleep(generateDelay
).then(function() {
3663 // Set start of next lot of rows to be from index 40
3664 // which means indexes 20-39 will not be in the table.
3665 driver
.findElement(By
.css('.more-rows-start-index'))
3667 driver
.findElement(By
.css('.more'))
3669 driver
.sleep(generateDelay
).then(function() {
3670 // Check actual indexes in the table match the expected pattern
3671 driver
.findElements(By
.css(".index"))
3672 .then(function(els
) {
3673 expect(els
.length
).toBe(expectedIndexes
.length
);
3674 var testRowAtIndex = function(i
) {
3675 if (i
>= expectedIndexes
.length
) {
3680 .then(function(actualPath
) {
3681 var noHardened
= actualPath
.replace(/'/g, "");
3682 var pathBits = noHardened.split("/")
3683 var lastBit = pathBits[pathBits.length-1];
3684 var actualIndex = parseInt(lastBit);
3685 var expectedIndex = expectedIndexes[i];
3686 expect(actualIndex).toBe(expectedIndex);
3687 testRowAtIndex(i+1);
3697 it('Can generate BIP141 addresses
with P2WPKH
-in-P2SH semanitcs
', function(done) {
3698 // Sourced from BIP49 official test specs
3699 driver.findElement(By.css('#bip141
-tab a
'))
3701 driver.findElement(By.css('.bip141
-path
'))
3703 driver.findElement(By.css('.bip141
-path
'))
3704 .sendKeys("m/49'/1'/0'/0");
3705 selectNetwork("BTC
- Bitcoin Testnet
");
3706 driver.findElement(By.css(".phrase
"))
3707 .sendKeys("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about
");
3708 driver.sleep(generateDelay).then(function() {
3709 getFirstAddress(function(address) {
3710 expect(address).toBe("2Mww8dCYPUpKHofjgcXcBCEGmniw9CoaiD2
");
3716 it('Can generate BIP141 addresses with P2WSH semanitcs', function(done) {
3717 driver.findElement(By.css('#bip141-tab a'))
3720 driver.executeScript(function() {
3721 $(".bip141
-semantics option
[selected
]").removeAttr("selected
");
3722 $(".bip141
-semantics option
").filter(function(i,e) {
3723 return $(e).html() == "P2WSH (1-of-1 multisig
)";
3724 }).prop("selected
", true);
3725 $(".bip141
-semantics
").trigger("change
");
3727 driver.findElement(By.css(".phrase
"))
3728 .sendKeys("abandon abandon ability
");
3729 driver.sleep(generateDelay).then(function() {
3730 driver.findElement(By.css("#root
-key
"))
3731 .getAttribute("value
")
3732 .then(function(rootKey) {
3733 expect(rootKey).toBe("ZprvAhadJRUYsNge9uHspaggavxU1BUQ8QwfT4Z9UGq5sKF2mSt1mVy8EckLAaoBdmLHyP5eYDJ3LxtmzMNnLg2MRFe7QN2ueF4NCH4s5PrCDR6
");
3734 getFirstAddress(function(address) {
3735 expect(address).toBe("bc1q2qhee847pv438tgg8hc7mjy38n8dklleshettn344l0tgs0kj5hskz9p9r
");
3742 it('Can generate BIP141 addresses with P2WSH-in-P2SH semanitcs', function(done) {
3743 driver.findElement(By.css('#bip141-tab a'))
3745 // Choose P2WSH-in-P2SH
3746 driver.executeScript(function() {
3747 $(".bip141
-semantics option
[selected
]").removeAttr("selected
");
3748 $(".bip141
-semantics option
").filter(function(i,e) {
3749 return $(e).html() == "P2WSH nested
in P2SH (1-of-1 multisig
)";
3750 }).prop("selected
", true);
3751 $(".bip141
-semantics
").trigger("change
");
3753 driver.findElement(By.css(".phrase
"))
3754 .sendKeys("abandon abandon ability
");
3755 driver.sleep(generateDelay).then(function() {
3756 driver.findElement(By.css("#root
-key
"))
3757 .getAttribute("value
")
3758 .then(function(rootKey) {
3759 expect(rootKey).toBe("YprvANkMzkodih9AJc6kzDu4NqrxqDKxBnxAXx2vgswCVJs9iM4nWqoZcZ6C9NqbdrgNZjxqnjhUtJYE74mDcycLd1xWY2LV4LEsvZ1DgqxuAKe
");
3760 getFirstAddress(function(address) {
3761 expect(address).toBe("343DLC4vGDyHBbBr9myL8zzZA1MdN9TM1G
");
3768 it('Uses Vprv for bitcoin testnet p2wsh', function(done) {
3769 selectNetwork("BTC
- Bitcoin Testnet
");
3770 driver.findElement(By.css('#bip141-tab a'))
3773 driver.executeScript(function() {
3774 $(".bip141
-semantics option
[selected
]").removeAttr("selected
");
3775 $(".bip141
-semantics option
").filter(function(i,e) {
3776 return $(e).html() == "P2WSH (1-of-1 multisig
)";
3777 }).prop("selected
", true);
3778 $(".bip141
-semantics
").trigger("change
");
3780 driver.findElement(By.css('.phrase'))
3781 .sendKeys('abandon abandon ability');
3782 driver.sleep(generateDelay).then(function() {
3783 driver.findElement(By.css('.root-key'))
3784 .getAttribute("value
")
3785 .then(function(path) {
3786 expect(path).toBe("Vprv16YtLrHXxePM5ja5hXQbiJs5JKDAc4WcaXo5rZcrVMU6bMhUg1oY7fpPku3i819gvMcHvq1h8aELDsyfCEs19vj1Q3iDHRrESWyJConkoT1
");
3792 it('Uses Uprv for bitcoin testnet p2wsh-in-p2sh', function(done) {
3793 selectNetwork("BTC
- Bitcoin Testnet
");
3794 driver.findElement(By.css('#bip141-tab a'))
3796 // Choose P2WSH-in-P2SH
3797 driver.executeScript(function() {
3798 $(".bip141
-semantics option
[selected
]").removeAttr("selected
");
3799 $(".bip141
-semantics option
").filter(function(i,e) {
3800 return $(e).html() == "P2WSH nested
in P2SH (1-of-1 multisig
)";
3801 }).prop("selected
", true);
3802 $(".bip141
-semantics
").trigger("change
");
3804 driver.findElement(By.css('.phrase'))
3805 .sendKeys('abandon abandon ability');
3806 driver.sleep(generateDelay).then(function() {
3807 driver.findElement(By.css('.root-key'))
3808 .getAttribute("value
")
3809 .then(function(path) {
3810 expect(path).toBe("Uprv95RJn67y7xyEuRLHenkZYVUx9LkARJzAsVx3ZJMeyHMdVwosWD9K8JTe4Z1FeE4gwBVcnqKF3f82ZvJxkBxHS5E74fYnigxvqeke8ZV3Fp2
");
3816 it('Can generate BIP141 addresses with P2WPKH semanitcs', function(done) {
3817 // This result tested against bitcoinjs-lib test spec for segwit address
3818 // using the first private key of this mnemonic and default path m/0
3819 // https://github.com/bitcoinjs/bitcoinjs-lib/blob/9c8503cab0c6c30a95127042703bc18e8d28c76d/test/integration/addresses.js#L50
3820 // so whilst not directly comparable, substituting the private key produces
3821 // identical results between this tool and the bitcoinjs-lib test.
3822 // Private key generated is:
3823 // L3L8Nu9whawPBNLGtFqDhKut9DKKfG3CQoysupT7BimqVCZsLFNP
3824 driver.findElement(By.css('#bip141-tab a'))
3827 driver.executeScript(function() {
3828 $(".bip141
-semantics option
[selected
]").removeAttr("selected
");
3829 $(".bip141
-semantics option
").filter(function(i,e) {
3830 return $(e).html() == "P2WPKH
";
3831 }).prop("selected
", true);
3832 $(".bip141
-semantics
").trigger("change
");
3834 driver.findElement(By.css(".phrase
"))
3835 .sendKeys("abandon abandon ability
");
3836 driver.sleep(generateDelay).then(function() {
3837 getFirstAddress(function(address) {
3838 expect(address).toBe("bc1qfwu6a5a3evygrk8zvdxxvz4547lmpyx5vsfxe9
");
3844 it('Shows the entropy used by the PRNG when clicking generate', function(done) {
3845 driver.findElement(By.css('.generate')).click();
3846 driver.sleep(generateDelay).then(function() {
3847 driver.findElement(By.css('.entropy'))
3848 .getAttribute("value
")
3849 .then(function(entropy) {
3850 expect(entropy).not.toBe("");
3856 it('Shows the index of each word in the mnemonic', function(done) {
3857 driver.findElement(By.css('.phrase'))
3858 .sendKeys("abandon abandon ability
");
3859 driver.sleep(generateDelay).then(function() {
3860 driver.findElement(By.css('.use-entropy'))
3862 driver.findElement(By.css('.word-indexes'))
3864 .then(function(indexes) {
3865 expect(indexes).toBe("0, 0, 1");
3871 it('Shows the derivation path for bip84 tab', function(done) {
3872 driver.findElement(By.css('#bip84-tab a'))
3874 driver.findElement(By.css('.phrase'))
3875 .sendKeys('abandon abandon ability');
3876 driver.sleep(generateDelay).then(function() {
3877 driver.findElement(By.css('#bip84 .path'))
3878 .getAttribute("value
")
3879 .then(function(path) {
3880 expect(path).toBe("m
/84'/0'/0'/0");
3886 it('Shows the extended private key for bip84 tab', function(done) {
3887 driver.findElement(By.css('#bip84-tab a'))
3889 driver.findElement(By.css('.phrase'))
3890 .sendKeys('abandon abandon ability');
3891 driver.sleep(generateDelay).then(function() {
3892 driver.findElement(By.css('.extended-priv-key'))
3893 .getAttribute("value
")
3894 .then(function(path) {
3895 expect(path).toBe("zprvAev3RKrZ3QVKiUFCfdeMRen1BPDJgdNt1XpxiDy8acSs4kkAGTCvq7HeRYRNNpo8EtEjCFQBWavJwtCUR29y4TUCH4X5RXMcyq48uN8y9BP
");
3901 it('Shows the extended public key for bip84 tab', function(done) {
3902 driver.findElement(By.css('#bip84-tab a'))
3904 driver.findElement(By.css('.phrase'))
3905 .sendKeys('abandon abandon ability');
3906 driver.sleep(generateDelay).then(function() {
3907 driver.findElement(By.css('.extended-pub-key'))
3908 .getAttribute("value
")
3909 .then(function(path) {
3910 expect(path).toBe("zpub6suPpqPSsn3cvxKfmfBMnnijjR3o666jNkkZWcNk8wyqwZ5JozXBNuc8Gs7DB3uLwTDvGVTspVEAUQcEjKF3pZHgywVbubdTqbXTUg7usyx
");
3916 it('Changes the address list if bip84 account is changed', function(done) {
3917 driver.findElement(By.css('#bip84-tab a'))
3919 driver.findElement(By.css('#bip84 .account'))
3921 driver.findElement(By.css('.phrase'))
3922 .sendKeys('abandon abandon ability');
3923 driver.sleep(generateDelay).then(function() {
3924 getFirstAddress(function(address) {
3925 expect(address).toBe("bc1qp7vv669t2fy965jdzvqwrraana89ctd5ewc662
");
3931 it('Changes the address list if bip84 change is changed', function(done) {
3932 driver.findElement(By.css('#bip84-tab a'))
3934 driver.findElement(By.css('#bip84 .change'))
3936 driver.findElement(By.css('.phrase'))
3937 .sendKeys('abandon abandon ability');
3938 driver.sleep(generateDelay).then(function() {
3939 getFirstAddress(function(address) {
3940 expect(address).toBe("bc1qr39vj6rh06ff05m53uxq8uazehwhccswylhrs2
");
3946 it('Passes the official BIP84 test spec for rootpriv', function(done) {
3947 driver.findElement(By.css('#bip84-tab a'))
3949 driver.findElement(By.css('.phrase'))
3950 .sendKeys('abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about');
3951 driver.sleep(generateDelay).then(function() {
3952 driver.findElement(By.css(".root
-key
"))
3953 .getAttribute("value
")
3954 .then(function(rootKey) {
3955 expect(rootKey).toBe("zprvAWgYBBk7JR8Gjrh4UJQ2uJdG1r3WNRRfURiABBE3RvMXYSrRJL62XuezvGdPvG6GFBZduosCc1YP5wixPox7zhZLfiUm8aunE96BBa4Kei5
");
3961 it('Passes the official BIP84 test spec for account 0 xprv', function(done) {
3962 driver.findElement(By.css('#bip84-tab a'))
3964 driver.findElement(By.css('.phrase'))
3965 .sendKeys('abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about');
3966 driver.sleep(generateDelay).then(function() {
3967 driver.findElement(By.css("#bip84
.account
-xprv
"))
3968 .getAttribute("value
")
3969 .then(function(rootKey) {
3970 expect(rootKey).toBe("zprvAdG4iTXWBoARxkkzNpNh8r6Qag3irQB8PzEMkAFeTRXxHpbF9z4QgEvBRmfvqWvGp42t42nvgGpNgYSJA9iefm1yYNZKEm7z6qUWCroSQnE
");
3976 it('Passes the official BIP84 test spec for account 0 xpub', function(done) {
3977 driver.findElement(By.css('#bip84-tab a'))
3979 driver.findElement(By.css('.phrase'))
3980 .sendKeys('abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about');
3981 driver.sleep(generateDelay).then(function() {
3982 driver.findElement(By.css("#bip84
.account
-xpub
"))
3983 .getAttribute("value
")
3984 .then(function(rootKey) {
3985 expect(rootKey).toBe("zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs
");
3991 it('Passes the official BIP84 test spec for account 0 first address', function(done) {
3992 driver.findElement(By.css('#bip84-tab a'))
3994 driver.findElement(By.css('.phrase'))
3995 .sendKeys('abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about');
3996 driver.sleep(generateDelay).then(function() {
3997 getFirstAddress(function(address) {
3998 expect(address).toBe("bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu
");
4004 it('Passes the official BIP84 test spec for account 0 first change address', function(done) {
4005 driver.findElement(By.css('#bip84-tab a'))
4007 driver.findElement(By.css('.phrase'))
4008 .sendKeys('abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about');
4009 driver.findElement(By.css('#bip84 .change'))
4011 driver.sleep(generateDelay).then(function() {
4012 getFirstAddress(function(address) {
4013 expect(address).toBe("bc1q8c6fshw2dlwun7ekn9qwf37cu2rn755upcp6el
");
4019 it('Can display the table as csv', function(done) {
4020 var headings = "path
,address
,public key
,private key
";
4021 var row1 = "m
/44'/0'/0'/0/0,1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug
,033f5aed5f6cfbafaf223188095b5980814897295f723815fea5d3f4b648d0d0b3
,L26cVSpWFkJ6aQkPkKmTzLqTdLJ923e6CzrVh9cmx21QHsoUmrEE
";
4022 var row20 = "m
/44'/0'/0'/0/19,1KhBy28XLAciXnnRvm71PvQJaETyrxGV55
,02b4b3e396434d8cdd20c03ac4aaa07387784d5d867b75987f516f5705ee68cb3a
,L4GrDrjReMsCAu5DkLXn79jSb95qR7Zfx7eshybCQZ1qL32MXJab
";
4023 driver.findElement(By.css('.phrase'))
4024 .sendKeys('abandon abandon ability');
4025 driver.sleep(generateDelay).then(function() {
4026 driver.findElement(By.css('.csv'))
4027 .getAttribute("value
")
4028 .then(function(csv) {
4029 expect(csv).toContain(headings);
4030 expect(csv).toContain(row1);
4031 expect(csv).toContain(row20);
4037 it('LeftPads ethereum keys that are less than 32 bytes', function(done) {
4038 // see https://github.com/iancoleman/bip39/issues/155
4039 selectNetwork("ETH
- Ethereum
");
4040 driver.findElement(By.css('#bip32-tab a'))
4042 driver.findElement(By.css('#bip32-path'))
4044 driver.findElement(By.css('#bip32-path'))
4045 .sendKeys("m
/44'/60'/0'");
4046 driver.findElement(By.css('.phrase'))
4047 .sendKeys('scout sort custom elite radar rare vivid thing trophy gesture cover snake change narrow kite list nation sustain buffalo erode open balance system young');
4048 driver.sleep(generateDelay).then(function() {
4049 getFirstAddress(function(address) {
4050 expect(address).toBe("0x8943E785B4a5714FC87a3aFAad1eB1FeB602B118");
4056 it('Can encrypt private keys using BIP38', function(done) {
4057 // see https://github.com/iancoleman/bip39/issues/140
4058 driver.executeScript(function() {
4059 $(".use-bip38
").prop("checked
", true);
4061 driver.findElement(By.css('.bip38-password'))
4062 .sendKeys('bip38password');
4063 driver.findElement(By.css('.rows-to-add'))
4065 driver.findElement(By.css('.rows-to-add'))
4067 driver.findElement(By.css('.phrase'))
4068 .sendKeys('abandon abandon ability');
4069 driver.sleep(bip38delay).then(function() {
4071 getFirstRowValue(function(address) {
4072 expect(address).toBe("1NCvSdumA3ngMM9c4aqU56AM6rqXddfuXB
");
4074 getFirstRowValue(function(pubkey) {
4075 expect(pubkey).toBe("043f5aed5f6cfbafaf223188095b5980814897295f723815fea5d3f4b648d0d0b3884a74447ea901729b1e73a999b7520e7cb55b4120e6432c64153ccab8a848e1
");
4077 getFirstRowValue(function(privkey) {
4078 expect(privkey).toBe("6PRNRiFnj1RoR3sXhymdCvoZCgnUHQpfupNdKkFbWJkwWQEKesWt1EDMDM
");
4084 }, bip38delay + 5000);
4086 it('Shows the checksum for the entropy', function(done) {
4087 driver.findElement(By.css('.use-entropy'))
4089 driver.findElement(By.css('.entropy'))
4090 .sendKeys("00000000000000000000000000000000");
4091 driver.sleep(generateDelay).then(function() {
4092 driver.findElement(By.css('.checksum'))
4094 .then(function(text) {
4095 expect(text).toBe("1");
4101 it('Shows the checksum for the entropy with the correct groupings', function(done) {
4102 driver.findElement(By.css('.use-entropy'))
4104 // create a checksum of 20 bits, which spans multiple words
4105 driver.findElement(By.css('.entropy'))
4106 .sendKeys("F000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
");
4107 driver.sleep(generateDelay).then(function() {
4108 driver.findElement(By.css('.checksum'))
4110 .then(function(text) {
4111 // first group is 9 bits, second group is 11
4112 expect(text).toBe("011010111 01110000110");
4118 it('Uses vprv for bitcoin testnet p2wpkh', function(done) {
4119 selectNetwork("BTC
- Bitcoin Testnet
");
4120 driver.findElement(By.css('#bip84-tab a'))
4122 driver.findElement(By.css('.phrase'))
4123 .sendKeys('abandon abandon ability');
4124 driver.sleep(generateDelay).then(function() {
4125 driver.findElement(By.css('.root-key'))
4126 .getAttribute("value
")
4127 .then(function(path) {
4128 expect(path).toBe("vprv9DMUxX4ShgxML9N2YV5CvWEebWrM9aJ5ULpbRRyzyWu6vs4BzTvbfFFrH41N5hVi7MYSfiugd765L3JmAfDM5po36Y8ouCKRDeYQwByCmS7
");
4134 it('Shows a warning if generating weak mnemonics', function(done) {
4135 driver.executeScript(function() {
4136 $(".strength option
[selected
]").removeAttr("selected
");
4137 $(".strength option
[value
=6]").prop("selected
", true);
4138 $(".strength
").trigger("change
");
4140 driver.findElement(By.css(".generate
-container
.warning
"))
4141 .getAttribute("class")
4142 .then(function(classes) {
4143 expect(classes).not.toContain("hidden
");
4148 it('Does not show a warning if generating strong mnemonics', function(done) {
4149 driver.executeScript(function() {
4150 $(".strength option
[selected
]").removeAttr("selected
");
4151 $(".strength option
[value
=12]").prop("selected
", true);
4153 driver.findElement(By.css(".generate
-container
.warning
"))
4154 .getAttribute("class")
4155 .then(function(classes) {
4156 expect(classes).toContain("hidden
");
4161 it('Shows a warning if overriding weak entropy with longer mnemonics', function(done) {
4162 driver.findElement(By.css('.use-entropy'))
4164 driver.findElement(By.css('.entropy'))
4165 .sendKeys("0123456789abcdef
"); // 6 words
4166 driver.executeScript(function() {
4167 $(".mnemonic
-length
").val("12").trigger("change
");
4169 driver.findElement(By.css(".weak
-entropy
-override
-warning
"))
4170 .getAttribute("class")
4171 .then(function(classes) {
4172 expect(classes).not.toContain("hidden
");
4177 it('Does not show a warning if entropy is stronger than mnemonic length', function(done) {
4178 driver.findElement(By.css('.use-entropy'))
4180 driver.findElement(By.css('.entropy'))
4181 .sendKeys("0123456789abcdef0123456789abcdef0123456789abcdef
"); // 18 words
4182 driver.executeScript(function() {
4183 $(".mnemonic
-length
").val("12").trigger("change
");
4185 driver.findElement(By.css(".weak
-entropy
-override
-warning
"))
4186 .getAttribute("class")
4187 .then(function(classes) {
4188 expect(classes).toContain("hidden
");
4193 it('Shows litecoin BIP49 addresses', function(done) {
4194 driver.findElement(By.css('.phrase'))
4195 .sendKeys('abandon abandon ability');
4196 selectNetwork("LTC
- Litecoin
");
4197 driver.findElement(By.css('#bip49-tab a'))
4199 // bip49 addresses are shown
4200 driver.sleep(generateDelay).then(function() {
4201 driver.findElement(By.css('#bip49 .available'))
4202 .getAttribute("class")
4203 .then(function(classes) {
4204 expect(classes).not.toContain("hidden
");
4205 // check first address
4206 getFirstAddress(function(address) {
4207 expect(address).toBe("MFwLPhsXoBuSLL8cLmW9uK6tChkzduV8qN
");
4214 it('Shows Groestlcoin BIP49 addresses', function(done) {
4215 driver.findElement(By.css('.phrase'))
4216 .sendKeys('abandon abandon ability');
4217 selectNetwork("GRS
- Groestlcoin
");
4218 driver.findElement(By.css('#bip49-tab a'))
4220 // bip49 addresses are shown
4221 driver.sleep(generateDelay).then(function() {
4222 driver.findElement(By.css('#bip49 .available'))
4223 .getAttribute("class")
4224 .then(function(classes) {
4225 expect(classes).not.toContain("hidden
");
4226 // check first address
4227 getFirstAddress(function(address) {
4228 expect(address).toBe("3HXSCZwCypLyixMsF4Z1sN49noJtrm8gnX
");
4235 it('Can use root keys to generate segwit table rows', function(done) {
4236 // segwit uses ypub / zpub instead of xpub but the root key should still
4237 // be valid regardless of the encoding used to import that key.
4238 // Maybe this breaks the reason for the different extended key prefixes, but
4239 // since the parsed root key is used behind the scenes anyhow this should be
4241 driver.findElement(By.css('#root-key'))
4242 .sendKeys('xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi');
4243 driver.findElement(By.css('#bip49-tab a'))
4245 // bip49 addresses are shown
4246 driver.sleep(generateDelay).then(function() {
4247 getFirstAddress(function(address) {
4248 expect(address).toBe("3QG2Y9AA4xZ846gKHZqNf7mvVKbLqMKxr2
");
4255 // Allow converting mnemonic back to raw entropy value
4256 it('Converts mnemonics into raw entropy', function(done) {
4257 driver.findElement(By.css('.phrase'))
4258 .sendKeys('abandon abandon about');
4259 driver.sleep(generateDelay).then(function() {
4260 driver.findElement(By.css('.use-entropy'))
4262 driver.findElement(By.css('.entropy'))
4263 .getAttribute("value
")
4264 .then(function(entropy) {
4265 expect(entropy).toBe("00000001");
4266 driver.findElement(By.css('.phrase'))
4267 .getAttribute("value
")
4268 .then(function(phrase) {
4269 expect(phrase).toBe("abandon abandon about
");
4277 // Added Split Phrase Card Output
4278 it('Shows split prase cards', function(done) {
4279 var originalPhrase = "ugly charge strong giant once anchor capable october thumb inject dwarf legal alley mixture shoot
";
4280 var originalWords = originalPhrase.split(' ');
4281 driver.findElement(By.css('.phrase'))
4282 .sendKeys(originalPhrase);
4283 driver.sleep(generateDelay).then(function() {
4284 driver.findElement(By.css('.phraseSplit'))
4285 .getAttribute("value
")
4286 .then(function(cardsStr) {
4287 var cards = cardsStr.split("\n");
4288 expect(cards.length).toBe(3);
4289 // test all 2-of-3 combos can be used to form full phrase
4290 var combos = [[0,1],[0,2],[1,2]];
4291 for (var i=0; i<combos.length; i++) {
4292 var combo = combos[i];
4295 var phrase = cards[a] + " " + cards[b];
4296 // check all original words are present
4297 for (var j=0; j<originalWords.length; j++) {
4298 var originalWord = originalWords[j];
4299 expect(phrase).toContain(originalWord);
4307 // It allows manually specifying the entropy type
4308 it('Allows entropy type to be manually selected', function(done) {
4309 driver.findElement(By.css('.use-entropy'))
4311 // use decimal entropy
4312 driver.findElement(By.css('.entropy'))
4314 // manually change to binary entropy
4315 driver.executeScript(function() {
4316 $(".entropy
-container input
[value
='binary']").click();
4318 driver.sleep(entropyFeedbackDelay).then(function() {
4319 driver.findElement(By.css('.entropy-container'))
4321 .then(function(text) {
4322 // overide 91 to be just 1
4323 var key = "Filtered Entropy
";
4325 var reText = key + "\\s
+" + value;
4326 var re = new RegExp(reText);
4327 expect(text).toMatch(re);
4328 // overide automatic decimal to binary
4329 var key = "Entropy Type
";
4330 var value = "binary
";
4331 var reText = key + "\\s
+" + value;
4332 var re = new RegExp(reText);
4333 expect(text).toMatch(re);
4334 // overide 2 events to 1
4335 var key = "Event Count
";
4337 var reText = key + "\\s
+" + value;
4338 var re = new RegExp(reText);
4339 expect(text).toMatch(re);
4340 // overide log2(10)*2 bits to 1 bit
4341 var key = "Total Bits
";
4343 var reText = key + "\\s
+" + value;
4344 var re = new RegExp(reText);
4345 expect(text).toMatch(re);
4351 // https://github.com/iancoleman/bip39/issues/388
4352 // Make field for bip39 seed editable
4353 it('Generates addresses when seed is set', function(done) {
4354 driver.findElement(By.css('.seed'))
4355 .sendKeys("20da140d3dd1df8713cefcc4d54ce0e445b4151027a1ab567b832f6da5fcc5afc1c3a3f199ab78b8e0ab4652efd7f414ac2c9a3b81bceb879a70f377aa0a58f3
");
4356 driver.sleep(generateDelay).then(function() {
4357 getFirstAddress(function(address) {
4358 expect(address).toBe("1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug
");
4364 // https://github.com/iancoleman/bip39/issues/169
4365 it('Generates ethereum addresses from a public key', function(done) {
4366 var pubkey = "xpub68UK3hrMEp2jLPxPASgXSiqiUsQsUWZHCeuu6NqcJLt259LMeWzwDyufXLN1QmjLeLRY5he4QfArDDLbsXiw3xN3kFcYtyDy74BY73RPhhW
";
4367 driver.findElement(By.css('.root-key'))
4369 driver.findElement(By.css('#bip32-tab a'))
4371 selectNetwork('ETH - Ethereum');
4372 driver.sleep(generateDelay).then(function() {
4373 getFirstAddress(function(address) {
4374 expect(address).toBe("0x1Bd54748903438C7E386b4a3fCbe16237A316a98");