]> git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/BIP39.git/blob - tests/spec/tests.js
90cdc7afd84a66031ab15ee33ed6112475a62d20
[perso/Immae/Projets/Cryptomonnaies/BIP39.git] / tests / spec / tests.js
1 // Usage:
2 // cd /path/to/repo/tests
3 // jasmine spec/tests.js
4 //
5 // Dependencies:
6 // nodejs
7 // selenium
8 // jasmine
9 // see https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode#Automated_testing_with_headless_mode
10
11 // USER SPECIFIED OPTIONS
12 var browser = process.env.BROWSER; //"firefox"; // or "chrome"
13 if (!browser) {
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");
18 browser = "chrome";
19 }
20 else {
21 console.log("Using browser: " + browser);
22 }
23
24 // Globals
25
26 var webdriver = require('selenium-webdriver');
27 var By = webdriver.By;
28 var Key = webdriver.Key;
29 var until = webdriver.until;
30 var newDriver = null;
31 var driver = null;
32 // Delays in ms
33 var generateDelay = 1500;
34 var feedbackDelay = 500;
35 var entropyFeedbackDelay = 500;
36 var bip38delay = 15000;
37
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";
49 }
50
51 // Variables dependent on specific browser selection
52
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))
61 .build();
62 }
63 }
64 else if (browser == "chrome") {
65 var chrome = require('selenium-webdriver/chrome');
66 newDriver = function() {
67 return new webdriver.Builder()
68 .forBrowser('chrome')
69 .setChromeOptions(new chrome.Options().addArguments("headless"))
70 .build();
71 }
72 }
73
74 // Helper functions
75
76 function testNetwork(done, params, comparePub = false) {
77 var phrase = params.phrase || 'abandon abandon ability';
78 driver.findElement(By.css('.phrase'))
79 .sendKeys(phrase);
80 selectNetwork(params.selectText);
81 driver.sleep(generateDelay).then(function() {
82 if (!comparePub) {
83 getFirstAddress(function(address) {
84 expect(address).toBe(params.firstAddress);
85 done();
86 });
87 } else {
88 getFirstPublicKey(function(pubkey) {
89 expect(pubkey).toBe(params.firstPubKey);
90 done();
91 });
92 }
93 });
94 }
95
96 function getFirstRowValue(handler, selector) {
97 driver.findElements(By.css(selector))
98 .then(function(els) {
99 els[0].getText()
100 .then(handler);
101 })
102 }
103
104 function getFirstAddress(handler) {
105 getFirstRowValue(handler, ".address");
106 }
107
108 function getFirstPublicKey(handler) {
109 getFirstRowValue(handler, ".pubkey");
110 }
111
112 function getFirstPath(handler) {
113 getFirstRowValue(handler, ".index");
114 }
115
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");
123 done();
124 });
125 })
126 }
127
128 function testRowsAreInCorrectOrder(done) {
129 driver.findElements(By.css('.index'))
130 .then(function(els) {
131 var testRowAtIndex = function(i) {
132 if (i >= els.length) {
133 done();
134 }
135 else {
136 els[i].getText()
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);
143 testRowAtIndex(i+1);
144 });
145 }
146 }
147 testRowAtIndex(0);
148 });
149 }
150
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");
159 }, name);
160 }
161
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'))
167 .click();
168 driver.findElement(By.css('.entropy'))
169 .sendKeys(entropyText);
170 driver.sleep(generateDelay).then(function() {
171 driver.findElement(By.css('.entropy-container'))
172 .getText()
173 .then(function(text) {
174 var re = new RegExp("Entropy Type\\s+" + entropyType);
175 expect(text).toMatch(re);
176 done();
177 });
178 });
179 }
180
181 function testEntropyBits(done, entropyText, entropyBits) {
182 driver.findElement(By.css('.use-entropy'))
183 .click();
184 driver.findElement(By.css('.entropy'))
185 .sendKeys(entropyText);
186 driver.sleep(generateDelay).then(function() {
187 driver.findElement(By.css('.entropy-container'))
188 .getText()
189 .then(function(text) {
190 var re = new RegExp("Total Bits\\s+" + entropyBits);
191 expect(text).toMatch(re);
192 done();
193 });
194 });
195 }
196
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, "\\$&");
202 }
203 driver.findElement(By.css('.use-entropy'))
204 .click();
205 driver.findElement(By.css('.entropy'))
206 .sendKeys(entropyDetail.entropy);
207 driver.sleep(entropyFeedbackDelay).then(function() {
208 driver.findElement(By.css('.entropy-container'))
209 .getText()
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);
220 }
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);
227 }
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);
234 }
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);
241 }
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);
248 }
249 if ("words" in entropyDetail) {
250 var actualWords = phrase.split(/\s+/)
251 .filter(function(w) { return w.length > 0 })
252 .length;
253 expect(actualWords).toBe(entropyDetail.words);
254 }
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);
261 }
262 done();
263 });
264 });
265 });
266 }
267
268 function testClientSelect(done, params) {
269 // set mnemonic and select bip32 tab
270 driver.findElement(By.css('#bip32-tab a'))
271 .click()
272 driver.findElement(By.css('.phrase'))
273 .sendKeys("abandon abandon ability");
274 driver.sleep(generateDelay).then(function() {
275 // BITCOIN CORE
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");
296 done();
297 });
298 });
299 });
300 });
301 });
302 }
303
304 // Tests
305
306 describe('BIP39 Tool Tests', function() {
307
308 beforeEach(function(done) {
309 driver = newDriver();
310 driver.get(url).then(done);
311 });
312
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);
316 });
317
318 // BEGIN TESTS
319
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('');
325 done();
326 });
327 });
328
329 // Page has text
330 it('Should have text on the page', function(done) {
331 driver.findElement(By.css('body'))
332 .getText()
333 .then(function(text) {
334 var textToFind = "You can enter an existing BIP39 mnemonic";
335 expect(text).toContain(textToFind);
336 done();
337 });
338 });
339
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);
348 done();
349 })
350 });
351 });
352
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);
360 // press generate
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);
368 done();
369 });
370 });
371 });
372 });
373
374 // Mnemonic length can be customized
375 it('Should allow custom length mnemonics', function(done) {
376 // set strength to 6
377 driver.executeScript(function() {
378 $(".strength option[selected]").removeAttr("selected");
379 $(".strength option[value=6]").prop("selected", true);
380 });
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);
388 done();
389 });
390 });
391 });
392
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");
402 done();
403 })
404 });
405 });
406
407 // Network can be set to networks other than bitcoin
408 it('Allows selection of bitcoin testnet', function(done) {
409 var params = {
410 selectText: "BTC - Bitcoin Testnet",
411 firstAddress: "mucaU5iiDaJDb69BHLeDv8JFfGiyg2nJKi",
412 };
413 testNetwork(done, params);
414 });
415 it('Allows selection of litecoin', function(done) {
416 var params = {
417 selectText: "LTC - Litecoin",
418 firstAddress: "LQ4XU8RX2ULPmPq9FcUHdVmPVchP9nwXdn",
419 };
420 testNetwork(done, params);
421 });
422 it('Allows selection of litecoin testnet', function(done) {
423 var params = {
424 selectText: "LTCt - Litecoin Testnet",
425 firstAddress: "mucaU5iiDaJDb69BHLeDv8JFfGiyg2nJKi",
426 };
427 testNetwork(done, params);
428 });
429 it('Allows selection of ripple', function(done) {
430 var params = {
431 selectText: "XRP - Ripple",
432 firstAddress: "rLTFnqbmCVPGx6VfaygdtuKWJgcN4v1zRS",
433 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",
434 };
435 testNetwork(done, params);
436 });
437 it('Allows selection of dogecoin', function(done) {
438 var params = {
439 selectText: "DOGE - Dogecoin",
440 firstAddress: "DPQH2AtuzkVSG6ovjKk4jbUmZ6iXLpgbJA",
441 };
442 testNetwork(done, params);
443 });
444 it('Allows selection of dogecoin testnet', function(done) {
445 var params = {
446 selectText: "DOGEt - Dogecoin testnet",
447 firstAddress: "niHnSJKHdwDyDxRMLBJrtNqpvHEsAFWe6B",
448 };
449 testNetwork(done, params);
450 });
451 it('Allows selection of denarius', function(done) {
452 var params = {
453 selectText: "DNR - Denarius",
454 firstAddress: "DFdFMVUMzU9xX88EywXvAGwjiwpxyh9vKb",
455 };
456 testNetwork(done, params);
457 });
458 it('Allows selection of shadowcash', function(done) {
459 var params = {
460 selectText: "SDC - ShadowCash",
461 firstAddress: "SiSZtfYAXEFvMm3XM8hmtkGDyViRwErtCG",
462 };
463 testNetwork(done, params);
464 });
465 it('Allows selection of shadowcash testnet', function(done) {
466 var params = {
467 selectText: "SDC - ShadowCash Testnet",
468 firstAddress: "tM2EDpVKaTiEg2NZg3yKg8eqjLr55BErHe",
469 };
470 testNetwork(done, params);
471 });
472 it('Allows selection of viacoin', function(done) {
473 var params = {
474 selectText: "VIA - Viacoin",
475 firstAddress: "Vq9Eq4N5SQnjqZvxtxzo7hZPW5XnyJsmXT",
476 };
477 testNetwork(done, params);
478 });
479 it('Allows selection of viacoin testnet', function(done) {
480 var params = {
481 selectText: "VIA - Viacoin Testnet",
482 firstAddress: "tM2EDpVKaTiEg2NZg3yKg8eqjLr55BErHe",
483 };
484 testNetwork(done, params);
485 });
486 it('Allows selection of jumbucks', function(done) {
487 var params = {
488 selectText: "JBS - Jumbucks",
489 firstAddress: "JLEXccwDXADK4RxBPkRez7mqsHVoJBEUew",
490 };
491 testNetwork(done, params);
492 });
493 it('Allows selection of clam', function(done) {
494 var params = {
495 selectText: "CLAM - Clams",
496 firstAddress: "xCp4sakjVx4pUAZ6cBCtuin8Ddb6U1sk9y",
497 };
498 testNetwork(done, params);
499 });
500 it('Allows selection of crown', function(done) {
501 var params = {
502 selectText: "CRW - Crown (Legacy)",
503 firstAddress: "18pWSwSUAQdiwMHUfFZB1fM2xue9X1FqE5",
504 };
505 testNetwork(done, params);
506 });
507 it('Allows selection of crown', function(done) {
508 var params = {
509 selectText: "CRW - Crown",
510 firstAddress: "CRWKnVmVhvH1KWTYe6sq8xV4dFGcFpBEEkPQ",
511 };
512 testNetwork(done, params);
513 });
514 it('Allows selection of dash', function(done) {
515 var params = {
516 selectText: "DASH - Dash",
517 firstAddress: "XdbhtMuGsPSkE6bPdNTHoFSszQKmK4S5LT",
518 };
519 testNetwork(done, params);
520 });
521 it('Allows selection of dash testnet', function(done) {
522 var params = {
523 selectText: "DASH - Dash Testnet",
524 firstAddress: "yaR52EN4oojdJfBgzWJTymC4uuCLPT29Gw",
525 };
526 testNetwork(done, params);
527 });
528 it('Allows selection of game', function(done) {
529 var params = {
530 selectText: "GAME - GameCredits",
531 firstAddress: "GSMY9bAp36cMR4zyT4uGVS7GFjpdXbao5Q",
532 };
533 testNetwork(done, params);
534 });
535 it('Allows selection of komodo', function(done) {
536 var params = {
537 selectText: "KMD - Komodo",
538 firstAddress: "RMPPzJwAjPVZZAwJvXivHJGGjdCx6WBD2t",
539 };
540 testNetwork(done, params);
541 });
542 it('Allows selection of namecoin', function(done) {
543 var params = {
544 selectText: "NMC - Namecoin",
545 firstAddress: "Mw2vK2Bvex1yYtYF6sfbEg2YGoUc98YUD2",
546 };
547 testNetwork(done, params);
548 });
549 it('Allows selection of onixcoin', function(done) {
550 var params = {
551 selectText: "ONX - Onixcoin",
552 firstAddress: "XGwMqddeKjT3ddgX73QokjVbCL3aK6Yxfk",
553 };
554 testNetwork(done, params);
555 });
556 it('Allows selection of lkrcoin', function(done) {
557 var params = {
558 selectText: "LKR - Lkrcoin",
559 firstAddress: "LfbT296e7AEEnn4bYDbL535Nd8P9g98CdJ",
560 };
561 testNetwork(done, params);
562 });
563 it('Allows selection of bolivarcoin', function(done) {
564 var params = {
565 selectText: "BOLI - Bolivarcoin",
566 firstAddress: "bbKzCAUR7hZ3nqfffy7VgrSz8LmAP3S5mK",
567 };
568 testNetwork(done, params);
569 });
570 it('Allows selection of peercoin', function(done) {
571 var params = {
572 selectText: "PPC - Peercoin",
573 firstAddress: "PVAiioTaK2eDHSEo3tppT9AVdBYqxRTBAm",
574 };
575 testNetwork(done, params);
576 });
577 it('Allows selection of ethereum', function(done) {
578 var params = {
579 selectText: "ETH - Ethereum",
580 firstAddress: "0xe5815d5902Ad612d49283DEdEc02100Bd44C2772",
581 };
582 testNetwork(done, params);
583 // TODO test private key and public key
584 });
585 it('Allows selection of slimcoin', function(done) {
586 var params = {
587 selectText: "SLM - Slimcoin",
588 firstAddress: "SNzPi1CafHFm3WWjRo43aMgiaEEj3ogjww",
589 };
590 testNetwork(done, params);
591 });
592 it('Allows selection of slimcoin testnet', function(done) {
593 var params = {
594 selectText: "SLM - Slimcoin Testnet",
595 firstAddress: "n3nMgWufTek5QQAr6uwMhg5xbzj8xqc4Dq",
596 };
597 testNetwork(done, params);
598 });
599 it('Allows selection of bitcoin cash', function(done) {
600 var params = {
601 selectText: "BCH - Bitcoin Cash",
602 firstAddress: "bitcoincash:qzlquk7w4hkudxypl4fgv8x279r754dkvur7jpcsps",
603 };
604 testNetwork(done, params);
605 });
606
607 it('Allows selection of simpleledger(SLP)', function(done) {
608 var params = {
609 selectText: "SLP - Simple Ledger Protocol",
610 firstAddress: "simpleledger:qrtffz6ajfsn74gpur7y3epjquz42pvww5acewqmre",
611 };
612 testNetwork(done, params);
613 });
614
615 it('Allows selection of myriadcoin', function(done) {
616 var params = {
617 selectText: "XMY - Myriadcoin",
618 firstAddress: "MJEswvRR46wh9BoiVj9DzKYMBkCramhoBV",
619 };
620 testNetwork(done, params);
621 });
622 it('Allows selection of pivx', function(done) {
623 var params = {
624 selectText: "PIVX - PIVX",
625 firstAddress: "DBxgT7faCuno7jmtKuu6KWCiwqsVPqh1tS",
626 };
627 testNetwork(done, params);
628 });
629 it('Allows selection of pivx testnet', function(done) {
630 var params = {
631 selectText: "PIVX - PIVX Testnet",
632 firstAddress: "yB5U384n6dGkVE3by5y9VdvHHPwPg68fQj",
633 };
634 testNetwork(done, params);
635 });
636 it('Allows selection of maza', function(done) {
637 var params = {
638 selectText: "MAZA - Maza",
639 firstAddress: "MGW4Bmi2NEm4PxSjgeFwhP9vg18JHoRnfw",
640 };
641 testNetwork(done, params);
642 });
643 it('Allows selection of fujicoin', function(done) {
644 var params = {
645 selectText: "FJC - Fujicoin",
646 firstAddress: "FgiaLpG7C99DyR4WnPxXedRVHXSfKzUDhF",
647 };
648 testNetwork(done, params);
649 });
650 it('Allows selection of nubits', function(done) {
651 var params = {
652 selectText: "USNBT - NuBits",
653 firstAddress: "BLxkabXuZSJSdesLD7KxZdqovd4YwyBTU6",
654 };
655 testNetwork(done, params);
656 });
657 it('Allows selection of bitcoin gold', function(done) {
658 var params = {
659 selectText: "BTG - Bitcoin Gold",
660 firstAddress: "GdDqug4WUsn5syNbSTHatNn4XnuwZtzedx",
661 };
662 testNetwork(done, params);
663 });
664 it('Allows selection of monacoin', function(done) {
665 var params = {
666 selectText: "MONA - Monacoin",
667 firstAddress: "MKMiMr7MyjDKjJbCBzgF6u4ByqTS4NkRB1",
668 };
669 testNetwork(done, params);
670 });
671 it('Allows selection of AXE', function(done) {
672 var params = {
673 selectText: "AXE - Axe",
674 firstAddress: "PScwtLUyPiGrqtKXrHF37DGETLXLZdw4up",
675 };
676 testNetwork(done, params);
677 });
678 it('Allows selection of BlackCoin', function(done) {
679 var params = {
680 selectText: "BLK - BlackCoin",
681 firstAddress: "B5MznAKwj7uQ42vDz3w4onhBXPcqhTwJ9z",
682 };
683 testNetwork(done, params);
684 });
685 it('Allows selection of Neblio', function(done) {
686 var params = {
687 selectText: "NEBL - Neblio",
688 firstAddress: "NefkeEEvhusbHMmTRrxx7H9wFnUXd8qQsE",
689 };
690 testNetwork(done, params);
691 });
692 it('Allows selection of Beetlecoin', function(done) {
693 var params = {
694 selectText: "BEET - Beetlecoin",
695 firstAddress: "BVmtbEsGrjpknprmpHFq26z4kYHJUFHE71",
696 };
697 testNetwork(done, params);
698 });
699 it('Allows selection of Adcoin', function(done) {
700 var params = {
701 selectText: "ACC - Adcoin",
702 firstAddress: "AcEDM6V5sF4kFHC76MJjjfProtS5Sw2qcd",
703 };
704 testNetwork(done, params);
705 });
706 it('Allows selection of Asiacoin', function(done) {
707 var params = {
708 selectText: "AC - Asiacoin",
709 firstAddress: "ALupuEEz7kJjQTAvmtcBMBVuEjPa7GqZzE",
710 };
711 testNetwork(done, params);
712 });
713 it('Allows selection of Auroracoin', function(done) {
714 var params = {
715 selectText: "AUR - Auroracoin",
716 firstAddress: "ANuraS6F4Jpi413FEnavjYkKYJJRHkgYCm",
717 };
718 testNetwork(done, params);
719 });
720 it('Allows selection of Bata', function(done) {
721 var params = {
722 selectText: "BTA - Bata",
723 firstAddress: "BGxBdNeYPtF3GCuTtZBPQdFxCkdBYSF3fj",
724 };
725 testNetwork(done, params);
726 });
727 it('Allows selection of Belacoin', function(done) {
728 var params = {
729 selectText: "BELA - Belacoin",
730 firstAddress: "BEeetqpNffdzeknSpNmQp5KAFh2KK1Qx7S",
731 };
732 testNetwork(done, params);
733 });
734 it('Allows selection of Bitcoin Atom', function(done) {
735 var params = {
736 selectText: "BCA - Bitcoin Atom",
737 firstAddress: "AMy6qMbJeC4zsGRL6iWszmeCdQH65fgfih",
738 };
739 testNetwork(done, params);
740 });
741 it('Allows selection of Bitcoinplus', function(done) {
742 var params = {
743 selectText: "XBC - Bitcoinplus",
744 firstAddress: "B7FSynZoDbEwTCSgsXq9nJ5ue8owYLVL8r",
745 };
746 testNetwork(done, params);
747 });
748 it('Allows selection of Bitcoin Private', function(done) {
749 var params = {
750 selectText: "BTCP - Bitcoin Private",
751 firstAddress: "b1M3PbiXXyN6Hdivdw5rJv5VKpLjPzhm4jM",
752 };
753 testNetwork(done, params);
754 });
755 it('Allows selection of Bitcoinz', function(done) {
756 var params = {
757 selectText: "BTCZ - Bitcoinz",
758 firstAddress: "t1X2YQoxs8cYRo2oaBYgVEwW5QNjCC59NYc",
759 };
760 testNetwork(done, params);
761 });
762 it('Allows selection of BitCloud', function(done) {
763 var params = {
764 selectText: "BTDX - BitCloud",
765 firstAddress: "BHbWitXCNgTf1BhsRDNMP186EeibuzmrBi",
766 };
767 testNetwork(done, params);
768 });
769 it('Allows selection of Bitcore', function(done) {
770 var params = {
771 selectText: "BTX - Bitcore",
772 firstAddress: "2Rgp5Znhpy34TK4QmPkfCiYs9r4KovfTH9",
773 };
774 testNetwork(done, params);
775 });
776 it('Allows selection of Bitsend', function(done) {
777 var params = {
778 selectText: "BSD - Bitsend",
779 firstAddress: "iBPk7LYjDun3EPk7CRR8UUmnPoceVc1bp2",
780 };
781 testNetwork(done, params);
782 });
783 it('Allows selection of Britcoin', function(done) {
784 var params = {
785 selectText: "BRIT - Britcoin",
786 firstAddress: "B6Aue4J2XLs1f1dtD4H1SHYFfh4XrmEbrw",
787 };
788 testNetwork(done, params);
789 });
790 it('Allows selection of Canadaecoin', function(done) {
791 var params = {
792 selectText: "CDN - Canadaecoin",
793 firstAddress: "CanAyCfd5Rj2CQVfaoAmvDUZunPM5W1AEQ",
794 };
795 testNetwork(done, params);
796 });
797 it('Allows selection of Cannacoin', function(done) {
798 var params = {
799 selectText: "CCN - Cannacoin",
800 firstAddress: "CYjW8xWB43g6krLJTmmrPk1PonoQX7h9Qd",
801 };
802 testNetwork(done, params);
803 });
804 it('Allows selection of Clubcoin', function(done) {
805 var params = {
806 selectText: "CLUB - Clubcoin",
807 firstAddress: "CHMDEXN4sihpSVX4GyAa2hZ62shnby7uyN",
808 };
809 testNetwork(done, params);
810 });
811 it('Allows selection of Compcoin', function(done) {
812 var params = {
813 selectText: "CMP - Compcoin",
814 firstAddress: "CLshtw3zhxkseBJS46UF12v3AFy9Dx7JVv",
815 };
816 testNetwork(done, params);
817 });
818 it('Allows selection of Crave', function(done) {
819 var params = {
820 selectText: "CRAVE - Crave",
821 firstAddress: "VCYJeti6uKMNBFKCL7eP96UwuFWYHM7c85",
822 };
823 testNetwork(done, params);
824 });
825 it('Allows selection of Defcoin', function(done) {
826 var params = {
827 selectText: "DFC - Defcoin",
828 firstAddress: "D8swcgyaaFUrXZU3ATwbgy16buCpWqbG1M",
829 };
830 testNetwork(done, params);
831 });
832 it('Allows selection of Diamond', function(done) {
833 var params = {
834 selectText: "DMD - Diamond",
835 firstAddress: "dJnrVbLL9UPjdaVRz2C8VpqHZknqAqjLek",
836 };
837 testNetwork(done, params);
838 });
839 it('Allows selection of Digibyte', function(done) {
840 var params = {
841 selectText: "DGB - Digibyte",
842 firstAddress: "D85Rp9jwLtMdmP6wGjTiqHBdVQLST3YCEq",
843 };
844 testNetwork(done, params);
845 });
846 it('Allows selection of Digitalcoin', function(done) {
847 var params = {
848 selectText: "DGC - Digitalcoin",
849 firstAddress: "DKw4UGKEAZWweDNEbBFNQx4EM8x1mpUdia",
850 };
851 testNetwork(done, params);
852 });
853 it('Allows selection of Ecoin', function(done) {
854 var params = {
855 selectText: "ECN - Ecoin",
856 firstAddress: "e6WFPLG5gcXyF7cESFteH1hE2XSmowW5yB",
857 };
858 testNetwork(done, params);
859 });
860 it('Allows selection of Edrcoin', function(done) {
861 var params = {
862 selectText: "EDRC - Edrcoin",
863 firstAddress: "eh1nUJsvgKPFv6ebMBfcwJ299GMCpjeZUG",
864 };
865 testNetwork(done, params);
866 });
867 it('Allows selection of Egulden', function(done) {
868 var params = {
869 selectText: "EFL - Egulden",
870 firstAddress: "Lg66yt55R7edRM58cDhKzXik2kFme3viX7",
871 };
872 testNetwork(done, params);
873 });
874 it('Allows selection of Einsteinium', function(done) {
875 var params = {
876 selectText: "EMC2 - Einsteinium",
877 firstAddress: "EVAABm9hXKHk2MpVMbwNakRubFnNha5m8m",
878 };
879 testNetwork(done, params);
880 });
881 it('Allows selection of EOSIO', function(done) {
882 var params = {
883 selectText: "EOS - EOSIO",
884 firstPubKey: "EOS692VJTBK3Rmw93onNnpnZ8ZtmE9PdxjDStArvbyzoe11QUTNoy",
885 };
886 testNetowrk(done, params, true);
887 });
888 it('Allows selection of Europecoin', function(done) {
889 var params = {
890 selectText: "ERC - Europecoin",
891 firstAddress: "ESA2YwPYntAoaPrE8Fm5qkKRtkcwLcwD6R",
892 };
893 testNetwork(done, params);
894 });
895 it('Allows selection of Exclusivecoin', function(done) {
896 var params = {
897 selectText: "EXCL - Exclusivecoin",
898 firstAddress: "EbUa6m8UZW6nTxsYZD2FsDjkadKbp5M6JT",
899 };
900 testNetwork(done, params);
901 });
902 it('Allows selection of Feathercoin', function(done) {
903 var params = {
904 selectText: "FTC - Feathercoin",
905 firstAddress: "6gDdjAMoSgQaW8UhqK3oboHs6ftGAroKkM",
906 };
907 testNetwork(done, params);
908 });
909 it('Allows selection of Firstcoin', function(done) {
910 var params = {
911 selectText: "FRST - Firstcoin",
912 firstAddress: "FJN9GzfMm7Q8R4DJwK1H9F6A1GTghvFiMJ",
913 };
914 testNetwork(done, params);
915 });
916 it('Allows selection of Flashcoin', function(done) {
917 var params = {
918 selectText: "FLASH - Flashcoin",
919 firstAddress: "UWfpf5LfMmLxZYooEb2EyvWhZ8NG7EZDRt",
920 };
921 testNetwork(done, params);
922 });
923 it('Allows selection of GCRCoin', function(done) {
924 var params = {
925 selectText: "GCR - GCRCoin",
926 firstAddress: "GJjF5cLwyXLacpuvXAVksxGxKvHDjx58d6",
927 };
928 testNetwork(done, params);
929 });
930 it('Allows selection of Gobyte', function(done) {
931 var params = {
932 selectText: "GBX - Gobyte",
933 firstAddress: "GS813Ys2brkmvSUw1rUqGPm2HqQVDHJRyA",
934 };
935 testNetwork(done, params);
936 });
937 it('Allows selection of Gridcoin', function(done) {
938 var params = {
939 selectText: "GRC - Gridcoin",
940 firstAddress: "SGrWbBPvobgqKRF8td1Kdc9vbRY7MJ78Y9",
941 };
942 testNetwork(done, params);
943 });
944 it('Allows selection of Gulden', function(done) {
945 var params = {
946 selectText: "NLG - Gulden",
947 firstAddress: "GcDP7cNEc33MPPdTFNJ8pZc6VMZJ2CbKxY",
948 };
949 testNetwork(done, params);
950 });
951 it('Allows selection of Helleniccoin', function(done) {
952 var params = {
953 selectText: "HNC - Helleniccoin",
954 firstAddress: "LbHEKe5H72zp9G1fuWNiiNePTUfJb88915",
955 };
956 testNetwork(done, params);
957 });
958 it('Allows selection of Hempcoin', function(done) {
959 var params = {
960 selectText: "THC - Hempcoin",
961 firstAddress: "H8sdWbZyJV4gyXyHtLXDaNnAuUDhK5mfTV",
962 };
963 testNetwork(done, params);
964 });
965 it('Allows selection of Insane', function(done) {
966 var params = {
967 selectText: "INSN - Insane",
968 firstAddress: "iMPqEJMiXWuxC9U2NVinCCMr4t72h58EWx",
969 };
970 testNetwork(done, params);
971 });
972 it('Allows selection of Iop', function(done) {
973 var params = {
974 selectText: "IOP - Iop",
975 firstAddress: "pGKQmcaPf95Ur5o6oHK4qdiZ52p1yaTvq1",
976 };
977 testNetwork(done, params);
978 });
979 it('Allows selection of Ixcoin', function(done) {
980 var params = {
981 selectText: "IXC - Ixcoin",
982 firstAddress: "xgE9bTZ6YypT3E6ByzkTt31Hq68E9BqywH",
983 };
984 testNetwork(done, params);
985 });
986 it('Allows selection of Kobocoin', function(done) {
987 var params = {
988 selectText: "KOBO - Kobocoin",
989 firstAddress: "FTVoNJETXDAM8x7MnmdE8RwWndSr9PQWhy",
990 };
991 testNetwork(done, params);
992 });
993 it('Allows selection of Landcoin', function(done) {
994 var params = {
995 selectText: "LDCN - Landcoin",
996 firstAddress: "LLvLwNjG1aJcn1RS4W4GJUbv8fNaRATG7c",
997 };
998 testNetwork(done, params);
999 });
1000 it('Allows selection of Library Credits', function(done) {
1001 var params = {
1002 selectText: "LBC - Library Credits",
1003 firstAddress: "bQJEQrHDJyHdqycB32uysh1SWn8Ln8LMdg",
1004 };
1005 testNetwork(done, params);
1006 });
1007 it('Allows selection of Linx', function(done) {
1008 var params = {
1009 selectText: "LINX - Linx",
1010 firstAddress: "XGWQ3cb3LGUB3VnHmj6xYSMgnokNbf6dyk",
1011 };
1012 testNetwork(done, params);
1013 });
1014 it('Allows selection of Litecoincash', function(done) {
1015 var params = {
1016 selectText: "LCC - Litecoincash",
1017 firstAddress: "Ce5n7fjUuQPLutJ4W5nCCfQLKdKLE1mv9A",
1018 };
1019 testNetwork(done, params);
1020 });
1021 it('Allows selection of Lynx', function(done) {
1022 var params = {
1023 selectText: "LYNX - Lynx",
1024 firstAddress: "KUeY3ZdZkg96p4W98pj1JjygCFU1XqWdw3",
1025 };
1026 testNetwork(done, params);
1027 });
1028 it('Allows selection of Megacoin', function(done) {
1029 var params = {
1030 selectText: "MEC - Megacoin",
1031 firstAddress: "MDfAj9CzkC1HpcUiVGnHp8yKTa7WXgu8AY",
1032 };
1033 testNetwork(done, params);
1034 });
1035 it('Allows selection of Minexcoin', function(done) {
1036 var params = {
1037 selectText: "MNX - Minexcoin",
1038 firstAddress: "XC1VnyJVfiMDwWgFtAHDp41cgY3AHk3dJT",
1039 };
1040 testNetwork(done, params);
1041 });
1042 it('Allows selection of Navcoin', function(done) {
1043 var params = {
1044 selectText: "NAV - Navcoin",
1045 firstAddress: "NTQVTPK3NWSQLKoffkiQw99T8PifkF1Y2U",
1046 };
1047 testNetwork(done, params);
1048 });
1049 it('Allows selection of Nebulas', function(done) {
1050 var params = {
1051 selectText: "NAS - Nebulas",
1052 firstAddress: "n1PbK61DGBfDoDusLw621G6sVSMfLLHdfnm",
1053 };
1054 testNetwork(done, params);
1055 });
1056 it('Allows selection of Neoscoin', function(done) {
1057 var params = {
1058 selectText: "NEOS - Neoscoin",
1059 firstAddress: "NgATz6QbQNXvayHQ4CpZayugb9HeaPDdby",
1060 };
1061 testNetwork(done, params);
1062 });
1063 it('Allows selection of Nix', function(done) {
1064 var params = {
1065 selectText: "NIX - NIX Platform",
1066 firstAddress: "GgcNW2SQQXB4LWHRQTHKkQF3GzXNSLqS8u",
1067 };
1068 testNetwork(done, params);
1069 });
1070 it('Allows selection of Neurocoin', function(done) {
1071 var params = {
1072 selectText: "NRO - Neurocoin",
1073 firstAddress: "NVdYErQ3mFpDuF5DquW9WMiT7sLc8ufFTn",
1074 };
1075 testNetwork(done, params);
1076 });
1077 it('Allows selection of Newyorkc', function(done) {
1078 var params = {
1079 selectText: "NYC - Newyorkc",
1080 firstAddress: "RSVMfyH1fKfy3puADJEhut2vfkRyon6imm",
1081 };
1082 testNetwork(done, params);
1083 });
1084 it('Allows selection of Novacoin', function(done) {
1085 var params = {
1086 selectText: "NVC - Novacoin",
1087 firstAddress: "4JRvUmxcKCJmaMXZyvRoSS1cmG2XvnZfHN",
1088 };
1089 testNetwork(done, params);
1090 });
1091 it('Allows selection of Nushares', function(done) {
1092 var params = {
1093 selectText: "NSR - Nushares",
1094 firstAddress: "SecjXzU3c7EecdT7EbC4vvmbdtBBokWh6J",
1095 };
1096 testNetwork(done, params);
1097 });
1098 it('Allows selection of Okcash', function(done) {
1099 var params = {
1100 selectText: "OK - Okcash",
1101 firstAddress: "PV4Qp1TUYuGv4TqVtLZtqvrsWWRycfx1Yi",
1102 };
1103 testNetwork(done, params);
1104 });
1105 it('Allows selection of Omnicore', function(done) {
1106 var params = {
1107 selectText: "OMNI - Omnicore",
1108 firstAddress: "1Q1t3gonjCT3rW38TsTsCvgSc3hh7zBGbi",
1109 };
1110 testNetwork(done, params);
1111 });
1112 it('Allows selection of DeepOnion', function(done) {
1113 var params = {
1114 selectText: "ONION - DeepOnion",
1115 firstAddress: "DYREY7XCFXVqJ3x5UuN43k2JwD2s1kif48",
1116 };
1117 testNetwork(done, params);
1118 });
1119 it('Allows selection of Pesobit', function(done) {
1120 var params = {
1121 selectText: "PSB - Pesobit",
1122 firstAddress: "PDePsF7ALyXP7JaywokdYiRTDtKa14MAr1",
1123 };
1124 testNetwork(done, params);
1125 });
1126 it('Allows selection of Pinkcoin', function(done) {
1127 var params = {
1128 selectText: "PINK - Pinkcoin",
1129 firstAddress: "2TgjYQffjbzUHJghNaVbdsjHbRwruC3yzC",
1130 };
1131 testNetwork(done, params);
1132 });
1133 it('Allows selection of POSWcoin', function(done) {
1134 var params = {
1135 selectText: "POSW - POSWcoin",
1136 firstAddress: "PNxewmZoPnGBvoEbH6hgQZCK1igDiBCdgC",
1137 };
1138 testNetwork(done, params);
1139 });
1140 it('Allows selection of Potcoin', function(done) {
1141 var params = {
1142 selectText: "POT - Potcoin",
1143 firstAddress: "PEo7Vg2ctXgpP4vuLPeY9aGJtZotyrmiHc",
1144 };
1145 testNetwork(done, params);
1146 });
1147 it('Allows selection of Putincoin', function(done) {
1148 var params = {
1149 selectText: "PUT - Putincoin",
1150 firstAddress: "PViWnfr2uFtovd6e7joM49C94CsGSnqJis",
1151 };
1152 testNetwork(done, params);
1153 });
1154 it('Allows selection of Ravencoin', function(done) {
1155 var params = {
1156 selectText: "RVN - Ravencoin",
1157 firstAddress: "RBuDoVNnzvFsEcX8XKPm8ic4mgiCzjUCNk",
1158 };
1159 testNetwork(done, params);
1160 });
1161 it('Allows selection of Reddcoin', function(done) {
1162 var params = {
1163 selectText: "RDD - Reddcoin",
1164 firstAddress: "RtgRvXMBng1y51ftteveFqwNfyRG18HpxQ",
1165 };
1166 testNetwork(done, params);
1167 });
1168 it('Allows selection of RevolutionVR', function(done) {
1169 var params = {
1170 selectText: "RVR - RevolutionVR",
1171 firstAddress: "VXeeoP2jkzZnMFxtc66ZBZK1NHN5QJnnjL",
1172 };
1173 testNetwork(done, params);
1174 });
1175 it('Allows selection of Rubycoin', function(done) {
1176 var params = {
1177 selectText: "RBY - Rubycoin",
1178 firstAddress: "RV76JDtjTs11JdMDRToYn6CHecMRPLnKS6",
1179 };
1180 testNetwork(done, params);
1181 });
1182 it('Allows selection of Salus', function(done) {
1183 var params = {
1184 selectText: "SLS - Salus",
1185 firstAddress: "SNzPi1CafHFm3WWjRo43aMgiaEEj3ogjww",
1186 };
1187 testNetwork(done, params);
1188 });
1189 it('Allows selection of Smileycoin', function(done) {
1190 var params = {
1191 selectText: "SMLY - Smileycoin",
1192 firstAddress: "BEZVnEBCAyFByrgKpwAgYgtvP4rKAd9Sj2",
1193 };
1194 testNetwork(done, params);
1195 });
1196 it('Allows selection of Solarcoin', function(done) {
1197 var params = {
1198 selectText: "SLR - Solarcoin",
1199 firstAddress: "8LZ13HbnjtaMJWSvvVFNTLf71zFfDrhwLu",
1200 };
1201 testNetwork(done, params);
1202 });
1203 it('Allows selection of stash', function(done) {
1204 var params = {
1205 selectText: "STASH - Stash",
1206 firstAddress: "XxwAsWB7REDKmAvHA85SbEZQQtpxeUDxS3",
1207 };
1208 testNetwork(done, params);
1209 });
1210 it('Allows selection of stash testnet', function(done) {
1211 var params = {
1212 selectText: "STASH - Stash Testnet",
1213 firstAddress: "yWQCTSkUst7ddYuebKsqa1kSoXEjpCkGKR",
1214 };
1215 testNetwork(done, params);
1216 });
1217 it('Allows selection of Stratis', function(done) {
1218 var params = {
1219 selectText: "STRAT - Stratis",
1220 firstAddress: "ScfJnq3QDhKgDMEds6sqUE1ot6ShfhmXXq",
1221 };
1222 testNetwork(done, params);
1223 });
1224 it('Allows selection of Stratis Test', function(done) {
1225 var params = {
1226 selectText: "TSTRAT - Stratis Testnet",
1227 firstAddress: "TRLWm3dye4FRrDWouwYUSUZP96xb76mBE3",
1228 };
1229 testNetwork(done, params);
1230 });
1231 it('Allows selection of Syscoin', function(done) {
1232 var params = {
1233 selectText: "SYS - Syscoin",
1234 firstAddress: "SZwJi42Pst3VAMomyK5DG4157WM5ofRmSj",
1235 };
1236 testNetwork(done, params);
1237 });
1238 it('Allows selection of Toa', function(done) {
1239 var params = {
1240 selectText: "TOA - Toa",
1241 firstAddress: "TSe1QAnUwQzUfbBusDzRJ9URttrRGKoNKF",
1242 };
1243 testNetwork(done, params);
1244 });
1245 it('Allows selection of Ultimatesecurecash', function(done) {
1246 var params = {
1247 selectText: "USC - Ultimatesecurecash",
1248 firstAddress: "UPyLAZU2Che5fiy7Ed8xVJFmXAUhitA4ug",
1249 };
1250 testNetwork(done, params);
1251 });
1252 it('Allows selection of Unobtanium', function(done) {
1253 var params = {
1254 selectText: "UNO - Unobtanium",
1255 firstAddress: "uUBMPVMXrR6qhqornJqKTWgr8L69vihSL9",
1256 };
1257 testNetwork(done, params);
1258 });
1259 it('Allows selection of Vcash', function(done) {
1260 var params = {
1261 selectText: "XVC - Vcash",
1262 firstAddress: "VuL53MSY6KjvAjKSeRkh3NDnKykacDVeps",
1263 };
1264 testNetwork(done, params);
1265 });
1266 it('Allows selection of Verge', function(done) {
1267 var params = {
1268 selectText: "XVG - Verge",
1269 firstAddress: "DCrVuGkMjLJpTGgwAgv9AcMdeb1nkWbjZA",
1270 };
1271 testNetwork(done, params);
1272 });
1273 it('Allows selection of Vertcoin', function(done) {
1274 var params = {
1275 selectText: "VTC - Vertcoin",
1276 firstAddress: "Vf6koGuiWdXQfx8tNqxoNeEDxh4xh5cxsG",
1277 };
1278 testNetwork(done, params);
1279 });
1280 it('Allows selection of Vivo', function(done) {
1281 var params = {
1282 selectText: "VIVO - Vivo",
1283 firstAddress: "VFmBwuXXGhJe7MarQG2GfzHMFebRHgfSpB",
1284 };
1285 testNetwork(done, params);
1286 });
1287 it('Allows selection of Vpncoin', function(done) {
1288 var params = {
1289 selectText: "VASH - Vpncoin",
1290 firstAddress: "VoEmH1qXC4TsSgBAStR21QYetwnFqbqCx9",
1291 };
1292 testNetwork(done, params);
1293 });
1294 it('Allows selection of Whitecoin', function(done) {
1295 var params = {
1296 selectText: "XWC - Whitecoin",
1297 firstAddress: "WcSwCAUqrSgeSYbsaS3SSWWhsx8KRYTFDR",
1298 };
1299 testNetwork(done, params);
1300 });
1301 it('Allows selection of Wincoin', function(done) {
1302 var params = {
1303 selectText: "WC - Wincoin",
1304 firstAddress: "WaDVCESMGgyKgNESdn3u43NnwmGSkZED3Z",
1305 };
1306 testNetwork(done, params);
1307 });
1308 it('Allows selection of Zcoin', function(done) {
1309 var params = {
1310 selectText: "XZC - Zcoin",
1311 firstAddress: "a6VcMdP4XgAA9Tr7xNszmPG5FZpfRf17Cq",
1312 };
1313 testNetwork(done, params);
1314 });
1315 it('Allows selection of Zcash', function(done) {
1316 var params = {
1317 selectText: "ZEC - Zcash",
1318 firstAddress: "t1Sz8AneMcVuzUg3tPJ8et5AS5LFJ7K2EF9",
1319 };
1320 testNetwork(done, params);
1321 });
1322 it('Allows selection of Zclassic', function(done) {
1323 var params = {
1324 selectText: "ZCL - Zclassic",
1325 firstAddress: "t1TBMxTvVJRybUbMLGWq8H4A8F4VUL7czEc",
1326 };
1327 testNetwork(done, params);
1328 });
1329 it('Allows selection of Zencash', function(done) {
1330 var params = {
1331 selectText: "ZEN - Zencash",
1332 firstAddress: "znWh9XASyW2dZq5tck84wFjiwuqVysi7q3p",
1333 };
1334 testNetwork(done, params);
1335 });
1336 it('Allows selection of Energi', function(done) {
1337 var params = {
1338 selectText: "NRG - Energi",
1339 firstAddress: "EejRy4t4nidzhGGzkJUgFP3z4HYBjhTsRt",
1340 };
1341 testNetwork(done, params);
1342 });
1343 it('Allows selection of Ethereum Classic', function(done) {
1344 var params = {
1345 selectText: "ETC - Ethereum Classic",
1346 firstAddress: "0x3c05e5556693808367afB62eF3b63e35d6eD249A",
1347 };
1348 testNetwork(done, params);
1349 });
1350 it('Allows selection of Pirl', function(done) {
1351 var params = {
1352 selectText: "PIRL - Pirl",
1353 firstAddress: "0xe77FC0723dA122B5025CA79193c28563eB47e776",
1354 };
1355 testNetwork(done, params);
1356 });
1357 it('Allows selection of MIX', function(done) {
1358 var params = {
1359 selectText: "MIX - MIX",
1360 firstAddress: "0x98BC5e63aeb6A4e82d72850d20710F07E29A29F1",
1361 };
1362 testNetwork(done, params);
1363 });
1364 it('Allows selection of Musicoin', function(done) {
1365 var params = {
1366 selectText: "MUSIC - Musicoin",
1367 firstAddress: "0xDc060e4A0b0313ea83Cf6B3A39B9db2D29004897",
1368 };
1369 testNetwork(done, params);
1370 });
1371 it('Allows selection of Poa', function(done) {
1372 var params = {
1373 selectText: "POA - Poa",
1374 firstAddress: "0x53aF28d754e106210C3d0467Dd581eaf7e3C5e60",
1375 };
1376 testNetwork(done, params);
1377 });
1378 it('Allows selection of Expanse', function(done) {
1379 var params = {
1380 selectText: "EXP - Expanse",
1381 firstAddress: "0xf57FeAbf26582b6E3E666559d3B1Cc6fB2b2c5F6",
1382 };
1383 testNetwork(done, params);
1384 });
1385 it('Allows selection of Callisto', function(done) {
1386 var params = {
1387 selectText: "CLO - Callisto",
1388 firstAddress: "0x4f9364F7420B317266C51Dc8eB979717D4dE3f4E",
1389 };
1390 testNetwork(done, params);
1391 });
1392 it('Allows selection of HUSH', function(done) {
1393 var params = {
1394 selectText: "HUSH - Hush",
1395 firstAddress: "t1g6rLXUnJaiJuu4q4zmJjoa9Gk4fwKpiuA",
1396 };
1397 testNetwork(done, params);
1398 });
1399 it('Allows selection of ExchangeCoin', function(done) {
1400 var params = {
1401 selectText: "EXCC - ExchangeCoin",
1402 firstAddress: "22txYKpFN5fwGwdSs2UBf7ywewbLM92YqK7E",
1403 };
1404 testNetwork(done, params);
1405 });
1406 it('Allows selection of Artax', function(done) {
1407 var params = {
1408 selectText: "XAX - Artax",
1409 firstAddress: "AYxaQPY7XLidG31V7F3yNzwxPYpYzRqG4q",
1410 };
1411 testNetwork(done, params);
1412 });
1413 it('Allows selection of BitcoinGreen', function(done) {
1414 var params = {
1415 selectText: "BITG - Bitcoin Green",
1416 firstAddress: "GeNGm9SkEfwbsws3UrrUSE2sJeyWYjzraY",
1417 };
1418 testNetwork(done, params);
1419 });
1420 it('Allows selection of ANON', function(done) {
1421 var params = {
1422 selectText: "ANON - ANON",
1423 firstAddress: "AnU6pijpEeUZFWSTyM2qTqZQn996Zq1Xard",
1424 };
1425 testNetwork(done, params);
1426 });
1427 it('Allows selection of ProjectCoin', function(done) {
1428 var params = {
1429 selectText: "PRJ - ProjectCoin",
1430 firstAddress: "PXZG97saRseSCftfe1mcFmfAA7pf6qBbaz",
1431 };
1432 testNetwork(done, params);
1433 });
1434 it('Allows selection of Phore', function(done) {
1435 var params = {
1436 selectText: "PHR - Phore",
1437 firstAddress: "PJThxpoXAG6hqrmdeQQbVDX4TJtFTMMymC",
1438 };
1439 testNetwork(done, params);
1440 });
1441 it('Allows selection of Safecoin', function(done) {
1442 var params = {
1443 selectText: "SAFE - Safecoin",
1444 firstAddress: "RtxHpnhJz6RY8k9owP3ua5QWraunmewB1G",
1445 };
1446 testNetwork(done, params);
1447 });
1448 it('Allows selection of Blocknode', function(done) {
1449 var params = {
1450 selectText: "BND - Blocknode",
1451 firstAddress: "BG8xZSAur2jYLG9VXt8dYfkKxxeR7w9bSe",
1452 };
1453 testNetwork(done, params);
1454 });
1455 it('Allows selection of Blocknode Testnet', function(done) {
1456 var params = {
1457 selectText: "tBND - Blocknode Testnet",
1458 firstAddress: "bSptsFyDktFSKpWveRywJsDoJA2TC6qfHv",
1459 };
1460 testNetwork(done, params);
1461 });
1462 it('Allows selection of LitecoinZ', function(done) {
1463 var params = {
1464 selectText: "LTZ - LitecoinZ",
1465 firstAddress: "L1VTXju7hLgKV4T7fGXS9sKsnm2gmtRCmyw",
1466 };
1467 testNetwork(done, params);
1468 });
1469 it('Allows selection of BlockStamp', function(done) {
1470 var params = {
1471 selectText: "BST - BlockStamp",
1472 firstAddress: "15gypKtim4cVTj137ApfryG17RkvSbPazZ",
1473 };
1474 testNetwork(done, params);
1475 });
1476 it('Allows selection of DEXON', function(done) {
1477 var params = {
1478 selectText: "DXN - DEXON",
1479 firstAddress: "0x136a58788033E028CCd740FbDec6734358DB56Ec",
1480 };
1481 testNetwork(done, params);
1482 });
1483 it('Allows selection of Ellaism', function(done) {
1484 var params = {
1485 selectText: "ELLA - Ellaism",
1486 firstAddress: "0xa8B0BeA09eeBc41062308546a01d6E544277e2Ca",
1487 };
1488 testNetwork(done, params);
1489 });
1490 it('Allows selection of Ethersocial Network', function(done) {
1491 var params = {
1492 selectText: "ESN - Ethersocial Network",
1493 firstAddress: "0x6EE99Be2A0C7F887a71e21C8608ACF0aa0D2b767",
1494 };
1495 testNetwork(done, params);
1496 });
1497 it('Allows selection of Monkey Project', function(done) {
1498 var params = {
1499 selectText: "MONK - Monkey Project",
1500 firstAddress: "MnLrcnnUzKnf7TzufjRe5DLZqQJz18oYyu",
1501 };
1502 testNetwork(done, params);
1503 });
1504
1505 // BIP39 seed is set from phrase
1506 it('Sets the bip39 seed from the prhase', function(done) {
1507 driver.findElement(By.css('.phrase'))
1508 .sendKeys('abandon abandon ability');
1509 driver.sleep(generateDelay).then(function() {
1510 driver.findElement(By.css('.seed'))
1511 .getAttribute("value")
1512 .then(function(seed) {
1513 expect(seed).toBe("20da140d3dd1df8713cefcc4d54ce0e445b4151027a1ab567b832f6da5fcc5afc1c3a3f199ab78b8e0ab4652efd7f414ac2c9a3b81bceb879a70f377aa0a58f3");
1514 done();
1515 })
1516 });
1517 });
1518
1519 // BIP32 root key is set from phrase
1520 it('Sets the bip39 root key from the prhase', function(done) {
1521 driver.findElement(By.css('.phrase'))
1522 .sendKeys('abandon abandon ability');
1523 driver.sleep(generateDelay).then(function() {
1524 driver.findElement(By.css('.root-key'))
1525 .getAttribute("value")
1526 .then(function(seed) {
1527 expect(seed).toBe("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi");
1528 done();
1529 })
1530 });
1531 });
1532
1533 // Tabs show correct addresses when changed
1534 it('Shows the correct address when tab is changed', function(done) {
1535 driver.findElement(By.css('.phrase'))
1536 .sendKeys('abandon abandon ability');
1537 driver.sleep(generateDelay).then(function() {
1538 driver.findElement(By.css('#bip32-tab a'))
1539 .click();
1540 driver.sleep(generateDelay).then(function() {
1541 getFirstAddress(function(address) {
1542 expect(address).toBe("17uQ7s2izWPwBmEVFikTmZUjbBKWYdJchz");
1543 done();
1544 });
1545 });
1546 });
1547 });
1548
1549 // BIP44 derivation path is shown
1550 it('Shows the derivation path for bip44 tab', function(done) {
1551 driver.findElement(By.css('.phrase'))
1552 .sendKeys('abandon abandon ability');
1553 driver.sleep(generateDelay).then(function() {
1554 driver.findElement(By.css('#bip44 .path'))
1555 .getAttribute("value")
1556 .then(function(path) {
1557 expect(path).toBe("m/44'/0'/0'/0");
1558 done();
1559 })
1560 });
1561 });
1562
1563 // BIP44 extended private key is shown
1564 it('Shows the extended private key for bip44 tab', function(done) {
1565 driver.findElement(By.css('.phrase'))
1566 .sendKeys('abandon abandon ability');
1567 driver.sleep(generateDelay).then(function() {
1568 driver.findElement(By.css('.extended-priv-key'))
1569 .getAttribute("value")
1570 .then(function(path) {
1571 expect(path).toBe("xprvA2DxxvPZcyRvYgZMGS53nadR32mVDeCyqQYyFhrCVbJNjPoxMeVf7QT5g7mQASbTf9Kp4cryvcXnu2qurjWKcrdsr91jXymdCDNxKgLFKJG");
1572 done();
1573 })
1574 });
1575 });
1576
1577 // BIP44 extended public key is shown
1578 it('Shows the extended public key for bip44 tab', function(done) {
1579 driver.findElement(By.css('.phrase'))
1580 .sendKeys('abandon abandon ability');
1581 driver.sleep(generateDelay).then(function() {
1582 driver.findElement(By.css('.extended-pub-key'))
1583 .getAttribute("value")
1584 .then(function(path) {
1585 expect(path).toBe("xpub6FDKNRvTTLzDmAdpNTc49ia9b4byd6vqCdUa46Fp3vqMcC96uBoufCmZXQLiN5AK3iSCJMhf9gT2sxkpyaPepRuA7W3MujV5tGmF5VfbueM");
1586 done();
1587 })
1588 });
1589 });
1590
1591 // BIP44 account field changes address list
1592 it('Changes the address list if bip44 account is changed', function(done) {
1593 driver.findElement(By.css('#bip44 .account'))
1594 .sendKeys('1');
1595 driver.findElement(By.css('.phrase'))
1596 .sendKeys('abandon abandon ability');
1597 driver.sleep(generateDelay).then(function() {
1598 getFirstAddress(function(address) {
1599 expect(address).toBe("1Nq2Wmu726XHCuGhctEtGmhxo3wzk5wZ1H");
1600 done();
1601 });
1602 });
1603 });
1604
1605 // BIP44 change field changes address list
1606 it('Changes the address list if bip44 change is changed', function(done) {
1607 driver.findElement(By.css('#bip44 .change'))
1608 .sendKeys('1');
1609 driver.findElement(By.css('.phrase'))
1610 .sendKeys('abandon abandon ability');
1611 driver.sleep(generateDelay).then(function() {
1612 getFirstAddress(function(address) {
1613 expect(address).toBe("1KAGfWgqfVbSSXY56fNQ7YnhyKuoskHtYo");
1614 done();
1615 });
1616 });
1617 });
1618
1619 // BIP32 derivation path can be set
1620 it('Can use a custom bip32 derivation path', function(done) {
1621 driver.findElement(By.css('#bip32-tab a'))
1622 .click();
1623 driver.findElement(By.css('#bip32 .path'))
1624 .clear();
1625 driver.findElement(By.css('#bip32 .path'))
1626 .sendKeys('m/1');
1627 driver.findElement(By.css('.phrase'))
1628 .sendKeys('abandon abandon ability');
1629 driver.sleep(generateDelay).then(function() {
1630 getFirstAddress(function(address) {
1631 expect(address).toBe("16pYQQdLD1hH4hwTGLXBaZ9Teboi1AGL8L");
1632 done();
1633 });
1634 });
1635 });
1636
1637 // BIP32 can use hardened derivation paths
1638 it('Can use a hardened derivation paths', function(done) {
1639 driver.findElement(By.css('#bip32-tab a'))
1640 .click();
1641 driver.findElement(By.css('#bip32 .path'))
1642 .clear();
1643 driver.findElement(By.css('#bip32 .path'))
1644 .sendKeys("m/0'");
1645 driver.findElement(By.css('.phrase'))
1646 .sendKeys('abandon abandon ability');
1647 driver.sleep(generateDelay).then(function() {
1648 getFirstAddress(function(address) {
1649 expect(address).toBe("14aXZeprXAE3UUKQc4ihvwBvww2LuEoHo4");
1650 done();
1651 });
1652 });
1653 });
1654
1655 // BIP32 extended private key is shown
1656 it('Shows the BIP32 extended private key', function(done) {
1657 driver.findElement(By.css('#bip32-tab a'))
1658 .click();
1659 driver.findElement(By.css('.phrase'))
1660 .sendKeys('abandon abandon ability');
1661 driver.sleep(generateDelay).then(function() {
1662 driver.findElement(By.css('.extended-priv-key'))
1663 .getAttribute("value")
1664 .then(function(privKey) {
1665 expect(privKey).toBe("xprv9va99uTVE5aLiutUVLTyfxfe8v8aaXjSQ1XxZbK6SezYVuikA9MnjQVTA8rQHpNA5LKvyQBpLiHbBQiiccKiBDs7eRmBogsvq3THFeLHYbe");
1666 done();
1667 });
1668 });
1669 });
1670
1671 // BIP32 extended public key is shown
1672 it('Shows the BIP32 extended public key', function(done) {
1673 driver.findElement(By.css('#bip32-tab a'))
1674 .click();
1675 driver.findElement(By.css('.phrase'))
1676 .sendKeys('abandon abandon ability');
1677 driver.sleep(generateDelay).then(function() {
1678 driver.findElement(By.css('.extended-pub-key'))
1679 .getAttribute("value")
1680 .then(function(pubKey) {
1681 expect(pubKey).toBe("xpub69ZVZQzP4T8dwPxwbMzz36cNgwy4yzTHmETZMyihzzXXNi3thgg3HCow1RtY252wdw5rS8369xKnraN5Q93y3FkFfJp2XEHWUrkyXsjS93P");
1682 done();
1683 });
1684 });
1685 });
1686
1687 // Derivation path is shown in table
1688 it('Shows the derivation path in the table', function(done) {
1689 driver.findElement(By.css('.phrase'))
1690 .sendKeys('abandon abandon ability');
1691 driver.sleep(generateDelay).then(function() {
1692 getFirstPath(function(path) {
1693 expect(path).toBe("m/44'/0'/0'/0/0");
1694 done();
1695 });
1696 });
1697 });
1698
1699 // Derivation path for address can be hardened
1700 it('Can derive hardened addresses', function(done) {
1701 driver.findElement(By.css('#bip32-tab a'))
1702 .click();
1703 driver.executeScript(function() {
1704 $(".hardened-addresses").prop("checked", true);
1705 });
1706 driver.findElement(By.css('.phrase'))
1707 .sendKeys('abandon abandon ability');
1708 driver.sleep(generateDelay).then(function() {
1709 getFirstAddress(function(address) {
1710 expect(address).toBe("18exLzUv7kfpiXRzmCjFDoC9qwNLFyvwyd");
1711 done();
1712 });
1713 });
1714 });
1715
1716 // Derivation path visibility can be toggled
1717 it('Can toggle visibility of the derivation path column', function(done) {
1718 driver.findElement(By.css('.phrase'))
1719 .sendKeys('abandon abandon ability');
1720 driver.sleep(generateDelay).then(function() {
1721 driver.findElement(By.css('.index-toggle'))
1722 .click();
1723 testColumnValuesAreInvisible(done, "index");
1724 });
1725 });
1726
1727 // Address is shown
1728 it('Shows the address in the table', function(done) {
1729 driver.findElement(By.css('.phrase'))
1730 .sendKeys('abandon abandon ability');
1731 driver.sleep(generateDelay).then(function() {
1732 getFirstAddress(function(address) {
1733 expect(address).toBe("1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug");
1734 done();
1735 });
1736 });
1737 });
1738
1739 // Addresses are shown in order of derivation path
1740 it('Shows the address in order of derivation path', function(done) {
1741 driver.findElement(By.css('.phrase'))
1742 .sendKeys('abandon abandon ability');
1743 driver.sleep(generateDelay).then(function() {
1744 testRowsAreInCorrectOrder(done);
1745 });
1746 });
1747
1748 // Address visibility can be toggled
1749 it('Can toggle visibility of the address column', function(done) {
1750 driver.findElement(By.css('.phrase'))
1751 .sendKeys('abandon abandon ability');
1752 driver.sleep(generateDelay).then(function() {
1753 driver.findElement(By.css('.address-toggle'))
1754 .click();
1755 testColumnValuesAreInvisible(done, "address");
1756 });
1757 });
1758
1759 // Public key is shown in table
1760 it('Shows the public key in the table', function(done) {
1761 driver.findElement(By.css('.phrase'))
1762 .sendKeys('abandon abandon ability');
1763 driver.sleep(generateDelay).then(function() {
1764 driver.findElements(By.css('.pubkey'))
1765 .then(function(els) {
1766 els[0].getText()
1767 .then(function(pubkey) {
1768 expect(pubkey).toBe("033f5aed5f6cfbafaf223188095b5980814897295f723815fea5d3f4b648d0d0b3");
1769 done();
1770 });
1771 });
1772 });
1773 });
1774
1775 // Public key visibility can be toggled
1776 it('Can toggle visibility of the public key column', function(done) {
1777 driver.findElement(By.css('.phrase'))
1778 .sendKeys('abandon abandon ability');
1779 driver.sleep(generateDelay).then(function() {
1780 driver.findElement(By.css('.public-key-toggle'))
1781 .click();
1782 testColumnValuesAreInvisible(done, "pubkey");
1783 });
1784 });
1785
1786 // Private key is shown in table
1787 it('Shows the private key in the table', function(done) {
1788 driver.findElement(By.css('.phrase'))
1789 .sendKeys('abandon abandon ability');
1790 driver.sleep(generateDelay).then(function() {
1791 driver.findElements(By.css('.privkey'))
1792 .then(function(els) {
1793 els[0].getText()
1794 .then(function(pubkey) {
1795 expect(pubkey).toBe("L26cVSpWFkJ6aQkPkKmTzLqTdLJ923e6CzrVh9cmx21QHsoUmrEE");
1796 done();
1797 });
1798 });
1799 });
1800 });
1801
1802 // Private key visibility can be toggled
1803 it('Can toggle visibility of the private key column', function(done) {
1804 driver.findElement(By.css('.phrase'))
1805 .sendKeys('abandon abandon ability');
1806 driver.sleep(generateDelay).then(function() {
1807 driver.findElement(By.css('.private-key-toggle'))
1808 .click();
1809 testColumnValuesAreInvisible(done, "privkey");
1810 });
1811 });
1812
1813 // More addresses can be generated
1814 it('Can generate more rows in the table', function(done) {
1815 driver.findElement(By.css('.phrase'))
1816 .sendKeys('abandon abandon ability');
1817 driver.sleep(generateDelay).then(function() {
1818 driver.findElement(By.css('.more'))
1819 .click();
1820 driver.sleep(generateDelay).then(function() {
1821 driver.findElements(By.css('.address'))
1822 .then(function(els) {
1823 expect(els.length).toBe(40);
1824 done();
1825 });
1826 });
1827 });
1828 });
1829
1830 // A custom number of additional addresses can be generated
1831 it('Can generate more rows in the table', function(done) {
1832 driver.findElement(By.css('.phrase'))
1833 .sendKeys('abandon abandon ability');
1834 driver.sleep(generateDelay).then(function() {
1835 driver.findElement(By.css('.rows-to-add'))
1836 .clear();
1837 driver.findElement(By.css('.rows-to-add'))
1838 .sendKeys('1');
1839 driver.findElement(By.css('.more'))
1840 .click();
1841 driver.sleep(generateDelay).then(function() {
1842 driver.findElements(By.css('.address'))
1843 .then(function(els) {
1844 expect(els.length).toBe(21);
1845 done();
1846 });
1847 });
1848 });
1849 });
1850
1851 // Additional addresses are shown in order of derivation path
1852 it('Shows additional addresses in order of derivation path', function(done) {
1853 driver.findElement(By.css('.phrase'))
1854 .sendKeys('abandon abandon ability');
1855 driver.sleep(generateDelay).then(function() {
1856 driver.findElement(By.css('.more'))
1857 .click();
1858 driver.sleep(generateDelay).then(function() {
1859 testRowsAreInCorrectOrder(done);
1860 });
1861 });
1862 });
1863
1864 // BIP32 root key can be set by the user
1865 it('Allows the user to set the BIP32 root key', function(done) {
1866 driver.findElement(By.css('.root-key'))
1867 .sendKeys('xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi');
1868 driver.sleep(generateDelay).then(function() {
1869 getFirstAddress(function(address) {
1870 expect(address).toBe("1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug");
1871 done();
1872 });
1873 });
1874 });
1875
1876 // Setting BIP32 root key clears the existing phrase, passphrase and seed
1877 // TODO this doesn't work in selenium with chrome
1878 it('Confirms the existing phrase should be cleared', function(done) {
1879 if (browser == "chrome") {
1880 pending("Selenium + Chrome headless bug for alert, see https://stackoverflow.com/q/45242264");
1881 }
1882 driver.findElement(By.css('.phrase'))
1883 .sendKeys('A non-blank but invalid value');
1884 driver.findElement(By.css('.root-key'))
1885 .sendKeys('xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi');
1886 driver.switchTo().alert().accept();
1887 driver.findElement(By.css('.phrase'))
1888 .getAttribute("value").then(function(value) {
1889 expect(value).toBe("");
1890 done();
1891 });
1892 });
1893
1894 // Clearing of phrase, passphrase and seed can be cancelled by user
1895 // TODO this doesn't work in selenium with chrome
1896 it('Allows the clearing of the phrase to be cancelled', function(done) {
1897 if (browser == "chrome") {
1898 pending("Selenium + Chrome headless bug for alert, see https://stackoverflow.com/q/45242264");
1899 }
1900 driver.findElement(By.css('.phrase'))
1901 .sendKeys('abandon abandon ability');
1902 driver.sleep(generateDelay).then(function() {
1903 driver.findElement(By.css('.root-key'))
1904 .clear();
1905 driver.findElement(By.css('.root-key'))
1906 .sendKeys('x');
1907 driver.switchTo().alert().dismiss();
1908 driver.findElement(By.css('.phrase'))
1909 .getAttribute("value").then(function(value) {
1910 expect(value).toBe("abandon abandon ability");
1911 done();
1912 });
1913 });
1914 });
1915
1916 // Custom BIP32 root key is used when changing the derivation path
1917 it('Can set derivation path for root key instead of phrase', function(done) {
1918 driver.findElement(By.css('#bip44 .account'))
1919 .sendKeys('1');
1920 driver.findElement(By.css('.root-key'))
1921 .sendKeys('xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi');
1922 driver.sleep(generateDelay).then(function() {
1923 getFirstAddress(function(address) {
1924 expect(address).toBe("1Nq2Wmu726XHCuGhctEtGmhxo3wzk5wZ1H");
1925 done();
1926 });
1927 });
1928 });
1929
1930 // Incorrect mnemonic shows error
1931 it('Shows an error for incorrect mnemonic', function(done) {
1932 driver.findElement(By.css('.phrase'))
1933 .sendKeys('abandon abandon abandon');
1934 driver.sleep(feedbackDelay).then(function() {
1935 driver.findElement(By.css('.feedback'))
1936 .getText()
1937 .then(function(feedback) {
1938 expect(feedback).toBe("Invalid mnemonic");
1939 done();
1940 });
1941 });
1942 });
1943
1944 // Incorrect word shows suggested replacement
1945 it('Shows word suggestion for incorrect word', function(done) {
1946 driver.findElement(By.css('.phrase'))
1947 .sendKeys('abandon abandon abiliti');
1948 driver.sleep(feedbackDelay).then(function() {
1949 driver.findElement(By.css('.feedback'))
1950 .getText()
1951 .then(function(feedback) {
1952 var msg = "abiliti not in wordlist, did you mean ability?";
1953 expect(feedback).toBe(msg);
1954 done();
1955 });
1956 });
1957 });
1958
1959 // Github pull request 48
1960 // First four letters of word shows that word, not closest
1961 // since first four letters gives unique word in BIP39 wordlist
1962 // eg ille should show illegal, not idle
1963 it('Shows word suggestion based on first four chars', function(done) {
1964 driver.findElement(By.css('.phrase'))
1965 .sendKeys('ille');
1966 driver.sleep(feedbackDelay).then(function() {
1967 driver.findElement(By.css('.feedback'))
1968 .getText()
1969 .then(function(feedback) {
1970 var msg = "ille not in wordlist, did you mean illegal?";
1971 expect(feedback).toBe(msg);
1972 done();
1973 });
1974 });
1975 });
1976
1977 // Incorrect BIP32 root key shows error
1978 it('Shows error for incorrect root key', function(done) {
1979 driver.findElement(By.css('.root-key'))
1980 .sendKeys('xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpj');
1981 driver.sleep(feedbackDelay).then(function() {
1982 driver.findElement(By.css('.feedback'))
1983 .getText()
1984 .then(function(feedback) {
1985 var msg = "Invalid root key";
1986 expect(feedback).toBe(msg);
1987 done();
1988 });
1989 });
1990 });
1991
1992 // Derivation path not starting with m shows error
1993 it('Shows error for derivation path not starting with m', function(done) {
1994 driver.findElement(By.css('#bip32-tab a'))
1995 .click();
1996 driver.findElement(By.css('#bip32 .path'))
1997 .clear();
1998 driver.findElement(By.css('#bip32 .path'))
1999 .sendKeys('n/0');
2000 driver.findElement(By.css('.phrase'))
2001 .sendKeys('abandon abandon ability');
2002 driver.sleep(feedbackDelay).then(function() {
2003 driver.findElement(By.css('.feedback'))
2004 .getText()
2005 .then(function(feedback) {
2006 var msg = "First character must be 'm'";
2007 expect(feedback).toBe(msg);
2008 done();
2009 });
2010 });
2011 });
2012
2013 // Derivation path containing invalid characters shows useful error
2014 it('Shows error for derivation path not starting with m', function(done) {
2015 driver.findElement(By.css('#bip32-tab a'))
2016 .click();
2017 driver.findElement(By.css('#bip32 .path'))
2018 .clear();
2019 driver.findElement(By.css('#bip32 .path'))
2020 .sendKeys('m/1/0wrong1/1');
2021 driver.findElement(By.css('.phrase'))
2022 .sendKeys('abandon abandon ability');
2023 driver.sleep(feedbackDelay).then(function() {
2024 driver.findElement(By.css('.feedback'))
2025 .getText()
2026 .then(function(feedback) {
2027 var msg = "Invalid characters 0wrong1 found at depth 2";
2028 expect(feedback).toBe(msg);
2029 done();
2030 });
2031 });
2032 });
2033
2034 // Github Issue 11: Default word length is 15
2035 // https://github.com/iancoleman/bip39/issues/11
2036 it('Sets the default word length to 15', function(done) {
2037 driver.findElement(By.css('.strength'))
2038 .getAttribute("value")
2039 .then(function(strength) {
2040 expect(strength).toBe("15");
2041 done();
2042 });
2043 });
2044
2045 // Github Issue 12: Generate more rows with private keys hidden
2046 // https://github.com/iancoleman/bip39/issues/12
2047 it('Sets the correct hidden column state on new rows', function(done) {
2048 driver.findElement(By.css('.phrase'))
2049 .sendKeys("abandon abandon ability");
2050 driver.sleep(generateDelay).then(function() {
2051 driver.findElement(By.css('.private-key-toggle'))
2052 .click();
2053 driver.findElement(By.css('.more'))
2054 .click();
2055 driver.sleep(generateDelay).then(function() {
2056 driver.findElements(By.css('.privkey'))
2057 .then(function(els) {
2058 expect(els.length).toBe(40);
2059 });
2060 testColumnValuesAreInvisible(done, "privkey");
2061 });
2062 });
2063 });
2064
2065 // Github Issue 19: Mnemonic is not sensitive to whitespace
2066 // https://github.com/iancoleman/bip39/issues/19
2067 it('Ignores excess whitespace in the mnemonic', function(done) {
2068 var doublespace = " ";
2069 var mnemonic = "urge cat" + doublespace + "bid";
2070 driver.findElement(By.css('.phrase'))
2071 .sendKeys(mnemonic);
2072 driver.sleep(generateDelay).then(function() {
2073 driver.findElement(By.css('.root-key'))
2074 .getAttribute("value")
2075 .then(function(seed) {
2076 expect(seed).toBe("xprv9s21ZrQH143K3isaZsWbKVoTtbvd34Y1ZGRugGdMeBGbM3AgBVzTH159mj1cbbtYSJtQr65w6L5xy5L9SFC7c9VJZWHxgAzpj4mun5LhrbC");
2077 done();
2078 });
2079 });
2080 });
2081
2082 // Github Issue 23: Part 1: Use correct derivation path when changing tabs
2083 // https://github.com/iancoleman/bip39/issues/23
2084 it('Uses the correct derivation path when changing tabs', function(done) {
2085 // 1) and 2) set the phrase
2086 driver.findElement(By.css('.phrase'))
2087 .sendKeys("abandon abandon ability");
2088 driver.sleep(generateDelay).then(function() {
2089 // 3) select bip32 tab
2090 driver.findElement(By.css('#bip32-tab a'))
2091 .click();
2092 driver.sleep(generateDelay).then(function() {
2093 // 4) switch from bitcoin to litecoin
2094 selectNetwork("LTC - Litecoin");
2095 driver.sleep(generateDelay).then(function() {
2096 // 5) Check address is displayed correctly
2097 getFirstAddress(function(address) {
2098 expect(address).toBe("LS8MP5LZ5AdzSZveRrjm3aYVoPgnfFh5T5");
2099 // 5) Check derivation path is displayed correctly
2100 getFirstPath(function(path) {
2101 expect(path).toBe("m/0/0");
2102 done();
2103 });
2104 });
2105 });
2106 });
2107 });
2108 });
2109
2110 // Github Issue 23 Part 2: Coin selection in derivation path
2111 // https://github.com/iancoleman/bip39/issues/23#issuecomment-238011920
2112 it('Uses the correct derivation path when changing coins', function(done) {
2113 // set the phrase
2114 driver.findElement(By.css('.phrase'))
2115 .sendKeys("abandon abandon ability");
2116 driver.sleep(generateDelay).then(function() {
2117 // switch from bitcoin to clam
2118 selectNetwork("CLAM - Clams");
2119 driver.sleep(generateDelay).then(function() {
2120 // check derivation path is displayed correctly
2121 getFirstPath(function(path) {
2122 expect(path).toBe("m/44'/23'/0'/0/0");
2123 done();
2124 });
2125 });
2126 });
2127 });
2128
2129 // Github Issue 26: When using a Root key derrived altcoins are incorrect
2130 // https://github.com/iancoleman/bip39/issues/26
2131 it('Uses the correct derivation for altcoins with root keys', function(done) {
2132 // 1) 2) and 3) set the root key
2133 driver.findElement(By.css('.root-key'))
2134 .sendKeys("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi");
2135 driver.sleep(generateDelay).then(function() {
2136 // 4) switch from bitcoin to viacoin
2137 selectNetwork("VIA - Viacoin");
2138 driver.sleep(generateDelay).then(function() {
2139 // 5) ensure the derived address is correct
2140 getFirstAddress(function(address) {
2141 expect(address).toBe("Vq9Eq4N5SQnjqZvxtxzo7hZPW5XnyJsmXT");
2142 done();
2143 });
2144 });
2145 });
2146 });
2147
2148 // Selecting a language with no existing phrase should generate a phrase in
2149 // that language.
2150 it('Generate a random phrase when language is selected and no current phrase', function(done) {
2151 driver.findElement(By.css("a[href='#japanese']"))
2152 .click();
2153 driver.sleep(generateDelay).then(function() {
2154 driver.findElement(By.css(".phrase"))
2155 .getAttribute("value").then(function(phrase) {
2156 expect(phrase.search(/[a-z]/)).toBe(-1);
2157 expect(phrase.length).toBeGreaterThan(0);
2158 done();
2159 });
2160 });
2161 });
2162
2163 // Selecting a language with existing phrase should update the phrase to use
2164 // that language.
2165 it('Updates existing phrases when the language is changed', function(done) {
2166 driver.findElement(By.css(".phrase"))
2167 .sendKeys("abandon abandon ability");
2168 driver.sleep(generateDelay).then(function() {
2169 driver.findElement(By.css("a[href='#italian']"))
2170 .click();
2171 driver.sleep(generateDelay).then(function() {
2172 driver.findElement(By.css(".phrase"))
2173 .getAttribute("value").then(function(phrase) {
2174 // Check only the language changes, not the phrase
2175 expect(phrase).toBe("abaco abaco abbaglio");
2176 getFirstAddress(function(address) {
2177 // Check the address is correct
2178 expect(address).toBe("1Dz5TgDhdki9spa6xbPFbBqv5sjMrx3xgV");
2179 done();
2180 });
2181 });
2182 });
2183 });
2184 });
2185
2186 // Suggested replacement for erroneous word in non-English language
2187 it('Shows word suggestion for incorrect word in non-English language', function(done) {
2188 driver.findElement(By.css('.phrase'))
2189 .sendKeys('abaco abaco zbbaglio');
2190 driver.sleep(feedbackDelay).then(function() {
2191 driver.findElement(By.css('.feedback'))
2192 .getText()
2193 .then(function(feedback) {
2194 var msg = "zbbaglio not in wordlist, did you mean abbaglio?";
2195 expect(feedback).toBe(msg);
2196 done();
2197 });
2198 });
2199 });
2200
2201 // Japanese word does not break across lines.
2202 // Point 2 from
2203 // https://github.com/bitcoin/bips/blob/master/bip-0039/bip-0039-wordlists.md#japanese
2204 it('Does not break Japanese words across lines', function(done) {
2205 driver.findElement(By.css('.phrase'))
2206 .getCssValue("word-break")
2207 .then(function(value) {
2208 expect(value).toBe("keep-all");
2209 done();
2210 });
2211 });
2212
2213 // Language can be specified at page load using hash value in url
2214 it('Can set the language from the url hash', function(done) {
2215 driver.get(url + "#japanese").then(function() {
2216 driver.findElement(By.css('.generate')).click();
2217 driver.sleep(generateDelay).then(function() {
2218 driver.findElement(By.css(".phrase"))
2219 .getAttribute("value").then(function(phrase) {
2220 expect(phrase.search(/[a-z]/)).toBe(-1);
2221 expect(phrase.length).toBeGreaterThan(0);
2222 done();
2223 });
2224 });
2225 });
2226 });
2227
2228 // Entropy can be entered by the user
2229 it('Allows entropy to be entered', function(done) {
2230 driver.findElement(By.css('.use-entropy'))
2231 .click();
2232 driver.findElement(By.css('.entropy'))
2233 .sendKeys('00000000 00000000 00000000 00000000');
2234 driver.sleep(generateDelay).then(function() {
2235 driver.findElement(By.css(".phrase"))
2236 .getAttribute("value").then(function(phrase) {
2237 expect(phrase).toBe("abandon abandon ability");
2238 getFirstAddress(function(address) {
2239 expect(address).toBe("1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug");
2240 done();
2241 })
2242 });
2243 });
2244 });
2245
2246 // A warning about entropy is shown to the user, with additional information
2247 it('Shows a warning about using entropy', function(done) {
2248 driver.findElement(By.css('.use-entropy'))
2249 .click();
2250 driver.findElement(By.css('.entropy-container'))
2251 .getText()
2252 .then(function(containerText) {
2253 var warning = "mnemonic may be insecure";
2254 expect(containerText).toContain(warning);
2255 driver.findElement(By.css('#entropy-notes'))
2256 .findElement(By.xpath("parent::*"))
2257 .getText()
2258 .then(function(notesText) {
2259 var detail = "flipping a fair coin, rolling a fair dice, noise measurements etc";
2260 expect(notesText).toContain(detail);
2261 done();
2262 });
2263 });
2264 });
2265
2266 // The types of entropy available are described to the user
2267 it('Shows the types of entropy available', function(done) {
2268 driver.findElement(By.css('.entropy'))
2269 .getAttribute("placeholder")
2270 .then(function(placeholderText) {
2271 var options = [
2272 "binary",
2273 "base 6",
2274 "dice",
2275 "base 10",
2276 "hexadecimal",
2277 "cards",
2278 ];
2279 for (var i=0; i<options.length; i++) {
2280 var option = options[i];
2281 expect(placeholderText).toContain(option);
2282 }
2283 done();
2284 });
2285 });
2286
2287 // The actual entropy used is shown to the user
2288 it('Shows the actual entropy used', function(done) {
2289 driver.findElement(By.css('.use-entropy'))
2290 .click();
2291 driver.findElement(By.css('.entropy'))
2292 .sendKeys('Not A Very Good Entropy Source At All');
2293 driver.sleep(generateDelay).then(function() {
2294 driver.findElement(By.css('.entropy-container'))
2295 .getText()
2296 .then(function(text) {
2297 expect(text).toMatch(/Filtered Entropy\s+AedEceAA/);
2298 done();
2299 });
2300 });
2301 });
2302
2303 // Binary entropy can be entered
2304 it('Allows binary entropy to be entered', function(done) {
2305 testEntropyType(done, "01", "binary");
2306 });
2307
2308 // Base 6 entropy can be entered
2309 it('Allows base 6 entropy to be entered', function(done) {
2310 testEntropyType(done, "012345", "base 6");
2311 });
2312
2313 // Base 6 dice entropy can be entered
2314 it('Allows base 6 dice entropy to be entered', function(done) {
2315 testEntropyType(done, "123456", "base 6 (dice)");
2316 });
2317
2318 // Base 10 entropy can be entered
2319 it('Allows base 10 entropy to be entered', function(done) {
2320 testEntropyType(done, "789", "base 10");
2321 });
2322
2323 // Hexadecimal entropy can be entered
2324 it('Allows hexadecimal entropy to be entered', function(done) {
2325 testEntropyType(done, "abcdef", "hexadecimal");
2326 });
2327
2328 // Dice entropy value is shown as the converted base 6 value
2329 // ie 123456 is converted to 123450
2330 it('Shows dice entropy as base 6', function(done) {
2331 driver.findElement(By.css('.use-entropy'))
2332 .click();
2333 driver.findElement(By.css('.entropy'))
2334 .sendKeys("123456");
2335 driver.sleep(generateDelay).then(function() {
2336 driver.findElement(By.css('.entropy-container'))
2337 .getText()
2338 .then(function(text) {
2339 expect(text).toMatch(/Filtered Entropy\s+123450/);
2340 done();
2341 });
2342 });
2343 });
2344
2345 // The number of bits of entropy accumulated is shown
2346 it("Shows the number of bits of entropy for 20 bits of binary", function(done) {
2347 testEntropyBits(done, "0000 0000 0000 0000 0000", "20");
2348 });
2349 it("Shows the number of bits of entropy for 1 bit of binary", function(done) {
2350 testEntropyBits(done, "0", "1");
2351 });
2352 it("Shows the number of bits of entropy for 4 bits of binary", function(done) {
2353 testEntropyBits(done, "0000", "4");
2354 });
2355 it("Shows the number of bits of entropy for 1 character of base 6 (dice)", function(done) {
2356 // 6 in card is 0 in base 6, 0 in base 6 is 2.6 bits (rounded down to 2 bits)
2357 testEntropyBits(done, "6", "2");
2358 });
2359 it("Shows the number of bits of entropy for 1 character of base 10 with 3 bits", function(done) {
2360 // 7 in base 10 is 111 in base 2, no leading zeros
2361 testEntropyBits(done, "7", "3");
2362 });
2363 it("Shows the number of bits of entropy for 1 character of base 10 with 4 bis", function(done) {
2364 testEntropyBits(done, "8", "4");
2365 });
2366 it("Shows the number of bits of entropy for 1 character of hex", function(done) {
2367 testEntropyBits(done, "F", "4");
2368 });
2369 it("Shows the number of bits of entropy for 2 characters of base 10", function(done) {
2370 testEntropyBits(done, "29", "6");
2371 });
2372 it("Shows the number of bits of entropy for 2 characters of hex", function(done) {
2373 testEntropyBits(done, "0A", "8");
2374 });
2375 it("Shows the number of bits of entropy for 2 characters of hex with 3 leading zeros", function(done) {
2376 // hex is always multiple of 4 bits of entropy
2377 testEntropyBits(done, "1A", "8");
2378 });
2379 it("Shows the number of bits of entropy for 2 characters of hex with 2 leading zeros", function(done) {
2380 testEntropyBits(done, "2A", "8");
2381 });
2382 it("Shows the number of bits of entropy for 2 characters of hex with 1 leading zero", function(done) {
2383 testEntropyBits(done, "4A", "8");
2384 });
2385 it("Shows the number of bits of entropy for 2 characters of hex with no leading zeros", function(done) {
2386 testEntropyBits(done, "8A", "8");
2387 });
2388 it("Shows the number of bits of entropy for 2 characters of hex starting with F", function(done) {
2389 testEntropyBits(done, "FA", "8");
2390 });
2391 it("Shows the number of bits of entropy for 4 characters of hex with leading zeros", function(done) {
2392 testEntropyBits(done, "000A", "16");
2393 });
2394 it("Shows the number of bits of entropy for 4 characters of base 6", function(done) {
2395 testEntropyBits(done, "5555", "11");
2396 });
2397 it("Shows the number of bits of entropy for 4 characters of base 6 dice", function(done) {
2398 // uses dice, so entropy is actually 0000 in base 6, which is 4 lots of
2399 // 2.58 bits, which is 10.32 bits (rounded down to 10 bits)
2400 testEntropyBits(done, "6666", "10");
2401 });
2402 it("Shows the number of bits of entropy for 4 charactes of base 10", function(done) {
2403 // Uses base 10, which is 4 lots of 3.32 bits, which is 13.3 bits (rounded
2404 // down to 13)
2405 testEntropyBits(done, "2227", "13");
2406 });
2407 it("Shows the number of bits of entropy for 4 characters of hex with 2 leading zeros", function(done) {
2408 testEntropyBits(done, "222F", "16");
2409 });
2410 it("Shows the number of bits of entropy for 4 characters of hex starting with F", function(done) {
2411 testEntropyBits(done, "FFFF", "16");
2412 });
2413 it("Shows the number of bits of entropy for 10 characters of base 10", function(done) {
2414 // 10 events at 3.32 bits per event
2415 testEntropyBits(done, "0000101017", "33");
2416 });
2417 it("Shows the number of bits of entropy for a full deck of cards", function(done) {
2418 // cards are not replaced, so a full deck is not 52^52 entropy which is 296
2419 // bits, it's 52!, which is 225 bits
2420 testEntropyBits(done, "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks", "225");
2421 });
2422
2423 it("Shows details about the entered entropy", function(done) {
2424 testEntropyFeedback(done,
2425 {
2426 entropy: "A",
2427 filtered: "A",
2428 type: "hexadecimal",
2429 events: "1",
2430 bits: "4",
2431 words: 0,
2432 strength: "less than a second",
2433 }
2434 );
2435 });
2436 it("Shows details about the entered entropy", function(done) {
2437 testEntropyFeedback(done,
2438 {
2439 entropy: "AAAAAAAA",
2440 filtered: "AAAAAAAA",
2441 type: "hexadecimal",
2442 events: "8",
2443 bits: "32",
2444 words: 3,
2445 strength: "less than a second - Repeats like \"aaa\" are easy to guess",
2446 }
2447 );
2448 });
2449 it("Shows details about the entered entropy", function(done) {
2450 testEntropyFeedback(done,
2451 {
2452 entropy: "AAAAAAAA B",
2453 filtered: "AAAAAAAAB",
2454 type: "hexadecimal",
2455 events: "9",
2456 bits: "36",
2457 words: 3,
2458 strength: "less than a second - Repeats like \"aaa\" are easy to guess",
2459 }
2460 );
2461 });
2462 it("Shows details about the entered entropy", function(done) {
2463 testEntropyFeedback(done,
2464 {
2465 entropy: "AAAAAAAA BBBBBBBB",
2466 filtered: "AAAAAAAABBBBBBBB",
2467 type: "hexadecimal",
2468 events: "16",
2469 bits: "64",
2470 words: 6,
2471 strength: "less than a second - Repeats like \"aaa\" are easy to guess",
2472 }
2473 );
2474 });
2475 it("Shows details about the entered entropy", function(done) {
2476 testEntropyFeedback(done,
2477 {
2478 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC",
2479 filtered: "AAAAAAAABBBBBBBBCCCCCCCC",
2480 type: "hexadecimal",
2481 events: "24",
2482 bits: "96",
2483 words: 9,
2484 strength: "less than a second",
2485 }
2486 );
2487 });
2488 it("Shows details about the entered entropy", function(done) {
2489 testEntropyFeedback(done,
2490 {
2491 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD",
2492 filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD",
2493 type: "hexadecimal",
2494 events: "32",
2495 bits: "128",
2496 words: 12,
2497 strength: "2 minutes",
2498 }
2499 );
2500 });
2501 it("Shows details about the entered entropy", function(done) {
2502 testEntropyFeedback(done,
2503 {
2504 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDA",
2505 filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDA",
2506 type: "hexadecimal",
2507 events: "32",
2508 bits: "128",
2509 words: 12,
2510 strength: "2 days",
2511 }
2512 );
2513 });
2514 it("Shows details about the entered entropy", function(done) {
2515 testEntropyFeedback(done,
2516 {
2517 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDA EEEEEEEE",
2518 filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDAEEEEEEEE",
2519 type: "hexadecimal",
2520 events: "40",
2521 bits: "160",
2522 words: 15,
2523 strength: "3 years",
2524 }
2525 );
2526 });
2527 it("Shows details about the entered entropy", function(done) {
2528 testEntropyFeedback(done,
2529 {
2530 entropy: "AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDA EEEEEEEE FFFFFFFF",
2531 filtered: "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDAEEEEEEEEFFFFFFFF",
2532 type: "hexadecimal",
2533 events: "48",
2534 bits: "192",
2535 words: 18,
2536 strength: "centuries",
2537 }
2538 );
2539 });
2540 it("Shows details about the entered entropy", function(done) {
2541 testEntropyFeedback(done,
2542 {
2543 entropy: "7d",
2544 type: "card",
2545 events: "1",
2546 bits: "4",
2547 words: 0,
2548 strength: "less than a second",
2549 }
2550 );
2551 });
2552 it("Shows details about the entered entropy", function(done) {
2553 testEntropyFeedback(done,
2554 {
2555 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
2556 type: "card (full deck)",
2557 events: "52",
2558 bits: "225",
2559 words: 21,
2560 strength: "centuries",
2561 }
2562 );
2563 });
2564 it("Shows details about the entered entropy", function(done) {
2565 testEntropyFeedback(done,
2566 {
2567 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks3d",
2568 type: "card (full deck, 1 duplicate: 3d)",
2569 events: "53",
2570 bits: "254",
2571 words: 21,
2572 strength: "centuries",
2573 }
2574 );
2575 });
2576 it("Shows details about the entered entropy", function(done) {
2577 testEntropyFeedback(done,
2578 {
2579 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqs3d4d",
2580 type: "card (2 duplicates: 3d 4d, 1 missing: KS)",
2581 events: "53",
2582 bits: "254",
2583 words: 21,
2584 strength: "centuries",
2585 }
2586 );
2587 });
2588 it("Shows details about the entered entropy", function(done) {
2589 testEntropyFeedback(done,
2590 {
2591 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqs3d4d5d6d",
2592 type: "card (4 duplicates: 3d 4d 5d..., 1 missing: KS)",
2593 events: "55",
2594 bits: "264",
2595 words: 24,
2596 strength: "centuries",
2597 }
2598 );
2599 });
2600 it("Shows details about the entered entropy", function(done) {
2601 testEntropyFeedback(done,
2602 // Next test was throwing uncaught error in zxcvbn
2603 // Also tests 451 bits, ie Math.log2(52!)*2 = 225.58 * 2
2604 {
2605 entropy: "ac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsksac2c3c4c5c6c7c8c9ctcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
2606 type: "card (full deck, 52 duplicates: ac 2c 3c...)",
2607 events: "104",
2608 bits: "499",
2609 words: 45,
2610 strength: "centuries",
2611 }
2612 );
2613 });
2614 it("Shows details about the entered entropy", function(done) {
2615 testEntropyFeedback(done,
2616 // Case insensitivity to duplicate cards
2617 {
2618 entropy: "asAS",
2619 type: "card (1 duplicate: AS)",
2620 events: "2",
2621 bits: "9",
2622 words: 0,
2623 strength: "less than a second",
2624 }
2625 );
2626 });
2627 it("Shows details about the entered entropy", function(done) {
2628 testEntropyFeedback(done,
2629 {
2630 entropy: "ASas",
2631 type: "card (1 duplicate: as)",
2632 events: "2",
2633 bits: "9",
2634 words: 0,
2635 strength: "less than a second",
2636 }
2637 );
2638 });
2639 it("Shows details about the entered entropy", function(done) {
2640 testEntropyFeedback(done,
2641 // Missing cards are detected
2642 {
2643 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d5d6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
2644 type: "card (1 missing: 9C)",
2645 events: "51",
2646 bits: "221",
2647 words: 18,
2648 strength: "centuries",
2649 }
2650 );
2651 });
2652 it("Shows details about the entered entropy", function(done) {
2653 testEntropyFeedback(done,
2654 {
2655 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d7d8d9dtdjdqdkdah2h3h4h5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
2656 type: "card (2 missing: 9C 5D)",
2657 events: "50",
2658 bits: "216",
2659 words: 18,
2660 strength: "centuries",
2661 }
2662 );
2663 });
2664 it("Shows details about the entered entropy", function(done) {
2665 testEntropyFeedback(done,
2666 {
2667 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d7d8d9dtdjd kdah2h3h 5h6h7h8h9hthjhqhkhas2s3s4s5s6s7s8s9stsjsqsks",
2668 type: "card (4 missing: 9C 5D QD...)",
2669 events: "48",
2670 bits: "208",
2671 words: 18,
2672 strength: "centuries",
2673 }
2674 );
2675 });
2676 it("Shows details about the entered entropy", function(done) {
2677 testEntropyFeedback(done,
2678 // More than six missing cards does not show message
2679 {
2680 entropy: "ac2c3c4c5c6c7c8c tcjcqckcad2d3d4d 6d 8d9d jd kdah2h3h 5h6h7h8h9hthjhqhkh 2s3s4s5s6s7s8s9stsjsqsks",
2681 type: "card",
2682 events: "45",
2683 bits: "195",
2684 words: 18,
2685 strength: "centuries",
2686 }
2687 );
2688 });
2689 it("Shows details about the entered entropy", function(done) {
2690 testEntropyFeedback(done,
2691 // Multiple decks of cards increases bits per event
2692 {
2693 entropy: "3d",
2694 events: "1",
2695 bits: "4",
2696 bitsPerEvent: "4.34",
2697 }
2698 );
2699 });
2700 it("Shows details about the entered entropy", function(done) {
2701 testEntropyFeedback(done,
2702 {
2703 entropy: "3d3d",
2704 events: "2",
2705 bits: "9",
2706 bitsPerEvent: "4.80",
2707 }
2708 );
2709 });
2710 it("Shows details about the entered entropy", function(done) {
2711 testEntropyFeedback(done,
2712 {
2713 entropy: "3d3d3d",
2714 events: "3",
2715 bits: "15",
2716 bitsPerEvent: "5.01",
2717 }
2718 );
2719 });
2720 it("Shows details about the entered entropy", function(done) {
2721 testEntropyFeedback(done,
2722 {
2723 entropy: "3d3d3d3d",
2724 events: "4",
2725 bits: "20",
2726 bitsPerEvent: "5.14",
2727 }
2728 );
2729 });
2730 it("Shows details about the entered entropy", function(done) {
2731 testEntropyFeedback(done,
2732 {
2733 entropy: "3d3d3d3d3d",
2734 events: "5",
2735 bits: "26",
2736 bitsPerEvent: "5.22",
2737 }
2738 );
2739 });
2740 it("Shows details about the entered entropy", function(done) {
2741 testEntropyFeedback(done,
2742 {
2743 entropy: "3d3d3d3d3d3d",
2744 events: "6",
2745 bits: "31",
2746 bitsPerEvent: "5.28",
2747 }
2748 );
2749 });
2750 it("Shows details about the entered entropy", function(done) {
2751 testEntropyFeedback(done,
2752 {
2753 entropy: "3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d",
2754 events: "33",
2755 bits: "184",
2756 bitsPerEvent: "5.59",
2757 strength: 'less than a second - Repeats like "abcabcabc" are only slightly harder to guess than "abc"',
2758 }
2759 );
2760 });
2761
2762 // Entropy is truncated from the left
2763 it('Truncates entropy from the left', function(done) {
2764 // Truncate from left means 0000 is removed from the start
2765 // which gives mnemonic 'avocado zoo zone'
2766 // not 1111 removed from the end
2767 // which gives the mnemonic 'abstract zoo zoo'
2768 var entropy = "00000000 00000000 00000000 00000000";
2769 entropy += "11111111 11111111 11111111 1111"; // Missing last byte
2770 driver.findElement(By.css('.use-entropy'))
2771 .click();
2772 driver.findElement(By.css('.entropy'))
2773 .sendKeys(entropy);
2774 driver.sleep(generateDelay).then(function() {
2775 driver.findElement(By.css(".phrase"))
2776 .getAttribute("value").then(function(phrase) {
2777 expect(phrase).toBe("avocado zoo zone");
2778 done();
2779 });
2780 });
2781 });
2782
2783 // Very large entropy results in very long mnemonics
2784 it('Converts very long entropy to very long mnemonics', function(done) {
2785 var entropy = "";
2786 for (var i=0; i<33; i++) {
2787 entropy += "AAAAAAAA"; // 3 words * 33 iterations = 99 words
2788 }
2789 driver.findElement(By.css('.use-entropy'))
2790 .click();
2791 driver.findElement(By.css('.entropy'))
2792 .sendKeys(entropy);
2793 driver.sleep(generateDelay).then(function() {
2794 driver.findElement(By.css(".phrase"))
2795 .getAttribute("value").then(function(phrase) {
2796 var wordCount = phrase.split(/\s+/g).length;
2797 expect(wordCount).toBe(99);
2798 done();
2799 });
2800 });
2801 });
2802
2803 // Is compatible with bip32jp entropy
2804 // https://bip32jp.github.io/english/index.html
2805 // NOTES:
2806 // Is incompatible with:
2807 // base 20
2808 it('Is compatible with bip32jp.github.io', function(done) {
2809 var entropy = "543210543210543210543210543210543210543210543210543210543210543210543210543210543210543210543210543";
2810 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";
2811 driver.findElement(By.css('.use-entropy'))
2812 .click();
2813 driver.findElement(By.css('.entropy'))
2814 .sendKeys(entropy);
2815 driver.sleep(generateDelay).then(function() {
2816 driver.findElement(By.css(".phrase"))
2817 .getAttribute("value").then(function(phrase) {
2818 expect(phrase).toBe(expectedPhrase);
2819 done();
2820 });
2821 });
2822 });
2823
2824 // Blank entropy does not generate mnemonic or addresses
2825 it('Does not generate mnemonic for blank entropy', function(done) {
2826 driver.findElement(By.css('.use-entropy'))
2827 .click();
2828 driver.findElement(By.css('.entropy'))
2829 .clear();
2830 // check there is no mnemonic
2831 driver.sleep(generateDelay).then(function() {
2832 driver.findElement(By.css(".phrase"))
2833 .getAttribute("value").then(function(phrase) {
2834 expect(phrase).toBe("");
2835 // check there is no mnemonic
2836 driver.findElements(By.css(".address"))
2837 .then(function(addresses) {
2838 expect(addresses.length).toBe(0);
2839 // Check the feedback says 'blank entropy'
2840 driver.findElement(By.css(".feedback"))
2841 .getText()
2842 .then(function(feedbackText) {
2843 expect(feedbackText).toBe("Blank entropy");
2844 done();
2845 });
2846 })
2847 });
2848 });
2849 });
2850
2851 // Mnemonic length can be selected even for weak entropy
2852 it('Allows selection of mnemonic length even for weak entropy', function(done) {
2853 driver.findElement(By.css('.use-entropy'))
2854 .click();
2855 driver.executeScript(function() {
2856 $(".mnemonic-length").val("18").trigger("change");
2857 });
2858 driver.findElement(By.css('.entropy'))
2859 .sendKeys("012345");
2860 driver.sleep(generateDelay).then(function() {
2861 driver.findElement(By.css(".phrase"))
2862 .getAttribute("value").then(function(phrase) {
2863 var wordCount = phrase.split(/\s+/g).length;
2864 expect(wordCount).toBe(18);
2865 done();
2866 });
2867 });
2868 });
2869
2870 // Github issue 33
2871 // https://github.com/iancoleman/bip39/issues/33
2872 // Final cards should contribute entropy
2873 it('Uses as much entropy as possible for the mnemonic', function(done) {
2874 driver.findElement(By.css('.use-entropy'))
2875 .click();
2876 driver.findElement(By.css('.entropy'))
2877 .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");
2878 driver.sleep(generateDelay).then(function() {
2879 // Get mnemonic
2880 driver.findElement(By.css(".phrase"))
2881 .getAttribute("value").then(function(originalPhrase) {
2882 // Set the last 12 cards to be AS
2883 driver.findElement(By.css('.entropy'))
2884 .clear();
2885 driver.findElement(By.css('.entropy'))
2886 .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");
2887 driver.sleep(generateDelay).then(function() {
2888 // Get new mnemonic
2889 driver.findElement(By.css(".phrase"))
2890 .getAttribute("value").then(function(newPhrase) {
2891 expect(originalPhrase).not.toEqual(newPhrase);
2892 done();
2893 });
2894 });
2895 });
2896 });
2897 });
2898
2899 // Github issue 35
2900 // https://github.com/iancoleman/bip39/issues/35
2901 // QR Code support
2902 // TODO this doesn't work in selenium with firefox
2903 // see https://stackoverflow.com/q/40360223
2904 it('Shows a qr code on hover for the phrase', function(done) {
2905 if (browser == "firefox") {
2906 pending("Selenium + Firefox bug for mouseMove, see https://stackoverflow.com/q/40360223");
2907 }
2908 // generate a random mnemonic
2909 var generateEl = driver.findElement(By.css('.generate'));
2910 generateEl.click();
2911 // toggle qr to show (hidden by default)
2912 var phraseEl = driver.findElement(By.css(".phrase"));
2913 phraseEl.click();
2914 var rootKeyEl = driver.findElement(By.css(".root-key"));
2915 driver.sleep(generateDelay).then(function() {
2916 // hover over the root key
2917 driver.actions().mouseMove(rootKeyEl).perform().then(function() {
2918 // check the qr code shows
2919 driver.executeScript(function() {
2920 return $(".qr-container").find("canvas").length > 0;
2921 })
2922 .then(function(qrShowing) {
2923 expect(qrShowing).toBe(true);
2924 // hover away from the phrase
2925 driver.actions().mouseMove(generateEl).perform().then(function() {;
2926 // check the qr code hides
2927 driver.executeScript(function() {
2928 return $(".qr-container").find("canvas").length == 0;
2929 })
2930 .then(function(qrHidden) {
2931 expect(qrHidden).toBe(true);
2932 done();
2933 });
2934 });
2935 });
2936 });
2937 });
2938 });
2939
2940 // BIP44 account extendend private key is shown
2941 // github issue 37 - compatibility with electrum
2942 it('Shows the bip44 account extended private key', function(done) {
2943 driver.findElement(By.css(".phrase"))
2944 .sendKeys("abandon abandon ability");
2945 driver.sleep(generateDelay).then(function() {
2946 driver.findElement(By.css("#bip44 .account-xprv"))
2947 .getAttribute("value")
2948 .then(function(xprv) {
2949 expect(xprv).toBe("xprv9yzrnt4zWVJUr1k2VxSPy9ettKz5PpeDMgaVG7UKedhqnw1tDkxP2UyYNhuNSumk2sLE5ctwKZs9vwjsq3e1vo9egCK6CzP87H2cVYXpfwQ");
2950 done();
2951 });
2952 });
2953 });
2954
2955 // BIP44 account extendend public key is shown
2956 // github issue 37 - compatibility with electrum
2957 it('Shows the bip44 account extended public key', function(done) {
2958 driver.findElement(By.css(".phrase"))
2959 .sendKeys("abandon abandon ability");
2960 driver.sleep(generateDelay).then(function() {
2961 driver.findElement(By.css("#bip44 .account-xpub"))
2962 .getAttribute("value")
2963 .then(function(xprv) {
2964 expect(xprv).toBe("xpub6CzDCPbtLrrn4VpVbyyQLHbdSMpZoHN4iuW64VswCyEpfjM2mJGdaHJ2DyuZwtst96E16VvcERb8BBeJdHSCVmAq9RhtRQg6eAZFrTKCNqf");
2965 done();
2966 });
2967 });
2968 });
2969
2970 // github issue 40
2971 // BIP32 root key can be set as an xpub
2972 it('Generates addresses from xpub as bip32 root key', function(done) {
2973 driver.findElement(By.css('#bip32-tab a'))
2974 .click();
2975 // set xpub for account 0 of bip44 for 'abandon abandon ability'
2976 driver.findElement(By.css("#root-key"))
2977 .sendKeys("xpub6CzDCPbtLrrn4VpVbyyQLHbdSMpZoHN4iuW64VswCyEpfjM2mJGdaHJ2DyuZwtst96E16VvcERb8BBeJdHSCVmAq9RhtRQg6eAZFrTKCNqf");
2978 driver.sleep(generateDelay).then(function() {
2979 // check the addresses are generated
2980 getFirstAddress(function(address) {
2981 expect(address).toBe("1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug");
2982 // check the xprv key is not set
2983 driver.findElement(By.css(".extended-priv-key"))
2984 .getAttribute("value")
2985 .then(function(xprv) {
2986 expect(xprv).toBe("NA");
2987 // check the private key is not set
2988 driver.findElements(By.css(".privkey"))
2989 .then(function(els) {
2990 els[0]
2991 .getText()
2992 .then(function(privkey) {
2993 expect(xprv).toBe("NA");
2994 done();
2995 });
2996 });
2997 });
2998 });
2999 });
3000 });
3001
3002 // github issue 40
3003 // xpub for bip32 root key will not work with hardened derivation paths
3004 it('Shows error for hardened derivation paths with xpub root key', function(done) {
3005 // set xpub for account 0 of bip44 for 'abandon abandon ability'
3006 driver.findElement(By.css("#root-key"))
3007 .sendKeys("xpub6CzDCPbtLrrn4VpVbyyQLHbdSMpZoHN4iuW64VswCyEpfjM2mJGdaHJ2DyuZwtst96E16VvcERb8BBeJdHSCVmAq9RhtRQg6eAZFrTKCNqf");
3008 driver.sleep(feedbackDelay).then(function() {
3009 // Check feedback is correct
3010 driver.findElement(By.css('.feedback'))
3011 .getText()
3012 .then(function(feedback) {
3013 var msg = "Hardened derivation path is invalid with xpub key";
3014 expect(feedback).toBe(msg);
3015 // Check no addresses are shown
3016 driver.findElements(By.css('.addresses tr'))
3017 .then(function(rows) {
3018 expect(rows.length).toBe(0);
3019 done();
3020 });
3021 });
3022 });
3023 });
3024
3025 // github issue 39
3026 // no root key shows feedback
3027 it('Shows feedback for no root key', function(done) {
3028 // set xpub for account 0 of bip44 for 'abandon abandon ability'
3029 driver.findElement(By.css('#bip32-tab a'))
3030 .click();
3031 driver.sleep(feedbackDelay).then(function() {
3032 // Check feedback is correct
3033 driver.findElement(By.css('.feedback'))
3034 .getText()
3035 .then(function(feedback) {
3036 expect(feedback).toBe("Invalid root key");
3037 done();
3038 });
3039 });
3040 });
3041
3042 // Github issue 44
3043 // display error switching tabs while addresses are generating
3044 it('Can change details while old addresses are still being generated', function(done) {
3045 // Set to generate 199 more addresses.
3046 // This will take a long time allowing a new set of addresses to be
3047 // generated midway through this lot.
3048 // The newly generated addresses should not include any from the old set.
3049 // Any more than 199 will show an alert which needs to be accepted.
3050 driver.findElement(By.css('.rows-to-add'))
3051 .clear();
3052 driver.findElement(By.css('.rows-to-add'))
3053 .sendKeys('199');
3054 // set the prhase
3055 driver.findElement(By.css('.phrase'))
3056 .sendKeys("abandon abandon ability");
3057 driver.sleep(generateDelay).then(function() {
3058 // change tabs which should cancel the previous generating
3059 driver.findElement(By.css('.rows-to-add'))
3060 .clear();
3061 driver.findElement(By.css('.rows-to-add'))
3062 .sendKeys('20');
3063 driver.findElement(By.css('#bip32-tab a'))
3064 .click()
3065 driver.sleep(generateDelay).then(function() {
3066 driver.findElements(By.css('.index'))
3067 .then(function(els) {
3068 // check the derivation paths have the right quantity
3069 expect(els.length).toBe(20);
3070 // check the derivation paths are in order
3071 testRowsAreInCorrectOrder(done);
3072 });
3073 });
3074 });
3075 }, generateDelay + 10000);
3076
3077 // Github issue 49
3078 // padding for binary should give length with multiple of 256
3079 // hashed entropy 1111 is length 252, so requires 4 leading zeros
3080 // prior to issue 49 it would only generate 2 leading zeros, ie missing 2
3081 it('Pads hashed entropy with leading zeros', function(done) {
3082 driver.findElement(By.css('.use-entropy'))
3083 .click();
3084 driver.executeScript(function() {
3085 $(".mnemonic-length").val("15").trigger("change");
3086 });
3087 driver.findElement(By.css('.entropy'))
3088 .sendKeys("1111");
3089 driver.sleep(generateDelay).then(function() {
3090 driver.findElement(By.css('.phrase'))
3091 .getAttribute("value")
3092 .then(function(phrase) {
3093 expect(phrase).toBe("avocado valid quantum cross link predict excuse edit street able flame large galaxy ginger nuclear");
3094 done();
3095 });
3096 });
3097 });
3098
3099 // Github pull request 55
3100 // https://github.com/iancoleman/bip39/pull/55
3101 // Client select
3102 it('Can set the derivation path on bip32 tab for bitcoincore', function(done) {
3103 testClientSelect(done, {
3104 selectValue: "0",
3105 bip32path: "m/0'/0'",
3106 useHardenedAddresses: "true",
3107 });
3108 });
3109 it('Can set the derivation path on bip32 tab for multibit', function(done) {
3110 testClientSelect(done, {
3111 selectValue: "2",
3112 bip32path: "m/0'/0",
3113 useHardenedAddresses: null,
3114 });
3115 });
3116 it('Can set the derivation path on bip32 tab for coinomi/ledger', function(done) {
3117 testClientSelect(done, {
3118 selectValue: "3",
3119 bip32path: "m/44'/0'/0'",
3120 useHardenedAddresses: null,
3121 });
3122 });
3123
3124 // github issue 58
3125 // https://github.com/iancoleman/bip39/issues/58
3126 // bip32 derivation is correct, does not drop leading zeros
3127 // see also
3128 // https://medium.com/@alexberegszaszi/why-do-my-bip32-wallets-disagree-6f3254cc5846
3129 it('Retains leading zeros for bip32 derivation', function(done) {
3130 driver.findElement(By.css(".phrase"))
3131 .sendKeys("fruit wave dwarf banana earth journey tattoo true farm silk olive fence");
3132 driver.findElement(By.css(".passphrase"))
3133 .sendKeys("banana");
3134 driver.sleep(generateDelay).then(function() {
3135 getFirstAddress(function(address) {
3136 // Note that bitcore generates an incorrect address
3137 // 13EuKhffWkBE2KUwcbkbELZb1MpzbimJ3Y
3138 // see the medium.com link above for more details
3139 expect(address).toBe("17rxURoF96VhmkcEGCj5LNQkmN9HVhWb7F");
3140 done();
3141 });
3142 });
3143 });
3144
3145 // github issue 60
3146 // Japanese mnemonics generate incorrect bip32 seed
3147 // BIP39 seed is set from phrase
3148 it('Generates correct seed for Japanese mnemonics', function(done) {
3149 driver.findElement(By.css(".phrase"))
3150 .sendKeys("あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あおぞら");
3151 driver.findElement(By.css(".passphrase"))
3152 .sendKeys("メートルガバヴァぱばぐゞちぢ十人十色");
3153 driver.sleep(generateDelay).then(function() {
3154 driver.findElement(By.css(".seed"))
3155 .getAttribute("value")
3156 .then(function(seed) {
3157 expect(seed).toBe("a262d6fb6122ecf45be09c50492b31f92e9beb7d9a845987a02cefda57a15f9c467a17872029a9e92299b5cbdf306e3a0ee620245cbd508959b6cb7ca637bd55");
3158 done();
3159 });
3160 });
3161 });
3162
3163 // BIP49 official test vectors
3164 // https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki#test-vectors
3165 it('Generates BIP49 addresses matching the official test vectors', function(done) {
3166 driver.findElement(By.css('#bip49-tab a'))
3167 .click();
3168 selectNetwork("BTC - Bitcoin Testnet");
3169 driver.findElement(By.css(".phrase"))
3170 .sendKeys("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about");
3171 driver.sleep(generateDelay).then(function() {
3172 getFirstAddress(function(address) {
3173 expect(address).toBe("2Mww8dCYPUpKHofjgcXcBCEGmniw9CoaiD2");
3174 done();
3175 });
3176 });
3177 });
3178
3179 // BIP49 derivation path is shown
3180 it('Shows the bip49 derivation path', function(done) {
3181 driver.findElement(By.css('#bip49-tab a'))
3182 .click();
3183 driver.findElement(By.css(".phrase"))
3184 .sendKeys("abandon abandon ability");
3185 driver.sleep(generateDelay).then(function() {
3186 driver.findElement(By.css('#bip49 .path'))
3187 .getAttribute("value")
3188 .then(function(path) {
3189 expect(path).toBe("m/49'/0'/0'/0");
3190 done();
3191 });
3192 });
3193 });
3194
3195 // BIP49 extended private key is shown
3196 it('Shows the bip49 extended private key', function(done) {
3197 driver.findElement(By.css('#bip49-tab a'))
3198 .click();
3199 driver.findElement(By.css(".phrase"))
3200 .sendKeys("abandon abandon ability");
3201 driver.sleep(generateDelay).then(function() {
3202 driver.findElement(By.css('.extended-priv-key'))
3203 .getAttribute("value")
3204 .then(function(xprv) {
3205 expect(xprv).toBe("yprvALYB4DYRG6CzzVgzQZwwqjAA2wjBGC3iEd7KYYScpoDdmf75qMRWZWxoFcRXBJjgEXdFqJ9vDRGRLJQsrL22Su5jMbNFeM9vetaGVqy9Qy2");
3206 done();
3207 });
3208 });
3209 });
3210
3211 // BIP49 extended public key is shown
3212 it('Shows the bip49 extended public key', function(done) {
3213 driver.findElement(By.css('#bip49-tab a'))
3214 .click();
3215 driver.findElement(By.css(".phrase"))
3216 .sendKeys("abandon abandon ability");
3217 driver.sleep(generateDelay).then(function() {
3218 driver.findElement(By.css('.extended-pub-key'))
3219 .getAttribute("value")
3220 .then(function(xprv) {
3221 expect(xprv).toBe("ypub6ZXXTj5K6TmJCymTWbUxCs6tayZffemZbr2vLvrEP8kceTSENtjm7KHH6thvAKxVar9fGe8rgsPEX369zURLZ68b4f7Vexz7RuXsjQ69YDt");
3222 done();
3223 });
3224 });
3225 });
3226
3227 // BIP49 account field changes address list
3228 it('Can set the bip49 account field', function(done) {
3229 driver.findElement(By.css('#bip49-tab a'))
3230 .click();
3231 driver.findElement(By.css('#bip49 .account'))
3232 .clear();
3233 driver.findElement(By.css('#bip49 .account'))
3234 .sendKeys("1");
3235 driver.findElement(By.css(".phrase"))
3236 .sendKeys("abandon abandon ability");
3237 driver.sleep(generateDelay).then(function() {
3238 getFirstAddress(function(address) {
3239 expect(address).toBe("381wg1GGN4rP88rNC9v7QWsiww63yLVPsn");
3240 done();
3241 });
3242 });
3243 });
3244
3245 // BIP49 change field changes address list
3246 it('Can set the bip49 change field', function(done) {
3247 driver.findElement(By.css('#bip49-tab a'))
3248 .click();
3249 driver.findElement(By.css('#bip49 .change'))
3250 .clear();
3251 driver.findElement(By.css('#bip49 .change'))
3252 .sendKeys("1");
3253 driver.findElement(By.css(".phrase"))
3254 .sendKeys("abandon abandon ability");
3255 driver.sleep(generateDelay).then(function() {
3256 getFirstAddress(function(address) {
3257 expect(address).toBe("3PEM7MiKed5konBoN66PQhK8r3hjGhy9dT");
3258 done();
3259 });
3260 });
3261 });
3262
3263 // BIP49 account extendend private key is shown
3264 it('Shows the bip49 account extended private key', function(done) {
3265 driver.findElement(By.css('#bip49-tab a'))
3266 .click();
3267 driver.findElement(By.css(".phrase"))
3268 .sendKeys("abandon abandon ability");
3269 driver.sleep(generateDelay).then(function() {
3270 driver.findElement(By.css('#bip49 .account-xprv'))
3271 .getAttribute("value")
3272 .then(function(xprv) {
3273 expect(xprv).toBe("yprvAHtB1M5Wp675aLzFy9TJYK2mSsLkg6mcBRh5DZTR7L4EnYSmYPaL63KFA4ycg1PngW5LfkmejxzosCs17TKZMpRFKc3z5SJar6QAKaFcaZL");
3274 done();
3275 });
3276 });
3277 });
3278
3279 // BIP49 account extendend public key is shown
3280 it('Shows the bip49 account extended public key', function(done) {
3281 driver.findElement(By.css('#bip49-tab a'))
3282 .click();
3283 driver.findElement(By.css(".phrase"))
3284 .sendKeys("abandon abandon ability");
3285 driver.sleep(generateDelay).then(function() {
3286 driver.findElement(By.css('#bip49 .account-xpub'))
3287 .getAttribute("value")
3288 .then(function(xprv) {
3289 expect(xprv).toBe("ypub6WsXQrcQeTfNnq4j5AzJuSyVzuBF5ZVTYecg1ws2ffbDfLmv5vtadqdj1NgR6C6gufMpMfJpHxvb6JEQKvETVNWCRanNedfJtnTchZiJtsL");
3290 done();
3291 });
3292 });
3293 });
3294
3295 // Test selecting coin where bip49 is unavailable (eg CLAM)
3296 it('Shows an error on bip49 tab for coins without bip49', function(done) {
3297 driver.findElement(By.css('#bip49-tab a'))
3298 .click();
3299 driver.findElement(By.css(".phrase"))
3300 .sendKeys("abandon abandon ability");
3301 driver.sleep(generateDelay).then(function() {
3302 selectNetwork("CLAM - Clams");
3303 // bip49 available is hidden
3304 driver.findElement(By.css('#bip49 .available'))
3305 .getAttribute("class")
3306 .then(function(classes) {
3307 expect(classes).toContain("hidden");
3308 // bip49 unavailable is shown
3309 driver.findElement(By.css('#bip49 .unavailable'))
3310 .getAttribute("class")
3311 .then(function(classes) {
3312 expect(classes).not.toContain("hidden");
3313 // check there are no addresses shown
3314 driver.findElements(By.css('.addresses tr'))
3315 .then(function(rows) {
3316 expect(rows.length).toBe(0);
3317 // check the derived private key is blank
3318 driver.findElement(By.css('.extended-priv-key'))
3319 .getAttribute("value")
3320 .then(function(xprv) {
3321 expect(xprv).toBe('');
3322 // check the derived public key is blank
3323 driver.findElement(By.css('.extended-pub-key'))
3324 .getAttribute("value")
3325 .then(function(xpub) {
3326 expect(xpub).toBe('');
3327 done();
3328 });
3329 });
3330 })
3331 });
3332 });
3333 });
3334 });
3335
3336 // github issue 43
3337 // Cleared mnemonic and root key still allows addresses to be generated
3338 // https://github.com/iancoleman/bip39/issues/43
3339 it('Clears old root keys from memory when mnemonic is cleared', function(done) {
3340 // set the phrase
3341 driver.findElement(By.css(".phrase"))
3342 .sendKeys("abandon abandon ability");
3343 driver.sleep(generateDelay).then(function() {
3344 // clear the mnemonic and root key
3345 // using selenium .clear() doesn't seem to trigger the 'input' event
3346 // so clear it using keys instead
3347 driver.findElement(By.css('.phrase'))
3348 .sendKeys(Key.CONTROL,"a");
3349 driver.findElement(By.css('.phrase'))
3350 .sendKeys(Key.DELETE);
3351 driver.findElement(By.css('.root-key'))
3352 .sendKeys(Key.CONTROL,"a");
3353 driver.findElement(By.css('.root-key'))
3354 .sendKeys(Key.DELETE);
3355 driver.sleep(generateDelay).then(function() {
3356 // try to generate more addresses
3357 driver.findElement(By.css('.more'))
3358 .click();
3359 driver.sleep(generateDelay).then(function() {
3360 driver.findElements(By.css(".addresses tr"))
3361 .then(function(els) {
3362 // check there are no addresses shown
3363 expect(els.length).toBe(0);
3364 done();
3365 });
3366 });
3367 });
3368 });
3369 });
3370
3371 // Github issue 95
3372 // error trying to generate addresses from xpub with hardened derivation
3373 it('Shows error for hardened addresses with xpub root key', function(done) {
3374 driver.findElement(By.css('#bip32-tab a'))
3375 .click()
3376 driver.executeScript(function() {
3377 $(".hardened-addresses").prop("checked", true);
3378 });
3379 // set xpub for account 0 of bip44 for 'abandon abandon ability'
3380 driver.findElement(By.css("#root-key"))
3381 .sendKeys("xpub6CzDCPbtLrrn4VpVbyyQLHbdSMpZoHN4iuW64VswCyEpfjM2mJGdaHJ2DyuZwtst96E16VvcERb8BBeJdHSCVmAq9RhtRQg6eAZFrTKCNqf");
3382 driver.sleep(feedbackDelay).then(function() {
3383 // Check feedback is correct
3384 driver.findElement(By.css('.feedback'))
3385 .getText()
3386 .then(function(feedback) {
3387 var msg = "Hardened derivation path is invalid with xpub key";
3388 expect(feedback).toBe(msg);
3389 done();
3390 });
3391 });
3392 });
3393
3394 // Litecoin uses ltub by default, and can optionally be set to xprv
3395 // github issue 96
3396 // https://github.com/iancoleman/bip39/issues/96
3397 // Issue with extended keys on Litecoin
3398 it('Uses ltub by default for litecoin, but can be set to xprv', function(done) {
3399 driver.findElement(By.css('.phrase'))
3400 .sendKeys("abandon abandon ability");
3401 selectNetwork("LTC - Litecoin");
3402 driver.sleep(generateDelay).then(function() {
3403 // check the extended key is generated correctly
3404 driver.findElement(By.css('.root-key'))
3405 .getAttribute("value")
3406 .then(function(rootKey) {
3407 expect(rootKey).toBe("Ltpv71G8qDifUiNesiPqf6h5V6eQ8ic77oxQiYtawiACjBEx3sTXNR2HGDGnHETYxESjqkMLFBkKhWVq67ey1B2MKQXannUqNy1RZVHbmrEjnEU");
3408 // set litecoin to use ltub
3409 driver.executeScript(function() {
3410 $(".litecoin-use-ltub").prop("checked", false);
3411 $(".litecoin-use-ltub").trigger("change");
3412 });
3413 driver.sleep(generateDelay).then(function() {
3414 driver.findElement(By.css('.root-key'))
3415 .getAttribute("value")
3416 .then(function(rootKey) {
3417 expect(rootKey).toBe("xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi");
3418 done();
3419 });
3420 })
3421 });
3422 });
3423 });
3424
3425 // github issue 99
3426 // https://github.com/iancoleman/bip39/issues/99#issuecomment-327094159
3427 // "warn me emphatically when they have detected invalid input" to the entropy field
3428 // A warning is shown when entropy is filtered and discarded
3429 it('Warns when entropy is filtered and discarded', function(done) {
3430 driver.findElement(By.css('.use-entropy'))
3431 .click();
3432 // set entropy to have no filtered content
3433 driver.findElement(By.css('.entropy'))
3434 .sendKeys("00000000 00000000 00000000 00000000");
3435 driver.sleep(generateDelay).then(function() {
3436 // check the filter warning does not show
3437 driver.findElement(By.css('.entropy-container .filter-warning'))
3438 .getAttribute("class")
3439 .then(function(classes) {
3440 expect(classes).toContain("hidden");
3441 // set entropy to have some filtered content
3442 driver.findElement(By.css('.entropy'))
3443 .sendKeys("10000000 zxcvbn 00000000 00000000 00000000");
3444 driver.sleep(entropyFeedbackDelay).then(function() {
3445 // check the filter warning shows
3446 driver.findElement(By.css('.entropy-container .filter-warning'))
3447 .getAttribute("class")
3448 .then(function(classes) {
3449 expect(classes).not.toContain("hidden");
3450 done();
3451 });
3452 });
3453 });
3454 });
3455 });
3456
3457 // Bitcoin Cash address can be set to use cashaddr format
3458 it('Can use cashaddr format for bitcoin cash addresses', function(done) {
3459 driver.executeScript(function() {
3460 $(".use-bch-cashaddr-addresses").prop("checked", true);
3461 });
3462 driver.findElement(By.css('.phrase'))
3463 .sendKeys("abandon abandon ability");
3464 selectNetwork("BCH - Bitcoin Cash");
3465 driver.sleep(generateDelay).then(function() {
3466 getFirstAddress(function(address) {
3467 expect(address).toBe("bitcoincash:qzlquk7w4hkudxypl4fgv8x279r754dkvur7jpcsps");
3468 done();
3469 });
3470 });
3471 });
3472
3473 // Bitcoin Cash address can be set to use bitpay format
3474 it('Can use bitpay format for bitcoin cash addresses', function(done) {
3475 driver.executeScript(function() {
3476 $(".use-bch-bitpay-addresses").prop("checked", true);
3477 });
3478 driver.findElement(By.css('.phrase'))
3479 .sendKeys("abandon abandon ability");
3480 selectNetwork("BCH - Bitcoin Cash");
3481 driver.sleep(generateDelay).then(function() {
3482 getFirstAddress(function(address) {
3483 expect(address).toBe("CZnpA9HPmvhuhLLPWJP8rNDpLUYXy1LXFk");
3484 done();
3485 });
3486 });
3487 });
3488
3489 // Bitcoin Cash address can be set to use legacy format
3490 it('Can use legacy format for bitcoin cash addresses', function(done) {
3491 driver.executeScript(function() {
3492 $(".use-bch-legacy-addresses").prop("checked", true);
3493 });
3494 driver.findElement(By.css('.phrase'))
3495 .sendKeys("abandon abandon ability");
3496 selectNetwork("BCH - Bitcoin Cash");
3497 driver.sleep(generateDelay).then(function() {
3498 getFirstAddress(function(address) {
3499 expect(address).toBe("1JKvb6wKtsjNoCRxpZ4DGrbniML7z5U16A");
3500 done();
3501 });
3502 });
3503 });
3504
3505 // End of tests ported from old suit, so no more comments above each test now
3506
3507 it('Can generate more addresses from a custom index', function(done) {
3508 var expectedIndexes = [
3509 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,
3510 40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59
3511 ];
3512 driver.findElement(By.css('.phrase'))
3513 .sendKeys("abandon abandon ability");
3514 driver.sleep(generateDelay).then(function() {
3515 // Set start of next lot of rows to be from index 40
3516 // which means indexes 20-39 will not be in the table.
3517 driver.findElement(By.css('.more-rows-start-index'))
3518 .sendKeys("40");
3519 driver.findElement(By.css('.more'))
3520 .click();
3521 driver.sleep(generateDelay).then(function() {
3522 // Check actual indexes in the table match the expected pattern
3523 driver.findElements(By.css(".index"))
3524 .then(function(els) {
3525 expect(els.length).toBe(expectedIndexes.length);
3526 var testRowAtIndex = function(i) {
3527 if (i >= expectedIndexes.length) {
3528 done();
3529 }
3530 else {
3531 els[i].getText()
3532 .then(function(actualPath) {
3533 var noHardened = actualPath.replace(/'/g, "");
3534 var pathBits = noHardened.split("/")
3535 var lastBit = pathBits[pathBits.length-1];
3536 var actualIndex = parseInt(lastBit);
3537 var expectedIndex = expectedIndexes[i];
3538 expect(actualIndex).toBe(expectedIndex);
3539 testRowAtIndex(i+1);
3540 });
3541 }
3542 }
3543 testRowAtIndex(0);
3544 });
3545 });
3546 });
3547 });
3548
3549 it('Can generate BIP141 addresses with P2WPKH-in-P2SH semanitcs', function(done) {
3550 // Sourced from BIP49 official test specs
3551 driver.findElement(By.css('#bip141-tab a'))
3552 .click();
3553 driver.findElement(By.css('.bip141-path'))
3554 .clear();
3555 driver.findElement(By.css('.bip141-path'))
3556 .sendKeys("m/49'/1'/0'/0");
3557 selectNetwork("BTC - Bitcoin Testnet");
3558 driver.findElement(By.css(".phrase"))
3559 .sendKeys("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about");
3560 driver.sleep(generateDelay).then(function() {
3561 getFirstAddress(function(address) {
3562 expect(address).toBe("2Mww8dCYPUpKHofjgcXcBCEGmniw9CoaiD2");
3563 done();
3564 });
3565 });
3566 });
3567
3568 it('Can generate BIP141 addresses with P2WPKH semanitcs', function(done) {
3569 // This result tested against bitcoinjs-lib test spec for segwit address
3570 // using the first private key of this mnemonic and default path m/0
3571 // https://github.com/bitcoinjs/bitcoinjs-lib/blob/9c8503cab0c6c30a95127042703bc18e8d28c76d/test/integration/addresses.js#L50
3572 // so whilst not directly comparable, substituting the private key produces
3573 // identical results between this tool and the bitcoinjs-lib test.
3574 // Private key generated is:
3575 // L3L8Nu9whawPBNLGtFqDhKut9DKKfG3CQoysupT7BimqVCZsLFNP
3576 driver.findElement(By.css('#bip141-tab a'))
3577 .click();
3578 // Choose P2WPKH
3579 driver.executeScript(function() {
3580 $(".bip141-semantics option[selected]").removeAttr("selected");
3581 $(".bip141-semantics option").filter(function(i,e) {
3582 return $(e).html() == "P2WPKH";
3583 }).prop("selected", true);
3584 $(".bip141-semantics").trigger("change");
3585 });
3586 driver.findElement(By.css(".phrase"))
3587 .sendKeys("abandon abandon ability");
3588 driver.sleep(generateDelay).then(function() {
3589 getFirstAddress(function(address) {
3590 expect(address).toBe("bc1qfwu6a5a3evygrk8zvdxxvz4547lmpyx5vsfxe9");
3591 done();
3592 });
3593 });
3594 });
3595
3596 it('Shows the entropy used by the PRNG when clicking generate', function(done) {
3597 driver.findElement(By.css('.generate')).click();
3598 driver.sleep(generateDelay).then(function() {
3599 driver.findElement(By.css('.entropy'))
3600 .getAttribute("value")
3601 .then(function(entropy) {
3602 expect(entropy).not.toBe("");
3603 done();
3604 });
3605 });
3606 });
3607
3608 it('Shows the index of each word in the mnemonic', function(done) {
3609 driver.findElement(By.css('.phrase'))
3610 .sendKeys("abandon abandon ability");
3611 driver.sleep(generateDelay).then(function() {
3612 driver.findElement(By.css('.use-entropy'))
3613 .click();
3614 driver.findElement(By.css('.word-indexes'))
3615 .getText()
3616 .then(function(indexes) {
3617 expect(indexes).toBe("0, 0, 1");
3618 done();
3619 });
3620 });
3621 });
3622
3623 it('Shows the derivation path for bip84 tab', function(done) {
3624 driver.findElement(By.css('#bip84-tab a'))
3625 .click()
3626 driver.findElement(By.css('.phrase'))
3627 .sendKeys('abandon abandon ability');
3628 driver.sleep(generateDelay).then(function() {
3629 driver.findElement(By.css('#bip84 .path'))
3630 .getAttribute("value")
3631 .then(function(path) {
3632 expect(path).toBe("m/84'/0'/0'/0");
3633 done();
3634 })
3635 });
3636 });
3637
3638 it('Shows the extended private key for bip84 tab', function(done) {
3639 driver.findElement(By.css('#bip84-tab a'))
3640 .click()
3641 driver.findElement(By.css('.phrase'))
3642 .sendKeys('abandon abandon ability');
3643 driver.sleep(generateDelay).then(function() {
3644 driver.findElement(By.css('.extended-priv-key'))
3645 .getAttribute("value")
3646 .then(function(path) {
3647 expect(path).toBe("zprvAev3RKrZ3QVKiUFCfdeMRen1BPDJgdNt1XpxiDy8acSs4kkAGTCvq7HeRYRNNpo8EtEjCFQBWavJwtCUR29y4TUCH4X5RXMcyq48uN8y9BP");
3648 done();
3649 })
3650 });
3651 });
3652
3653 it('Shows the extended public key for bip84 tab', function(done) {
3654 driver.findElement(By.css('#bip84-tab a'))
3655 .click()
3656 driver.findElement(By.css('.phrase'))
3657 .sendKeys('abandon abandon ability');
3658 driver.sleep(generateDelay).then(function() {
3659 driver.findElement(By.css('.extended-pub-key'))
3660 .getAttribute("value")
3661 .then(function(path) {
3662 expect(path).toBe("zpub6suPpqPSsn3cvxKfmfBMnnijjR3o666jNkkZWcNk8wyqwZ5JozXBNuc8Gs7DB3uLwTDvGVTspVEAUQcEjKF3pZHgywVbubdTqbXTUg7usyx");
3663 done();
3664 })
3665 });
3666 });
3667
3668 it('Changes the address list if bip84 account is changed', function(done) {
3669 driver.findElement(By.css('#bip84-tab a'))
3670 .click()
3671 driver.findElement(By.css('#bip84 .account'))
3672 .sendKeys('1');
3673 driver.findElement(By.css('.phrase'))
3674 .sendKeys('abandon abandon ability');
3675 driver.sleep(generateDelay).then(function() {
3676 getFirstAddress(function(address) {
3677 expect(address).toBe("bc1qp7vv669t2fy965jdzvqwrraana89ctd5ewc662");
3678 done();
3679 });
3680 });
3681 });
3682
3683 it('Changes the address list if bip84 change is changed', function(done) {
3684 driver.findElement(By.css('#bip84-tab a'))
3685 .click()
3686 driver.findElement(By.css('#bip84 .change'))
3687 .sendKeys('1');
3688 driver.findElement(By.css('.phrase'))
3689 .sendKeys('abandon abandon ability');
3690 driver.sleep(generateDelay).then(function() {
3691 getFirstAddress(function(address) {
3692 expect(address).toBe("bc1qr39vj6rh06ff05m53uxq8uazehwhccswylhrs2");
3693 done();
3694 });
3695 });
3696 });
3697
3698 it('Passes the official BIP84 test spec for rootpriv', function(done) {
3699 driver.findElement(By.css('#bip84-tab a'))
3700 .click()
3701 driver.findElement(By.css('.phrase'))
3702 .sendKeys('abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about');
3703 driver.sleep(generateDelay).then(function() {
3704 driver.findElement(By.css(".root-key"))
3705 .getAttribute("value")
3706 .then(function(rootKey) {
3707 expect(rootKey).toBe("zprvAWgYBBk7JR8Gjrh4UJQ2uJdG1r3WNRRfURiABBE3RvMXYSrRJL62XuezvGdPvG6GFBZduosCc1YP5wixPox7zhZLfiUm8aunE96BBa4Kei5");
3708 done();
3709 })
3710 });
3711 });
3712
3713 it('Passes the official BIP84 test spec for account 0 xprv', function(done) {
3714 driver.findElement(By.css('#bip84-tab a'))
3715 .click()
3716 driver.findElement(By.css('.phrase'))
3717 .sendKeys('abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about');
3718 driver.sleep(generateDelay).then(function() {
3719 driver.findElement(By.css("#bip84 .account-xprv"))
3720 .getAttribute("value")
3721 .then(function(rootKey) {
3722 expect(rootKey).toBe("zprvAdG4iTXWBoARxkkzNpNh8r6Qag3irQB8PzEMkAFeTRXxHpbF9z4QgEvBRmfvqWvGp42t42nvgGpNgYSJA9iefm1yYNZKEm7z6qUWCroSQnE");
3723 done();
3724 })
3725 });
3726 });
3727
3728 it('Passes the official BIP84 test spec for account 0 xpub', function(done) {
3729 driver.findElement(By.css('#bip84-tab a'))
3730 .click()
3731 driver.findElement(By.css('.phrase'))
3732 .sendKeys('abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about');
3733 driver.sleep(generateDelay).then(function() {
3734 driver.findElement(By.css("#bip84 .account-xpub"))
3735 .getAttribute("value")
3736 .then(function(rootKey) {
3737 expect(rootKey).toBe("zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs");
3738 done();
3739 })
3740 });
3741 });
3742
3743 it('Passes the official BIP84 test spec for account 0 first address', function(done) {
3744 driver.findElement(By.css('#bip84-tab a'))
3745 .click()
3746 driver.findElement(By.css('.phrase'))
3747 .sendKeys('abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about');
3748 driver.sleep(generateDelay).then(function() {
3749 getFirstAddress(function(address) {
3750 expect(address).toBe("bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu");
3751 done();
3752 });
3753 });
3754 });
3755
3756 it('Passes the official BIP84 test spec for account 0 first change address', function(done) {
3757 driver.findElement(By.css('#bip84-tab a'))
3758 .click()
3759 driver.findElement(By.css('.phrase'))
3760 .sendKeys('abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about');
3761 driver.findElement(By.css('#bip84 .change'))
3762 .sendKeys('1');
3763 driver.sleep(generateDelay).then(function() {
3764 getFirstAddress(function(address) {
3765 expect(address).toBe("bc1q8c6fshw2dlwun7ekn9qwf37cu2rn755upcp6el");
3766 done();
3767 });
3768 });
3769 });
3770
3771 it('Can display the table as csv', function(done) {
3772 var headings = "path,address,public key,private key";
3773 var row1 = "m/44'/0'/0'/0/0,1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug,033f5aed5f6cfbafaf223188095b5980814897295f723815fea5d3f4b648d0d0b3,L26cVSpWFkJ6aQkPkKmTzLqTdLJ923e6CzrVh9cmx21QHsoUmrEE";
3774 var row20 = "m/44'/0'/0'/0/19,1KhBy28XLAciXnnRvm71PvQJaETyrxGV55,02b4b3e396434d8cdd20c03ac4aaa07387784d5d867b75987f516f5705ee68cb3a,L4GrDrjReMsCAu5DkLXn79jSb95qR7Zfx7eshybCQZ1qL32MXJab";
3775 driver.findElement(By.css('.phrase'))
3776 .sendKeys('abandon abandon ability');
3777 driver.sleep(generateDelay).then(function() {
3778 driver.findElement(By.css('.csv'))
3779 .getAttribute("value")
3780 .then(function(csv) {
3781 expect(csv).toContain(headings);
3782 expect(csv).toContain(row1);
3783 expect(csv).toContain(row20);
3784 done();
3785 });
3786 });
3787 });
3788
3789 it('LeftPads ethereum keys that are less than 32 bytes', function(done) {
3790 // see https://github.com/iancoleman/bip39/issues/155
3791 selectNetwork("ETH - Ethereum");
3792 driver.findElement(By.css('#bip32-tab a'))
3793 .click()
3794 driver.findElement(By.css('#bip32-path'))
3795 .clear();
3796 driver.findElement(By.css('#bip32-path'))
3797 .sendKeys("m/44'/60'/0'");
3798 driver.findElement(By.css('.phrase'))
3799 .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');
3800 driver.sleep(generateDelay).then(function() {
3801 getFirstAddress(function(address) {
3802 expect(address).toBe("0x8943E785B4a5714FC87a3aFAad1eB1FeB602B118");
3803 done();
3804 });
3805 });
3806 });
3807
3808 it('Can encrypt private keys using BIP38', function(done) {
3809 // see https://github.com/iancoleman/bip39/issues/140
3810 driver.executeScript(function() {
3811 $(".use-bip38").prop("checked", true);
3812 });
3813 driver.findElement(By.css('.bip38-password'))
3814 .sendKeys('bip38password');
3815 driver.findElement(By.css('.rows-to-add'))
3816 .clear();
3817 driver.findElement(By.css('.rows-to-add'))
3818 .sendKeys('1');
3819 driver.findElement(By.css('.phrase'))
3820 .sendKeys('abandon abandon ability');
3821 driver.sleep(bip38delay).then(function() {
3822 // address
3823 getFirstRowValue(function(address) {
3824 expect(address).toBe("1NCvSdumA3ngMM9c4aqU56AM6rqXddfuXB");
3825 // pubkey
3826 getFirstRowValue(function(pubkey) {
3827 expect(pubkey).toBe("043f5aed5f6cfbafaf223188095b5980814897295f723815fea5d3f4b648d0d0b3884a74447ea901729b1e73a999b7520e7cb55b4120e6432c64153ccab8a848e1");
3828 // privkey
3829 getFirstRowValue(function(privkey) {
3830 expect(privkey).toBe("6PRNRiFnj1RoR3sXhymdCvoZCgnUHQpfupNdKkFbWJkwWQEKesWt1EDMDM");
3831 done();
3832 }, ".privkey");
3833 }, ".pubkey");
3834 }, ".address");
3835 });
3836 }, bip38delay + 5000);
3837
3838 it('Shows the checksum for the entropy', function(done) {
3839 driver.findElement(By.css('.use-entropy'))
3840 .click();
3841 driver.findElement(By.css('.entropy'))
3842 .sendKeys("00000000000000000000000000000000");
3843 driver.sleep(generateDelay).then(function() {
3844 driver.findElement(By.css('.checksum'))
3845 .getText()
3846 .then(function(text) {
3847 expect(text).toBe("1");
3848 done();
3849 });
3850 });
3851 });
3852
3853 it('Shows the checksum for the entropy with the correct groupings', function(done) {
3854 driver.findElement(By.css('.use-entropy'))
3855 .click();
3856 // create a checksum of 20 bits, which spans multiple words
3857 driver.findElement(By.css('.entropy'))
3858 .sendKeys("F000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
3859 driver.sleep(generateDelay).then(function() {
3860 driver.findElement(By.css('.checksum'))
3861 .getText()
3862 .then(function(text) {
3863 // first group is 9 bits, second group is 11
3864 expect(text).toBe("011010111 01110000110");
3865 done();
3866 });
3867 });
3868 });
3869
3870 it('Uses vprv for bitcoin testnet p2wpkh', function(done) {
3871 selectNetwork("BTC - Bitcoin Testnet");
3872 driver.findElement(By.css('#bip84-tab a'))
3873 .click()
3874 driver.findElement(By.css('.phrase'))
3875 .sendKeys('abandon abandon ability');
3876 driver.sleep(generateDelay).then(function() {
3877 driver.findElement(By.css('.root-key'))
3878 .getAttribute("value")
3879 .then(function(path) {
3880 expect(path).toBe("vprv9DMUxX4ShgxML9N2YV5CvWEebWrM9aJ5ULpbRRyzyWu6vs4BzTvbfFFrH41N5hVi7MYSfiugd765L3JmAfDM5po36Y8ouCKRDeYQwByCmS7");
3881 done();
3882 })
3883 });
3884 });
3885
3886 it('Shows a warning if generating weak mnemonics', function(done) {
3887 driver.executeScript(function() {
3888 $(".strength option[selected]").removeAttr("selected");
3889 $(".strength option[value=6]").prop("selected", true);
3890 $(".strength").trigger("change");
3891 });
3892 driver.findElement(By.css(".generate-container .warning"))
3893 .getAttribute("class")
3894 .then(function(classes) {
3895 expect(classes).not.toContain("hidden");
3896 done();
3897 });
3898 });
3899
3900 it('Does not show a warning if generating strong mnemonics', function(done) {
3901 driver.executeScript(function() {
3902 $(".strength option[selected]").removeAttr("selected");
3903 $(".strength option[value=12]").prop("selected", true);
3904 });
3905 driver.findElement(By.css(".generate-container .warning"))
3906 .getAttribute("class")
3907 .then(function(classes) {
3908 expect(classes).toContain("hidden");
3909 done();
3910 });
3911 });
3912
3913 it('Shows a warning if overriding weak entropy with longer mnemonics', function(done) {
3914 driver.findElement(By.css('.use-entropy'))
3915 .click();
3916 driver.findElement(By.css('.entropy'))
3917 .sendKeys("0123456789abcdef"); // 6 words
3918 driver.executeScript(function() {
3919 $(".mnemonic-length").val("12").trigger("change");
3920 });
3921 driver.findElement(By.css(".weak-entropy-override-warning"))
3922 .getAttribute("class")
3923 .then(function(classes) {
3924 expect(classes).not.toContain("hidden");
3925 done();
3926 });
3927 });
3928
3929 it('Does not show a warning if entropy is stronger than mnemonic length', function(done) {
3930 driver.findElement(By.css('.use-entropy'))
3931 .click();
3932 driver.findElement(By.css('.entropy'))
3933 .sendKeys("0123456789abcdef0123456789abcdef0123456789abcdef"); // 18 words
3934 driver.executeScript(function() {
3935 $(".mnemonic-length").val("12").trigger("change");
3936 });
3937 driver.findElement(By.css(".weak-entropy-override-warning"))
3938 .getAttribute("class")
3939 .then(function(classes) {
3940 expect(classes).toContain("hidden");
3941 done();
3942 });
3943 });
3944
3945 it('Shows litecoin BIP49 addresses', function(done) {
3946 driver.findElement(By.css('.phrase'))
3947 .sendKeys('abandon abandon ability');
3948 selectNetwork("LTC - Litecoin");
3949 driver.findElement(By.css('#bip49-tab a'))
3950 .click()
3951 // bip49 addresses are shown
3952 driver.sleep(generateDelay).then(function() {
3953 driver.findElement(By.css('#bip49 .available'))
3954 .getAttribute("class")
3955 .then(function(classes) {
3956 expect(classes).not.toContain("hidden");
3957 // check first address
3958 getFirstAddress(function(address) {
3959 expect(address).toBe("MFwLPhsXoBuSLL8cLmW9uK6tChkzduV8qN");
3960 done();
3961 });
3962 });
3963 });
3964 });
3965
3966 it('Can use root keys to generate segwit table rows', function(done) {
3967 // segwit uses ypub / zpub instead of xpub but the root key should still
3968 // be valid regardless of the encoding used to import that key.
3969 // Maybe this breaks the reason for the different extended key prefixes, but
3970 // since the parsed root key is used behind the scenes anyhow this should be
3971 // allowed.
3972 driver.findElement(By.css('#root-key'))
3973 .sendKeys('xprv9s21ZrQH143K2jkGDCeTLgRewT9F2pH5JZs2zDmmjXes34geVnFiuNa8KTvY5WoYvdn4Ag6oYRoB6cXtc43NgJAEqDXf51xPm6fhiMCKwpi');
3974 driver.findElement(By.css('#bip49-tab a'))
3975 .click()
3976 // bip49 addresses are shown
3977 driver.sleep(generateDelay).then(function() {
3978 getFirstAddress(function(address) {
3979 expect(address).toBe("3QG2Y9AA4xZ846gKHZqNf7mvVKbLqMKxr2");
3980 done();
3981 });
3982 });
3983 });
3984
3985 });